root/ext/oci8/oci8.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_INI_BEGIN
  2. php_oci_cleanup_global_handles
  3. PHP_GINIT_FUNCTION
  4. PHP_GSHUTDOWN_FUNCTION
  5. PHP_MINIT_FUNCTION
  6. PHP_RINIT_FUNCTION
  7. PHP_MSHUTDOWN_FUNCTION
  8. PHP_RSHUTDOWN_FUNCTION
  9. PHP_MINFO_FUNCTION
  10. php_oci_connection_list_dtor
  11. php_oci_pconnection_list_dtor
  12. php_oci_pconnection_list_np_dtor
  13. php_oci_statement_list_dtor
  14. php_oci_descriptor_list_dtor
  15. php_oci_collection_list_dtor
  16. php_oci_define_hash_dtor
  17. php_oci_bind_hash_dtor
  18. php_oci_column_hash_dtor
  19. php_oci_descriptor_flush_hash_dtor
  20. php_oci_connection_descriptors_free
  21. php_oci_error
  22. php_oci_fetch_errmsg
  23. php_oci_fetch_sqltext_offset
  24. php_oci_do_connect
  25. php_oci_do_connect_ex
  26. php_oci_connection_ping
  27. php_oci_connection_status
  28. php_oci_connection_rollback
  29. php_oci_connection_commit
  30. php_oci_connection_close
  31. php_oci_connection_release
  32. php_oci_password_change
  33. php_oci_client_get_version
  34. php_oci_server_get_version
  35. php_oci_column_to_zval
  36. php_oci_fetch_row
  37. php_oci_persistent_helper
  38. php_oci_create_spool
  39. php_oci_get_spool
  40. php_oci_create_env
  41. php_oci_old_create_session
  42. php_oci_create_session
  43. php_oci_spool_list_dtor
  44. php_oci_spool_close
  45. php_oci_ping_init

/*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2013 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
   |          Thies C. Arntzen <thies@thieso.net>                         |
   |          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: 44bfa713983a99b3e59477f6532e5fb51b6dee94 $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_ini.h"
#include "ext/standard/php_smart_str.h"

#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef PHP_WIN32
#include "win32/php_stdint.h"
#endif

#if HAVE_OCI8

#if PHP_MAJOR_VERSION > 5
#error This version of the PHP OCI8 extension is not compatible with PHP 6 or later
#elif PHP_MAJOR_VERSION < 5
#ifdef ZTS
#error The PHP OCI8 extension does not support ZTS mode in PHP 4
#endif
#endif

#include "php_oci8.h"
#include "php_oci8_int.h"
#include "zend_hash.h"

#if defined(HAVE_STDINT_H) || defined(PHP_WIN32)
#define OCI8_INT_TO_PTR(I)  ((void *)(intptr_t)(I))
#define OCI8_PTR_TO_INT(P)  ((int)(intptr_t)(P))
#else
#define OCI8_INT_TO_PTR(I)  ((void *)(I))
#define OCI8_PTR_TO_INT(P)  ((int)(P))
#endif

ZEND_DECLARE_MODULE_GLOBALS(oci)
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
/* This "if" allows PECL builds from this file to be portable to older PHP releases */
static PHP_GINIT_FUNCTION(oci);
static PHP_GSHUTDOWN_FUNCTION(oci);
#endif

/* Allow PHP 5.3 branch to be used in PECL for 5.x compatible builds */
#ifndef Z_ADDREF_P
#define Z_ADDREF_P(x) ZVAL_ADDREF(x)
#endif

/* For a user friendly message about environment setup */
#if defined(PHP_WIN32)
#define PHP_OCI8_LIB_PATH_MSG "PATH"
#elif defined(__APPLE__)
#define PHP_OCI8_LIB_PATH_MSG "DYLD_LIBRARY_PATH"
#elif defined(_AIX)
#define PHP_OCI8_LIB_PATH_MSG "LIBPATH"
#elif defined(__hpux)
#define PHP_OCI8_LIB_PATH_MSG "SHLIB_PATH"
#else
#define PHP_OCI8_LIB_PATH_MSG "LD_LIBRARY_PATH"
#endif

/* True globals, no need for thread safety */
int le_connection;
int le_pconnection;
int le_statement;
int le_descriptor;
int le_psessionpool;
int le_collection;

zend_class_entry *oci_lob_class_entry_ptr;
zend_class_entry *oci_coll_class_entry_ptr;

#ifndef SQLT_BFILEE
#define SQLT_BFILEE 114
#endif
#ifndef SQLT_CFILEE
#define SQLT_CFILEE 115
#endif

#ifdef OCI_ERROR_MAXMSG_SIZE2
/* Bigger size is defined from 11.2.0.3 onwards */
#define PHP_OCI_ERRBUF_LEN OCI_ERROR_MAXMSG_SIZE2
#else
#define PHP_OCI_ERRBUF_LEN OCI_ERROR_MAXMSG_SIZE
#endif 

#if ZEND_MODULE_API_NO > 20020429
#define ONUPDATELONGFUNC OnUpdateLong
#else
#define ONUPDATELONGFUNC OnUpdateInt
#endif

#ifdef ZTS
#define PHP_OCI_INIT_MODE (OCI_DEFAULT | OCI_OBJECT | OCI_THREADED | OCI_NO_MUTEX)
#else
#define PHP_OCI_INIT_MODE (OCI_DEFAULT | OCI_OBJECT)
#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_pconnection_list_np_dtor (zend_rsrc_list_entry * TSRMLS_DC);
static void php_oci_statement_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
static void php_oci_descriptor_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC);
static void php_oci_collection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);

static int php_oci_persistent_helper(zend_rsrc_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);
static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC);

static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC);
static int php_oci_create_session(php_oci_connection *connection, php_oci_spool *session_pool, char *dbname, int dbname_len, char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, int session_mode TSRMLS_DC);
static int php_oci_old_create_session(php_oci_connection *connection, char *dbname, int dbname_len, char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, int session_mode TSRMLS_DC);
static php_oci_spool *php_oci_get_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, int charsetid TSRMLS_DC);
static php_oci_spool *php_oci_create_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, char *hash_key, int hash_key_len, int charsetid TSRMLS_DC);
static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC);
/* }}} */

/* {{{ dynamically loadable module stuff */
#if defined(COMPILE_DL_OCI8) || defined(COMPILE_DL_OCI8_11G)
ZEND_GET_MODULE(oci8)
#endif /* COMPILE_DL */
/* }}} */

#ifdef ZEND_ENGINE_2

/* {{{ Function arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_define_by_name, 0, 0, 3)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_name)
        ZEND_ARG_INFO(1, variable)
        ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_bind_by_name, 0, 0, 3)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_name)
        ZEND_ARG_INFO(1, variable)
        ZEND_ARG_INFO(0, maximum_length)
        ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_bind_array_by_name, 0, 0, 4)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_name)
        ZEND_ARG_INFO(1, variable)
        ZEND_ARG_INFO(0, maximum_array_length)
        ZEND_ARG_INFO(0, maximum_item_length)
        ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_descriptor, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_save, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, data)
        ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_import, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_load, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_read, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_eof, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_tell, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_rewind, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_seek, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, offset)
        ZEND_ARG_INFO(0, whence)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_size, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, string)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_append, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor_to)
        ZEND_ARG_INFO(0, lob_descriptor_from)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_truncate, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_erase, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, offset)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_flush, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, flag)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_ocisetbufferinglob, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_ocigetbufferinglob, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_copy, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor_to)
        ZEND_ARG_INFO(0, lob_descriptor_from)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_is_equal, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, lob_descriptor)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_export, 0, 0, 2)
        ZEND_ARG_INFO(0, lob_descriptor)
        ZEND_ARG_INFO(0, filename)
        ZEND_ARG_INFO(0, start)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_descriptor, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_rollback, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_commit, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_name, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_size, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number_or_name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_scale, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_precision, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_type, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_type_raw, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_is_null, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number_or_name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_internal_debug, 0, 0, 1)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_execute, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_cancel, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_ocifetchinto, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(1, result)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_all, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(1, output)
        ZEND_ARG_INFO(0, skip)
        ZEND_ARG_INFO(0, maximum_rows)
        ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_object, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_row, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_assoc, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_array, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_statement, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_close, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_connect, 0, 0, 2)
        ZEND_ARG_INFO(0, username)
        ZEND_ARG_INFO(0, password)
        ZEND_ARG_INFO(0, connection_string)
        ZEND_ARG_INFO(0, character_set)
        ZEND_ARG_INFO(0, session_mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_connect, 0, 0, 2)
        ZEND_ARG_INFO(0, username)
        ZEND_ARG_INFO(0, password)
        ZEND_ARG_INFO(0, connection_string)
        ZEND_ARG_INFO(0, character_set)
        ZEND_ARG_INFO(0, session_mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_pconnect, 0, 0, 2)
        ZEND_ARG_INFO(0, username)
        ZEND_ARG_INFO(0, password)
        ZEND_ARG_INFO(0, connection_string)
        ZEND_ARG_INFO(0, character_set)
        ZEND_ARG_INFO(0, session_mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_error, 0, 0, 0)
        ZEND_ARG_INFO(0, connection_or_statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_num_fields, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_parse, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, sql_text)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_prefetch, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, number_of_rows)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_client_identifier, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, client_identifier)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_edition, 0, 0, 1)
        ZEND_ARG_INFO(0, edition_name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_module_name, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, module_name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_action, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, action)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_client_info, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, client_information)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_password_change, 0, 0, 4)
        ZEND_ARG_INFO(0, connection_resource_or_connection_string)
        ZEND_ARG_INFO(0, username)
        ZEND_ARG_INFO(0, old_password)
        ZEND_ARG_INFO(0, new_password)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_cursor, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_result, 0, 0, 2)
        ZEND_ARG_INFO(0, statement_resource)
        ZEND_ARG_INFO(0, column_number_or_name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_client_version, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_server_version, 0, 0, 1)
        ZEND_ARG_INFO(0, connection_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_statement_type, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_num_rows, 0, 0, 1)
        ZEND_ARG_INFO(0, statement_resource)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_collection, 0, 0, 1)
        ZEND_ARG_INFO(0, collection)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_append, 0, 0, 2)
        ZEND_ARG_INFO(0, collection)
        ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_get, 0, 0, 2)
        ZEND_ARG_INFO(0, collection)
        ZEND_ARG_INFO(0, index)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_assign, 0, 0, 2)
        ZEND_ARG_INFO(0, collection_to)
        ZEND_ARG_INFO(0, collection_from)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_assign, 0, 0, 3)
        ZEND_ARG_INFO(0, collection)
        ZEND_ARG_INFO(0, index)
        ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_size, 0, 0, 1)
        ZEND_ARG_INFO(0, collection)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_max, 0, 0, 1)
        ZEND_ARG_INFO(0, collection)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_trim, 0, 0, 2)
        ZEND_ARG_INFO(0, collection)
        ZEND_ARG_INFO(0, number)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_collection, 0, 0, 2)
        ZEND_ARG_INFO(0, connection_resource)
        ZEND_ARG_INFO(0, type_name)
        ZEND_ARG_INFO(0, schema_name)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ LOB Method arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_save_method, 0, 0, 1)
        ZEND_ARG_INFO(0, data)
        ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_import_method, 0, 0, 1)
        ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_load_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_read_method, 0, 0, 1)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_eof_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_tell_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_rewind_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_seek_method, 0, 0, 1)
        ZEND_ARG_INFO(0, offset)
        ZEND_ARG_INFO(0, whence)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_size_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write_method, 0, 0, 1)
        ZEND_ARG_INFO(0, string)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_append_method, 0, 0, 1)
        ZEND_ARG_INFO(0, lob_descriptor_from)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_truncate_method, 0, 0, 0)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_erase_method, 0, 0, 0)
        ZEND_ARG_INFO(0, offset)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_flush_method, 0, 0, 0)
        ZEND_ARG_INFO(0, flag)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_setbuffering_method, 0, 0, 1)
        ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_getbuffering_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_export_method, 0, 0, 1)
        ZEND_ARG_INFO(0, filename)
        ZEND_ARG_INFO(0, start)
        ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write_temporary_method, 0, 0, 1)
        ZEND_ARG_INFO(0, data)
        ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_close_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_free_descriptor_method, 0)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ Collection Method arginfo */
ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_free_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_append_method, 0, 0, 1)
        ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_get_method, 0, 0, 1)
        ZEND_ARG_INFO(0, index)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_assign_method, 0, 0, 1)
        ZEND_ARG_INFO(0, collection_from)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_assign_method, 0, 0, 2)
        ZEND_ARG_INFO(0, index)
        ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_size_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_max_method, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_trim_method, 0, 0, 1)
        ZEND_ARG_INFO(0, number)
ZEND_END_ARG_INFO()
/* }}} */

#else /* ZEND_ENGINE_2 */
/* {{{ Keep the old arginfo behavior when building with PHP 4 */

static unsigned char arginfo_ocifetchinto[]  = { 2, BYREF_NONE, BYREF_FORCE };
static unsigned char arginfo_oci_fetch_all[] = { 2, BYREF_NONE, BYREF_FORCE };
static unsigned char arginfo_oci_define_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
static unsigned char arginfo_oci_bind_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
static unsigned char arginfo_oci_bind_array_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };

#define arginfo_oci_free_descriptor                                             NULL
#define arginfo_oci_lob_save                                                    NULL
#define arginfo_oci_lob_import                                                  NULL
#define arginfo_oci_lob_load                                                    NULL
#define arginfo_oci_lob_read                                                    NULL
#define arginfo_oci_lob_eof                                                             NULL
#define arginfo_oci_lob_tell                                                    NULL
#define arginfo_oci_lob_rewind                                                  NULL
#define arginfo_oci_lob_seek                                                    NULL
#define arginfo_oci_lob_size                                                    NULL
#define arginfo_oci_lob_write                                                   NULL
#define arginfo_oci_lob_append                                                  NULL
#define arginfo_oci_lob_truncate                                                NULL
#define arginfo_oci_lob_erase                                                   NULL
#define arginfo_oci_lob_flush                                                   NULL
#define arginfo_ocisetbufferinglob                                              NULL
#define arginfo_ocigetbufferinglob                                              NULL
#define arginfo_oci_lob_copy                                                    NULL
#define arginfo_oci_lob_is_equal                                                NULL
#define arginfo_oci_lob_export                                                  NULL
#define arginfo_oci_new_descriptor                                              NULL
#define arginfo_oci_rollback                                                    NULL
#define arginfo_oci_commit                                                              NULL
#define arginfo_oci_field_name                                                  NULL
#define arginfo_oci_field_size                                                  NULL
#define arginfo_oci_field_scale                                                 NULL
#define arginfo_oci_field_precision                                             NULL
#define arginfo_oci_field_type                                                  NULL
#define arginfo_oci_field_type_raw                                              NULL
#define arginfo_oci_field_is_null                                               NULL
#define arginfo_oci_internal_debug                                              NULL
#define arginfo_oci_execute                                                             NULL
#define arginfo_oci_cancel                                                              NULL
#define arginfo_oci_fetch                                                               NULL
#define arginfo_oci_fetch_object                                                NULL
#define arginfo_oci_fetch_row                                                   NULL
#define arginfo_oci_fetch_assoc                                                 NULL
#define arginfo_oci_fetch_array                                                 NULL
#define arginfo_oci_free_statement                                              NULL
#define arginfo_oci_close                                                               NULL
#define arginfo_oci_new_connect                                                 NULL
#define arginfo_oci_connect                                                             NULL
#define arginfo_oci_pconnect                                                    NULL
#define arginfo_oci_error                                                               NULL
#define arginfo_oci_num_fields                                                  NULL
#define arginfo_oci_parse                                                               NULL
#define arginfo_oci_set_prefetch                                                NULL
#define arginfo_oci_set_client_identifier                               NULL
#define arginfo_oci_set_edition                                                 NULL
#define arginfo_oci_set_module_name                                             NULL
#define arginfo_oci_set_action                                                  NULL
#define arginfo_oci_set_client_info                                             NULL
#define arginfo_oci_password_change                                             NULL
#define arginfo_oci_new_cursor                                                  NULL
#define arginfo_oci_result                                                              NULL
#define arginfo_oci_client_version                                              NULL
#define arginfo_oci_server_version                                              NULL
#define arginfo_oci_statement_type                                              NULL
#define arginfo_oci_num_rows                                                    NULL
#define arginfo_oci_free_collection                                             NULL
#define arginfo_oci_collection_append                                   NULL
#define arginfo_oci_collection_element_get                              NULL
#define arginfo_oci_collection_assign                                   NULL
#define arginfo_oci_collection_element_assign                   NULL
#define arginfo_oci_collection_size                                             NULL
#define arginfo_oci_collection_max                                              NULL
#define arginfo_oci_collection_trim                                             NULL
#define arginfo_oci_new_collection                                              NULL
#define arginfo_oci_lob_size_method                                             NULL
#define arginfo_oci_lob_getbuffering_method                             NULL
#define arginfo_oci_lob_close_method                                    NULL
#define arginfo_oci_lob_save_method                                             NULL
#define arginfo_oci_lob_import_method                                   NULL
#define arginfo_oci_lob_read_method                                             NULL
#define arginfo_oci_lob_seek_method                                             NULL
#define arginfo_oci_lob_write_method                                    NULL
#define arginfo_oci_lob_append_method                                   NULL
#define arginfo_oci_lob_truncate_method                                 NULL
#define arginfo_oci_lob_erase_method                                    NULL
#define arginfo_oci_lob_flush_method                                    NULL
#define arginfo_oci_lob_setbuffering_method                             NULL
#define arginfo_oci_lob_export_method                                   NULL
#define arginfo_oci_lob_write_temporary_method                  NULL
#define arginfo_oci_lob_load_method                                             NULL
#define arginfo_oci_lob_tell_method                                             NULL
#define arginfo_oci_lob_rewind_method                                   NULL
#define arginfo_oci_lob_eof_method                                              NULL
#define arginfo_oci_free_descriptor_method                              NULL
#define arginfo_oci_collection_append_method                    NULL
#define arginfo_oci_collection_element_get_method               NULL
#define arginfo_oci_collection_assign_method                    NULL
#define arginfo_oci_collection_size_method                              NULL
#define arginfo_oci_collection_element_assign_method    NULL
#define arginfo_oci_collection_max_method                               NULL
#define arginfo_oci_collection_trim_method                              NULL
#define arginfo_oci_collection_free_method                              NULL
/* }}} */
#endif /* ZEND_ENGINE_2 */

/* {{{ extension function prototypes
*/
PHP_FUNCTION(oci_bind_by_name);
PHP_FUNCTION(oci_bind_array_by_name);
PHP_FUNCTION(oci_define_by_name);
PHP_FUNCTION(oci_field_is_null);
PHP_FUNCTION(oci_field_name);
PHP_FUNCTION(oci_field_size);
PHP_FUNCTION(oci_field_scale);
PHP_FUNCTION(oci_field_precision);
PHP_FUNCTION(oci_field_type);
PHP_FUNCTION(oci_field_type_raw);
PHP_FUNCTION(oci_execute);
PHP_FUNCTION(oci_fetch);
PHP_FUNCTION(oci_cancel);
PHP_FUNCTION(ocifetchinto);
PHP_FUNCTION(oci_fetch_object);
PHP_FUNCTION(oci_fetch_row);
PHP_FUNCTION(oci_fetch_assoc);
PHP_FUNCTION(oci_fetch_array);
PHP_FUNCTION(ocifetchstatement);
PHP_FUNCTION(oci_fetch_all);
PHP_FUNCTION(oci_free_statement);
PHP_FUNCTION(oci_internal_debug);
PHP_FUNCTION(oci_close);
PHP_FUNCTION(oci_connect);
PHP_FUNCTION(oci_new_connect);
PHP_FUNCTION(oci_pconnect);
PHP_FUNCTION(oci_error);
PHP_FUNCTION(oci_free_descriptor);
PHP_FUNCTION(oci_commit);
PHP_FUNCTION(oci_rollback);
PHP_FUNCTION(oci_new_descriptor);
PHP_FUNCTION(oci_num_fields);
PHP_FUNCTION(oci_parse);
PHP_FUNCTION(oci_new_cursor);
PHP_FUNCTION(oci_result);
PHP_FUNCTION(oci_client_version);
PHP_FUNCTION(oci_server_version);
PHP_FUNCTION(oci_statement_type);
PHP_FUNCTION(oci_num_rows);
PHP_FUNCTION(oci_set_prefetch);
PHP_FUNCTION(oci_set_client_identifier);
PHP_FUNCTION(oci_set_edition);
PHP_FUNCTION(oci_set_module_name);
PHP_FUNCTION(oci_set_action);
PHP_FUNCTION(oci_set_client_info);
PHP_FUNCTION(oci_password_change);
PHP_FUNCTION(oci_lob_save);
PHP_FUNCTION(oci_lob_import);
PHP_FUNCTION(oci_lob_export);
PHP_FUNCTION(oci_lob_load);
PHP_FUNCTION(oci_lob_tell);
PHP_FUNCTION(oci_lob_write);
PHP_FUNCTION(oci_lob_append);
PHP_FUNCTION(oci_lob_copy);
PHP_FUNCTION(oci_lob_truncate);
PHP_FUNCTION(oci_lob_erase);
PHP_FUNCTION(oci_lob_flush);
PHP_FUNCTION(ocisetbufferinglob);
PHP_FUNCTION(ocigetbufferinglob);
PHP_FUNCTION(oci_lob_is_equal);
PHP_FUNCTION(oci_lob_rewind);
PHP_FUNCTION(oci_lob_read);
PHP_FUNCTION(oci_lob_eof);
PHP_FUNCTION(oci_lob_seek);
PHP_FUNCTION(oci_lob_size);
PHP_FUNCTION(oci_lob_write_temporary);
PHP_FUNCTION(oci_lob_close);
PHP_FUNCTION(oci_new_collection);
PHP_FUNCTION(oci_free_collection);
PHP_FUNCTION(oci_collection_append);
PHP_FUNCTION(oci_collection_element_get);
PHP_FUNCTION(oci_collection_element_assign);
PHP_FUNCTION(oci_collection_assign);
PHP_FUNCTION(oci_collection_size);
PHP_FUNCTION(oci_collection_max);
PHP_FUNCTION(oci_collection_trim);
/* }}} */

/* {{{ extension definition structures
*/
static
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
/* This "if" allows PECL builds from this file to be portable to older PHP releases */
const
#endif
zend_function_entry php_oci_functions[] = {
        PHP_FE(oci_define_by_name,                      arginfo_oci_define_by_name)
        PHP_FE(oci_bind_by_name,                        arginfo_oci_bind_by_name)
        PHP_FE(oci_bind_array_by_name,          arginfo_oci_bind_array_by_name)
        PHP_FE(oci_field_is_null,                       arginfo_oci_field_is_null)
        PHP_FE(oci_field_name,                          arginfo_oci_field_name)
        PHP_FE(oci_field_size,                          arginfo_oci_field_size)
        PHP_FE(oci_field_scale,                         arginfo_oci_field_scale)
        PHP_FE(oci_field_precision,                     arginfo_oci_field_precision)
        PHP_FE(oci_field_type,                          arginfo_oci_field_type)
        PHP_FE(oci_field_type_raw,                      arginfo_oci_field_type_raw)
        PHP_FE(oci_execute,                                     arginfo_oci_execute)
        PHP_FE(oci_cancel,                                      arginfo_oci_cancel)
        PHP_FE(oci_fetch,                                       arginfo_oci_fetch)
        PHP_FE(oci_fetch_object,                        arginfo_oci_fetch_object)
        PHP_FE(oci_fetch_row,                           arginfo_oci_fetch_row)
        PHP_FE(oci_fetch_assoc,                         arginfo_oci_fetch_assoc)
        PHP_FE(oci_fetch_array,                         arginfo_oci_fetch_array)
        PHP_FE(ocifetchinto,                            arginfo_ocifetchinto)
        PHP_FE(oci_fetch_all,                           arginfo_oci_fetch_all)
        PHP_FE(oci_free_statement,                      arginfo_oci_free_statement)
        PHP_FE(oci_internal_debug,                      arginfo_oci_internal_debug)
        PHP_FE(oci_num_fields,                          arginfo_oci_num_fields)
        PHP_FE(oci_parse,                                       arginfo_oci_parse)
        PHP_FE(oci_new_cursor,                          arginfo_oci_new_cursor)
        PHP_FE(oci_result,                                      arginfo_oci_result)
        PHP_FE(oci_client_version,                      arginfo_oci_client_version)
        PHP_FE(oci_server_version,                      arginfo_oci_server_version)
        PHP_FE(oci_statement_type,                      arginfo_oci_statement_type)
        PHP_FE(oci_num_rows,                            arginfo_oci_num_rows)
        PHP_FE(oci_close,                                       arginfo_oci_close)
        PHP_FE(oci_connect,                                     arginfo_oci_connect)
        PHP_FE(oci_new_connect,                         arginfo_oci_new_connect)
        PHP_FE(oci_pconnect,                            arginfo_oci_pconnect)
        PHP_FE(oci_error,                                       arginfo_oci_error)
        PHP_FE(oci_free_descriptor,                     arginfo_oci_free_descriptor)
        PHP_FE(oci_lob_save,                            arginfo_oci_lob_save)
        PHP_FE(oci_lob_import,                          arginfo_oci_lob_import)
        PHP_FE(oci_lob_size,                            arginfo_oci_lob_size)
        PHP_FE(oci_lob_load,                            arginfo_oci_lob_load)
        PHP_FE(oci_lob_read,                            arginfo_oci_lob_read)
        PHP_FE(oci_lob_eof,                                     arginfo_oci_lob_eof)
        PHP_FE(oci_lob_tell,                            arginfo_oci_lob_tell)
        PHP_FE(oci_lob_truncate,                        arginfo_oci_lob_truncate)
        PHP_FE(oci_lob_erase,                           arginfo_oci_lob_erase)
        PHP_FE(oci_lob_flush,                           arginfo_oci_lob_flush)
        PHP_FE(ocisetbufferinglob,                      arginfo_ocisetbufferinglob)
        PHP_FE(ocigetbufferinglob,                      arginfo_ocigetbufferinglob)
        PHP_FE(oci_lob_is_equal,                        arginfo_oci_lob_is_equal)
        PHP_FE(oci_lob_rewind,                          arginfo_oci_lob_rewind)
        PHP_FE(oci_lob_write,                           arginfo_oci_lob_write)
        PHP_FE(oci_lob_append,                          arginfo_oci_lob_append)
        PHP_FE(oci_lob_copy,                            arginfo_oci_lob_copy)
        PHP_FE(oci_lob_export,                          arginfo_oci_lob_export)
        PHP_FE(oci_lob_seek,                            arginfo_oci_lob_seek)
        PHP_FE(oci_commit,                                      arginfo_oci_commit)
        PHP_FE(oci_rollback,                            arginfo_oci_rollback)
        PHP_FE(oci_new_descriptor,                      arginfo_oci_new_descriptor)
        PHP_FE(oci_set_prefetch,                        arginfo_oci_set_prefetch)
        PHP_FE(oci_set_client_identifier,       arginfo_oci_set_client_identifier)
        PHP_FE(oci_set_edition,                         arginfo_oci_set_edition)
        PHP_FE(oci_set_module_name,                     arginfo_oci_set_module_name)
        PHP_FE(oci_set_action,                          arginfo_oci_set_action)
        PHP_FE(oci_set_client_info,                     arginfo_oci_set_client_info)
        PHP_FE(oci_password_change,                     arginfo_oci_password_change)
        PHP_FE(oci_free_collection,                     arginfo_oci_free_collection)
        PHP_FE(oci_collection_append,           arginfo_oci_collection_append)
        PHP_FE(oci_collection_element_get,      arginfo_oci_collection_element_get)
        PHP_FE(oci_collection_element_assign,   arginfo_oci_collection_element_assign)
        PHP_FE(oci_collection_assign,           arginfo_oci_collection_assign)
        PHP_FE(oci_collection_size,                     arginfo_oci_collection_size)
        PHP_FE(oci_collection_max,                      arginfo_oci_collection_max)
        PHP_FE(oci_collection_trim,                     arginfo_oci_collection_trim)
        PHP_FE(oci_new_collection,                      arginfo_oci_new_collection)

        PHP_FALIAS(oci_free_cursor,             oci_free_statement,             arginfo_oci_free_statement)
        PHP_FALIAS(ocifreecursor,               oci_free_statement,             arginfo_oci_free_statement)
        PHP_FALIAS(ocibindbyname,               oci_bind_by_name,               arginfo_oci_bind_by_name)
        PHP_FALIAS(ocidefinebyname,             oci_define_by_name,             arginfo_oci_define_by_name)
        PHP_FALIAS(ocicolumnisnull,             oci_field_is_null,              arginfo_oci_field_is_null)
        PHP_FALIAS(ocicolumnname,               oci_field_name,                 arginfo_oci_field_name)
        PHP_FALIAS(ocicolumnsize,               oci_field_size,                 arginfo_oci_field_size)
        PHP_FALIAS(ocicolumnscale,              oci_field_scale,                arginfo_oci_field_scale)
        PHP_FALIAS(ocicolumnprecision,  oci_field_precision,    arginfo_oci_field_precision)
        PHP_FALIAS(ocicolumntype,               oci_field_type,                 arginfo_oci_field_type)
        PHP_FALIAS(ocicolumntyperaw,    oci_field_type_raw,             arginfo_oci_field_type_raw)
        PHP_FALIAS(ociexecute,                  oci_execute,                    arginfo_oci_execute)
        PHP_FALIAS(ocicancel,                   oci_cancel,                             arginfo_oci_cancel)
        PHP_FALIAS(ocifetch,                    oci_fetch,                              arginfo_oci_fetch)
        PHP_FALIAS(ocifetchstatement,   oci_fetch_all,                  arginfo_oci_fetch_all)
        PHP_FALIAS(ocifreestatement,    oci_free_statement,             arginfo_oci_free_statement)
        PHP_FALIAS(ociinternaldebug,    oci_internal_debug,             arginfo_oci_internal_debug)
        PHP_FALIAS(ocinumcols,                  oci_num_fields,                 arginfo_oci_num_fields)
        PHP_FALIAS(ociparse,                    oci_parse,                              arginfo_oci_parse)
        PHP_FALIAS(ocinewcursor,                oci_new_cursor,                 arginfo_oci_new_cursor)
        PHP_FALIAS(ociresult,                   oci_result,                             arginfo_oci_result)
        PHP_FALIAS(ociserverversion,    oci_server_version,             arginfo_oci_server_version)
        PHP_FALIAS(ocistatementtype,    oci_statement_type,             arginfo_oci_statement_type)
        PHP_FALIAS(ocirowcount,                 oci_num_rows,                   arginfo_oci_num_rows)
        PHP_FALIAS(ocilogoff,                   oci_close,                              arginfo_oci_close)
        PHP_FALIAS(ocilogon,                    oci_connect,                    arginfo_oci_connect)
        PHP_FALIAS(ocinlogon,                   oci_new_connect,                arginfo_oci_new_connect)
        PHP_FALIAS(ociplogon,                   oci_pconnect,                   arginfo_oci_pconnect)
        PHP_FALIAS(ocierror,                    oci_error,                              arginfo_oci_error)
        PHP_FALIAS(ocifreedesc,                 oci_free_descriptor,    arginfo_oci_free_descriptor)
        PHP_FALIAS(ocisavelob,                  oci_lob_save,                   arginfo_oci_lob_save)
        PHP_FALIAS(ocisavelobfile,              oci_lob_import,                 arginfo_oci_lob_import)
        PHP_FALIAS(ociwritelobtofile,   oci_lob_export,                 arginfo_oci_lob_export)
        PHP_FALIAS(ociloadlob,                  oci_lob_load,                   arginfo_oci_lob_load)
        PHP_FALIAS(ocicommit,                   oci_commit,                             arginfo_oci_commit)
        PHP_FALIAS(ocirollback,                 oci_rollback,                   arginfo_oci_rollback)
        PHP_FALIAS(ocinewdescriptor,    oci_new_descriptor,             arginfo_oci_new_descriptor)
        PHP_FALIAS(ocisetprefetch,              oci_set_prefetch,               arginfo_oci_set_prefetch)
        PHP_FALIAS(ocipasswordchange,   oci_password_change,    arginfo_oci_password_change)
        PHP_FALIAS(ocifreecollection,   oci_free_collection,    arginfo_oci_free_collection)
        PHP_FALIAS(ocinewcollection,    oci_new_collection,             arginfo_oci_new_collection)
        PHP_FALIAS(ocicollappend,               oci_collection_append,  arginfo_oci_collection_append)
        PHP_FALIAS(ocicollgetelem,              oci_collection_element_get,             arginfo_oci_collection_element_get)
        PHP_FALIAS(ocicollassignelem,   oci_collection_element_assign,  arginfo_oci_collection_element_assign)
        PHP_FALIAS(ocicollsize,                 oci_collection_size,    arginfo_oci_collection_size)
        PHP_FALIAS(ocicollmax,                  oci_collection_max,             arginfo_oci_collection_max)
        PHP_FALIAS(ocicolltrim,                 oci_collection_trim,    arginfo_oci_collection_trim)
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION >= 7) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
        PHP_FE_END
#else
        {NULL,NULL,NULL}
#endif
};

static
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
/* This "if" allows PECL builds from this file to be portable to older PHP releases */
const
#endif
zend_function_entry php_oci_lob_class_functions[] = {
        PHP_FALIAS(load,                oci_lob_load,                   arginfo_oci_lob_load_method)
        PHP_FALIAS(tell,                oci_lob_tell,                   arginfo_oci_lob_tell_method)
        PHP_FALIAS(truncate,    oci_lob_truncate,               arginfo_oci_lob_truncate_method)
        PHP_FALIAS(erase,               oci_lob_erase,                  arginfo_oci_lob_erase_method)
        PHP_FALIAS(flush,               oci_lob_flush,                  arginfo_oci_lob_flush_method)
        PHP_FALIAS(setbuffering,ocisetbufferinglob,             arginfo_oci_lob_setbuffering_method)
        PHP_FALIAS(getbuffering,ocigetbufferinglob,             arginfo_oci_lob_getbuffering_method)
        PHP_FALIAS(rewind,              oci_lob_rewind,                 arginfo_oci_lob_rewind_method)
        PHP_FALIAS(read,                oci_lob_read,                   arginfo_oci_lob_read_method)
        PHP_FALIAS(eof,                 oci_lob_eof,                    arginfo_oci_lob_eof_method)
        PHP_FALIAS(seek,                oci_lob_seek,                   arginfo_oci_lob_seek_method)
        PHP_FALIAS(write,               oci_lob_write,                  arginfo_oci_lob_write_method)
        PHP_FALIAS(append,              oci_lob_append,                 arginfo_oci_lob_append_method)
        PHP_FALIAS(size,                oci_lob_size,                   arginfo_oci_lob_size_method)
        PHP_FALIAS(writetofile, oci_lob_export,                 arginfo_oci_lob_export_method)
        PHP_FALIAS(export,              oci_lob_export,                 arginfo_oci_lob_export_method)
        PHP_FALIAS(import,              oci_lob_import,                 arginfo_oci_lob_import_method)
        PHP_FALIAS(writetemporary,      oci_lob_write_temporary,        arginfo_oci_lob_write_temporary_method)
        PHP_FALIAS(close,                       oci_lob_close,                          arginfo_oci_lob_close_method)
        PHP_FALIAS(save,                oci_lob_save,                   arginfo_oci_lob_save_method)
        PHP_FALIAS(savefile,    oci_lob_import,                 arginfo_oci_lob_import_method)
        PHP_FALIAS(free,                oci_free_descriptor,    arginfo_oci_free_descriptor_method)
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION >= 7) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
        PHP_FE_END
#else
        {NULL,NULL,NULL}
#endif
};

static
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
/* This "if" allows PECL builds from this file to be portable to older PHP releases */
const
#endif
zend_function_entry php_oci_coll_class_functions[] = {
        PHP_FALIAS(append,                oci_collection_append,                        arginfo_oci_collection_append_method)
        PHP_FALIAS(getelem,               oci_collection_element_get,           arginfo_oci_collection_element_get_method)
        PHP_FALIAS(assignelem,    oci_collection_element_assign,        arginfo_oci_collection_element_assign_method)
        PHP_FALIAS(assign,                oci_collection_assign,                        arginfo_oci_collection_assign_method)
        PHP_FALIAS(size,                  oci_collection_size,                          arginfo_oci_collection_size_method)
        PHP_FALIAS(max,                   oci_collection_max,                           arginfo_oci_collection_max_method)
        PHP_FALIAS(trim,                  oci_collection_trim,                          arginfo_oci_collection_trim_method)
        PHP_FALIAS(free,                  oci_free_collection,                          arginfo_oci_collection_free_method)
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION >= 7) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
        PHP_FE_END
#else
        {NULL,NULL,NULL}
#endif
};

zend_module_entry oci8_module_entry = {
        STANDARD_MODULE_HEADER,
        "oci8",                           /* extension name */
        php_oci_functions,        /* extension function list */
        PHP_MINIT(oci),           /* extension-wide startup function */
        PHP_MSHUTDOWN(oci),       /* extension-wide shutdown function */
        PHP_RINIT(oci),           /* per-request startup function */
        PHP_RSHUTDOWN(oci),       /* per-request shutdown function */
        PHP_MINFO(oci),           /* information function */
        PHP_OCI8_VERSION,
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
        /* This check allows PECL builds from this file to be portable to older PHP releases */
        PHP_MODULE_GLOBALS(oci),  /* globals descriptor */
        PHP_GINIT(oci),                   /* globals ctor */
        PHP_GSHUTDOWN(oci),               /* globals dtor */
        NULL,                                     /* post deactivate */
        STANDARD_MODULE_PROPERTIES_EX
#else
        STANDARD_MODULE_PROPERTIES
#endif
};
/* }}} */

/* {{{ PHP_INI */
PHP_INI_BEGIN()
        STD_PHP_INI_ENTRY(      "oci8.max_persistent",                  "-1",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       max_persistent,                 zend_oci_globals,       oci_globals)
        STD_PHP_INI_ENTRY(      "oci8.persistent_timeout",              "-1",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       persistent_timeout,             zend_oci_globals,       oci_globals)
        STD_PHP_INI_ENTRY(      "oci8.ping_interval",                   "60",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       ping_interval,                  zend_oci_globals,       oci_globals)
        STD_PHP_INI_BOOLEAN("oci8.privileged_connect",          "0",    PHP_INI_SYSTEM, OnUpdateBool,           privileged_connect,             zend_oci_globals,       oci_globals)
        STD_PHP_INI_ENTRY(      "oci8.statement_cache_size",    "20",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       statement_cache_size,   zend_oci_globals,       oci_globals)
        STD_PHP_INI_ENTRY(      "oci8.default_prefetch",                "100",  PHP_INI_SYSTEM, ONUPDATELONGFUNC,       default_prefetch,               zend_oci_globals,       oci_globals)
        STD_PHP_INI_BOOLEAN("oci8.old_oci_close_semantics",     "0",    PHP_INI_SYSTEM, OnUpdateBool,           old_oci_close_semantics,zend_oci_globals,       oci_globals)
        STD_PHP_INI_ENTRY(      "oci8.connection_class",                "",             PHP_INI_ALL,    OnUpdateString,         connection_class,               zend_oci_globals,       oci_globals)
        STD_PHP_INI_BOOLEAN("oci8.events",                                      "0",    PHP_INI_SYSTEM, OnUpdateBool,           events,                                 zend_oci_globals,       oci_globals)
PHP_INI_END()
/* }}} */

/* {{{ startup, shutdown and info functions
*/

/* {{{  php_oci_init_global_handles()
 *
 * Initialize global handles only when they are needed
 */
static void php_oci_init_global_handles(TSRMLS_D)
{
        sword errstatus;
        sb4   ora_error_code = 0;
        text  tmp_buf[OCI_ERROR_MAXMSG_SIZE];  /* Use traditional smaller size: non-PL/SQL errors should fit and it keeps the stack smaller */

        errstatus = OCIEnvNlsCreate(&OCI_G(env), PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, 0, 0);

        if (errstatus == OCI_ERROR) {
#ifdef HAVE_OCI_INSTANT_CLIENT
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIEnvNlsCreate() failed. There is something wrong with your system - please check that " PHP_OCI8_LIB_PATH_MSG " includes the directory with Oracle Instant Client libraries");
#else
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIEnvNlsCreate() failed. There is something wrong with your system - please check that ORACLE_HOME and " PHP_OCI8_LIB_PATH_MSG " are set and point to the right directories");
#endif
                if (OCI_G(env)
                        && OCIErrorGet(OCI_G(env), (ub4)1, NULL, &ora_error_code, tmp_buf, (ub4)OCI_ERROR_MAXMSG_SIZE, (ub4)OCI_HTYPE_ENV) == OCI_SUCCESS
                        && *tmp_buf) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tmp_buf);
                }
                
                OCI_G(env) = NULL;
                OCI_G(err) = NULL;
                return;
        }

        errstatus = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL);

        if (errstatus == OCI_SUCCESS) {
#if !defined(OCI_MAJOR_VERSION) || (OCI_MAJOR_VERSION < 11)
                /* This fixes PECL bug 15988 (sqlnet.ora not being read).  The
                 * root cause was fixed in Oracle 10.2.0.4 but there is no
                 * compile time method to check for that precise patch level,
                 * nor can it be guaranteed that runtime will use the same
                 * patch level the code was compiled with.  So, we do this
                 * code for all non 11g versions.
                 */
                OCICPool *cpoolh;
                ub4 cpoolmode = 0x80000000;     /* Pass invalid mode to OCIConnectionPoolCreate */
                PHP_OCI_CALL(OCIHandleAlloc, (OCI_G(env), (dvoid **) &cpoolh, OCI_HTYPE_CPOOL, (size_t) 0, (dvoid **) 0));
                PHP_OCI_CALL(OCIConnectionPoolCreate, (OCI_G(env), OCI_G(err), cpoolh, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, NULL, 0, cpoolmode));
                PHP_OCI_CALL(OCIConnectionPoolDestroy, (cpoolh, OCI_G(err), OCI_DEFAULT));
                PHP_OCI_CALL(OCIHandleFree, (cpoolh, OCI_HTYPE_CPOOL));
#endif
        } else {
                OCIErrorGet(OCI_G(env), (ub4)1, NULL, &ora_error_code, tmp_buf, (ub4)OCI_ERROR_MAXMSG_SIZE, (ub4)OCI_HTYPE_ERROR);

                if (ora_error_code) {
                        int tmp_buf_len = strlen((char *)tmp_buf);
                        
                        if (tmp_buf_len > 0 && tmp_buf[tmp_buf_len - 1] == '\n') {
                                tmp_buf[tmp_buf_len - 1] = '\0';
                        }
                        
                        if (errstatus == OCI_SUCCESS_WITH_INFO) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Initialization error: OCI_SUCCESS_WITH_INFO: %s", tmp_buf);
                        } else {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Initialization error: OCI_ERROR: %s", tmp_buf);
                                
                                OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV);
                                
                                OCI_G(env) = NULL;
                                OCI_G(err) = NULL;
                        }
                }
        }
} /* }}} */

/* {{{ php_oci_cleanup_global_handles()
 *
 * Free global handles (if they were initialized before)
 */
static void php_oci_cleanup_global_handles(TSRMLS_D)
{
        if (OCI_G(err)) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR));
                OCI_G(err) = NULL;
        }

        if (OCI_G(env)) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV));
                OCI_G(env) = NULL;
        }
} /* }}} */

/* {{{ PHP_GINIT_FUNCTION
 *
 * Zerofill globals during module init
 */
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
/* This check allows PECL builds from this file to be portable to older PHP releases */
static PHP_GINIT_FUNCTION(oci)
#else
static void php_oci_init_globals(zend_oci_globals *oci_globals TSRMLS_DC)
#endif
{
        memset(oci_globals, 0, sizeof(zend_oci_globals));
}
/* }}} */

/* {{{ PHP_GSHUTDOWN_FUNCTION
 *
 * Called for thread shutdown in ZTS, after module shutdown for non-ZTS
 */
/* This check allows PECL builds from this file to be portable to older PHP releases */
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
static PHP_GSHUTDOWN_FUNCTION(oci)
#else
static void php_oci_shutdown_globals(zend_oci_globals *oci_globals TSRMLS_DC)
#endif
{
        php_oci_cleanup_global_handles(TSRMLS_C);
}
/* }}} */

PHP_MINIT_FUNCTION(oci)
{
        zend_class_entry oci_lob_class_entry;
        zend_class_entry oci_coll_class_entry;

#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
        /* This check allows PECL builds from this file to be portable to older PHP releases */
        /* this is handled by new globals management code */
#else
        ZEND_INIT_MODULE_GLOBALS(oci, php_oci_init_globals, php_oci_shutdown_globals);
#endif
        REGISTER_INI_ENTRIES();

        le_statement = zend_register_list_destructors_ex(php_oci_statement_list_dtor, NULL, "oci8 statement", module_number);
        le_connection = zend_register_list_destructors_ex(php_oci_connection_list_dtor, NULL, "oci8 connection", module_number);
        le_pconnection = zend_register_list_destructors_ex(php_oci_pconnection_list_np_dtor, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number);
        le_psessionpool = zend_register_list_destructors_ex(NULL, php_oci_spool_list_dtor, "oci8 persistent session pool", module_number);
        le_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number);
        le_collection = zend_register_list_destructors_ex(php_oci_collection_list_dtor, NULL, "oci8 collection", module_number);

        INIT_CLASS_ENTRY(oci_lob_class_entry, "OCI-Lob", php_oci_lob_class_functions);
        INIT_CLASS_ENTRY(oci_coll_class_entry, "OCI-Collection", php_oci_coll_class_functions);

        oci_lob_class_entry_ptr = zend_register_internal_class(&oci_lob_class_entry TSRMLS_CC);
        oci_coll_class_entry_ptr = zend_register_internal_class(&oci_coll_class_entry TSRMLS_CC);

/* 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_CRED_EXT",PHP_OCI_CRED_EXT, 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_NO_AUTO_COMMIT",OCI_DEFAULT, 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",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);

/* for OCIBindByName (real "oci" names + short "php" names */
        REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_AFC",SQLT_AFC, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CHR",SQLT_CHR, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_VCS",SQLT_VCS, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_AVC",SQLT_AVC, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_STR",SQLT_STR, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_LVC",SQLT_LVC, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_FLT",SQLT_FLT, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_UIN",SQLT_UIN, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_LNG",SQLT_LNG, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_LBI",SQLT_LBI, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_ODT",SQLT_ODT, CONST_CS | CONST_PERSISTENT);
#if defined(HAVE_OCI_INSTANT_CLIENT) || (defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 10)
        REGISTER_LONG_CONSTANT("SQLT_BDOUBLE",SQLT_BDOUBLE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_BFLOAT",SQLT_BFLOAT, CONST_CS | CONST_PERSISTENT);
#endif

        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_CS | CONST_PERSISTENT);

        REGISTER_LONG_CONSTANT("OCI_B_BFILE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_B_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_B_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_B_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
        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", 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",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);
        REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);

        REGISTER_LONG_CONSTANT("OCI_D_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_D_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_D_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);

/* for OCIWriteTemporaryLob */
        REGISTER_LONG_CONSTANT("OCI_TEMP_CLOB",OCI_TEMP_CLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_TEMP_BLOB",OCI_TEMP_BLOB, CONST_CS | CONST_PERSISTENT);

        return SUCCESS;
}

PHP_RINIT_FUNCTION(oci)
{
        OCI_G(debug_mode) = 0; /* start "fresh" */
        OCI_G(num_links) = OCI_G(num_persistent);
        OCI_G(errcode) = 0;
        OCI_G(edition) = NULL;

        return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(oci)
{
/* Work around PHP_GSHUTDOWN_FUNCTION not being called in older versions of PHP */
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 2) || (PHP_MAJOR_VERSION < 5)
#ifndef ZTS
        php_oci_cleanup_global_handles(TSRMLS_C);
#endif
#endif

        OCI_G(shutdown) = 1;

        UNREGISTER_INI_ENTRIES();

        return SUCCESS;
}

PHP_RSHUTDOWN_FUNCTION(oci)
{
        /* Check persistent connections and do the necessary actions if needed. If persistent_helper is
         * unable to process a pconnection because of a refcount, the processing would happen from
         * np-destructor which is called when refcount goes to zero - php_oci_pconnection_list_np_dtor
         */
        zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC);

        if (OCI_G(edition)) {
                efree(OCI_G(edition));
        }

        return SUCCESS;
}

PHP_MINFO_FUNCTION(oci)
{
        char buf[32];
        char *ver;

        php_info_print_table_start();
        php_info_print_table_row(2, "OCI8 Support", "enabled");
        php_info_print_table_row(2, "Version", PHP_OCI8_VERSION);
        php_info_print_table_row(2, "Revision", "$Id: 44bfa713983a99b3e59477f6532e5fb51b6dee94 $");

        snprintf(buf, sizeof(buf), "%ld", OCI_G(num_persistent));
        php_info_print_table_row(2, "Active Persistent Connections", buf);
        snprintf(buf, sizeof(buf), "%ld", OCI_G(num_links));
        php_info_print_table_row(2, "Active Connections", buf);

#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
        php_oci_client_get_version(&ver TSRMLS_CC);
        php_info_print_table_row(2, "Oracle Run-time Client Library Version", ver);
        efree(ver);
#endif
#if     defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
        snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION);
#elif defined(PHP_OCI8_ORACLE_VERSION)
        snprintf(buf, sizeof(buf), "%s", PHP_OCI8_ORACLE_VERSION);
#else
        snprintf(buf, sizeof(buf), "Unknown");
#endif
#if defined(HAVE_OCI_INSTANT_CLIENT)
        php_info_print_table_row(2, "Oracle Instant Client Version", buf);
#else
        php_info_print_table_row(2, "Oracle Version", buf);
#endif

#if !defined(PHP_WIN32) && !defined(HAVE_OCI_INSTANT_CLIENT)
#if defined(PHP_OCI8_DEF_DIR)
        php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DEF_DIR);
#endif
#if defined(PHP_OCI8_DEF_SHARED_LIBADD)
        php_info_print_table_row(2, "Libraries Used", PHP_OCI8_DEF_SHARED_LIBADD);
#endif
#endif

        php_info_print_table_row(2, "Temporary Lob support", "enabled");
        php_info_print_table_row(2, "Collections support", "enabled");
        php_info_print_table_end();
        DISPLAY_INI_ENTRIES();
}
/* }}} */

/* list destructors {{{ */

/* {{{ 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;

        if (connection) {
                php_oci_connection_close(connection TSRMLS_CC);
                OCI_G(num_links)--;
        }
} /* }}} */

/* {{{ 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;

        if (connection) {
                php_oci_connection_close(connection TSRMLS_CC);
                OCI_G(num_persistent)--;
                OCI_G(num_links)--;
        }
} /* }}} */

/* {{{ php_oci_pconnection_list_np_dtor()
 *
 * Non-Persistent destructor for persistent connection - This gets invoked when
 * the refcount of this goes to zero in the regular list
 */
static void php_oci_pconnection_list_np_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
{
        php_oci_connection *connection = (php_oci_connection *)entry->ptr;
        zend_rsrc_list_entry *le;

        /*
         * We cannot get connection as NULL or as a stub in this function. This is the function that
         * turns a pconnection to a stub
         *
         * If oci_password_change() changed the password of a persistent connection, close the
         * connection and remove it from the persistent connection cache.  This means subsequent scripts
         * will be prevented from being able to present the old (now invalid) password to a usable
         * connection to the database; they must use the new password.
         *
         * Check for conditions that warrant removal of the hash entry
         */

        if (!connection->is_open ||
                connection->passwd_changed ||
                (PG(connection_status) & PHP_CONNECTION_TIMEOUT) ||
                OCI_G(in_call)) {

                /* Remove the hash entry if present */
                if ((zend_hash_find(&EG(persistent_list), connection->hash_key, strlen(connection->hash_key)+1, (void **) &le)== SUCCESS) && (le->type == le_pconnection) && (le->ptr == connection)) {
                        zend_hash_del(&EG(persistent_list), connection->hash_key, strlen(connection->hash_key)+1);
                }
                else {
                        php_oci_connection_close(connection TSRMLS_CC);
                        OCI_G(num_persistent)--;
                }

                if (OCI_G(debug_mode)) {
                        php_printf ("OCI8 DEBUG L1: np_dtor cleaning up: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                }
        }
        else {
                /*
                 * Release the connection to underlying pool.  We do this unconditionally so that
                 * out-of-scope pconnects are now consistent with oci_close and out-of-scope new connect
                 * semantics. With the PECL OCI 1.3.x extensions, we release pconnections when oci_close
                 * takes the refcount to zero.
                 *
                 * If oci_old_close_semantics is set, we artifically bump up the refcount and decremented
                 * only at request shutdown.
                 */
                php_oci_connection_release(connection TSRMLS_CC);

                if (OCI_G(debug_mode)) {
                        php_printf ("OCI8 DEBUG L1: np_dtor releasing: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                }
        }
} /* }}} */

/* {{{ php_oci_statement_list_dtor()
 *
 * Statement destructor
 */
static void php_oci_statement_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
{
        php_oci_statement *statement = (php_oci_statement *)entry->ptr;
        php_oci_statement_free(statement TSRMLS_CC);
} /* }}} */

/* {{{ php_oci_descriptor_list_dtor()
 *
 *      Descriptor destructor
 */
static void php_oci_descriptor_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
{
        php_oci_descriptor *descriptor = (php_oci_descriptor *)entry->ptr;
        php_oci_lob_free(descriptor TSRMLS_CC);
} /* }}} */

/* {{{ 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);
} /* }}} */

/* }}} */

/* Hash Destructors {{{ */

/* {{{ php_oci_define_hash_dtor()
 *
 * Define hash destructor
 */
void php_oci_define_hash_dtor(void *data)
{
        php_oci_define *define = (php_oci_define *) data;

        zval_ptr_dtor(&define->zval);

        if (define->name) {
                efree(define->name);
                define->name = NULL;
        }
}
/* }}} */

/* {{{ php_oci_bind_hash_dtor()
 *
 * Bind hash destructor
 */
void php_oci_bind_hash_dtor(void *data)
{
        php_oci_bind *bind = (php_oci_bind *) data;

        if (bind->array.elements) {
                efree(bind->array.elements);
        }

        if (bind->array.element_lengths) {
                efree(bind->array.element_lengths);
        }

        if (bind->array.indicators) {
                efree(bind->array.indicators);
        }

        zval_ptr_dtor(&bind->zval);
}
/* }}} */

/* {{{ php_oci_column_hash_dtor()
 *
 * Column hash destructor
 */
void php_oci_column_hash_dtor(void *data)
{
        php_oci_out_column *column = (php_oci_out_column *) data;
        TSRMLS_FETCH();

        if (column->stmtid) {
                zend_list_delete(column->stmtid);
        }

        if (column->is_descr) {
                zend_list_delete(column->descid);
        }

        if (column->data) {
                efree(column->data);
        }

        if (column->name) {
                efree(column->name);
        }
}
/* }}} */

/* {{{ php_oci_descriptor_flush_hash_dtor()
 *
 * Flush descriptors on commit
 */
void php_oci_descriptor_flush_hash_dtor(void *data)
{
        php_oci_descriptor *descriptor = *(php_oci_descriptor **)data;
        TSRMLS_FETCH();

        if (descriptor && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) {
                php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
                descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
        }
        data = NULL;
}
/* }}} */

/* }}} */

/* {{{ php_oci_connection_descriptors_free()
 *
 * Free descriptors for a connection
 */
void php_oci_connection_descriptors_free(php_oci_connection *connection TSRMLS_DC)
{
        zend_hash_destroy(connection->descriptors);
        efree(connection->descriptors);
        connection->descriptors = NULL;
        connection->descriptor_count = 0;
}
/* }}} */


/* {{{ php_oci_error()
 *
 * Fetch & print out error message if we get an error
 * Returns an Oracle error number
 */
sb4 php_oci_error(OCIError *err_p, sword status TSRMLS_DC)
{
        text *errbuf = (text *)NULL;
        sb4 errcode = 0;

        switch (status) {
                case OCI_SUCCESS:
                        break;
                case OCI_SUCCESS_WITH_INFO:
                        errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
                        if (errbuf) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_SUCCESS_WITH_INFO: %s", errbuf);
                                efree(errbuf);
                        } else {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_SUCCESS_WITH_INFO: failed to fetch error message");
                        }
                        break;
                case OCI_NEED_DATA:
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NEED_DATA");
                        break;
                case OCI_NO_DATA:
                        errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
                        if (errbuf) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errbuf);
                                efree(errbuf);
                        } else {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NO_DATA: failed to fetch error message");
                        }
                        break;
                case OCI_ERROR:
                        errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
                        if (errbuf) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errbuf);
                                efree(errbuf);
                        } else {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to fetch error message");
                        }
                        break;
                case OCI_INVALID_HANDLE:
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_INVALID_HANDLE");
                        break;
                case OCI_STILL_EXECUTING:
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_STILL_EXECUTING");
                        break;
                case OCI_CONTINUE:
                        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;
}
/* }}} */

/* {{{ 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)
{
        sb4 error_code = 0;
        text err_buf[PHP_OCI_ERRBUF_LEN];

        memset(err_buf, 0, sizeof(err_buf));
        PHP_OCI_CALL(OCIErrorGet, (error_handle, (ub4)1, NULL, &error_code, err_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR));

        if (error_code) {
                int err_buf_len = strlen((char *)err_buf);

                if (err_buf_len && err_buf[err_buf_len - 1] == '\n') {
                        err_buf[err_buf_len - 1] = '\0';
                }
                if (err_buf_len && error_buf) {
                        *error_buf = NULL;
                        *error_buf = (text *)estrndup((char *)err_buf, err_buf_len);
                }
        }
        return error_code;
} /* }}} */

/* {{{ 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)
{
        sword errstatus;

        *sqltext = NULL;
        *error_offset = 0;
        PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *) sqltext, (ub4 *)0, OCI_ATTR_STATEMENT, statement->err));

        if (errstatus != OCI_SUCCESS) {
                statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
                return 1;
        }

        PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err));

        if (errstatus != OCI_SUCCESS) {
                statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
                return 1;
        }
        return 0;
} /* }}} */

/* {{{ php_oci_do_connect()
 *
 * Connect wrapper
 */
void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive)
{
        php_oci_connection *connection;
        char *username, *password;
        char *dbname = NULL, *charset = NULL;
        int username_len = 0, password_len = 0;
        int dbname_len = 0, charset_len = 0;
        long session_mode = OCI_DEFAULT;

        /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
        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 (!connection) {
                RETURN_FALSE;
        }
        RETURN_RESOURCE(connection->rsrc_id);

} /* }}} */

/* {{{ php_oci_do_connect_ex()
 *
 * The real connect function. Allocates all the resources needed, establishes the connection and
 * returns the result handle (or NULL)
 */
php_oci_connection *php_oci_do_connect_ex(char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, char *dbname, int dbname_len, char *charset, long session_mode, int persistent, int exclusive TSRMLS_DC)
{
        zend_rsrc_list_entry *le;
        zend_rsrc_list_entry new_le;
        php_oci_connection *connection = NULL;
        smart_str hashed_details = {0};
        time_t timestamp;
        php_oci_spool *session_pool = NULL;
        zend_bool use_spool = 1;           /* Default is to use client-side session pool */
        zend_bool ping_done = 0;

        ub2 charsetid = 0;
        ub2 charsetid_nls_lang = 0;

        if (session_mode & ~(OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid session mode specified (%ld)", session_mode);
                return NULL;
        }
        if (session_mode & (OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) {
                if ((session_mode & OCI_SYSOPER) && (session_mode & OCI_SYSDBA)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_SYSDBA and OCI_SYSOPER cannot be used together");
                        return NULL;
                }
                if (session_mode & PHP_OCI_CRED_EXT) {
#ifdef PHP_WIN32
                        /* Disable external authentication on Windows as Impersonation is not yet handled.
                         * TODO: Re-enable this once OCI provides capability.
                         */
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "External Authentication is not supported on Windows");
                        return NULL;
#endif
                        if (username_len != 1 || username[0] != '/' || password_len != 0) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_CRED_EXT can only be used with a username of \"/\" and a NULL password");
                                return NULL;
                        }
                }
                if (session_mode & (OCI_SYSOPER | OCI_SYSDBA)) {
                        /* Increase security by not caching privileged oci_pconnect() connections. The
                         * connection becomes equivalent to oci_connect() or oci_new_connect().
                         */
                        persistent = 0;
                        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;
                        }
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || (PHP_MAJOR_VERSION < 5)
                        /* Safe mode has been removed in PHP 5.4 */
                        if (PG(safe_mode)) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Privileged connect is disabled in Safe Mode");
                                return NULL;
                        }
#endif
                }
        }

        /* Initialize global handles if they weren't initialized before */
        if (OCI_G(env) == NULL) {
                php_oci_init_global_handles(TSRMLS_C);
                if (OCI_G(env) == NULL) {
                        return NULL;
                }
        }

        /* We cannot use the new session create logic (OCISessionGet from
         * client-side session pool) when privileged connect or password
         * change is attempted or OCI_CRED_EXT mode is specified.
         * TODO: Re-enable this when OCI provides support.
         */
        if ((session_mode & (OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) || (new_password_len)) {
                use_spool = 0;
        }

        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);

        /* DRCP: connection_class is an attribute of a connection */
        if (OCI_G(connection_class)){
                smart_str_appendl_ex(&hashed_details, OCI_G(connection_class), strlen(OCI_G(connection_class)), 0);
        }
        smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);

        /* Add edition attribute to the hash */
        if (OCI_G(edition)){
                smart_str_appendl_ex(&hashed_details, OCI_G(edition), strlen(OCI_G(edition)), 0);
        }
        smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);

        if (password_len) {
                ulong password_hash;
                password_hash = zend_inline_hash_func(password, password_len);
                smart_str_append_unsigned_ex(&hashed_details, password_hash, 0);
        }
        smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);

        if (dbname) {
                smart_str_appendl_ex(&hashed_details, dbname, dbname_len, 0);
        }
        smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);

        if (charset && *charset) {
                PHP_OCI_CALL_RETURN(charsetid, OCINlsCharSetNameToId, (OCI_G(env), (CONST oratext *)charset));
                if (!charsetid) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid character set name: %s", charset);
                } else {
                        smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
                }
        }

        /* use NLS_LANG if no or invalid charset specified */
        if (!charsetid) {
                size_t rsize = 0;
                sword result;

                PHP_OCI_CALL_RETURN(result, OCINlsEnvironmentVariableGet, (&charsetid_nls_lang, 0, OCI_NLS_CHARSET_ID, 0, &rsize));
                if (result != OCI_SUCCESS) {
                        charsetid_nls_lang = 0;
                }
                smart_str_append_unsigned_ex(&hashed_details, charsetid_nls_lang, 0);
        }

        timestamp = time(NULL);

        smart_str_append_unsigned_ex(&hashed_details, session_mode, 0);
        smart_str_0(&hashed_details);

        /* make it lowercase */
        php_strtolower(hashed_details.c, hashed_details.len);

        if (!exclusive && !new_password) {
                zend_bool found = 0;

                if (persistent && zend_hash_find(&EG(persistent_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) {
                        found = 1;
                        /* 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) {
                        found = 1;
                        if (le->type == le_index_ptr) {
                                int type, link;
                                void *ptr;

                                link = OCI8_PTR_TO_INT(le->ptr);
                                ptr = zend_list_find(link,&type);
                                if (ptr && (type == le_connection)) {
                                        connection = (php_oci_connection *)ptr;
                                }
                        }
                }

                /* Debug statements {{{ */
                if (OCI_G(debug_mode)) {
                        if (connection && connection->is_stub) {
                                php_printf ("OCI8 DEBUG L1: Got a cached stub: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                        } else if (connection) {
                                php_printf ("OCI8 DEBUG L1: Got a cached connection: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                        } else {
                                php_printf ("OCI8 DEBUG L1: Got NO cached connection at (%s:%d) \n", __FILE__, __LINE__);
                        }
                } /* }}} */

                /* If we got a pconnection stub, then 'load'(OCISessionGet) the real connection from its
                 * private spool A connection is a stub if it is only a cached structure and the real
                 * connection is released to its underlying private session pool.  We currently do not have
                 * stub support for non-persistent conns.
                 *
                 * TODO: put in negative code for non-persistent stubs
                 */
                if (connection && connection->is_persistent && connection->is_stub) {
                        if (php_oci_create_session(connection, NULL, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode TSRMLS_CC)) {
                                smart_str_free_ex(&hashed_details, 0);
                                zend_hash_del(&EG(persistent_list), connection->hash_key, strlen(connection->hash_key)+1);

                                return NULL;
                        }
                        /* We do the ping in php_oci_create_session, no need to ping again below */
                        ping_done = 1;
                }

                if (connection) {
                        if (connection->is_open) {
                                /* found an open connection. now ping it */
                                if (connection->is_persistent) {
                                        int rsrc_type;

                                        /* Check connection liveness in the following order:
                                         * 1) always check OCI_ATTR_SERVER_STATUS
                                         * 2) see if it's time to ping it
                                         * 3) ping it if needed
                                         */
                                        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 (!ping_done && (*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp)) && !php_oci_connection_ping(connection TSRMLS_CC)) {
                                                        /* server died */
                                                } else {
                                                        php_oci_connection *tmp;

                                                        /* okay, the connection is open and the server is still alive */
                                                        connection->used_this_request = 1;
                                                        tmp = (php_oci_connection *)zend_list_find(connection->rsrc_id, &rsrc_type);

                                                        if (tmp != NULL && rsrc_type == le_pconnection && strlen(tmp->hash_key) == hashed_details.len &&
                                                                memcmp(tmp->hash_key, hashed_details.c, hashed_details.len) == 0 && zend_list_addref(connection->rsrc_id) == SUCCESS) {
                                                                /* do nothing */
                                                        } else {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
                                                                connection->rsrc_id = zend_list_insert(connection, le_pconnection TSRMLS_CC);
#else
                                                                connection->rsrc_id = zend_list_insert(connection, le_pconnection);
#endif
                                                                /* Persistent connections: For old close semantics we artificially
                                                                 * bump up the refcount to prevent the non-persistent destructor
                                                                 * from getting called until request shutdown. The refcount is
                                                                 * decremented in the persistent helper
                                                                 */
                                                                if (OCI_G(old_oci_close_semantics)) {
                                                                        zend_list_addref(connection->rsrc_id);
                                                                }
                                                        }
                                                        smart_str_free_ex(&hashed_details, 0);
                                                        return connection;
                                                }
                                        }
                                        /* server died */
                                } else {
                                        /* we do not ping non-persistent connections */
                                        smart_str_free_ex(&hashed_details, 0);
                                        zend_list_addref(connection->rsrc_id);
                                        return connection;
                                }
                        } /* is_open is true? */

                        /* Server died - connection not usable. The is_open=true can also fall through to here,
                         * if ping fails
                         */
                        if (persistent){
                                int rsrc_type;

                                connection->is_open = 0;
                                connection->used_this_request = 1;

                                /* We have to do a hash_del but need to preserve the resource if there is a positive
                                 * refcount. Set the data pointer in the list entry to NULL
                                 */
                                if (connection == zend_list_find(connection->rsrc_id, &rsrc_type) && rsrc_type == le_pconnection) {
                                        le->ptr = NULL;
                                }

                                zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1);
                        } else {
                                /* We only remove the hash entry. The resource and the list entry with its pointer
                                 * to the resource are still intact
                                 */
                                zend_hash_del(&EG(regular_list), hashed_details.c, hashed_details.len+1);
                        }

                        connection = NULL;
                } else if (found) {
                        /* 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);
                        } else {
                                zend_hash_del(&EG(regular_list), hashed_details.c, hashed_details.len+1);
                        }
                }
        }

        /* Check if we have reached max_persistent. If so, try to remove a few timed-out connections. As
         * a last resort, return a non-persistent connection.
         */
        if (persistent) {
                zend_bool alloc_non_persistent = 0;

                if (OCI_G(max_persistent) != -1 && OCI_G(num_persistent) >= OCI_G(max_persistent)) {
                        /* try to find an idle connection and kill it */
                        zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC);

                        if (OCI_G(max_persistent) != -1 && OCI_G(num_persistent) >= OCI_G(max_persistent)) {
                                /* all persistent connactions are in use, fallback to non-persistent connection creation */
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Too many open persistent connections (%ld)", OCI_G(num_persistent));
                                alloc_non_persistent = 1;
                        }
                }

                if (alloc_non_persistent) {
                        connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
                        connection->hash_key = estrndup(hashed_details.c, hashed_details.len);
                        connection->is_persistent = 0;
                } else {
                        connection = (php_oci_connection *) calloc(1, sizeof(php_oci_connection));
                        if (connection == NULL) {
                                return NULL;
                        }
                        connection->hash_key = zend_strndup(hashed_details.c, hashed_details.len);
                        if (connection->hash_key == NULL) {
                                free(connection);
                                return NULL;
                        }
                        connection->is_persistent = 1;
                }
        } else {
                connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
                connection->hash_key = estrndup(hashed_details.c, hashed_details.len);
                connection->is_persistent = 0;
        }

        /* {{{ Get the session pool that suits this connection request from the persistent list. This
         * step is only for non-persistent connections as persistent connections have private session
         * pools. Non-persistent conns use shared session pool to allow for optimizations such as
         * caching the physical connection (for DRCP) even when the non-persistent php connection is
         * destroyed.
         *
         * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability
         */
        if (use_spool && !connection->is_persistent) {
                if ((session_pool = php_oci_get_spool(username, username_len, password, password_len, dbname, dbname_len, charsetid ? charsetid:charsetid_nls_lang TSRMLS_CC))==NULL)
                {
                        php_oci_connection_close(connection TSRMLS_CC);
                        smart_str_free_ex(&hashed_details, 0);
                        return NULL;
                }
        } /* }}} */

        connection->idle_expiry = (OCI_G(persistent_timeout) > 0) ? (timestamp + OCI_G(persistent_timeout)) : 0;

        /* Mark password as unchanged by PHP during the duration of the database session */
        connection->passwd_changed = 0;

        smart_str_free_ex(&hashed_details, 0);

        if (charsetid) {
                connection->charset = charsetid;
        } else {
                connection->charset = charsetid_nls_lang;
        }

        /* Old session creation semantics when session pool cannot be used Eg: privileged
         * connect/password change
         */
        if (!use_spool) {
                if (php_oci_old_create_session(connection, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode TSRMLS_CC)) {
                        php_oci_connection_close(connection TSRMLS_CC);
                        return NULL;
                }
        } else {
                /* create using the client-side session pool */
                if (php_oci_create_session(connection, session_pool, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode TSRMLS_CC)) {
                        php_oci_connection_close(connection TSRMLS_CC);
                        return NULL;
                }
        }

        /* Mark it as open */
        connection->is_open = 1;

        /* add to the appropriate hash */
        if (connection->is_persistent) {
                new_le.ptr = connection;
                new_le.type = le_pconnection;
                connection->used_this_request = 1;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
                connection->rsrc_id = zend_list_insert(connection, le_pconnection TSRMLS_CC);
#else
                connection->rsrc_id = zend_list_insert(connection, le_pconnection);
#endif

                /* Persistent connections: For old close semantics we artificially bump up the refcount to
                 * prevent the non-persistent destructor from getting called until request shutdown. The
                 * refcount is decremented in the persistent helper
                 */
                if (OCI_G(old_oci_close_semantics)) {
                        zend_list_addref(connection->rsrc_id);
                }
                zend_hash_update(&EG(persistent_list), connection->hash_key, strlen(connection->hash_key)+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL);
                OCI_G(num_persistent)++;
                OCI_G(num_links)++;
        } else if (!exclusive) {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
                connection->rsrc_id = zend_list_insert(connection, le_connection TSRMLS_CC);
#else
                connection->rsrc_id = zend_list_insert(connection, le_connection);
#endif
                new_le.ptr = OCI8_INT_TO_PTR(connection->rsrc_id);
                new_le.type = le_index_ptr;
                zend_hash_update(&EG(regular_list), connection->hash_key, strlen(connection->hash_key)+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL);
                OCI_G(num_links)++;
        } else {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
                connection->rsrc_id = zend_list_insert(connection, le_connection TSRMLS_CC);
#else
                connection->rsrc_id = zend_list_insert(connection, le_connection);
#endif
                OCI_G(num_links)++;
        }

        /* Debug statements {{{ */
        if (OCI_G(debug_mode)) {
                if (connection->is_persistent) {
                        php_printf ("OCI8 DEBUG L1: New Persistent Connection address: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                } else {
                        php_printf ("OCI8 DEBUG L1: New Non-Persistent Connection address: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                }
                php_printf ("OCI8 DEBUG L1: num_persistent=(%ld), num_links=(%ld) at (%s:%d) \n", OCI_G(num_persistent), OCI_G(num_links), __FILE__, __LINE__);
        } /* }}} */

        return connection;
}
/* }}} */

/* {{{ 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)
{
        /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
         * such as from Pre-10.1 servers, the error is still from the server and we would have
         * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
         * Pre-10.2 clients
         */
#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))       /* OCIPing available 10.2 onwards */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT));
#else
        char version[256];
        /* use good old OCIServerVersion() */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX));
#endif

        if (OCI_G(errcode) == OCI_SUCCESS) {
                return 1;
        } else {
                sb4 error_code = 0;
                text tmp_buf[OCI_ERROR_MAXMSG_SIZE];

                /* Treat ORA-1010 as a successful Ping */
                OCIErrorGet(OCI_G(err), (ub4)1, NULL, &error_code, tmp_buf, (ub4)OCI_ERROR_MAXMSG_SIZE, (ub4)OCI_HTYPE_ERROR);
                if (error_code == 1010) {
                        return 1;
                }
        }

        /* ignore errors here, just return failure
         * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
        return 0;
}
/* }}} */

/* {{{ php_oci_connection_status()
 *
 * Check connection status (pre-ping check)
 */
static int php_oci_connection_status(php_oci_connection *connection TSRMLS_DC)
{
        ub4 ss = 0;

        /* get OCI_ATTR_SERVER_STATUS */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err)));

        if (OCI_G(errcode) == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) {
                return 1;
        }

        /* ignore errors here, just return failure
         * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
        return 0;
}
/* }}} */

/* {{{ php_oci_connection_rollback()
 *
 * Rollback connection
 */
int php_oci_connection_rollback(php_oci_connection *connection TSRMLS_DC)
{
        PHP_OCI_CALL_RETURN(connection->errcode, OCITransRollback, (connection->svc, connection->err, (ub4) 0));
        connection->needs_commit = 0;

        if (connection->errcode != OCI_SUCCESS) {
                connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                return 1;
        }
        return 0;
} /* }}} */

/* {{{ php_oci_connection_commit()
 *
 * Commit connection
 */
int php_oci_connection_commit(php_oci_connection *connection TSRMLS_DC)
{
        PHP_OCI_CALL_RETURN(connection->errcode, OCITransCommit, (connection->svc, connection->err, (ub4) 0));
        connection->needs_commit = 0;

        if (connection->errcode != OCI_SUCCESS) {
                connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                return 1;
        }
        return 0;
} /* }}} */

/* {{{ php_oci_connection_close()
 *
 * Close the connection and free all its resources
 */
static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
{
        int result = 0;
        zend_bool in_call_save = OCI_G(in_call);

        if (!connection->is_stub) {
                /* Release resources associated with connection */
                php_oci_connection_release(connection TSRMLS_CC);
        }

        if (!connection->using_spool && connection->svc) {
                        PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0));
        }

        if (connection->err) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->err, (ub4) OCI_HTYPE_ERROR));
        }
        if (connection->authinfo) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO));
        }

        /* No Handlefrees for session pool connections */
        if (!connection->using_spool) {
                if (connection->session) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION));
                }

                if (connection->is_attached) {
                        PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT));
                }

                if (connection->svc) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX));
                }

                if (connection->server) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER));
                }

                if (connection->env) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV));
                }
        } else if (connection->private_spool) {
        /* Keep this as the last member to be freed, as there are dependencies
         * (like env) on the session pool
         */
                php_oci_spool_close(connection->private_spool TSRMLS_CC);
        }

        if (connection->is_persistent) {
                if (connection->hash_key) {
                        free(connection->hash_key);
                }
                free(connection);
        } else {
                if (connection->hash_key) {
                        efree(connection->hash_key);
                }
                efree(connection);
        }
        connection = NULL;
        OCI_G(in_call) = in_call_save;
        return result;
} /* }}} */

/* {{{ php_oci_connection_release()
 *
 * Release the connection's resources. This involves freeing descriptors and rolling back
 * transactions, setting timeout-related parameters etc. For session-pool using connections, the
 * underlying connection is released to its session pool.
 */
int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC)
{
        int result = 0;
        zend_bool in_call_save = OCI_G(in_call);
        time_t timestamp = time(NULL);

        if (connection->is_stub) {
                return 0;
        }

        if (connection->descriptors) {
                php_oci_connection_descriptors_free(connection TSRMLS_CC);
        }

        if (connection->svc) {
                /* rollback outstanding transactions */
                if (connection->needs_commit) {
                        if (php_oci_connection_rollback(connection TSRMLS_CC)) {
                                /* rollback failed */
                                result = 1;
                        }
                }
        }

        if (OCI_G(persistent_timeout) > 0) {
                connection->idle_expiry = timestamp + OCI_G(persistent_timeout);
        }

        /* We may have half-cooked connections to clean up */
        if (connection->next_pingp) {
                if (OCI_G(ping_interval) >= 0) {
                        *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
                } else {
                        /* ping_interval is -1 */
                        *(connection->next_pingp) = 0;
                }
        }

        /* Release the session (stubs are filtered out at the beginning)*/
        if (connection->using_spool) {
                ub4 rlsMode = OCI_DEFAULT;

                if (result) {
                        rlsMode |= OCI_SESSRLS_DROPSESS;
                }

                /* Sessions for non-persistent connections should be dropped.  For 11 and above, the session
                 * pool has its own mechanism for doing so for purity NEW connections. We need to do so
                 * explicitly for 10.2 and earlier.
                 */
#if (!(OCI_MAJOR_VERSION >= 11))
                if (!connection->is_persistent) {
                        rlsMode |= OCI_SESSRLS_DROPSESS;
                }
#endif

                if (connection->svc) {
                        PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,
                                                                                 0, rlsMode));
                }
                /* It no longer has relation with the database session. However authinfo and env are
                 * cached
                 */
                connection->svc = NULL;
                connection->server = NULL;
                connection->session = NULL;

                connection->is_attached = connection->is_open = connection->needs_commit = connection->used_this_request = 0;
                connection->is_stub = 1;

                /* Cut the link between the connection structure and the time_t structure allocated within
                 * the OCI session
                 */
                connection->next_pingp = NULL;
        }

        OCI_G(in_call) = in_call_save;
        return result;
} /* }}} */

/* {{{ php_oci_password_change()
 *
 * Change password for the user with the username given
 */
int php_oci_password_change(php_oci_connection *connection, char *user, int user_len, char *pass_old, int pass_old_len, char *pass_new, int pass_new_len TSRMLS_DC)
{
        PHP_OCI_CALL_RETURN(connection->errcode, OCIPasswordChange, (connection->svc, connection->err, (text *)user, user_len, (text *)pass_old, pass_old_len, (text *)pass_new, pass_new_len, OCI_DEFAULT));

        if (connection->errcode != OCI_SUCCESS) {
                connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                return 1;
        }
        connection->passwd_changed = 1;
        return 0;
} /* }}} */


/* {{{ php_oci_client_get_version()
 *
 * Get Oracle client library version
 */
void php_oci_client_get_version(char **version TSRMLS_DC)
{
        char  version_buff[256];
        sword major_version = 0;
        sword minor_version = 0; 
        sword update_num = 0;
        sword patch_num = 0;
        sword port_update_num = 0;

#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))       /* OCIClientVersion only available 10.2 onwards */
        PHP_OCI_CALL(OCIClientVersion, (&major_version, &minor_version, &update_num, &patch_num, &port_update_num));
        snprintf(version_buff, sizeof(version_buff), "%d.%d.%d.%d.%d", major_version, minor_version, update_num, patch_num, port_update_num);
#else
        memcpy(version_buff, "Unknown", sizeof("Unknown"));
#endif
        *version = estrdup(version_buff);
} /* }}} */


/* {{{ 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];

        PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text *)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX));

        if (connection->errcode != OCI_SUCCESS) {
                connection->errcode = 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_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)
{
        php_oci_descriptor *descriptor;
        ub4 lob_length;
        int column_size;
        char *lob_buffer;
        int lob_fetch_status;

        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 (!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;
                }

                if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
                        /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */

                        lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC);
                        php_oci_temp_lob_close(descriptor TSRMLS_CC);
                        if (lob_fetch_status) {
                                ZVAL_FALSE(value);
                                return 1;
                        } else {
                                if (lob_length > 0) {
                                        ZVAL_STRINGL(value, lob_buffer, lob_length, 0);
                                } else {
                                        ZVAL_EMPTY_STRING(value);
                                }
                                return 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);
                }
        } else {
                switch (column->retcode) {
                        case 0:
                                /* intact value */
                                if (column->piecewise) {
                                        column_size = column->retlen4;
                                } else {
                                        column_size = column->retlen;
                                }
                                break;

                        default:
                                ZVAL_FALSE(value);
                                return 0;
                }

                ZVAL_STRINGL(value, column->data, column_size, 1);
        }
        return 0;
}
/* }}} */

/* {{{ 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 *z_statement, *array;
        php_oci_statement *statement;
        php_oci_out_column *column;
        ub4 nrows = 1;
        int i;
        long fetch_mode = 0;

        if (expected_args > 2) {
                /* only for ocifetchinto BC */

                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;
                }
        } else if (expected_args == 2) {
                /* only for oci_fetch_array() */

                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &fetch_mode) == FAILURE) {
                        return;
                }

                if (ZEND_NUM_ARGS() == 1) {
                        fetch_mode = mode;
                }
        } else {
                /* for all oci_fetch_*() */

                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
                        return;
                }

                fetch_mode = mode;
        }

        if (!(fetch_mode & PHP_OCI_NUM) && !(fetch_mode & PHP_OCI_ASSOC)) {
                /* none of the modes present, use the default one */
                if (mode & PHP_OCI_ASSOC) {
                        fetch_mode |= PHP_OCI_ASSOC;
                }
                if (mode & PHP_OCI_NUM) {
                        fetch_mode |= PHP_OCI_NUM;
                }
        }

        PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);

        if (php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
                RETURN_FALSE;
        }

        array_init(return_value);

        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;
                }

                if (!(column->indicator == -1)) {
                        zval *element;

                        MAKE_STD_ZVAL(element);
                        php_oci_column_to_zval(column, element, fetch_mode TSRMLS_CC);

                        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) {
                                        Z_ADDREF_P(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);
                        }
                }
        }

        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);
        }
}
/* }}} */

/* {{{ php_oci_persistent_helper()
 *
 * Helper function to close/rollback persistent connections at the end of request. A return value of
 * 1 indicates that the connection is to be destroyed
 */
static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
{
        time_t timestamp;
        php_oci_connection *connection;

        timestamp = time(NULL);

        /* Persistent connection stubs are also counted as they have private session pools */
        if (le->type == le_pconnection) {
                connection = (php_oci_connection *)le->ptr;

                if (!connection->used_this_request && OCI_G(persistent_timeout) != -1) {
                        if (OCI_G(debug_mode)) {
                                php_printf ("OCI8 DEBUG L1: persistent_helper processing for timeout: (%p stub=%d) at (%s:%d) \n", connection, connection->is_stub, __FILE__, __LINE__);
                        }
                        if (connection->idle_expiry < timestamp) {
                                /* connection has timed out */
                                return ZEND_HASH_APPLY_REMOVE;
                        }
                }
        }
        return ZEND_HASH_APPLY_KEEP;
} /* }}} */

/* {{{ php_oci_create_spool()
 *
 *       Create(alloc + Init) Session pool for the given dbname and charsetid
 */
static php_oci_spool *php_oci_create_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, char *hash_key, int hash_key_len, int charsetid TSRMLS_DC)
{
        php_oci_spool *session_pool = NULL;
        zend_bool iserror = 0;
        ub4 poolmode = OCI_DEFAULT;     /* Mode to be passed to OCISessionPoolCreate */
        OCIAuthInfo *spoolAuth = NULL;

        /* Allocate sessionpool out of persistent memory */
        session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool));
        if (session_pool == NULL) {
                iserror = 1;
                goto exit_create_spool;
        }

        /* Populate key if passed */
        if (hash_key_len) {
                session_pool->spool_hash_key = zend_strndup(hash_key, hash_key_len);
                if (session_pool->spool_hash_key == NULL) {
                        iserror = 1;
                        goto exit_create_spool;
                }
        }

        /* Create the session pool's env */
        if (!(session_pool->env = php_oci_create_env(charsetid TSRMLS_CC))) {
                iserror = 1;
                goto exit_create_spool;
        }

        /* Allocate the pool handle */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (session_pool->env, (dvoid **) &session_pool->poolh, OCI_HTYPE_SPOOL, (size_t) 0, (dvoid **) 0));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
        }

        /* Allocate the session pool error handle - This only for use in the destructor, as there is a
         * generic bug which can free up the OCI_G(err) variable before destroying connections. We
         * cannot use this for other roundtrip calls as there is no way the user can access this error
         */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, ((dvoid *) session_pool->env, (dvoid **)&(session_pool->err), (ub4) OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
        }

/* Disable RLB as we mostly have single-connection pools */
#if (OCI_MAJOR_VERSION > 10)
        poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS;
#else
        poolmode = OCI_SPC_HOMOGENEOUS;
#endif

#if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2)))
        /* Allocate auth handle for session pool {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (session_pool->env, (dvoid **)&(spoolAuth), OCI_HTYPE_AUTHINFO, 0, NULL));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
        } /* }}} */

        /* Set the edition attribute on the auth handle {{{ */
        if (OCI_G(edition)) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) spoolAuth, (ub4) OCI_HTYPE_AUTHINFO, (dvoid *) OCI_G(edition), (ub4)(strlen(OCI_G(edition))), (ub4)OCI_ATTR_EDITION, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        iserror = 1;
                        goto exit_create_spool;
                }
        } /* }}} */

        /* Set the driver name attribute on the auth handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) spoolAuth, (ub4) OCI_HTYPE_AUTHINFO, (dvoid *) PHP_OCI8_DRIVER_NAME, (ub4) sizeof(PHP_OCI8_DRIVER_NAME)-1, (ub4) OCI_ATTR_DRIVER_NAME, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
        } /* }}} */

        /* Set the auth handle on the session pool {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) (session_pool->poolh),(ub4) OCI_HTYPE_SPOOL, (dvoid *) spoolAuth, (ub4)0, (ub4)OCI_ATTR_SPOOL_AUTH, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
        } /* }}} */
#endif

        /* Create the homogeneous session pool - We have different session pools for every different
         * username, password, charset and dbname.
         */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname, (ub4)dbname_len, 0, UB4MAXVAL, 1,(OraText *)username, (ub4)username_len, (OraText *)password,(ub4)password_len, poolmode));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
        }

exit_create_spool:
        if (iserror && session_pool) {
                php_oci_spool_close(session_pool TSRMLS_CC);
                session_pool = NULL;
        }

        if (spoolAuth) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) spoolAuth, (ub4) OCI_HTYPE_AUTHINFO));
        }

        if (OCI_G(debug_mode)) {
                php_printf ("OCI8 DEBUG L1: create_spool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__);
        }

        return session_pool;
} /* }}} */

/* {{{ php_oci_get_spool()
 *
 * Get Session pool for the given dbname and charsetid from the persistent list. Function called for
 * non-persistent connections.
 */
static php_oci_spool *php_oci_get_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, int charsetid TSRMLS_DC)
{
        smart_str spool_hashed_details = {0};
        php_oci_spool *session_pool = NULL;
        zend_rsrc_list_entry spool_le = {0};
        zend_rsrc_list_entry *spool_out_le = NULL;
        zend_bool iserror = 0;

        /* Create the spool hash key {{{ */
        smart_str_appendl_ex(&spool_hashed_details, "oci8spool***", sizeof("oci8spool***") - 1, 0);
        smart_str_appendl_ex(&spool_hashed_details, username, username_len, 0);
        smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
        /* Add edition attribute to the hash */
        if (OCI_G(edition)){
                smart_str_appendl_ex(&spool_hashed_details, OCI_G(edition), strlen(OCI_G(edition)), 0);
        }
        smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
        if (password_len) {
                ulong password_hash;
                password_hash = zend_inline_hash_func(password, password_len);
                smart_str_append_unsigned_ex(&spool_hashed_details, password_hash, 0);
        }
        smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);

        if (dbname_len) {
                smart_str_appendl_ex(&spool_hashed_details, dbname, dbname_len, 0);
        }
        smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);

        smart_str_append_unsigned_ex(&spool_hashed_details, charsetid, 0);

        /* Session Pool Hash Key : oci8spool***username**edition**hashedpassword**dbname**charset */

        smart_str_0(&spool_hashed_details);
        php_strtolower(spool_hashed_details.c, spool_hashed_details.len);
        /* }}} */

        if (zend_hash_find(&EG(persistent_list),spool_hashed_details.c, spool_hashed_details.len+1, (void **)&spool_out_le) == FAILURE) {

                session_pool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, spool_hashed_details.c, spool_hashed_details.len, charsetid TSRMLS_CC);

                if (session_pool == NULL) {
                        iserror = 1;
                        goto exit_get_spool;
                }
                spool_le.ptr  = session_pool;
                spool_le.type = le_psessionpool;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
                zend_list_insert(session_pool, le_psessionpool TSRMLS_CC);
#else
                zend_list_insert(session_pool, le_psessionpool);
#endif
                zend_hash_update(&EG(persistent_list), session_pool->spool_hash_key, strlen(session_pool->spool_hash_key)+1,(void *)&spool_le, sizeof(zend_rsrc_list_entry),NULL);
        } else if (spool_out_le->type == le_psessionpool &&
                strlen(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key) == spool_hashed_details.len &&
                memcmp(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key, spool_hashed_details.c, spool_hashed_details.len) == 0) {
                /* retrieve the cached session pool */
                session_pool = (php_oci_spool *)(spool_out_le->ptr);
        }

exit_get_spool:
        smart_str_free_ex(&spool_hashed_details, 0);
        if (iserror && session_pool) {
                php_oci_spool_close(session_pool TSRMLS_CC);
                session_pool = NULL;
        }

        return session_pool;

} /* }}} */

/* {{{ php_oci_create_env()
 *
 * Create the OCI environment choosing the correct function for the OCI version
 */
static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC)
{
        OCIEnv *retenv = NULL;

        /* create an environment using the character set id */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvNlsCreate, (&retenv, OCI_G(events) ? PHP_OCI_INIT_MODE | OCI_EVENTS : PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, charsetid, charsetid));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                sb4   ora_error_code = 0;
                text  ora_msg_buf[OCI_ERROR_MAXMSG_SIZE];  /* Use traditional smaller size: non-PL/SQL errors should fit and it keeps the stack smaller */

#ifdef HAVE_OCI_INSTANT_CLIENT
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIEnvNlsCreate() failed. There is something wrong with your system - please check that " PHP_OCI8_LIB_PATH_MSG " includes the directory with Oracle Instant Client libraries");
#else
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIEnvNlsCreate() failed. There is something wrong with your system - please check that ORACLE_HOME and " PHP_OCI8_LIB_PATH_MSG " are set and point to the right directories");
#endif
                if (retenv
                        && OCIErrorGet(retenv, (ub4)1, NULL, &ora_error_code, ora_msg_buf, (ub4)OCI_ERROR_MAXMSG_SIZE, (ub4)OCI_HTYPE_ENV) == OCI_SUCCESS
                        && *ora_msg_buf) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", ora_msg_buf);
                }
                
                return NULL;
        }
        return retenv;
}/* }}} */

/* {{{ php_oci_old_create_session()
 *
 * This function is to be deprecated in future in favour of OCISessionGet which is used in
 * php_oci_do_connect_ex
 */
static int php_oci_old_create_session(php_oci_connection *connection, char *dbname, int dbname_len, char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, int session_mode TSRMLS_DC)
{
        ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0;

        if (OCI_G(debug_mode)) {
                php_printf ("OCI8 DEBUG: Bypassing client-side session pool for session create at (%s:%d) \n", __FILE__, __LINE__);
        }

        /* Create the OCI environment separate for each connection */
        if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) {
                return 1;
        }

        /* Allocate our server handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->server), OCI_HTYPE_SERVER, 0, NULL));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        /* Attach to the server {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text *)dbname, dbname_len, (ub4) OCI_DEFAULT));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */
        connection->is_attached = 1;

        /* Allocate our session handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->session), OCI_HTYPE_SESSION, 0, NULL));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        /* Allocate our private error-handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        /* Allocate our service-context {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->svc), OCI_HTYPE_SVCCTX, 0, NULL));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        /* Set the username {{{ */
        if (username) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) username, (ub4) username_len, (ub4) OCI_ATTR_USERNAME, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
        }/* }}} */

        /* Set the password {{{ */
        if (password) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) password, (ub4) password_len, (ub4) OCI_ATTR_PASSWORD, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
        }/* }}} */

        /* Set the edition attribute on the session handle {{{ */
#if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2)))
        if (OCI_G(edition)) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(edition), (ub4) (strlen(OCI_G(edition))), (ub4) OCI_ATTR_EDITION, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
        }
#endif /* }}} */

        /* Set the driver name attribute on the session handle {{{ */
#if (OCI_MAJOR_VERSION >= 11)
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) PHP_OCI8_DRIVER_NAME, (ub4) sizeof(PHP_OCI8_DRIVER_NAME)-1, (ub4) OCI_ATTR_DRIVER_NAME, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        }
#endif /* }}} */

        /* Set the server handle in the service handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        /* Set the authentication handle in the service handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->session, 0, OCI_ATTR_SESSION, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */

        if (new_password) {
                /* Try to change password if new one was provided {{{ */
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPasswordChange, (connection->svc, OCI_G(err), (text *)username, username_len, (text *)password, password_len, (text *)new_password, new_password_len, OCI_AUTH));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }

                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                } /* }}} */
        } else {
                /* start the session {{{ */
                ub4 cred_type = OCI_CRED_RDBMS;

                /* Extract the overloaded session_mode parameter into valid Oracle credential and session mode values */
                if (session_mode & PHP_OCI_CRED_EXT) {
                        cred_type = OCI_CRED_EXT;
                        session_mode ^= PHP_OCI_CRED_EXT;
                }

                session_mode |= OCI_STMT_CACHE;

                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) cred_type, (ub4) session_mode));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when
                         * user's password has expired, but is still usable.
                         */
                        if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
                                return 1;
                        }
                } /* }}} */
        }

        /* Brand new connection: Init and update the next_ping in the connection */
        if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        }

        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        }

        /* Successfully created session */
        return 0;
} /* }}} */

/* {{{ php_oci_create_session()
 *
 * Create session using client-side session pool - new norm
 */
static int php_oci_create_session(php_oci_connection *connection, php_oci_spool *session_pool, char *dbname, int dbname_len, char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, int session_mode TSRMLS_DC)
{
        php_oci_spool *actual_spool = NULL;
#if (OCI_MAJOR_VERSION > 10)
        ub4 purity = -2;                                /* Illegal value to initialize */
#endif
        time_t timestamp = time(NULL);
        ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0;

        /* Persistent connections have private session pools */
        if (connection->is_persistent && !connection->private_spool &&
                !(connection->private_spool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, NULL, 0, connection->charset TSRMLS_CC))) {
                        return 1;
        }
        actual_spool = (connection->is_persistent) ? (connection->private_spool) : (session_pool);

        connection->env = actual_spool->env;

        /* Do this upfront so that connection close on an error would know that this is a session pool
         * connection. Failure to do this would result in crashes in error scenarios
         */
        if (!connection->using_spool) {
                connection->using_spool = 1;
        }

        if (OCI_G(debug_mode)) {
                if (session_pool) {
                        php_printf ("OCI8 DEBUG L1: using shared pool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__);
                } else {
                        php_printf ("OCI8 DEBUG L1: using private pool: (%p) at (%s:%d) \n", connection->private_spool, __FILE__, __LINE__);
                }
        }

        /* The passed in "connection" can be a cached stub from plist or freshly created. In the former
         * case, we do not have to allocate any handles
         */

        if (!connection->err) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
        }

        /* {{{ Allocate and initialize the connection-private authinfo handle if not allocated yet */
        if (!connection->authinfo) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }

                /* Set the Connection class and purity if OCI client version >= 11g */
#if (OCI_MAJOR_VERSION > 10)
                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(connection_class), (ub4)(strlen(OCI_G(connection_class))), (ub4)OCI_ATTR_CONNECTION_CLASS, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }

                if (connection->is_persistent)
                        purity = OCI_ATTR_PURITY_SELF;
                else
                        purity = OCI_ATTR_PURITY_NEW;

                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_AUTHINFO, (dvoid *) &purity, (ub4)0, (ub4)OCI_ATTR_PURITY, OCI_G(err)));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
#endif
        } /* }}} */

        /* Debug statements {{{ */
        if (OCI_G(debug_mode)) {
                ub4 numfree = 0, numbusy = 0, numopen = 0;
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numopen, (ub4 *)0, OCI_ATTR_SPOOL_OPEN_COUNT, OCI_G(err)));
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numbusy, (ub4 *)0, OCI_ATTR_SPOOL_BUSY_COUNT, OCI_G(err)));
                numfree = numopen - numbusy;    /* number of free connections in the pool */
                php_printf ("OCI8 DEBUG L1: (numopen=%d)(numbusy=%d)(numfree=%d) at (%s:%d) \n", numopen, numbusy, numfree, __FILE__, __LINE__);
        } /* }}} */

                /* Ping loop: Ping and loop till we get a good connection. When a database instance goes
                 * down, it can leave several bad connections that need to be flushed out before getting a
                 * good one. In non-RAC, we always get a brand new connection at the end of the loop and in
                 * RAC, we can get a good connection from a different instance before flushing out all bad
                 * ones. We do not need to ping brand new connections.
                 */
        do {
                /* Continue to use the global error handle as the connection is closed when an error occurs */
                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL));

                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);

                        /* Session creation returns OCI_SUCCESS_WITH_INFO when user's password has expired, but
                         * is still usable.
                         */

                        if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
                                return 1;
                        }
                }

                /* {{{ Populate the session and server fields of the connection */
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err)));

                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */

                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, OCI_G(err), (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&(connection->next_pingp)));
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }

                if (!(connection->next_pingp)){
                        /* This is a brand new connection, we need not ping, but have to initialize ping */
                        if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) {
                                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                                return 1;
                        }
                } else if ((*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp))) {
                        if (php_oci_connection_ping(connection TSRMLS_CC)) {
                                /* Got a good connection - update next_ping and get out of ping loop */
                                *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
                        } else {
                                /* Bad connection - remove from pool */
                                PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) OCI_SESSRLS_DROPSESS));
                                connection->svc = NULL;
                                connection->server = NULL;
                                connection->session = NULL;
                        }
                }       /* If ping applicable */
        } while (!(connection->svc));

        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err)));

        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        }

        /* Session is now taken from the session pool and attached and open */
        connection->is_stub = 0;
        connection->is_attached = connection->is_open = 1;

        return 0;
} /* }}} */

/* {{{ php_oci_spool_list_dtor()
 *
 * Session pool destructor function
 */
static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
{
        php_oci_spool *session_pool = (php_oci_spool *)entry->ptr;

        if (session_pool) {
                php_oci_spool_close(session_pool TSRMLS_CC);
        }

        return;
} /* }}} */

/* {{{  php_oci_spool_close()
 *
 * Destroys the OCI Session Pool
 */
static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC)
{
        if (session_pool->poolname_len) {
                PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh,
                        (dvoid *) session_pool->err, OCI_SPD_FORCE));
        }

        if (session_pool->poolh) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL));
        }

        if (session_pool->err) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR));
        }

        if (session_pool->env) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->env, OCI_HTYPE_ENV));
        }

        if (session_pool->spool_hash_key) {
                free(session_pool->spool_hash_key);
        }

        free(session_pool);
} /* }}} */

/* {{{ php_oci_ping_init()
 *
 * Initializes the next_ping time as a context value in the connection.  We now use
 * OCIContext{Get,Set}Value to store the next_ping because we need to support ping for
 * non-persistent DRCP connections
 */
static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC)
{
        time_t *next_pingp = NULL;

        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, errh, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&next_pingp));
        if (OCI_G(errcode) != OCI_SUCCESS) {
                return OCI_G(errcode);
        }

        /* This must be a brand-new connection. Allocate memory for the ping */
        if (!next_pingp) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIMemoryAlloc, (connection->session, errh, (void **)&next_pingp, OCI_DURATION_SESSION, sizeof(time_t), OCI_MEMORY_CLEARED));
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        return OCI_G(errcode);
                }
        }

        if (OCI_G(ping_interval) >= 0) {
                time_t timestamp = time(NULL);
                *next_pingp = timestamp + OCI_G(ping_interval);
        } else {
                *next_pingp = 0;
        }

        /* Set the new ping value into the connection */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextSetValue, (connection->session, errh, OCI_DURATION_SESSION, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), next_pingp));
        if (OCI_G(errcode) != OCI_SUCCESS) {
                OCIMemoryFree(connection->session, errh, next_pingp);
                return OCI_G(errcode);
        }

        /* Cache the pointer so we do not have to do OCIContextGetValue repeatedly */
        connection->next_pingp = next_pingp;

        return OCI_SUCCESS;
} /* }}} */

#endif /* HAVE_OCI8 */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */

/* [<][>][^][v][top][bottom][index][help] */