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
  46. php_oci_dtrace_check_connection

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
  16    |          Thies C. Arntzen <thies@thieso.net>                         |
  17    |          Maxim Maletsky <maxim@maxim.cx>                             |
  18    |                                                                      |
  19    | Collection support by Andy Sautins <asautins@veripost.net>           |
  20    | Temporary LOB support by David Benson <dbenson@mancala.com>          |
  21    | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at>        |
  22    |                                                                      |
  23    | Redesigned by: Antony Dovgal <antony@zend.com>                       |
  24    |                Andi Gutmans <andi@zend.com>                          |
  25    |                Wez Furlong <wez@omniti.com>                          |
  26    +----------------------------------------------------------------------+
  27 */
  28 
  29 #ifdef HAVE_CONFIG_H
  30 #include "config.h"
  31 #endif
  32 
  33 #include "php.h"
  34 #include "ext/standard/info.h"
  35 #include "php_ini.h"
  36 #include "zend_smart_str.h"
  37 
  38 #if HAVE_OCI8
  39 
  40 /* PHP 5.2 is the minimum supported version for OCI8 2.0 */
  41 #if PHP_MAJOR_VERSION < 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1)
  42 #error Use PHP OCI8 1.4 for your version of PHP
  43 #elif PHP_MAJOR_VERSION < 7
  44 /* PHP 7 is the minimum supported version for OCI8 2.1 */
  45 #error Use PHP OCI8 2.0 for your version of PHP
  46 #endif
  47 
  48 #include "php_oci8.h"
  49 #include "php_oci8_int.h"
  50 #include "zend_hash.h"
  51 
  52 #if defined(__PTRDIFF_TYPE__)
  53 # define OCI8_INT_TO_PTR(I)  ((void*)(__PTRDIFF_TYPE__)(I))
  54 # define OCI8_PTR_TO_INT(P)  ((int)(__PTRDIFF_TYPE__)(P))
  55 #elif !defined(__GNUC__)
  56 #define OCI8_INT_TO_PTR(I)  ((void*)&((char*)0)[I])
  57 #define OCI8_PTR_TO_INT(P)  ((int)(((char*)P)-(char*)0))
  58 #elif defined(HAVE_STDINT_H)
  59 #define OCI8_INT_TO_PTR(I)  ((void*)(intptr_t)(I))
  60 #define OCI8_PTR_TO_INT(P)  ((int)(intptr_t)(P))
  61 #else
  62 #define OCI8_INT_TO_PTR(I)  ((void*)(I))
  63 #define OCI8_PTR_TO_INT(P)  ((int)(P))
  64 #endif
  65 
  66 ZEND_DECLARE_MODULE_GLOBALS(oci)
  67 static PHP_GINIT_FUNCTION(oci);
  68 static PHP_GSHUTDOWN_FUNCTION(oci);
  69 
  70 /* Allow PHP 5.3 branch to be used in PECL for 5.x compatible builds */
  71 #ifndef Z_ADDREF_P
  72 #define Z_ADDREF_P(x) ZVAL_ADDREF(x)
  73 #endif
  74 
  75 /* For a user friendly message about environment setup */
  76 #if defined(PHP_WIN32)
  77 #define PHP_OCI8_LIB_PATH_MSG "PATH"
  78 #elif defined(__APPLE__)
  79 #define PHP_OCI8_LIB_PATH_MSG "DYLD_LIBRARY_PATH"
  80 #elif defined(_AIX)
  81 #define PHP_OCI8_LIB_PATH_MSG "LIBPATH"
  82 #elif defined(__hpux)
  83 #define PHP_OCI8_LIB_PATH_MSG "SHLIB_PATH"
  84 #else
  85 #define PHP_OCI8_LIB_PATH_MSG "LD_LIBRARY_PATH"
  86 #endif
  87 
  88 /* True globals, no need for thread safety */
  89 int le_connection;
  90 int le_pconnection;
  91 int le_statement;
  92 int le_descriptor;
  93 int le_psessionpool;
  94 int le_collection;
  95 
  96 zend_class_entry *oci_lob_class_entry_ptr;
  97 zend_class_entry *oci_coll_class_entry_ptr;
  98 
  99 #ifndef SQLT_BFILEE
 100 #define SQLT_BFILEE 114
 101 #endif
 102 #ifndef SQLT_CFILEE
 103 #define SQLT_CFILEE 115
 104 #endif
 105 
 106 #if ZEND_MODULE_API_NO > 20020429
 107 #define ONUPDATELONGFUNC OnUpdateLong
 108 #else
 109 #define ONUPDATELONGFUNC OnUpdateInt
 110 #endif
 111 
 112 #ifdef ZTS
 113 #define PHP_OCI_INIT_MODE (OCI_DEFAULT | OCI_OBJECT | OCI_THREADED | OCI_NO_MUTEX)
 114 #else
 115 #define PHP_OCI_INIT_MODE (OCI_DEFAULT | OCI_OBJECT)
 116 #endif
 117 
 118 /* {{{ static protos */
 119 static void php_oci_connection_list_dtor (zend_resource *);
 120 static void php_oci_pconnection_list_dtor (zend_resource *);
 121 static void php_oci_pconnection_list_np_dtor (zend_resource *);
 122 static void php_oci_statement_list_dtor (zend_resource *);
 123 static void php_oci_descriptor_list_dtor (zend_resource *);
 124 static void php_oci_spool_list_dtor(zend_resource *entry);
 125 static void php_oci_collection_list_dtor (zend_resource *);
 126 
 127 static int php_oci_persistent_helper(zval *zv);
 128 static int php_oci_connection_ping(php_oci_connection *);
 129 static int php_oci_connection_status(php_oci_connection *);
 130 static int php_oci_connection_close(php_oci_connection *);
 131 static void php_oci_spool_close(php_oci_spool *session_pool);
 132 
 133 static OCIEnv *php_oci_create_env(ub2 charsetid);
 134 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);
 135 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);
 136 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);
 137 static php_oci_spool *php_oci_create_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, zend_string *hash_key, int charsetid);
 138 static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh);
 139 /* }}} */
 140 
 141 /* {{{ dynamically loadable module stuff */
 142 #if defined(COMPILE_DL_OCI8) || defined(COMPILE_DL_OCI8_11G) || defined(COMPILE_DL_OCI8_12C)
 143 ZEND_GET_MODULE(oci8)
 144 #endif /* COMPILE_DL */
 145 /* }}} */
 146 
 147 #if defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3)
 148 
 149 /* {{{ Function arginfo */
 150 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_define_by_name, 0, 0, 3)
 151         ZEND_ARG_INFO(0, statement_resource)
 152         ZEND_ARG_INFO(0, column_name)
 153         ZEND_ARG_INFO(1, variable)
 154         ZEND_ARG_INFO(0, type)
 155 ZEND_END_ARG_INFO()
 156 
 157 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_bind_by_name, 0, 0, 3)
 158         ZEND_ARG_INFO(0, statement_resource)
 159         ZEND_ARG_INFO(0, column_name)
 160         ZEND_ARG_INFO(1, variable)
 161         ZEND_ARG_INFO(0, maximum_length)
 162         ZEND_ARG_INFO(0, type)
 163 ZEND_END_ARG_INFO()
 164 
 165 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_bind_array_by_name, 0, 0, 4)
 166         ZEND_ARG_INFO(0, statement_resource)
 167         ZEND_ARG_INFO(0, column_name)
 168         ZEND_ARG_INFO(1, variable)
 169         ZEND_ARG_INFO(0, maximum_array_length)
 170         ZEND_ARG_INFO(0, maximum_item_length)
 171         ZEND_ARG_INFO(0, type)
 172 ZEND_END_ARG_INFO()
 173 
 174 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_descriptor, 0, 0, 1)
 175         ZEND_ARG_INFO(0, lob_descriptor)
 176 ZEND_END_ARG_INFO()
 177 
 178 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_save, 0, 0, 2)
 179         ZEND_ARG_INFO(0, lob_descriptor)
 180         ZEND_ARG_INFO(0, data)
 181         ZEND_ARG_INFO(0, offset)
 182 ZEND_END_ARG_INFO()
 183 
 184 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_import, 0, 0, 2)
 185         ZEND_ARG_INFO(0, lob_descriptor)
 186         ZEND_ARG_INFO(0, filename)
 187 ZEND_END_ARG_INFO()
 188 
 189 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_load, 0, 0, 1)
 190         ZEND_ARG_INFO(0, lob_descriptor)
 191 ZEND_END_ARG_INFO()
 192 
 193 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_read, 0, 0, 2)
 194         ZEND_ARG_INFO(0, lob_descriptor)
 195         ZEND_ARG_INFO(0, length)
 196 ZEND_END_ARG_INFO()
 197 
 198 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_eof, 0, 0, 1)
 199         ZEND_ARG_INFO(0, lob_descriptor)
 200 ZEND_END_ARG_INFO()
 201 
 202 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_tell, 0, 0, 1)
 203         ZEND_ARG_INFO(0, lob_descriptor)
 204 ZEND_END_ARG_INFO()
 205 
 206 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_rewind, 0, 0, 1)
 207         ZEND_ARG_INFO(0, lob_descriptor)
 208 ZEND_END_ARG_INFO()
 209 
 210 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_seek, 0, 0, 2)
 211         ZEND_ARG_INFO(0, lob_descriptor)
 212         ZEND_ARG_INFO(0, offset)
 213         ZEND_ARG_INFO(0, whence)
 214 ZEND_END_ARG_INFO()
 215 
 216 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_size, 0, 0, 1)
 217         ZEND_ARG_INFO(0, lob_descriptor)
 218 ZEND_END_ARG_INFO()
 219 
 220 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write, 0, 0, 2)
 221         ZEND_ARG_INFO(0, lob_descriptor)
 222         ZEND_ARG_INFO(0, string)
 223         ZEND_ARG_INFO(0, length)
 224 ZEND_END_ARG_INFO()
 225 
 226 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_append, 0, 0, 2)
 227         ZEND_ARG_INFO(0, lob_descriptor_to)
 228         ZEND_ARG_INFO(0, lob_descriptor_from)
 229 ZEND_END_ARG_INFO()
 230 
 231 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_truncate, 0, 0, 1)
 232         ZEND_ARG_INFO(0, lob_descriptor)
 233         ZEND_ARG_INFO(0, length)
 234 ZEND_END_ARG_INFO()
 235 
 236 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_erase, 0, 0, 1)
 237         ZEND_ARG_INFO(0, lob_descriptor)
 238         ZEND_ARG_INFO(0, offset)
 239         ZEND_ARG_INFO(0, length)
 240 ZEND_END_ARG_INFO()
 241 
 242 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_flush, 0, 0, 1)
 243         ZEND_ARG_INFO(0, lob_descriptor)
 244         ZEND_ARG_INFO(0, flag)
 245 ZEND_END_ARG_INFO()
 246 
 247 ZEND_BEGIN_ARG_INFO_EX(arginfo_ocisetbufferinglob, 0, 0, 2)
 248         ZEND_ARG_INFO(0, lob_descriptor)
 249         ZEND_ARG_INFO(0, mode)
 250 ZEND_END_ARG_INFO()
 251 
 252 ZEND_BEGIN_ARG_INFO_EX(arginfo_ocigetbufferinglob, 0, 0, 1)
 253         ZEND_ARG_INFO(0, lob_descriptor)
 254 ZEND_END_ARG_INFO()
 255 
 256 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_copy, 0, 0, 2)
 257         ZEND_ARG_INFO(0, lob_descriptor_to)
 258         ZEND_ARG_INFO(0, lob_descriptor_from)
 259         ZEND_ARG_INFO(0, length)
 260 ZEND_END_ARG_INFO()
 261 
 262 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_is_equal, 0, 0, 2)
 263         ZEND_ARG_INFO(0, lob_descriptor)
 264         ZEND_ARG_INFO(0, lob_descriptor)
 265 ZEND_END_ARG_INFO()
 266 
 267 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_export, 0, 0, 2)
 268         ZEND_ARG_INFO(0, lob_descriptor)
 269         ZEND_ARG_INFO(0, filename)
 270         ZEND_ARG_INFO(0, start)
 271         ZEND_ARG_INFO(0, length)
 272 ZEND_END_ARG_INFO()
 273 
 274 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_descriptor, 0, 0, 1)
 275         ZEND_ARG_INFO(0, connection_resource)
 276         ZEND_ARG_INFO(0, type)
 277 ZEND_END_ARG_INFO()
 278 
 279 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_rollback, 0, 0, 1)
 280         ZEND_ARG_INFO(0, connection_resource)
 281 ZEND_END_ARG_INFO()
 282 
 283 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_commit, 0, 0, 1)
 284         ZEND_ARG_INFO(0, connection_resource)
 285 ZEND_END_ARG_INFO()
 286 
 287 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_name, 0, 0, 2)
 288         ZEND_ARG_INFO(0, statement_resource)
 289         ZEND_ARG_INFO(0, column_number_or_name)
 290 ZEND_END_ARG_INFO()
 291 
 292 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_size, 0, 0, 2)
 293         ZEND_ARG_INFO(0, statement_resource)
 294         ZEND_ARG_INFO(0, column_number_or_name)
 295 ZEND_END_ARG_INFO()
 296 
 297 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_scale, 0, 0, 2)
 298         ZEND_ARG_INFO(0, statement_resource)
 299         ZEND_ARG_INFO(0, column_number_or_name)
 300 ZEND_END_ARG_INFO()
 301 
 302 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_precision, 0, 0, 2)
 303         ZEND_ARG_INFO(0, statement_resource)
 304         ZEND_ARG_INFO(0, column_number_or_name)
 305 ZEND_END_ARG_INFO()
 306 
 307 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_type, 0, 0, 2)
 308         ZEND_ARG_INFO(0, statement_resource)
 309         ZEND_ARG_INFO(0, column_number_or_name)
 310 ZEND_END_ARG_INFO()
 311 
 312 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_type_raw, 0, 0, 2)
 313         ZEND_ARG_INFO(0, statement_resource)
 314         ZEND_ARG_INFO(0, column_number_or_name)
 315 ZEND_END_ARG_INFO()
 316 
 317 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_field_is_null, 0, 0, 2)
 318         ZEND_ARG_INFO(0, statement_resource)
 319         ZEND_ARG_INFO(0, column_number_or_name)
 320 ZEND_END_ARG_INFO()
 321 
 322 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_internal_debug, 0, 0, 1)
 323         ZEND_ARG_INFO(0, mode)
 324 ZEND_END_ARG_INFO()
 325 
 326 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_execute, 0, 0, 1)
 327         ZEND_ARG_INFO(0, statement_resource)
 328         ZEND_ARG_INFO(0, mode)
 329 ZEND_END_ARG_INFO()
 330 
 331 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_cancel, 0, 0, 1)
 332         ZEND_ARG_INFO(0, statement_resource)
 333 ZEND_END_ARG_INFO()
 334 
 335 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch, 0, 0, 1)
 336         ZEND_ARG_INFO(0, statement_resource)
 337 ZEND_END_ARG_INFO()
 338 
 339 ZEND_BEGIN_ARG_INFO_EX(arginfo_ocifetchinto, 0, 0, 2)
 340         ZEND_ARG_INFO(0, statement_resource)
 341         ZEND_ARG_INFO(1, result)
 342         ZEND_ARG_INFO(0, mode)
 343 ZEND_END_ARG_INFO()
 344 
 345 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_all, 0, 0, 2)
 346         ZEND_ARG_INFO(0, statement_resource)
 347         ZEND_ARG_INFO(1, output)
 348         ZEND_ARG_INFO(0, skip)
 349         ZEND_ARG_INFO(0, maximum_rows)
 350         ZEND_ARG_INFO(0, flags)
 351 ZEND_END_ARG_INFO()
 352 
 353 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_object, 0, 0, 1)
 354         ZEND_ARG_INFO(0, statement_resource)
 355 ZEND_END_ARG_INFO()
 356 
 357 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_row, 0, 0, 1)
 358         ZEND_ARG_INFO(0, statement_resource)
 359 ZEND_END_ARG_INFO()
 360 
 361 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_assoc, 0, 0, 1)
 362         ZEND_ARG_INFO(0, statement_resource)
 363 ZEND_END_ARG_INFO()
 364 
 365 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_fetch_array, 0, 0, 1)
 366         ZEND_ARG_INFO(0, statement_resource)
 367         ZEND_ARG_INFO(0, mode)
 368 ZEND_END_ARG_INFO()
 369 
 370 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_statement, 0, 0, 1)
 371         ZEND_ARG_INFO(0, statement_resource)
 372 ZEND_END_ARG_INFO()
 373 
 374 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_close, 0, 0, 1)
 375         ZEND_ARG_INFO(0, connection_resource)
 376 ZEND_END_ARG_INFO()
 377 
 378 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_connect, 0, 0, 2)
 379         ZEND_ARG_INFO(0, username)
 380         ZEND_ARG_INFO(0, password)
 381         ZEND_ARG_INFO(0, connection_string)
 382         ZEND_ARG_INFO(0, character_set)
 383         ZEND_ARG_INFO(0, session_mode)
 384 ZEND_END_ARG_INFO()
 385 
 386 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_connect, 0, 0, 2)
 387         ZEND_ARG_INFO(0, username)
 388         ZEND_ARG_INFO(0, password)
 389         ZEND_ARG_INFO(0, connection_string)
 390         ZEND_ARG_INFO(0, character_set)
 391         ZEND_ARG_INFO(0, session_mode)
 392 ZEND_END_ARG_INFO()
 393 
 394 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_pconnect, 0, 0, 2)
 395         ZEND_ARG_INFO(0, username)
 396         ZEND_ARG_INFO(0, password)
 397         ZEND_ARG_INFO(0, connection_string)
 398         ZEND_ARG_INFO(0, character_set)
 399         ZEND_ARG_INFO(0, session_mode)
 400 ZEND_END_ARG_INFO()
 401 
 402 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_error, 0, 0, 0)
 403         ZEND_ARG_INFO(0, connection_or_statement_resource)
 404 ZEND_END_ARG_INFO()
 405 
 406 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_num_fields, 0, 0, 1)
 407         ZEND_ARG_INFO(0, statement_resource)
 408 ZEND_END_ARG_INFO()
 409 
 410 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_parse, 0, 0, 2)
 411         ZEND_ARG_INFO(0, connection_resource)
 412         ZEND_ARG_INFO(0, sql_text)
 413 ZEND_END_ARG_INFO()
 414 
 415 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_get_implicit_resultset, 0, 0, 1)
 416 ZEND_ARG_INFO(0, statement_resource)
 417 ZEND_END_ARG_INFO()
 418 
 419 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_prefetch, 0, 0, 2)
 420         ZEND_ARG_INFO(0, statement_resource)
 421         ZEND_ARG_INFO(0, number_of_rows)
 422 ZEND_END_ARG_INFO()
 423 
 424 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_client_identifier, 0, 0, 2)
 425         ZEND_ARG_INFO(0, connection_resource)
 426         ZEND_ARG_INFO(0, client_identifier)
 427 ZEND_END_ARG_INFO()
 428 
 429 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_edition, 0, 0, 1)
 430         ZEND_ARG_INFO(0, edition_name)
 431 ZEND_END_ARG_INFO()
 432 
 433 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_module_name, 0, 0, 2)
 434         ZEND_ARG_INFO(0, connection_resource)
 435         ZEND_ARG_INFO(0, module_name)
 436 ZEND_END_ARG_INFO()
 437 
 438 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_action, 0, 0, 2)
 439         ZEND_ARG_INFO(0, connection_resource)
 440         ZEND_ARG_INFO(0, action)
 441 ZEND_END_ARG_INFO()
 442 
 443 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_client_info, 0, 0, 2)
 444         ZEND_ARG_INFO(0, connection_resource)
 445         ZEND_ARG_INFO(0, client_information)
 446 ZEND_END_ARG_INFO()
 447 
 448 #ifdef WAITIING_ORACLE_BUG_16695981_FIX
 449 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_set_db_operation, 0, 0, 2)
 450 ZEND_ARG_INFO(0, connection_resource)
 451 ZEND_ARG_INFO(0, action)
 452 ZEND_END_ARG_INFO()
 453 #endif
 454 
 455 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_password_change, 0, 0, 4)
 456         ZEND_ARG_INFO(0, connection_resource_or_connection_string)
 457         ZEND_ARG_INFO(0, username)
 458         ZEND_ARG_INFO(0, old_password)
 459         ZEND_ARG_INFO(0, new_password)
 460 ZEND_END_ARG_INFO()
 461 
 462 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_cursor, 0, 0, 1)
 463         ZEND_ARG_INFO(0, connection_resource)
 464 ZEND_END_ARG_INFO()
 465 
 466 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_result, 0, 0, 2)
 467         ZEND_ARG_INFO(0, statement_resource)
 468         ZEND_ARG_INFO(0, column_number_or_name)
 469 ZEND_END_ARG_INFO()
 470 
 471 ZEND_BEGIN_ARG_INFO(arginfo_oci_client_version, 0)
 472 ZEND_END_ARG_INFO()
 473 
 474 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_server_version, 0, 0, 1)
 475         ZEND_ARG_INFO(0, connection_resource)
 476 ZEND_END_ARG_INFO()
 477 
 478 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_statement_type, 0, 0, 1)
 479         ZEND_ARG_INFO(0, statement_resource)
 480 ZEND_END_ARG_INFO()
 481 
 482 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_num_rows, 0, 0, 1)
 483         ZEND_ARG_INFO(0, statement_resource)
 484 ZEND_END_ARG_INFO()
 485 
 486 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_free_collection, 0, 0, 1)
 487         ZEND_ARG_INFO(0, collection)
 488 ZEND_END_ARG_INFO()
 489 
 490 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_append, 0, 0, 2)
 491         ZEND_ARG_INFO(0, collection)
 492         ZEND_ARG_INFO(0, value)
 493 ZEND_END_ARG_INFO()
 494 
 495 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_get, 0, 0, 2)
 496         ZEND_ARG_INFO(0, collection)
 497         ZEND_ARG_INFO(0, index)
 498 ZEND_END_ARG_INFO()
 499 
 500 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_assign, 0, 0, 2)
 501         ZEND_ARG_INFO(0, collection_to)
 502         ZEND_ARG_INFO(0, collection_from)
 503 ZEND_END_ARG_INFO()
 504 
 505 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_assign, 0, 0, 3)
 506         ZEND_ARG_INFO(0, collection)
 507         ZEND_ARG_INFO(0, index)
 508         ZEND_ARG_INFO(0, value)
 509 ZEND_END_ARG_INFO()
 510 
 511 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_size, 0, 0, 1)
 512         ZEND_ARG_INFO(0, collection)
 513 ZEND_END_ARG_INFO()
 514 
 515 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_max, 0, 0, 1)
 516         ZEND_ARG_INFO(0, collection)
 517 ZEND_END_ARG_INFO()
 518 
 519 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_trim, 0, 0, 2)
 520         ZEND_ARG_INFO(0, collection)
 521         ZEND_ARG_INFO(0, number)
 522 ZEND_END_ARG_INFO()
 523 
 524 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_collection, 0, 0, 2)
 525         ZEND_ARG_INFO(0, connection_resource)
 526         ZEND_ARG_INFO(0, type_name)
 527         ZEND_ARG_INFO(0, schema_name)
 528 ZEND_END_ARG_INFO()
 529 /* }}} */
 530 
 531 /* {{{ LOB Method arginfo */
 532 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_save_method, 0, 0, 1)
 533         ZEND_ARG_INFO(0, data)
 534         ZEND_ARG_INFO(0, offset)
 535 ZEND_END_ARG_INFO()
 536 
 537 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_import_method, 0, 0, 1)
 538         ZEND_ARG_INFO(0, filename)
 539 ZEND_END_ARG_INFO()
 540 
 541 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_load_method, 0)
 542 ZEND_END_ARG_INFO()
 543 
 544 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_read_method, 0, 0, 1)
 545         ZEND_ARG_INFO(0, length)
 546 ZEND_END_ARG_INFO()
 547 
 548 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_eof_method, 0)
 549 ZEND_END_ARG_INFO()
 550 
 551 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_tell_method, 0)
 552 ZEND_END_ARG_INFO()
 553 
 554 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_rewind_method, 0)
 555 ZEND_END_ARG_INFO()
 556 
 557 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_seek_method, 0, 0, 1)
 558         ZEND_ARG_INFO(0, offset)
 559         ZEND_ARG_INFO(0, whence)
 560 ZEND_END_ARG_INFO()
 561 
 562 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_size_method, 0)
 563 ZEND_END_ARG_INFO()
 564 
 565 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write_method, 0, 0, 1)
 566         ZEND_ARG_INFO(0, string)
 567         ZEND_ARG_INFO(0, length)
 568 ZEND_END_ARG_INFO()
 569 
 570 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_append_method, 0, 0, 1)
 571         ZEND_ARG_INFO(0, lob_descriptor_from)
 572 ZEND_END_ARG_INFO()
 573 
 574 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_truncate_method, 0, 0, 0)
 575         ZEND_ARG_INFO(0, length)
 576 ZEND_END_ARG_INFO()
 577 
 578 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_erase_method, 0, 0, 0)
 579         ZEND_ARG_INFO(0, offset)
 580         ZEND_ARG_INFO(0, length)
 581 ZEND_END_ARG_INFO()
 582 
 583 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_flush_method, 0, 0, 0)
 584         ZEND_ARG_INFO(0, flag)
 585 ZEND_END_ARG_INFO()
 586 
 587 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_setbuffering_method, 0, 0, 1)
 588         ZEND_ARG_INFO(0, mode)
 589 ZEND_END_ARG_INFO()
 590 
 591 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_getbuffering_method, 0)
 592 ZEND_END_ARG_INFO()
 593 
 594 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_export_method, 0, 0, 1)
 595         ZEND_ARG_INFO(0, filename)
 596         ZEND_ARG_INFO(0, start)
 597         ZEND_ARG_INFO(0, length)
 598 ZEND_END_ARG_INFO()
 599 
 600 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_lob_write_temporary_method, 0, 0, 1)
 601         ZEND_ARG_INFO(0, data)
 602         ZEND_ARG_INFO(0, type)
 603 ZEND_END_ARG_INFO()
 604 
 605 ZEND_BEGIN_ARG_INFO(arginfo_oci_lob_close_method, 0)
 606 ZEND_END_ARG_INFO()
 607 
 608 ZEND_BEGIN_ARG_INFO(arginfo_oci_free_descriptor_method, 0)
 609 ZEND_END_ARG_INFO()
 610 /* }}} */
 611 
 612 /* {{{ Collection Method arginfo */
 613 ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_free_method, 0)
 614 ZEND_END_ARG_INFO()
 615 
 616 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_append_method, 0, 0, 1)
 617         ZEND_ARG_INFO(0, value)
 618 ZEND_END_ARG_INFO()
 619 
 620 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_get_method, 0, 0, 1)
 621         ZEND_ARG_INFO(0, index)
 622 ZEND_END_ARG_INFO()
 623 
 624 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_assign_method, 0, 0, 1)
 625         ZEND_ARG_INFO(0, collection_from)
 626 ZEND_END_ARG_INFO()
 627 
 628 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_element_assign_method, 0, 0, 2)
 629         ZEND_ARG_INFO(0, index)
 630         ZEND_ARG_INFO(0, value)
 631 ZEND_END_ARG_INFO()
 632 
 633 ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_size_method, 0)
 634 ZEND_END_ARG_INFO()
 635 
 636 ZEND_BEGIN_ARG_INFO(arginfo_oci_collection_max_method, 0)
 637 ZEND_END_ARG_INFO()
 638 
 639 ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_collection_trim_method, 0, 0, 1)
 640         ZEND_ARG_INFO(0, number)
 641 ZEND_END_ARG_INFO()
 642 /* }}} */
 643 
 644 #else /* defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3) */
 645 /* {{{ Keep the old arginfo behavior when building with PHP 4 */
 646 
 647 static unsigned char arginfo_ocifetchinto[]  = { 2, BYREF_NONE, BYREF_FORCE };
 648 static unsigned char arginfo_oci_fetch_all[] = { 2, BYREF_NONE, BYREF_FORCE };
 649 static unsigned char arginfo_oci_define_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
 650 static unsigned char arginfo_oci_bind_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
 651 static unsigned char arginfo_oci_bind_array_by_name[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
 652 
 653 #define arginfo_oci_free_descriptor                                             NULL
 654 #define arginfo_oci_lob_save                                                    NULL
 655 #define arginfo_oci_lob_import                                                  NULL
 656 #define arginfo_oci_lob_load                                                    NULL
 657 #define arginfo_oci_lob_read                                                    NULL
 658 #define arginfo_oci_lob_eof                                                             NULL
 659 #define arginfo_oci_lob_tell                                                    NULL
 660 #define arginfo_oci_lob_rewind                                                  NULL
 661 #define arginfo_oci_lob_seek                                                    NULL
 662 #define arginfo_oci_lob_size                                                    NULL
 663 #define arginfo_oci_lob_write                                                   NULL
 664 #define arginfo_oci_lob_append                                                  NULL
 665 #define arginfo_oci_lob_truncate                                                NULL
 666 #define arginfo_oci_lob_erase                                                   NULL
 667 #define arginfo_oci_lob_flush                                                   NULL
 668 #define arginfo_ocisetbufferinglob                                              NULL
 669 #define arginfo_ocigetbufferinglob                                              NULL
 670 #define arginfo_oci_lob_copy                                                    NULL
 671 #define arginfo_oci_lob_is_equal                                                NULL
 672 #define arginfo_oci_lob_export                                                  NULL
 673 #define arginfo_oci_new_descriptor                                              NULL
 674 #define arginfo_oci_rollback                                                    NULL
 675 #define arginfo_oci_commit                                                              NULL
 676 #define arginfo_oci_field_name                                                  NULL
 677 #define arginfo_oci_field_size                                                  NULL
 678 #define arginfo_oci_field_scale                                                 NULL
 679 #define arginfo_oci_field_precision                                             NULL
 680 #define arginfo_oci_field_type                                                  NULL
 681 #define arginfo_oci_field_type_raw                                              NULL
 682 #define arginfo_oci_field_is_null                                               NULL
 683 #define arginfo_oci_internal_debug                                              NULL
 684 #define arginfo_oci_execute                                                             NULL
 685 #define arginfo_oci_cancel                                                              NULL
 686 #define arginfo_oci_fetch                                                               NULL
 687 #define arginfo_oci_fetch_object                                                NULL
 688 #define arginfo_oci_fetch_row                                                   NULL
 689 #define arginfo_oci_fetch_assoc                                                 NULL
 690 #define arginfo_oci_fetch_array                                                 NULL
 691 #define arginfo_oci_free_statement                                              NULL
 692 #define arginfo_oci_close                                                               NULL
 693 #define arginfo_oci_new_connect                                                 NULL
 694 #define arginfo_oci_connect                                                             NULL
 695 #define arginfo_oci_pconnect                                                    NULL
 696 #define arginfo_oci_error                                                               NULL
 697 #define arginfo_oci_num_fields                                                  NULL
 698 #define arginfo_oci_parse                                                               NULL
 699 #define arginfo_oci_get_implicit_resultset                              NULL
 700 #define arginfo_oci_set_prefetch                                                NULL
 701 #define arginfo_oci_set_client_identifier                               NULL
 702 #define arginfo_oci_set_edition                                                 NULL
 703 #define arginfo_oci_set_module_name                                             NULL
 704 #define arginfo_oci_set_action                                                  NULL
 705 #define arginfo_oci_set_client_info                                             NULL
 706 #ifdef WAITIING_ORACLE_BUG_16695981_FIX
 707 #define arginfo_oci_set_db_operation                                    NULL
 708 #endif
 709 #define arginfo_oci_password_change                                             NULL
 710 #define arginfo_oci_new_cursor                                                  NULL
 711 #define arginfo_oci_result                                                              NULL
 712 #define arginfo_oci_client_version                                              NULL
 713 #define arginfo_oci_server_version                                              NULL
 714 #define arginfo_oci_statement_type                                              NULL
 715 #define arginfo_oci_num_rows                                                    NULL
 716 #define arginfo_oci_free_collection                                             NULL
 717 #define arginfo_oci_collection_append                                   NULL
 718 #define arginfo_oci_collection_element_get                              NULL
 719 #define arginfo_oci_collection_assign                                   NULL
 720 #define arginfo_oci_collection_element_assign                   NULL
 721 #define arginfo_oci_collection_size                                             NULL
 722 #define arginfo_oci_collection_max                                              NULL
 723 #define arginfo_oci_collection_trim                                             NULL
 724 #define arginfo_oci_new_collection                                              NULL
 725 #define arginfo_oci_lob_size_method                                             NULL
 726 #define arginfo_oci_lob_getbuffering_method                             NULL
 727 #define arginfo_oci_lob_close_method                                    NULL
 728 #define arginfo_oci_lob_save_method                                             NULL
 729 #define arginfo_oci_lob_import_method                                   NULL
 730 #define arginfo_oci_lob_read_method                                             NULL
 731 #define arginfo_oci_lob_seek_method                                             NULL
 732 #define arginfo_oci_lob_write_method                                    NULL
 733 #define arginfo_oci_lob_append_method                                   NULL
 734 #define arginfo_oci_lob_truncate_method                                 NULL
 735 #define arginfo_oci_lob_erase_method                                    NULL
 736 #define arginfo_oci_lob_flush_method                                    NULL
 737 #define arginfo_oci_lob_setbuffering_method                             NULL
 738 #define arginfo_oci_lob_export_method                                   NULL
 739 #define arginfo_oci_lob_write_temporary_method                  NULL
 740 #define arginfo_oci_lob_load_method                                             NULL
 741 #define arginfo_oci_lob_tell_method                                             NULL
 742 #define arginfo_oci_lob_rewind_method                                   NULL
 743 #define arginfo_oci_lob_eof_method                                              NULL
 744 #define arginfo_oci_free_descriptor_method                              NULL
 745 #define arginfo_oci_collection_append_method                    NULL
 746 #define arginfo_oci_collection_element_get_method               NULL
 747 #define arginfo_oci_collection_assign_method                    NULL
 748 #define arginfo_oci_collection_size_method                              NULL
 749 #define arginfo_oci_collection_element_assign_method    NULL
 750 #define arginfo_oci_collection_max_method                               NULL
 751 #define arginfo_oci_collection_trim_method                              NULL
 752 #define arginfo_oci_collection_free_method                              NULL
 753 /* }}} */
 754 #endif /* defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3) */
 755 
 756 /* {{{ extension function prototypes
 757 */
 758 PHP_FUNCTION(oci_bind_by_name);
 759 PHP_FUNCTION(oci_bind_array_by_name);
 760 PHP_FUNCTION(oci_define_by_name);
 761 PHP_FUNCTION(oci_field_is_null);
 762 PHP_FUNCTION(oci_field_name);
 763 PHP_FUNCTION(oci_field_size);
 764 PHP_FUNCTION(oci_field_scale);
 765 PHP_FUNCTION(oci_field_precision);
 766 PHP_FUNCTION(oci_field_type);
 767 PHP_FUNCTION(oci_field_type_raw);
 768 PHP_FUNCTION(oci_execute);
 769 PHP_FUNCTION(oci_fetch);
 770 PHP_FUNCTION(oci_cancel);
 771 PHP_FUNCTION(ocifetchinto);
 772 PHP_FUNCTION(oci_fetch_object);
 773 PHP_FUNCTION(oci_fetch_row);
 774 PHP_FUNCTION(oci_fetch_assoc);
 775 PHP_FUNCTION(oci_fetch_array);
 776 PHP_FUNCTION(ocifetchstatement);
 777 PHP_FUNCTION(oci_fetch_all);
 778 PHP_FUNCTION(oci_free_statement);
 779 PHP_FUNCTION(oci_internal_debug);
 780 PHP_FUNCTION(oci_close);
 781 PHP_FUNCTION(oci_connect);
 782 PHP_FUNCTION(oci_new_connect);
 783 PHP_FUNCTION(oci_pconnect);
 784 PHP_FUNCTION(oci_error);
 785 PHP_FUNCTION(oci_free_descriptor);
 786 PHP_FUNCTION(oci_commit);
 787 PHP_FUNCTION(oci_rollback);
 788 PHP_FUNCTION(oci_new_descriptor);
 789 PHP_FUNCTION(oci_num_fields);
 790 PHP_FUNCTION(oci_parse);
 791 PHP_FUNCTION(oci_get_implicit_resultset);
 792 PHP_FUNCTION(oci_new_cursor);
 793 PHP_FUNCTION(oci_result);
 794 PHP_FUNCTION(oci_client_version);
 795 PHP_FUNCTION(oci_server_version);
 796 PHP_FUNCTION(oci_statement_type);
 797 PHP_FUNCTION(oci_num_rows);
 798 PHP_FUNCTION(oci_set_prefetch);
 799 PHP_FUNCTION(oci_set_client_identifier);
 800 #ifdef WAITIING_ORACLE_BUG_16695981_FIX
 801 PHP_FUNCTION(oci_set_db_operation);
 802 #endif
 803 PHP_FUNCTION(oci_set_edition);
 804 PHP_FUNCTION(oci_set_module_name);
 805 PHP_FUNCTION(oci_set_action);
 806 PHP_FUNCTION(oci_set_client_info);
 807 PHP_FUNCTION(oci_password_change);
 808 PHP_FUNCTION(oci_lob_save);
 809 PHP_FUNCTION(oci_lob_import);
 810 PHP_FUNCTION(oci_lob_export);
 811 PHP_FUNCTION(oci_lob_load);
 812 PHP_FUNCTION(oci_lob_tell);
 813 PHP_FUNCTION(oci_lob_write);
 814 PHP_FUNCTION(oci_lob_append);
 815 PHP_FUNCTION(oci_lob_copy);
 816 PHP_FUNCTION(oci_lob_truncate);
 817 PHP_FUNCTION(oci_lob_erase);
 818 PHP_FUNCTION(oci_lob_flush);
 819 PHP_FUNCTION(ocisetbufferinglob);
 820 PHP_FUNCTION(ocigetbufferinglob);
 821 PHP_FUNCTION(oci_lob_is_equal);
 822 PHP_FUNCTION(oci_lob_rewind);
 823 PHP_FUNCTION(oci_lob_read);
 824 PHP_FUNCTION(oci_lob_eof);
 825 PHP_FUNCTION(oci_lob_seek);
 826 PHP_FUNCTION(oci_lob_size);
 827 PHP_FUNCTION(oci_lob_write_temporary);
 828 PHP_FUNCTION(oci_lob_close);
 829 PHP_FUNCTION(oci_new_collection);
 830 PHP_FUNCTION(oci_free_collection);
 831 PHP_FUNCTION(oci_collection_append);
 832 PHP_FUNCTION(oci_collection_element_get);
 833 PHP_FUNCTION(oci_collection_element_assign);
 834 PHP_FUNCTION(oci_collection_assign);
 835 PHP_FUNCTION(oci_collection_size);
 836 PHP_FUNCTION(oci_collection_max);
 837 PHP_FUNCTION(oci_collection_trim);
 838 /* }}} */
 839 
 840 /* {{{ extension definition structures
 841 */
 842 static
 843 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
 844 /* This "if" allows PECL builds from this file to be portable to older PHP releases */
 845 const
 846 #endif
 847 zend_function_entry php_oci_functions[] = {
 848         PHP_FE(oci_define_by_name,                      arginfo_oci_define_by_name)
 849         PHP_FE(oci_bind_by_name,                        arginfo_oci_bind_by_name)
 850         PHP_FE(oci_bind_array_by_name,          arginfo_oci_bind_array_by_name)
 851         PHP_FE(oci_field_is_null,                       arginfo_oci_field_is_null)
 852         PHP_FE(oci_field_name,                          arginfo_oci_field_name)
 853         PHP_FE(oci_field_size,                          arginfo_oci_field_size)
 854         PHP_FE(oci_field_scale,                         arginfo_oci_field_scale)
 855         PHP_FE(oci_field_precision,                     arginfo_oci_field_precision)
 856         PHP_FE(oci_field_type,                          arginfo_oci_field_type)
 857         PHP_FE(oci_field_type_raw,                      arginfo_oci_field_type_raw)
 858         PHP_FE(oci_execute,                                     arginfo_oci_execute)
 859         PHP_FE(oci_cancel,                                      arginfo_oci_cancel)
 860         PHP_FE(oci_fetch,                                       arginfo_oci_fetch)
 861         PHP_FE(oci_fetch_object,                        arginfo_oci_fetch_object)
 862         PHP_FE(oci_fetch_row,                           arginfo_oci_fetch_row)
 863         PHP_FE(oci_fetch_assoc,                         arginfo_oci_fetch_assoc)
 864         PHP_FE(oci_fetch_array,                         arginfo_oci_fetch_array)
 865         PHP_FE(ocifetchinto,                            arginfo_ocifetchinto)
 866         PHP_FE(oci_fetch_all,                           arginfo_oci_fetch_all)
 867         PHP_FE(oci_free_statement,                      arginfo_oci_free_statement)
 868         PHP_FE(oci_internal_debug,                      arginfo_oci_internal_debug)
 869         PHP_FE(oci_num_fields,                          arginfo_oci_num_fields)
 870         PHP_FE(oci_parse,                                       arginfo_oci_parse)
 871         PHP_FE(oci_get_implicit_resultset,      arginfo_oci_get_implicit_resultset)
 872         PHP_FE(oci_new_cursor,                          arginfo_oci_new_cursor)
 873         PHP_FE(oci_result,                                      arginfo_oci_result)
 874         PHP_FE(oci_client_version,                      arginfo_oci_client_version)
 875         PHP_FE(oci_server_version,                      arginfo_oci_server_version)
 876         PHP_FE(oci_statement_type,                      arginfo_oci_statement_type)
 877         PHP_FE(oci_num_rows,                            arginfo_oci_num_rows)
 878         PHP_FE(oci_close,                                       arginfo_oci_close)
 879         PHP_FE(oci_connect,                                     arginfo_oci_connect)
 880         PHP_FE(oci_new_connect,                         arginfo_oci_new_connect)
 881         PHP_FE(oci_pconnect,                            arginfo_oci_pconnect)
 882         PHP_FE(oci_error,                                       arginfo_oci_error)
 883         PHP_FE(oci_free_descriptor,                     arginfo_oci_free_descriptor)
 884         PHP_FE(oci_lob_save,                            arginfo_oci_lob_save)
 885         PHP_FE(oci_lob_import,                          arginfo_oci_lob_import)
 886         PHP_FE(oci_lob_size,                            arginfo_oci_lob_size)
 887         PHP_FE(oci_lob_load,                            arginfo_oci_lob_load)
 888         PHP_FE(oci_lob_read,                            arginfo_oci_lob_read)
 889         PHP_FE(oci_lob_eof,                                     arginfo_oci_lob_eof)
 890         PHP_FE(oci_lob_tell,                            arginfo_oci_lob_tell)
 891         PHP_FE(oci_lob_truncate,                        arginfo_oci_lob_truncate)
 892         PHP_FE(oci_lob_erase,                           arginfo_oci_lob_erase)
 893         PHP_FE(oci_lob_flush,                           arginfo_oci_lob_flush)
 894         PHP_FE(ocisetbufferinglob,                      arginfo_ocisetbufferinglob)
 895         PHP_FE(ocigetbufferinglob,                      arginfo_ocigetbufferinglob)
 896         PHP_FE(oci_lob_is_equal,                        arginfo_oci_lob_is_equal)
 897         PHP_FE(oci_lob_rewind,                          arginfo_oci_lob_rewind)
 898         PHP_FE(oci_lob_write,                           arginfo_oci_lob_write)
 899         PHP_FE(oci_lob_append,                          arginfo_oci_lob_append)
 900         PHP_FE(oci_lob_copy,                            arginfo_oci_lob_copy)
 901         PHP_FE(oci_lob_export,                          arginfo_oci_lob_export)
 902         PHP_FE(oci_lob_seek,                            arginfo_oci_lob_seek)
 903         PHP_FE(oci_commit,                                      arginfo_oci_commit)
 904         PHP_FE(oci_rollback,                            arginfo_oci_rollback)
 905         PHP_FE(oci_new_descriptor,                      arginfo_oci_new_descriptor)
 906         PHP_FE(oci_set_prefetch,                        arginfo_oci_set_prefetch)
 907         PHP_FE(oci_set_client_identifier,       arginfo_oci_set_client_identifier)
 908 #ifdef WAITIING_ORACLE_BUG_16695981_FIX
 909         PHP_FE(oci_set_db_operation,            arginfo_oci_set_db_operation)
 910 #endif
 911         PHP_FE(oci_set_edition,                         arginfo_oci_set_edition)
 912         PHP_FE(oci_set_module_name,                     arginfo_oci_set_module_name)
 913         PHP_FE(oci_set_action,                          arginfo_oci_set_action)
 914         PHP_FE(oci_set_client_info,                     arginfo_oci_set_client_info)
 915         PHP_FE(oci_password_change,                     arginfo_oci_password_change)
 916         PHP_FE(oci_free_collection,                     arginfo_oci_free_collection)
 917         PHP_FE(oci_collection_append,           arginfo_oci_collection_append)
 918         PHP_FE(oci_collection_element_get,      arginfo_oci_collection_element_get)
 919         PHP_FE(oci_collection_element_assign,   arginfo_oci_collection_element_assign)
 920         PHP_FE(oci_collection_assign,           arginfo_oci_collection_assign)
 921         PHP_FE(oci_collection_size,                     arginfo_oci_collection_size)
 922         PHP_FE(oci_collection_max,                      arginfo_oci_collection_max)
 923         PHP_FE(oci_collection_trim,                     arginfo_oci_collection_trim)
 924         PHP_FE(oci_new_collection,                      arginfo_oci_new_collection)
 925 
 926         PHP_FALIAS(oci_free_cursor,             oci_free_statement,             arginfo_oci_free_statement)
 927         PHP_FALIAS(ocifreecursor,               oci_free_statement,             arginfo_oci_free_statement)
 928         PHP_FALIAS(ocibindbyname,               oci_bind_by_name,               arginfo_oci_bind_by_name)
 929         PHP_FALIAS(ocidefinebyname,             oci_define_by_name,             arginfo_oci_define_by_name)
 930         PHP_FALIAS(ocicolumnisnull,             oci_field_is_null,              arginfo_oci_field_is_null)
 931         PHP_FALIAS(ocicolumnname,               oci_field_name,                 arginfo_oci_field_name)
 932         PHP_FALIAS(ocicolumnsize,               oci_field_size,                 arginfo_oci_field_size)
 933         PHP_FALIAS(ocicolumnscale,              oci_field_scale,                arginfo_oci_field_scale)
 934         PHP_FALIAS(ocicolumnprecision,  oci_field_precision,    arginfo_oci_field_precision)
 935         PHP_FALIAS(ocicolumntype,               oci_field_type,                 arginfo_oci_field_type)
 936         PHP_FALIAS(ocicolumntyperaw,    oci_field_type_raw,             arginfo_oci_field_type_raw)
 937         PHP_FALIAS(ociexecute,                  oci_execute,                    arginfo_oci_execute)
 938         PHP_FALIAS(ocicancel,                   oci_cancel,                             arginfo_oci_cancel)
 939         PHP_FALIAS(ocifetch,                    oci_fetch,                              arginfo_oci_fetch)
 940         PHP_FALIAS(ocifetchstatement,   oci_fetch_all,                  arginfo_oci_fetch_all)
 941         PHP_FALIAS(ocifreestatement,    oci_free_statement,             arginfo_oci_free_statement)
 942         PHP_FALIAS(ociinternaldebug,    oci_internal_debug,             arginfo_oci_internal_debug)
 943         PHP_FALIAS(ocinumcols,                  oci_num_fields,                 arginfo_oci_num_fields)
 944         PHP_FALIAS(ociparse,                    oci_parse,                              arginfo_oci_parse)
 945         PHP_FALIAS(ocinewcursor,                oci_new_cursor,                 arginfo_oci_new_cursor)
 946         PHP_FALIAS(ociresult,                   oci_result,                             arginfo_oci_result)
 947         PHP_FALIAS(ociserverversion,    oci_server_version,             arginfo_oci_server_version)
 948         PHP_FALIAS(ocistatementtype,    oci_statement_type,             arginfo_oci_statement_type)
 949         PHP_FALIAS(ocirowcount,                 oci_num_rows,                   arginfo_oci_num_rows)
 950         PHP_FALIAS(ocilogoff,                   oci_close,                              arginfo_oci_close)
 951         PHP_FALIAS(ocilogon,                    oci_connect,                    arginfo_oci_connect)
 952         PHP_FALIAS(ocinlogon,                   oci_new_connect,                arginfo_oci_new_connect)
 953         PHP_FALIAS(ociplogon,                   oci_pconnect,                   arginfo_oci_pconnect)
 954         PHP_FALIAS(ocierror,                    oci_error,                              arginfo_oci_error)
 955         PHP_FALIAS(ocifreedesc,                 oci_free_descriptor,    arginfo_oci_free_descriptor)
 956         PHP_FALIAS(ocisavelob,                  oci_lob_save,                   arginfo_oci_lob_save)
 957         PHP_FALIAS(ocisavelobfile,              oci_lob_import,                 arginfo_oci_lob_import)
 958         PHP_FALIAS(ociwritelobtofile,   oci_lob_export,                 arginfo_oci_lob_export)
 959         PHP_FALIAS(ociloadlob,                  oci_lob_load,                   arginfo_oci_lob_load)
 960         PHP_FALIAS(ocicommit,                   oci_commit,                             arginfo_oci_commit)
 961         PHP_FALIAS(ocirollback,                 oci_rollback,                   arginfo_oci_rollback)
 962         PHP_FALIAS(ocinewdescriptor,    oci_new_descriptor,             arginfo_oci_new_descriptor)
 963         PHP_FALIAS(ocisetprefetch,              oci_set_prefetch,               arginfo_oci_set_prefetch)
 964         PHP_FALIAS(ocipasswordchange,   oci_password_change,    arginfo_oci_password_change)
 965         PHP_FALIAS(ocifreecollection,   oci_free_collection,    arginfo_oci_free_collection)
 966         PHP_FALIAS(ocinewcollection,    oci_new_collection,             arginfo_oci_new_collection)
 967         PHP_FALIAS(ocicollappend,               oci_collection_append,  arginfo_oci_collection_append)
 968         PHP_FALIAS(ocicollgetelem,              oci_collection_element_get,             arginfo_oci_collection_element_get)
 969         PHP_FALIAS(ocicollassignelem,   oci_collection_element_assign,  arginfo_oci_collection_element_assign)
 970         PHP_FALIAS(ocicollsize,                 oci_collection_size,    arginfo_oci_collection_size)
 971         PHP_FALIAS(ocicollmax,                  oci_collection_max,             arginfo_oci_collection_max)
 972         PHP_FALIAS(ocicolltrim,                 oci_collection_trim,    arginfo_oci_collection_trim)
 973 #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)
 974         PHP_FE_END
 975 #else
 976         {NULL,NULL,NULL}
 977 #endif
 978 };
 979 
 980 static
 981 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
 982 /* This "if" allows PECL builds from this file to be portable to older PHP releases */
 983 const
 984 #endif
 985 zend_function_entry php_oci_lob_class_functions[] = {
 986         PHP_FALIAS(load,                oci_lob_load,                   arginfo_oci_lob_load_method)
 987         PHP_FALIAS(tell,                oci_lob_tell,                   arginfo_oci_lob_tell_method)
 988         PHP_FALIAS(truncate,    oci_lob_truncate,               arginfo_oci_lob_truncate_method)
 989         PHP_FALIAS(erase,               oci_lob_erase,                  arginfo_oci_lob_erase_method)
 990         PHP_FALIAS(flush,               oci_lob_flush,                  arginfo_oci_lob_flush_method)
 991         PHP_FALIAS(setbuffering,ocisetbufferinglob,             arginfo_oci_lob_setbuffering_method)
 992         PHP_FALIAS(getbuffering,ocigetbufferinglob,             arginfo_oci_lob_getbuffering_method)
 993         PHP_FALIAS(rewind,              oci_lob_rewind,                 arginfo_oci_lob_rewind_method)
 994         PHP_FALIAS(read,                oci_lob_read,                   arginfo_oci_lob_read_method)
 995         PHP_FALIAS(eof,                 oci_lob_eof,                    arginfo_oci_lob_eof_method)
 996         PHP_FALIAS(seek,                oci_lob_seek,                   arginfo_oci_lob_seek_method)
 997         PHP_FALIAS(write,               oci_lob_write,                  arginfo_oci_lob_write_method)
 998         PHP_FALIAS(append,              oci_lob_append,                 arginfo_oci_lob_append_method)
 999         PHP_FALIAS(size,                oci_lob_size,                   arginfo_oci_lob_size_method)
1000         PHP_FALIAS(writetofile, oci_lob_export,                 arginfo_oci_lob_export_method)
1001         PHP_FALIAS(export,              oci_lob_export,                 arginfo_oci_lob_export_method)
1002         PHP_FALIAS(import,              oci_lob_import,                 arginfo_oci_lob_import_method)
1003         PHP_FALIAS(writetemporary,      oci_lob_write_temporary,        arginfo_oci_lob_write_temporary_method)
1004         PHP_FALIAS(close,                       oci_lob_close,                          arginfo_oci_lob_close_method)
1005         PHP_FALIAS(save,                oci_lob_save,                   arginfo_oci_lob_save_method)
1006         PHP_FALIAS(savefile,    oci_lob_import,                 arginfo_oci_lob_import_method)
1007         PHP_FALIAS(free,                oci_free_descriptor,    arginfo_oci_free_descriptor_method)
1008 #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)
1009         PHP_FE_END
1010 #else
1011         {NULL,NULL,NULL}
1012 #endif
1013 };
1014 
1015 static
1016 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION > 5)
1017 /* This "if" allows PECL builds from this file to be portable to older PHP releases */
1018 const
1019 #endif
1020 zend_function_entry php_oci_coll_class_functions[] = {
1021         PHP_FALIAS(append,                oci_collection_append,                        arginfo_oci_collection_append_method)
1022         PHP_FALIAS(getelem,               oci_collection_element_get,           arginfo_oci_collection_element_get_method)
1023         PHP_FALIAS(assignelem,    oci_collection_element_assign,        arginfo_oci_collection_element_assign_method)
1024         PHP_FALIAS(assign,                oci_collection_assign,                        arginfo_oci_collection_assign_method)
1025         PHP_FALIAS(size,                  oci_collection_size,                          arginfo_oci_collection_size_method)
1026         PHP_FALIAS(max,                   oci_collection_max,                           arginfo_oci_collection_max_method)
1027         PHP_FALIAS(trim,                  oci_collection_trim,                          arginfo_oci_collection_trim_method)
1028         PHP_FALIAS(free,                  oci_free_collection,                          arginfo_oci_collection_free_method)
1029 #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)
1030         PHP_FE_END
1031 #else
1032         {NULL,NULL,NULL}
1033 #endif
1034 };
1035 
1036 zend_module_entry oci8_module_entry = {
1037         STANDARD_MODULE_HEADER,
1038         "oci8",                           /* extension name */
1039         php_oci_functions,        /* extension function list */
1040         PHP_MINIT(oci),           /* extension-wide startup function */
1041         PHP_MSHUTDOWN(oci),       /* extension-wide shutdown function */
1042         PHP_RINIT(oci),           /* per-request startup function */
1043         PHP_RSHUTDOWN(oci),       /* per-request shutdown function */
1044         PHP_MINFO(oci),           /* information function */
1045         PHP_OCI8_VERSION,
1046         PHP_MODULE_GLOBALS(oci),  /* globals descriptor */
1047         PHP_GINIT(oci),                   /* globals ctor */
1048         PHP_GSHUTDOWN(oci),               /* globals dtor */
1049         NULL,                                     /* post deactivate */
1050         STANDARD_MODULE_PROPERTIES_EX
1051 };
1052 /* }}} */
1053 
1054 /* {{{ PHP_INI */
1055 PHP_INI_BEGIN()
1056         STD_PHP_INI_ENTRY(      "oci8.max_persistent",                  "-1",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       max_persistent,                 zend_oci_globals,       oci_globals)
1057         STD_PHP_INI_ENTRY(      "oci8.persistent_timeout",              "-1",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       persistent_timeout,             zend_oci_globals,       oci_globals)
1058         STD_PHP_INI_ENTRY(      "oci8.ping_interval",                   "60",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       ping_interval,                  zend_oci_globals,       oci_globals)
1059         STD_PHP_INI_BOOLEAN("oci8.privileged_connect",          "0",    PHP_INI_SYSTEM, OnUpdateBool,           privileged_connect,             zend_oci_globals,       oci_globals)
1060         STD_PHP_INI_ENTRY(      "oci8.statement_cache_size",    "20",   PHP_INI_SYSTEM, ONUPDATELONGFUNC,       statement_cache_size,   zend_oci_globals,       oci_globals)
1061         STD_PHP_INI_ENTRY(      "oci8.default_prefetch",                "100",  PHP_INI_SYSTEM, ONUPDATELONGFUNC,       default_prefetch,               zend_oci_globals,       oci_globals)
1062         STD_PHP_INI_BOOLEAN("oci8.old_oci_close_semantics",     "0",    PHP_INI_SYSTEM, OnUpdateBool,           old_oci_close_semantics,zend_oci_globals,       oci_globals)
1063 #if (OCI_MAJOR_VERSION >= 11)
1064         STD_PHP_INI_ENTRY(      "oci8.connection_class",                "",             PHP_INI_ALL,    OnUpdateString,         connection_class,               zend_oci_globals,       oci_globals)
1065 #endif
1066 #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
1067         STD_PHP_INI_BOOLEAN("oci8.events",                                      "0",    PHP_INI_SYSTEM, OnUpdateBool,           events,                                 zend_oci_globals,       oci_globals)
1068 #endif
1069 PHP_INI_END()
1070 /* }}} */
1071 
1072 /* {{{ startup, shutdown and info functions
1073 */
1074 
1075 /* {{{  php_oci_init_global_handles()
1076  *
1077  * Initialize global handles only when they are needed
1078  */
1079 static void php_oci_init_global_handles(void)
1080 {
1081         sword errstatus;
1082         sb4   ora_error_code = 0;
1083         text  tmp_buf[PHP_OCI_ERRBUF_LEN];  /* Use traditional smaller size: non-PL/SQL errors should fit and it keeps the stack smaller */
1084 
1085         errstatus = OCIEnvNlsCreate(&OCI_G(env), PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, 0, 0);
1086 
1087         if (errstatus == OCI_ERROR) {
1088 #ifdef HAVE_OCI_INSTANT_CLIENT
1089                 php_error_docref(NULL, 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");
1090 #else
1091                 php_error_docref(NULL, 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");
1092 #endif
1093                 if (OCI_G(env)
1094                         && OCIErrorGet(OCI_G(env), (ub4)1, NULL, &ora_error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ENV) == OCI_SUCCESS
1095                         && *tmp_buf) {
1096                         php_error_docref(NULL, E_WARNING, "%s", tmp_buf);
1097                 }
1098 
1099                 OCI_G(env) = NULL;
1100                 OCI_G(err) = NULL;
1101                 return;
1102         }
1103 
1104         errstatus = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL);
1105 
1106         if (errstatus == OCI_SUCCESS) {
1107 #if !defined(OCI_MAJOR_VERSION) || (OCI_MAJOR_VERSION < 11)
1108                 /* This fixes PECL bug 15988 (sqlnet.ora not being read).  The
1109                  * root cause was fixed in Oracle 10.2.0.4 but there is no
1110                  * compile time method to check for that precise patch level,
1111                  * nor can it be guaranteed that runtime will use the same
1112                  * patch level the code was compiled with.  So, we do this
1113                  * code for all non 11g versions.
1114                  */
1115                 OCICPool *cpoolh;
1116                 ub4 cpoolmode = 0x80000000;     /* Pass invalid mode to OCIConnectionPoolCreate */
1117                 PHP_OCI_CALL(OCIHandleAlloc, (OCI_G(env), (dvoid **) &cpoolh, OCI_HTYPE_CPOOL, (size_t) 0, (dvoid **) 0));
1118                 PHP_OCI_CALL(OCIConnectionPoolCreate, (OCI_G(env), OCI_G(err), cpoolh, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, NULL, 0, cpoolmode));
1119                 PHP_OCI_CALL(OCIConnectionPoolDestroy, (cpoolh, OCI_G(err), OCI_DEFAULT));
1120                 PHP_OCI_CALL(OCIHandleFree, (cpoolh, OCI_HTYPE_CPOOL));
1121 #endif
1122         } else {
1123                 OCIErrorGet(OCI_G(env), (ub4)1, NULL, &ora_error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR);
1124 
1125                 if (ora_error_code) {
1126                         int tmp_buf_len = (int) strlen((char *)tmp_buf);
1127 
1128                         if (tmp_buf_len > 0 && tmp_buf[tmp_buf_len - 1] == '\n') {
1129                                 tmp_buf[tmp_buf_len - 1] = '\0';
1130                         }
1131 
1132                         if (errstatus == OCI_SUCCESS_WITH_INFO) {
1133                                 php_error_docref(NULL, E_WARNING, "Initialization error: OCI_SUCCESS_WITH_INFO: %s", tmp_buf);
1134                         } else {
1135                                 php_error_docref(NULL, E_WARNING, "Initialization error: OCI_ERROR: %s", tmp_buf);
1136 
1137                                 OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV);
1138 
1139                                 OCI_G(env) = NULL;
1140                                 OCI_G(err) = NULL;
1141                         }
1142                 }
1143         }
1144 }
1145 /* }}} */
1146 
1147 /* {{{ php_oci_cleanup_global_handles()
1148  *
1149  * Free global handles (if they were initialized before)
1150  */
1151 static void php_oci_cleanup_global_handles(void)
1152 {
1153         if (OCI_G(err)) {
1154                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR));
1155                 OCI_G(err) = NULL;
1156         }
1157 
1158         if (OCI_G(env)) {
1159                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV));
1160                 OCI_G(env) = NULL;
1161         }
1162 }
1163 /* }}} */
1164 
1165 /* {{{ PHP_GINIT_FUNCTION
1166  *
1167  * Zerofill globals during module init
1168  */
1169 static PHP_GINIT_FUNCTION(oci)
1170 {
1171         memset(oci_globals, 0, sizeof(zend_oci_globals));
1172 }
1173 /* }}} */
1174 
1175 /* {{{ PHP_GSHUTDOWN_FUNCTION
1176  *
1177  * Called for thread shutdown in ZTS, after module shutdown for non-ZTS
1178  */
1179 static PHP_GSHUTDOWN_FUNCTION(oci)
1180 {
1181         php_oci_cleanup_global_handles();
1182 }
1183 /* }}} */
1184 
1185 PHP_MINIT_FUNCTION(oci)
1186 {
1187         zend_class_entry oci_lob_class_entry;
1188         zend_class_entry oci_coll_class_entry;
1189 
1190         REGISTER_INI_ENTRIES();
1191 
1192         le_statement = zend_register_list_destructors_ex(php_oci_statement_list_dtor, NULL, "oci8 statement", module_number);
1193         le_connection = zend_register_list_destructors_ex(php_oci_connection_list_dtor, NULL, "oci8 connection", module_number);
1194         le_pconnection = zend_register_list_destructors_ex(php_oci_pconnection_list_np_dtor, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number);
1195         le_psessionpool = zend_register_list_destructors_ex(NULL, php_oci_spool_list_dtor, "oci8 persistent session pool", module_number);
1196         le_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number);
1197         le_collection = zend_register_list_destructors_ex(php_oci_collection_list_dtor, NULL, "oci8 collection", module_number);
1198 
1199         INIT_CLASS_ENTRY(oci_lob_class_entry, "OCI-Lob", php_oci_lob_class_functions);
1200         INIT_CLASS_ENTRY(oci_coll_class_entry, "OCI-Collection", php_oci_coll_class_functions);
1201 
1202         oci_lob_class_entry_ptr = zend_register_internal_class(&oci_lob_class_entry);
1203         oci_coll_class_entry_ptr = zend_register_internal_class(&oci_coll_class_entry);
1204 
1205 /* thies@thieso.net 990203 i do not think that we will need all of them - just in here for completeness for now! */
1206         REGISTER_LONG_CONSTANT("OCI_DEFAULT",OCI_DEFAULT, CONST_CS | CONST_PERSISTENT);
1207         REGISTER_LONG_CONSTANT("OCI_SYSOPER",OCI_SYSOPER, CONST_CS | CONST_PERSISTENT);
1208         REGISTER_LONG_CONSTANT("OCI_SYSDBA",OCI_SYSDBA, CONST_CS | CONST_PERSISTENT);
1209         REGISTER_LONG_CONSTANT("OCI_CRED_EXT",PHP_OCI_CRED_EXT, CONST_CS | CONST_PERSISTENT);
1210         REGISTER_LONG_CONSTANT("OCI_DESCRIBE_ONLY",OCI_DESCRIBE_ONLY, CONST_CS | CONST_PERSISTENT);
1211         REGISTER_LONG_CONSTANT("OCI_COMMIT_ON_SUCCESS",OCI_COMMIT_ON_SUCCESS, CONST_CS | CONST_PERSISTENT);
1212         REGISTER_LONG_CONSTANT("OCI_NO_AUTO_COMMIT",OCI_DEFAULT, CONST_CS | CONST_PERSISTENT);
1213         REGISTER_LONG_CONSTANT("OCI_EXACT_FETCH",OCI_EXACT_FETCH, CONST_CS | CONST_PERSISTENT);
1214 
1215 /* for $LOB->seek() */
1216         REGISTER_LONG_CONSTANT("OCI_SEEK_SET",PHP_OCI_SEEK_SET, CONST_CS | CONST_PERSISTENT);
1217         REGISTER_LONG_CONSTANT("OCI_SEEK_CUR",PHP_OCI_SEEK_CUR, CONST_CS | CONST_PERSISTENT);
1218         REGISTER_LONG_CONSTANT("OCI_SEEK_END",PHP_OCI_SEEK_END, CONST_CS | CONST_PERSISTENT);
1219 
1220 /*      for $LOB->flush() */
1221         REGISTER_LONG_CONSTANT("OCI_LOB_BUFFER_FREE",OCI_LOB_BUFFER_FREE, CONST_CS | CONST_PERSISTENT);
1222 
1223 /* for OCIBindByName (real "oci" names + short "php" names */
1224         REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
1225         REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
1226         REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
1227         REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
1228         REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
1229         REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);
1230         REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);
1231         REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
1232         REGISTER_LONG_CONSTANT("SQLT_AFC",SQLT_AFC, CONST_CS | CONST_PERSISTENT);
1233         REGISTER_LONG_CONSTANT("SQLT_CHR",SQLT_CHR, CONST_CS | CONST_PERSISTENT);
1234         REGISTER_LONG_CONSTANT("SQLT_VCS",SQLT_VCS, CONST_CS | CONST_PERSISTENT);
1235         REGISTER_LONG_CONSTANT("SQLT_AVC",SQLT_AVC, CONST_CS | CONST_PERSISTENT);
1236         REGISTER_LONG_CONSTANT("SQLT_STR",SQLT_STR, CONST_CS | CONST_PERSISTENT);
1237         REGISTER_LONG_CONSTANT("SQLT_LVC",SQLT_LVC, CONST_CS | CONST_PERSISTENT);
1238         REGISTER_LONG_CONSTANT("SQLT_FLT",SQLT_FLT, CONST_CS | CONST_PERSISTENT);
1239         REGISTER_LONG_CONSTANT("SQLT_UIN",SQLT_UIN, CONST_CS | CONST_PERSISTENT);
1240         REGISTER_LONG_CONSTANT("SQLT_LNG",SQLT_LNG, CONST_CS | CONST_PERSISTENT);
1241         REGISTER_LONG_CONSTANT("SQLT_LBI",SQLT_LBI, CONST_CS | CONST_PERSISTENT);
1242         REGISTER_LONG_CONSTANT("SQLT_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT);
1243         REGISTER_LONG_CONSTANT("SQLT_ODT",SQLT_ODT, CONST_CS | CONST_PERSISTENT);
1244 #if defined(HAVE_OCI_INSTANT_CLIENT) || (defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 10)
1245         REGISTER_LONG_CONSTANT("SQLT_BDOUBLE",SQLT_BDOUBLE, CONST_CS | CONST_PERSISTENT);
1246         REGISTER_LONG_CONSTANT("SQLT_BFLOAT",SQLT_BFLOAT, CONST_CS | CONST_PERSISTENT);
1247 #endif
1248 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
1249         REGISTER_LONG_CONSTANT("SQLT_BOL",SQLT_BOL, CONST_CS | CONST_PERSISTENT);
1250 #endif
1251 
1252         REGISTER_LONG_CONSTANT("OCI_B_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);
1253         REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);
1254         REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE", CONST_CS | CONST_PERSISTENT);
1255 
1256         REGISTER_LONG_CONSTANT("OCI_B_BFILE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
1257         REGISTER_LONG_CONSTANT("OCI_B_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
1258         REGISTER_LONG_CONSTANT("OCI_B_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
1259         REGISTER_LONG_CONSTANT("OCI_B_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
1260         REGISTER_LONG_CONSTANT("OCI_B_ROWID",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
1261         REGISTER_LONG_CONSTANT("OCI_B_CURSOR",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
1262         REGISTER_LONG_CONSTANT("OCI_B_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT);
1263         REGISTER_LONG_CONSTANT("OCI_B_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);
1264         REGISTER_LONG_CONSTANT("OCI_B_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);
1265 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
1266         REGISTER_LONG_CONSTANT("OCI_B_BOL",SQLT_BOL, CONST_CS | CONST_PERSISTENT);
1267 #endif
1268 
1269 /* for OCIFetchStatement */
1270         REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_COLUMN", PHP_OCI_FETCHSTATEMENT_BY_COLUMN, CONST_CS | CONST_PERSISTENT);
1271         REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_ROW", PHP_OCI_FETCHSTATEMENT_BY_ROW, CONST_CS | CONST_PERSISTENT);
1272 
1273 /* for OCIFetchInto & OCIResult */
1274         REGISTER_LONG_CONSTANT("OCI_ASSOC",PHP_OCI_ASSOC, CONST_CS | CONST_PERSISTENT);
1275         REGISTER_LONG_CONSTANT("OCI_NUM",PHP_OCI_NUM, CONST_CS | CONST_PERSISTENT);
1276         REGISTER_LONG_CONSTANT("OCI_BOTH",PHP_OCI_BOTH, CONST_CS | CONST_PERSISTENT);
1277         REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",PHP_OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT);
1278         REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",PHP_OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT);
1279 
1280 /* for OCINewDescriptor (real "oci" names + short "php" names */
1281         REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
1282         REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
1283         REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);
1284 
1285         REGISTER_LONG_CONSTANT("OCI_D_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
1286         REGISTER_LONG_CONSTANT("OCI_D_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
1287         REGISTER_LONG_CONSTANT("OCI_D_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);
1288 
1289 /* for OCIWriteTemporaryLob */
1290         REGISTER_LONG_CONSTANT("OCI_TEMP_CLOB",OCI_TEMP_CLOB, CONST_CS | CONST_PERSISTENT);
1291         REGISTER_LONG_CONSTANT("OCI_TEMP_BLOB",OCI_TEMP_BLOB, CONST_CS | CONST_PERSISTENT);
1292 
1293         return SUCCESS;
1294 }
1295 
1296 PHP_RINIT_FUNCTION(oci)
1297 {
1298         OCI_G(num_links) = OCI_G(num_persistent);
1299         OCI_G(errcode) = 0;
1300         OCI_G(edition) = NULL;
1301 
1302         return SUCCESS;
1303 }
1304 
1305 PHP_MSHUTDOWN_FUNCTION(oci)
1306 {
1307         OCI_G(shutdown) = 1;
1308 
1309         UNREGISTER_INI_ENTRIES();
1310 
1311         return SUCCESS;
1312 }
1313 
1314 PHP_RSHUTDOWN_FUNCTION(oci)
1315 {
1316         /* Check persistent connections and do the necessary actions if needed. If persistent_helper is
1317          * unable to process a pconnection because of a refcount, the processing would happen from
1318          * np-destructor which is called when refcount goes to zero - php_oci_pconnection_list_np_dtor
1319          */
1320         zend_hash_apply(&EG(persistent_list), php_oci_persistent_helper);
1321 
1322         if (OCI_G(edition)) {
1323                 efree(OCI_G(edition));
1324         }
1325 
1326         return SUCCESS;
1327 }
1328 
1329 PHP_MINFO_FUNCTION(oci)
1330 {
1331         char buf[32];
1332 #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
1333         char ver[256];
1334 #endif
1335 
1336         php_info_print_table_start();
1337         php_info_print_table_row(2, "OCI8 Support", "enabled");
1338 #if defined(HAVE_OCI8_DTRACE)
1339         php_info_print_table_row(2, "OCI8 DTrace Support", "enabled");
1340 #else
1341         php_info_print_table_row(2, "OCI8 DTrace Support", "disabled");
1342 #endif
1343         php_info_print_table_row(2, "OCI8 Version", PHP_OCI8_VERSION);
1344         php_info_print_table_row(2, "Revision", "$Id: 86f22a208f89dcd5b305e82929a7429683968b11 $");
1345 
1346 #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
1347         php_oci_client_get_version(ver, sizeof(ver));
1348         php_info_print_table_row(2, "Oracle Run-time Client Library Version", ver);
1349 #else
1350         php_info_print_table_row(2, "Oracle Run-time Client Library Version", "Unknown");
1351 #endif
1352 #if     defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
1353         snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION);
1354 #elif defined(PHP_OCI8_ORACLE_VERSION)
1355         snprintf(buf, sizeof(buf), "%s", PHP_OCI8_ORACLE_VERSION);
1356 #else
1357         snprintf(buf, sizeof(buf), "Unknown");
1358 #endif
1359 #if defined(HAVE_OCI_INSTANT_CLIENT)
1360         php_info_print_table_row(2, "Oracle Compile-time Instant Client Version", buf);
1361 #else
1362         php_info_print_table_row(2, "Oracle Compile-time Version", buf);
1363 #endif
1364 
1365 #if !defined(PHP_WIN32) && !defined(HAVE_OCI_INSTANT_CLIENT)
1366 #if defined(PHP_OCI8_DEF_DIR)
1367         php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DEF_DIR);
1368 #endif
1369 #if defined(PHP_OCI8_DEF_SHARED_LIBADD)
1370         php_info_print_table_row(2, "Libraries Used", PHP_OCI8_DEF_SHARED_LIBADD);
1371 #endif
1372 #endif
1373 
1374 
1375         php_info_print_table_end();
1376 
1377         DISPLAY_INI_ENTRIES();
1378 
1379         php_info_print_table_start();
1380         php_info_print_table_header(2, "Statistics", "");
1381         snprintf(buf, sizeof(buf), "%pd", OCI_G(num_persistent));
1382         php_info_print_table_row(2, "Active Persistent Connections", buf);
1383         snprintf(buf, sizeof(buf), "%pd", OCI_G(num_links));
1384         php_info_print_table_row(2, "Active Connections", buf);
1385         php_info_print_table_end();
1386 }
1387 /* }}} */
1388 
1389 /* {{{ list destructors */
1390 
1391 /* {{{ php_oci_connection_list_dtor()
1392  *
1393  * Non-persistent connection destructor
1394  */
1395 static void php_oci_connection_list_dtor(zend_resource *entry)
1396 {
1397         php_oci_connection *connection = (php_oci_connection *)entry->ptr;
1398 
1399         if (connection) {
1400                 php_oci_connection_close(connection);
1401                 OCI_G(num_links)--;
1402         }
1403 }
1404 /* }}} */
1405 
1406 /* {{{ php_oci_pconnection_list_dtor()
1407  *
1408  * Persistent connection destructor
1409  */
1410 static void php_oci_pconnection_list_dtor(zend_resource *entry)
1411 {
1412         php_oci_connection *connection = (php_oci_connection *)entry->ptr;
1413 
1414         if (connection) {
1415                 php_oci_connection_close(connection);
1416                 OCI_G(num_persistent)--;
1417                 OCI_G(num_links)--;
1418         }
1419 }
1420 /* }}} */
1421 
1422 /* {{{ php_oci_pconnection_list_np_dtor()
1423  *
1424  * Non-Persistent destructor for persistent connection - This gets invoked when
1425  * the refcount of this goes to zero in the regular list
1426  */
1427 static void php_oci_pconnection_list_np_dtor(zend_resource *entry)
1428 {
1429         php_oci_connection *connection = (php_oci_connection *)entry->ptr;
1430         zval *zvp;
1431         zend_resource *le;
1432 
1433         /*
1434          * We cannot get connection as NULL or as a stub in this function. This is the function that
1435          * turns a pconnection to a stub
1436          *
1437          * If oci_password_change() changed the password of a persistent connection, close the
1438          * connection and remove it from the persistent connection cache.  This means subsequent scripts
1439          * will be prevented from being able to present the old (now invalid) password to a usable
1440          * connection to the database; they must use the new password.
1441          *
1442          * Check for conditions that warrant removal of the hash entry
1443          */
1444 
1445         if (!connection->is_open ||
1446                 connection->passwd_changed ||
1447                 (PG(connection_status) & PHP_CONNECTION_TIMEOUT) ||
1448                 OCI_G(in_call)) {
1449 
1450                 /* Remove the hash entry if present */
1451                 if (connection->hash_key) {
1452                         zvp = zend_hash_find(&EG(persistent_list), connection->hash_key);
1453                         le = zvp ? Z_RES_P(zvp) : NULL;
1454                         if (le != NULL && le->type == le_pconnection && le->ptr == connection) {
1455                                 zend_hash_del(&EG(persistent_list), connection->hash_key);
1456                         }
1457                         else {
1458                                 php_oci_connection_close(connection);
1459                                 OCI_G(num_persistent)--;
1460                         }
1461                 }
1462 
1463 #ifdef HAVE_OCI8_DTRACE
1464                 if (DTRACE_OCI8_CONNECT_P_DTOR_CLOSE_ENABLED()) {
1465                         DTRACE_OCI8_CONNECT_P_DTOR_CLOSE(connection);
1466                 }
1467 #endif /* HAVE_OCI8_DTRACE */
1468         } else {
1469                 /*
1470                  * Release the connection to underlying pool.  We do this unconditionally so that
1471                  * out-of-scope pconnects are now consistent with oci_close and out-of-scope new connect
1472                  * semantics. With the PECL OCI 1.3.x extensions, we release pconnections when oci_close
1473                  * takes the refcount to zero.
1474                  *
1475                  * If oci_old_close_semantics is set, we artificially bump up the refcount and decremented
1476                  * only at request shutdown.
1477                  */
1478                 php_oci_connection_release(connection);
1479 
1480 #ifdef HAVE_OCI8_DTRACE
1481                 if (DTRACE_OCI8_CONNECT_P_DTOR_RELEASE_ENABLED()) {
1482                         DTRACE_OCI8_CONNECT_P_DTOR_RELEASE(connection);
1483                 }
1484 #endif /* HAVE_OCI8_DTRACE */
1485         }
1486 }
1487 /* }}} */
1488 
1489 /* {{{ php_oci_statement_list_dtor()
1490  *
1491  * Statement destructor
1492  */
1493 static void php_oci_statement_list_dtor(zend_resource *entry)
1494 {
1495         php_oci_statement *statement = (php_oci_statement *)entry->ptr;
1496         php_oci_statement_free(statement);
1497 }
1498 /* }}} */
1499 
1500 /* {{{ php_oci_descriptor_list_dtor()
1501  *
1502  *      Descriptor destructor
1503  */
1504 static void php_oci_descriptor_list_dtor(zend_resource *entry)
1505 {
1506         php_oci_descriptor *descriptor = (php_oci_descriptor *)entry->ptr;
1507         php_oci_lob_free(descriptor);
1508 }
1509 /* }}} */
1510 
1511 /* {{{ php_oci_collection_list_dtor()
1512  *
1513  * Collection destructor
1514  */
1515 static void php_oci_collection_list_dtor(zend_resource *entry)
1516 {
1517         php_oci_collection *collection = (php_oci_collection *)entry->ptr;
1518         php_oci_collection_close(collection);
1519 }
1520 /* }}} */
1521 
1522 /* }}} */
1523 
1524 /* {{{ Hash Destructors */
1525 
1526 /* {{{ php_oci_define_hash_dtor()
1527  *
1528  * Define hash destructor
1529  */
1530 void php_oci_define_hash_dtor(zval *data)
1531 {
1532         php_oci_define *define = (php_oci_define *) Z_PTR_P(data);
1533 
1534         if (define->name) {
1535                 efree(define->name);
1536                 define->name = NULL;
1537         }
1538 
1539     efree(define);
1540 }
1541 /* }}} */
1542 
1543 /* {{{ php_oci_bind_hash_dtor()
1544  *
1545  * Bind hash destructor
1546  */
1547 void php_oci_bind_hash_dtor(zval *data)
1548 {
1549         php_oci_bind *bind = (php_oci_bind *) Z_PTR_P(data);
1550 
1551         if (bind->array.elements) {
1552                 efree(bind->array.elements);
1553                 bind->array.elements = NULL;
1554         }
1555 
1556         if (bind->array.element_lengths) {
1557                 efree(bind->array.element_lengths);
1558                 bind->array.element_lengths = NULL;
1559         }
1560 
1561         if (bind->array.indicators) {
1562                 efree(bind->array.indicators);
1563                 bind->array.indicators = NULL;
1564         }
1565 
1566         efree(bind);
1567 }
1568 /* }}} */
1569 
1570 /* {{{ php_oci_column_hash_dtor()
1571  *
1572  * Column hash destructor
1573  */
1574 void php_oci_column_hash_dtor(zval *data)
1575 {
1576         php_oci_out_column *column = (php_oci_out_column *) Z_PTR_P(data);
1577 
1578         if (column->stmtid) {
1579                 zend_list_close(column->stmtid);
1580         }
1581 
1582         if (column->descid) {
1583                 if (GC_REFCOUNT(column->descid) == 1)
1584                         zend_list_close(column->descid);
1585                 else
1586                         GC_REFCOUNT(column->descid)--;
1587         }
1588 
1589         if (column->data) {
1590                 efree(column->data);
1591         }
1592 
1593         if (column->name) {
1594                 efree(column->name);
1595         }
1596 
1597         efree(column);
1598 }
1599 /* }}} */
1600 
1601 /* {{{ php_oci_descriptor_flush_hash_dtor()
1602  *
1603  * Flush descriptors on commit
1604  */
1605 void php_oci_descriptor_flush_hash_dtor(zval *data)
1606 {
1607         php_oci_descriptor *descriptor = (php_oci_descriptor *) Z_PTR_P(data);
1608 
1609         if (descriptor && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) {
1610                 php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE);
1611                 descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
1612         }
1613         data = NULL;
1614 }
1615 /* }}} */
1616 
1617 /* }}} */
1618 
1619 /* {{{ php_oci_connection_descriptors_free()
1620  *
1621  * Free descriptors for a connection
1622  */
1623 void php_oci_connection_descriptors_free(php_oci_connection *connection)
1624 {
1625         zend_hash_destroy(connection->descriptors);
1626         efree(connection->descriptors);
1627         connection->descriptors = NULL;
1628         connection->descriptor_count = 0;
1629 }
1630 /* }}} */
1631 
1632 /* {{{ php_oci_error()
1633  *
1634  * Fetch & print out error message if we get an error
1635  * Returns an Oracle error number
1636  */
1637 sb4 php_oci_error(OCIError *err_p, sword errstatus)
1638 {
1639         text errbuf[PHP_OCI_ERRBUF_LEN];
1640         sb4 errcode = 0; /* Oracle error number */
1641 
1642         switch (errstatus) {
1643                 case OCI_SUCCESS:
1644                         break;
1645                 case OCI_SUCCESS_WITH_INFO:
1646                         errcode = php_oci_fetch_errmsg(err_p, errbuf, sizeof(errbuf));
1647                         if (errcode) {
1648                                 php_error_docref(NULL, E_WARNING, "OCI_SUCCESS_WITH_INFO: %s", errbuf);
1649                         } else {
1650                                 php_error_docref(NULL, E_WARNING, "OCI_SUCCESS_WITH_INFO: failed to fetch error message");
1651                         }
1652                         break;
1653                 case OCI_NEED_DATA:
1654                         php_error_docref(NULL, E_WARNING, "OCI_NEED_DATA");
1655                         break;
1656                 case OCI_NO_DATA:
1657                         errcode = php_oci_fetch_errmsg(err_p, errbuf, sizeof(errbuf));
1658                         if (errcode) {
1659                                 php_error_docref(NULL, E_WARNING, "%s", errbuf);
1660                         } else {
1661                                 php_error_docref(NULL, E_WARNING, "OCI_NO_DATA: failed to fetch error message");
1662                         }
1663                         break;
1664                 case OCI_ERROR:
1665                         errcode = php_oci_fetch_errmsg(err_p, errbuf, sizeof(errbuf));
1666                         if (errcode) {
1667                                 php_error_docref(NULL, E_WARNING, "%s", errbuf, sizeof(errbuf));
1668                         } else {
1669                                 php_error_docref(NULL, E_WARNING, "failed to fetch error message");
1670                         }
1671                         break;
1672                 case OCI_INVALID_HANDLE:
1673                         php_error_docref(NULL, E_WARNING, "OCI_INVALID_HANDLE");
1674                         break;
1675                 case OCI_STILL_EXECUTING:
1676                         php_error_docref(NULL, E_WARNING, "OCI_STILL_EXECUTING");
1677                         break;
1678                 case OCI_CONTINUE:
1679                         php_error_docref(NULL, E_WARNING, "OCI_CONTINUE");
1680                         break;
1681                 default:
1682                         php_error_docref(NULL, E_WARNING, "Unknown OCI error code: %d", errstatus);
1683                         break;
1684         }
1685 
1686 #ifdef HAVE_OCI8_DTRACE
1687         if (DTRACE_OCI8_ERROR_ENABLED()) {
1688                 DTRACE_OCI8_ERROR((int)errstatus, (long)errcode);
1689         }
1690 #endif /* HAVE_OCI8_DTRACE */
1691 
1692         return errcode;
1693 }
1694 /* }}} */
1695 
1696 /* {{{ php_oci_fetch_errmsg()
1697  *
1698  * Fetch error message into the buffer from the error handle provided
1699  */
1700 sb4 php_oci_fetch_errmsg(OCIError *error_handle, text *error_buf, size_t error_buf_size)
1701 {
1702         sb4 error_code = 0;
1703 
1704         PHP_OCI_CALL(OCIErrorGet, (error_handle, (ub4)1, NULL, &error_code, error_buf, (ub4)error_buf_size, (ub4)OCI_HTYPE_ERROR));
1705 
1706         if (error_code) {
1707                 int err_buf_len = (int) strlen((char *)error_buf);
1708 
1709                 if (err_buf_len && error_buf[err_buf_len - 1] == '\n') {
1710                         error_buf[err_buf_len - 1] = '\0';
1711                 }
1712         }
1713         return error_code;
1714 }
1715 /* }}} */
1716 
1717 /* {{{ php_oci_fetch_sqltext_offset()
1718  *
1719  * Compute offset in the SQL statement
1720  */
1721 int php_oci_fetch_sqltext_offset(php_oci_statement *statement, text **sqltext, ub2 *error_offset)
1722 {
1723         sword errstatus;
1724 
1725         *sqltext = NULL;
1726         *error_offset = 0;
1727         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *) sqltext, (ub4 *)0, OCI_ATTR_STATEMENT, statement->err));
1728 
1729         if (errstatus != OCI_SUCCESS) {
1730                 statement->errcode = php_oci_error(statement->err, errstatus);
1731                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1732                 return 1;
1733         }
1734 
1735         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err));
1736 
1737         if (errstatus != OCI_SUCCESS) {
1738                 statement->errcode = php_oci_error(statement->err, errstatus);
1739                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1740                 return 1;
1741         }
1742         return 0;
1743 }
1744 /* }}} */
1745 
1746 /* {{{ php_oci_do_connect()
1747  *
1748  * Connect wrapper
1749  */
1750 void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive)
1751 {
1752         php_oci_connection *connection;
1753         char *username, *password;
1754         char *dbname = NULL, *charset = NULL;
1755         size_t username_len = 0, password_len = 0;
1756         size_t dbname_len = 0, charset_len = 0;
1757         zend_long session_mode = OCI_DEFAULT;
1758 
1759         /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
1760         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ssl", &username, &username_len, &password, &password_len, &dbname, &dbname_len, &charset, &charset_len, &session_mode) == FAILURE) {
1761                 return;
1762         }
1763 
1764 #ifdef HAVE_OCI8_DTRACE
1765         if (DTRACE_OCI8_CONNECT_ENTRY_ENABLED()) {
1766                 DTRACE_OCI8_CONNECT_ENTRY(username, dbname, charset, session_mode, persistent, exclusive);
1767         }
1768 #endif /* HAVE_OCI8_DTRACE */
1769 
1770         if (!charset_len) {
1771                 charset = NULL;
1772         }
1773 
1774         connection = php_oci_do_connect_ex(username, (int) username_len, password, (int) password_len, NULL, 0, dbname, (int) dbname_len, charset, session_mode, persistent, exclusive);
1775 
1776 #ifdef HAVE_OCI8_DTRACE
1777         if (DTRACE_OCI8_CONNECT_RETURN_ENABLED()) {
1778                 DTRACE_OCI8_CONNECT_RETURN(connection);
1779         }
1780 #endif /* HAVE_OCI8_DTRACE */
1781 
1782 
1783         if (!connection) {
1784                 RETURN_FALSE;
1785         }
1786         RETURN_RES(connection->id);
1787 
1788 }
1789 /* }}} */
1790 
1791 /* {{{ php_oci_do_connect_ex()
1792  *
1793  * The real connect function. Allocates all the resources needed, establishes the connection and
1794  * returns the result handle (or NULL)
1795  */
1796 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, zend_long session_mode, int persistent, int exclusive)
1797 {
1798         zval *zvp;
1799         zend_resource *le;
1800         zend_resource new_le;
1801         php_oci_connection *connection = NULL;
1802         smart_str hashed_details = {0};
1803         time_t timestamp;
1804         php_oci_spool *session_pool = NULL;
1805         zend_bool use_spool = 1;           /* Default is to use client-side session pool */
1806         zend_bool ping_done = 0;
1807 
1808         ub2 charsetid = 0;
1809         ub2 charsetid_nls_lang = 0;
1810 
1811         if (session_mode & ~(OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) {
1812                 php_error_docref(NULL, E_WARNING, "Invalid session mode specified (%pd)", session_mode);
1813                 return NULL;
1814         }
1815         if (session_mode & (OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) {
1816                 if ((session_mode & OCI_SYSOPER) && (session_mode & OCI_SYSDBA)) {
1817                         php_error_docref(NULL, E_WARNING, "OCI_SYSDBA and OCI_SYSOPER cannot be used together");
1818                         return NULL;
1819                 }
1820                 if (session_mode & PHP_OCI_CRED_EXT) {
1821 #ifdef PHP_WIN32
1822                         /* Disable external authentication on Windows as Impersonation is not yet handled.
1823                          * TODO: Re-enable this once OCI provides capability.
1824                          */
1825                         php_error_docref(NULL, E_WARNING, "External Authentication is not supported on Windows");
1826                         return NULL;
1827 #endif
1828                         if (username_len != 1 || username[0] != '/' || password_len != 0) {
1829                                 php_error_docref(NULL, E_WARNING, "OCI_CRED_EXT can only be used with a username of \"/\" and a NULL password");
1830                                 return NULL;
1831                         }
1832                 }
1833                 if (session_mode & (OCI_SYSOPER | OCI_SYSDBA)) {
1834                         /* Increase security by not caching privileged oci_pconnect() connections. The
1835                          * connection becomes equivalent to oci_connect() or oci_new_connect().
1836                          */
1837                         persistent = 0;
1838                         if (!OCI_G(privileged_connect)) {
1839                                 php_error_docref(NULL, E_WARNING, "Privileged connect is disabled. Enable oci8.privileged_connect to be able to connect as SYSOPER or SYSDBA");
1840                                 return NULL;
1841                         }
1842 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || (PHP_MAJOR_VERSION < 5)
1843                         /* Safe mode has been removed in PHP 5.4 */
1844                         if (PG(safe_mode)) {
1845                                 php_error_docref(NULL, E_WARNING, "Privileged connect is disabled in Safe Mode");
1846                                 return NULL;
1847                         }
1848 #endif
1849                 }
1850         }
1851 
1852         /* Initialize global handles if they weren't initialized before */
1853         if (OCI_G(env) == NULL) {
1854                 php_oci_init_global_handles();
1855                 if (OCI_G(env) == NULL) {
1856                         return NULL;
1857                 }
1858         }
1859 
1860         /* We cannot use the new session create logic (OCISessionGet from
1861          * client-side session pool) when privileged connect or password
1862          * change is attempted or OCI_CRED_EXT mode is specified.
1863          * TODO: Re-enable this when OCI provides support.
1864          */
1865         if ((session_mode & (OCI_SYSOPER | OCI_SYSDBA | PHP_OCI_CRED_EXT)) || (new_password_len)) {
1866                 use_spool = 0;
1867         }
1868 
1869         smart_str_appendl_ex(&hashed_details, "oci8***", sizeof("oci8***") - 1, 0);
1870         smart_str_appendl_ex(&hashed_details, username, username_len, 0);
1871         smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
1872 
1873         /* DRCP: connection_class is an attribute of a connection */
1874         if (OCI_G(connection_class)){
1875                 smart_str_appendl_ex(&hashed_details, OCI_G(connection_class), strlen(OCI_G(connection_class)), 0);
1876         }
1877         smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
1878 
1879         /* Add edition attribute to the hash */
1880         if (OCI_G(edition)){
1881                 smart_str_appendl_ex(&hashed_details, OCI_G(edition), strlen(OCI_G(edition)), 0);
1882         }
1883         smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
1884 
1885         if (password_len) {
1886                 zend_ulong password_hash;
1887                 password_hash = zend_inline_hash_func(password, password_len);
1888                 smart_str_append_unsigned_ex(&hashed_details, password_hash, 0);
1889         }
1890         smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
1891 
1892         if (dbname) {
1893                 smart_str_appendl_ex(&hashed_details, dbname, dbname_len, 0);
1894         }
1895         smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
1896 
1897         if (charset && *charset) {
1898                 PHP_OCI_CALL_RETURN(charsetid, OCINlsCharSetNameToId, (OCI_G(env), (CONST oratext *)charset));
1899                 if (!charsetid) {
1900                         php_error_docref(NULL, E_WARNING, "Invalid character set name: %s", charset);
1901                 } else {
1902                         smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
1903                 }
1904         }
1905 
1906         /* use NLS_LANG if no or invalid charset specified */
1907         if (!charsetid) {
1908                 size_t rsize = 0;
1909                 sword result;
1910 
1911                 PHP_OCI_CALL_RETURN(result, OCINlsEnvironmentVariableGet, (&charsetid_nls_lang, 0, OCI_NLS_CHARSET_ID, 0, &rsize));
1912                 if (result != OCI_SUCCESS) {
1913                         charsetid_nls_lang = 0;
1914                 }
1915                 smart_str_append_unsigned_ex(&hashed_details, charsetid_nls_lang, 0);
1916         }
1917 
1918         timestamp = time(NULL);
1919 
1920         smart_str_append_unsigned_ex(&hashed_details, session_mode, 0);
1921         smart_str_0(&hashed_details);
1922 
1923         if (persistent) {
1924                 smart_str_appendl_ex(&hashed_details, "pc", sizeof("pc") - 1, 0);
1925         }
1926 
1927         /* make it lowercase */
1928         php_strtolower(ZSTR_VAL(hashed_details.s), ZSTR_LEN(hashed_details.s));
1929 
1930         if (!exclusive && !new_password) {
1931                 zend_bool found = 0;
1932 
1933                 if (persistent && ((zvp = zend_hash_find(&EG(persistent_list), hashed_details.s))) != NULL) {
1934                         zend_resource *le = Z_RES_P(zvp);
1935 
1936                         found = 1;
1937                         /* found */
1938                         if (le->type == le_pconnection) {
1939                                 connection = (php_oci_connection *)le->ptr;
1940                         }
1941                 } else if (!persistent && ((zvp = zend_hash_find(&EG(regular_list), hashed_details.s)) != NULL)) {
1942                         le = Z_RES_P(zvp);
1943                         found = 1;
1944                         if (le->type == le_index_ptr) {
1945                                 zend_resource *ptr;
1946 
1947                                 ptr = (zend_resource *) le->ptr;
1948                                 if (ptr && (ptr->type == le_connection)) {
1949                                         connection = (php_oci_connection *)ptr->ptr;
1950                                 }
1951                         }
1952                 }
1953 
1954 #ifdef HAVE_OCI8_DTRACE
1955                 if (DTRACE_OCI8_CONNECT_LOOKUP_ENABLED()) {
1956                         DTRACE_OCI8_CONNECT_LOOKUP(connection, connection && connection->is_stub ? 1 : 0);
1957                 }
1958 #endif /* HAVE_OCI8_DTRACE */
1959 
1960                 /* If we got a pconnection stub, then 'load'(OCISessionGet) the real connection from its
1961                  * private spool A connection is a stub if it is only a cached structure and the real
1962                  * connection is released to its underlying private session pool.  We currently do not have
1963                  * stub support for non-persistent conns.
1964                  *
1965                  * TODO: put in negative code for non-persistent stubs
1966                  */
1967                 if (connection && connection->is_persistent && connection->is_stub) {
1968                         if (php_oci_create_session(connection, NULL, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, (int) session_mode)) {
1969                                 smart_str_free(&hashed_details);
1970                                 zend_hash_del(&EG(persistent_list), connection->hash_key);
1971 
1972                                 return NULL;
1973                         }
1974                         /* We do the ping in php_oci_create_session, no need to ping again below */
1975                         ping_done = 1;
1976                 }
1977 
1978                 if (connection) {
1979                         if (connection->is_open) {
1980                                 /* found an open connection. now ping it */
1981                                 if (connection->is_persistent) {
1982 
1983                                         /* Check connection liveness in the following order:
1984                                          * 1) always check OCI_ATTR_SERVER_STATUS
1985                                          * 2) see if it's time to ping it
1986                                          * 3) ping it if needed
1987                                          */
1988                                         if (php_oci_connection_status(connection)) {
1989                                                 /* Only ping if:
1990                                                  *
1991                                                  * 1) next_ping > 0, which means that ping_interval is not -1 (aka "Off")
1992                                                  *
1993                                                  * 2) current_timestamp > next_ping, which means "it's time to check if it's
1994                                                  * still alive"
1995                                                  */
1996                                                 if (!ping_done && (*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp)) && !php_oci_connection_ping(connection)) {
1997                                                         /* server died */
1998                                                 } else {
1999                                                         php_oci_connection *tmp = (php_oci_connection *) NULL;
2000                                                         zval *tmp_val = (zval *) NULL;
2001 
2002                                                         /* okay, the connection is open and the server is still alive */
2003                                                         connection->used_this_request = 1;
2004                                                         if (connection->id) {
2005                                                                 tmp_val = zend_hash_index_find(&EG(regular_list), connection->id->handle);
2006                                                                 if ((tmp_val != NULL) && (Z_TYPE_P(tmp_val) == IS_RESOURCE)) {
2007                                                                         tmp = Z_RES_VAL_P(tmp_val);
2008                                                                 }
2009                                                         
2010                                                                 if ((tmp_val != NULL) && (tmp != NULL) &&
2011                                                                         (ZSTR_LEN(tmp->hash_key) == ZSTR_LEN(hashed_details.s)) &&
2012                                                                         (memcmp(ZSTR_VAL(tmp->hash_key), ZSTR_VAL(hashed_details.s),
2013                                                                          ZSTR_LEN(tmp->hash_key)) == 0)) {
2014                                                                         connection = tmp;
2015                                                                         ++GC_REFCOUNT(connection->id);
2016                                                                 }
2017                                                         } else {
2018                                                                 PHP_OCI_REGISTER_RESOURCE(connection, le_pconnection);
2019                                                                 /* Persistent connections: For old close semantics we artificially
2020                                                                  * bump up the refcount to prevent the non-persistent destructor
2021                                                                  * from getting called until request shutdown. The refcount is
2022                                                                  * decremented in the persistent helper
2023                                                                  */
2024                                                                 if (OCI_G(old_oci_close_semantics)) {
2025                                                                         ++GC_REFCOUNT(connection->id);
2026                                                                 }
2027                                                         }
2028                                                         smart_str_free(&hashed_details);
2029                                                         return connection;
2030                                                 }
2031                                         }
2032                                         /* server died */
2033                                 } else {
2034                                         /* we do not ping non-persistent connections */
2035                                         smart_str_free(&hashed_details);
2036                                         ++GC_REFCOUNT(connection->id);
2037                                         return connection;
2038                                 }
2039                         } /* is_open is true? */
2040 
2041                         /* Server died - connection not usable. The is_open=true can also fall through to here,
2042                          * if ping fails
2043                          */
2044                         if (persistent){
2045 
2046                                 connection->is_open = 0;
2047                                 connection->used_this_request = 1;
2048 
2049                                 /* We have to do a hash_del but need to preserve the resource if there is a positive
2050                                  * refcount. Set the data pointer in the list entry to NULL
2051                                  */
2052                                 if (connection == connection->id->ptr) {
2053                                         le->ptr = NULL;
2054                                 }
2055 
2056                                 zend_hash_del(&EG(persistent_list), hashed_details.s);
2057                         } else {
2058                                 /* We only remove the hash entry. The resource and the list entry with its pointer
2059                                  * to the resource are still intact
2060                                  */
2061                                 zend_hash_del(&EG(regular_list), hashed_details.s);
2062                         }
2063 
2064                         connection = NULL;
2065                 } else if (found) {
2066                         /* found something, but it's not a connection, delete it */
2067                         if (persistent) {
2068                                 zend_hash_del(&EG(persistent_list), hashed_details.s);
2069                         } else {
2070                                 zend_hash_del(&EG(regular_list), hashed_details.s);
2071                         }
2072                 }
2073         }
2074 
2075         /* Check if we have reached max_persistent. If so, try to remove a few timed-out connections. As
2076          * a last resort, return a non-persistent connection.
2077          */
2078         if (persistent) {
2079                 zend_bool alloc_non_persistent = 0;
2080 
2081                 if (OCI_G(max_persistent) != -1 && OCI_G(num_persistent) >= OCI_G(max_persistent)) {
2082                         /* try to find an idle connection and kill it */
2083                         zend_hash_apply(&EG(persistent_list), php_oci_persistent_helper);
2084 
2085                         if (OCI_G(max_persistent) != -1 && OCI_G(num_persistent) >= OCI_G(max_persistent)) {
2086                                 /* all persistent connactions are in use, fallback to non-persistent connection creation */
2087                                 php_error_docref(NULL, E_NOTICE, "Too many open persistent connections (%pd)", OCI_G(num_persistent));
2088                                 alloc_non_persistent = 1;
2089                         }
2090                 }
2091 
2092                 if (alloc_non_persistent) {
2093                         connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
2094                         connection->hash_key = zend_string_dup(hashed_details.s, 0);
2095                         connection->is_persistent = 0;
2096 #ifdef HAVE_OCI8_DTRACE
2097                         connection->client_id = NULL;
2098 #endif
2099                 } else {
2100                         connection = (php_oci_connection *) calloc(1, sizeof(php_oci_connection));
2101                         if (connection == NULL) {
2102                                 return NULL;
2103                         }
2104                         connection->hash_key = zend_string_dup(hashed_details.s, 1);
2105                         if (connection->hash_key == NULL) {
2106                                 free(connection);
2107                                 return NULL;
2108                         }
2109                         connection->is_persistent = 1;
2110 #ifdef HAVE_OCI8_DTRACE
2111                         connection->client_id = NULL;
2112 #endif
2113                 }
2114         } else {
2115                 connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
2116                 connection->hash_key = zend_string_dup(hashed_details.s, 0);
2117                 connection->is_persistent = 0;
2118 #ifdef HAVE_OCI8_DTRACE
2119                 connection->client_id = NULL;
2120 #endif
2121         }
2122 
2123         /* {{{ Get the session pool that suits this connection request from the persistent list. This
2124          * step is only for non-persistent connections as persistent connections have private session
2125          * pools. Non-persistent conns use shared session pool to allow for optimizations such as
2126          * caching the physical connection (for DRCP) even when the non-persistent php connection is
2127          * destroyed.
2128          *
2129          * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability
2130          */
2131         if (use_spool && !connection->is_persistent) {
2132                 if ((session_pool = php_oci_get_spool(username, username_len, password, password_len, dbname, dbname_len, charsetid ? charsetid:charsetid_nls_lang))==NULL)
2133                 {
2134                         php_oci_connection_close(connection);
2135                         smart_str_free(&hashed_details);
2136                         return NULL;
2137                 }
2138         }
2139         /* }}} */
2140 
2141         connection->idle_expiry = (OCI_G(persistent_timeout) > 0) ? (timestamp + OCI_G(persistent_timeout)) : 0;
2142 
2143         /* Mark password as unchanged by PHP during the duration of the database session */
2144         connection->passwd_changed = 0;
2145 
2146         smart_str_free(&hashed_details);
2147 
2148         if (charsetid) {
2149                 connection->charset = charsetid;
2150         } else {
2151                 connection->charset = charsetid_nls_lang;
2152         }
2153 
2154         /* Old session creation semantics when session pool cannot be used Eg: privileged
2155          * connect/password change
2156          */
2157         if (!use_spool) {
2158                 if (php_oci_old_create_session(connection, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, (int) session_mode)) {
2159                         php_oci_connection_close(connection);
2160                         return NULL;
2161                 }
2162         } else {
2163                 /* create using the client-side session pool */
2164                 if (php_oci_create_session(connection, session_pool, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, (int) session_mode)) {
2165                         php_oci_connection_close(connection);
2166                         return NULL;
2167                 }
2168         }
2169 
2170         /* Mark it as open */
2171         connection->is_open = 1;
2172 
2173         /* add to the appropriate hash */
2174         if (connection->is_persistent) {
2175                 new_le.ptr = connection;
2176                 new_le.type = le_pconnection;
2177                 connection->used_this_request = 1;
2178                 PHP_OCI_REGISTER_RESOURCE(connection, le_pconnection);
2179 
2180                 /* Persistent connections: For old close semantics we artificially bump up the refcount to
2181                  * prevent the non-persistent destructor from getting called until request shutdown. The
2182                  * refcount is decremented in the persistent helper
2183                  */
2184                 if (OCI_G(old_oci_close_semantics)) {
2185                         ++GC_REFCOUNT(connection->id);
2186                 }
2187                 zend_hash_update_mem(&EG(persistent_list), connection->hash_key, (void *)&new_le, sizeof(zend_resource));
2188                 OCI_G(num_persistent)++;
2189                 OCI_G(num_links)++;
2190         } else if (!exclusive) {
2191                 PHP_OCI_REGISTER_RESOURCE(connection, le_connection);
2192                 new_le.ptr = connection->id;
2193                 new_le.type = le_index_ptr;
2194                 zend_hash_update_mem(&EG(regular_list), connection->hash_key, (void *)&new_le, sizeof(zend_resource));
2195                 OCI_G(num_links)++;
2196         } else {
2197                 PHP_OCI_REGISTER_RESOURCE(connection, le_connection);
2198                 OCI_G(num_links)++;
2199         }
2200 
2201 #ifdef HAVE_OCI8_DTRACE
2202         if (DTRACE_OCI8_CONNECT_TYPE_ENABLED()) {
2203                 DTRACE_OCI8_CONNECT_TYPE(connection->is_persistent ? 1 : 0, exclusive ? 1 : 0, connection, OCI_G(num_persistent), OCI_G(num_links));
2204         }
2205 #endif /* HAVE_OCI8_DTRACE */
2206 
2207         return connection;
2208 }
2209 /* }}} */
2210 
2211 /* {{{ php_oci_connection_ping()
2212  *
2213  * Ping connection. Uses OCIPing() or OCIServerVersion() depending on the Oracle Client version
2214  */
2215 static int php_oci_connection_ping(php_oci_connection *connection)
2216 {
2217         sword errstatus;
2218 #if (!((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))))
2219         char version[256];
2220 #endif
2221 
2222         OCI_G(errcode) = 0;             /* assume ping is successful */
2223 
2224         /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
2225          * such as from Pre-10.1 servers, the error is still from the server and we would have
2226          * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
2227          * Pre-10.2 clients
2228          */
2229 #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))       /* OCIPing available 10.2 onwards */
2230         PHP_OCI_CALL_RETURN(errstatus, OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT));
2231 #else
2232         /* use good old OCIServerVersion() */
2233         PHP_OCI_CALL_RETURN(errstatus, OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX));
2234 #endif
2235 
2236         if (errstatus == OCI_SUCCESS) {
2237                 return 1;
2238         } else {
2239                 sb4 error_code = 0;
2240                 text tmp_buf[PHP_OCI_ERRBUF_LEN];
2241 
2242                 /* Treat ORA-1010 as a successful Ping */
2243                 OCIErrorGet(OCI_G(err), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR);
2244                 if (error_code == 1010) {
2245                         return 1;
2246                 }
2247                 OCI_G(errcode) = error_code;
2248         }
2249 
2250         return 0;
2251 }
2252 /* }}} */
2253 
2254 /* {{{ php_oci_connection_status()
2255  *
2256  * Check connection status (pre-ping check)
2257  */
2258 static int php_oci_connection_status(php_oci_connection *connection)
2259 {
2260         ub4 ss = OCI_SERVER_NOT_CONNECTED;
2261         sword errstatus;
2262 
2263         /* get OCI_ATTR_SERVER_STATUS */
2264         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err)));
2265 
2266         if (errstatus == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) {
2267                 return 1;
2268         }
2269 
2270         /* ignore errors here, just return failure */
2271         return 0;
2272 }
2273 /* }}} */
2274 
2275 /* {{{ php_oci_connection_rollback()
2276  *
2277  * Rollback connection
2278  */
2279 int php_oci_connection_rollback(php_oci_connection *connection)
2280 {
2281         sword errstatus;
2282 
2283         PHP_OCI_CALL_RETURN(errstatus, OCITransRollback, (connection->svc, connection->err, (ub4) 0));
2284         connection->rb_on_disconnect = 0;
2285 
2286         if (errstatus != OCI_SUCCESS) {
2287                 connection->errcode = php_oci_error(connection->err, errstatus);
2288                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
2289                 return 1;
2290         }
2291         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
2292         return 0;
2293 }
2294 /* }}} */
2295 
2296 /* {{{ php_oci_connection_commit()
2297  *
2298  * Commit connection
2299  */
2300 int php_oci_connection_commit(php_oci_connection *connection)
2301 {
2302         sword errstatus;
2303 
2304         PHP_OCI_CALL_RETURN(errstatus, OCITransCommit, (connection->svc, connection->err, (ub4) 0));
2305         connection->rb_on_disconnect = 0;
2306 
2307         if (errstatus != OCI_SUCCESS) {
2308                 connection->errcode = php_oci_error(connection->err, errstatus);
2309                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
2310                 return 1;
2311         }
2312         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
2313         return 0;
2314 }
2315 /* }}} */
2316 
2317 /* {{{ php_oci_connection_close()
2318  *
2319  * Close the connection and free all its resources
2320  */
2321 static int php_oci_connection_close(php_oci_connection *connection)
2322 {
2323         int result = 0;
2324         zend_bool in_call_save = OCI_G(in_call);
2325 
2326 #ifdef HAVE_OCI8_DTRACE
2327         if (DTRACE_OCI8_CONNECTION_CLOSE_ENABLED()) {
2328                 DTRACE_OCI8_CONNECTION_CLOSE(connection);
2329         }
2330 #endif /* HAVE_OCI8_DTRACE */
2331 
2332         if (!connection->is_stub) {
2333                 /* Release resources associated with connection */
2334                 php_oci_connection_release(connection);
2335         }
2336 
2337         if (!connection->using_spool && connection->svc) {
2338                 PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0));
2339         }
2340 
2341         if (connection->err) {
2342                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->err, (ub4) OCI_HTYPE_ERROR));
2343         }
2344         if (connection->authinfo) {
2345                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO));
2346         }
2347 
2348         /* No Handlefrees for session pool connections */
2349         if (!connection->using_spool) {
2350                 if (connection->session) {
2351                         PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION));
2352                 }
2353 
2354                 if (connection->is_attached) {
2355                         PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT));
2356                 }
2357 
2358                 if (connection->svc) {
2359                         PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX));
2360                 }
2361 
2362                 if (connection->server) {
2363                         PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER));
2364                 }
2365 
2366                 if (connection->env) {
2367                         PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV));
2368                 }
2369         } else if (connection->private_spool) {
2370         /* Keep this as the last member to be freed, as there are dependencies
2371          * (like env) on the session pool
2372          */
2373                 php_oci_spool_close(connection->private_spool);
2374                 connection->private_spool = NULL;
2375         }
2376 
2377         if (GC_REFCOUNT(connection->hash_key) >= 2) {
2378                 zend_hash_del(&EG(regular_list), connection->hash_key);
2379         }
2380 
2381         if (connection->hash_key) {
2382                 pefree(connection->hash_key, connection->is_persistent);
2383                 connection->hash_key = NULL;
2384         }
2385 #ifdef HAVE_OCI8_DTRACE
2386         if (connection->client_id) {
2387                 pefree(connection->client_id, connection->is_persistent);
2388                 connection->client_id = NULL;
2389         }
2390 #endif /* HAVE_OCI8_DTRACE */
2391         pefree(connection, connection->is_persistent);
2392         connection = NULL;
2393         OCI_G(in_call) = in_call_save;
2394         return result;
2395 }
2396 /* }}} */
2397 
2398 /* {{{ php_oci_connection_release()
2399  *
2400  * Release the connection's resources. This involves freeing descriptors and rolling back
2401  * transactions, setting timeout-related parameters etc. For session-pool using connections, the
2402  * underlying connection is released to its session pool.
2403  */
2404 int php_oci_connection_release(php_oci_connection *connection)
2405 {
2406         int result = 0;
2407         zend_bool in_call_save = OCI_G(in_call);
2408         time_t timestamp = time(NULL);
2409 
2410         if (connection->is_stub) {
2411                 return 0;
2412         }
2413 
2414         if (connection->descriptors) {
2415                 php_oci_connection_descriptors_free(connection);
2416         }
2417 
2418         if (connection->svc) {
2419                 /* rollback outstanding transactions */
2420                 if (connection->rb_on_disconnect) {
2421                         if (php_oci_connection_rollback(connection)) {
2422                                 /* rollback failed */
2423                                 result = 1;
2424                         }
2425                 }
2426         }
2427 
2428         if (OCI_G(persistent_timeout) > 0) {
2429                 connection->idle_expiry = timestamp + OCI_G(persistent_timeout);
2430         }
2431 
2432         /* We may have half-cooked connections to clean up */
2433         if (connection->next_pingp) {
2434                 if (OCI_G(ping_interval) >= 0) {
2435                         *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
2436                 } else {
2437                         /* ping_interval is -1 */
2438                         *(connection->next_pingp) = 0;
2439                 }
2440         }
2441 
2442         /* Release the session (stubs are filtered out at the beginning)*/
2443         if (connection->using_spool) {
2444                 ub4 rlsMode = OCI_DEFAULT;
2445 
2446                 if (result) {
2447                         rlsMode |= OCI_SESSRLS_DROPSESS;
2448                 }
2449 
2450                 /* Sessions for non-persistent connections should be dropped.  For 11 and above, the session
2451                  * pool has its own mechanism for doing so for purity NEW connections. We need to do so
2452                  * explicitly for 10.2 and earlier.
2453                  */
2454 #if (!(OCI_MAJOR_VERSION >= 11))
2455                 if (!connection->is_persistent) {
2456                         rlsMode |= OCI_SESSRLS_DROPSESS;
2457                 }
2458 #endif
2459 
2460                 if (connection->svc) {
2461                         PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,
2462                                                                                  0, rlsMode));
2463                 }
2464                 /* It no longer has relation with the database session. However authinfo and env are
2465                  * cached
2466                  */
2467                 connection->svc = NULL;
2468                 connection->server = NULL;
2469                 connection->session = NULL;
2470                 connection->id = NULL;
2471 
2472                 connection->is_attached = connection->is_open = connection->rb_on_disconnect = connection->used_this_request = 0;
2473                 connection->is_stub = 1;
2474 
2475                 /* Cut the link between the connection structure and the time_t structure allocated within
2476                  * the OCI session
2477                  */
2478                 connection->next_pingp = NULL;
2479 #ifdef HAVE_OCI8_DTRACE
2480                 if (connection->client_id) {
2481                         pefree(connection->client_id, connection->is_persistent);
2482                         connection->client_id = NULL;
2483                 }
2484 #endif /* HAVE_OCI8_DTRACE */
2485         }
2486 
2487         OCI_G(in_call) = in_call_save;
2488         return result;
2489 }
2490 /* }}} */
2491 
2492 /* {{{ php_oci_password_change()
2493  *
2494  * Change password for the user with the username given
2495  */
2496 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)
2497 {
2498         sword errstatus;
2499 
2500         PHP_OCI_CALL_RETURN(errstatus, OCIPasswordChange, (connection->svc, connection->err, (text *)user, user_len, (text *)pass_old, pass_old_len, (text *)pass_new, pass_new_len, OCI_DEFAULT));
2501 
2502         if (errstatus != OCI_SUCCESS) {
2503                 connection->errcode = php_oci_error(connection->err, errstatus);
2504                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
2505                 return 1;
2506         }
2507         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
2508         connection->passwd_changed = 1;
2509         return 0;
2510 }
2511 /* }}} */
2512 
2513 /* {{{ php_oci_client_get_version()
2514  *
2515  * Get Oracle client library version
2516  */
2517 void php_oci_client_get_version(char *version, size_t version_size)
2518 {
2519 #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))       /* OCIClientVersion only available 10.2 onwards */
2520         sword major_version = 0;
2521         sword minor_version = 0;
2522         sword update_num = 0;
2523         sword patch_num = 0;
2524         sword port_update_num = 0;
2525 
2526         PHP_OCI_CALL(OCIClientVersion, (&major_version, &minor_version, &update_num, &patch_num, &port_update_num));
2527         snprintf(version, version_size, "%d.%d.%d.%d.%d", major_version, minor_version, update_num, patch_num, port_update_num);
2528 #else
2529         memcpy(version, "Unknown", sizeof("Unknown"));
2530 #endif
2531 }
2532 /* }}} */
2533 
2534 /* {{{ php_oci_server_get_version()
2535  *
2536  * Get Oracle server version
2537  */
2538 int php_oci_server_get_version(php_oci_connection *connection, char *version, size_t version_size)
2539 {
2540         sword errstatus;
2541 
2542         PHP_OCI_CALL_RETURN(errstatus, OCIServerVersion, (connection->svc, connection->err, (text *)version, (ub4) version_size, OCI_HTYPE_SVCCTX));
2543 
2544         if (errstatus != OCI_SUCCESS) {
2545                 connection->errcode = php_oci_error(connection->err, errstatus);
2546                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
2547                 return 1;
2548         }
2549 
2550         return 0;
2551 }
2552 /* }}} */
2553 
2554 /* {{{ php_oci_column_to_zval()
2555  *
2556  * Convert php_oci_out_column struct into zval
2557  */
2558 int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode)
2559 {
2560         php_oci_descriptor *descriptor;
2561         ub4 lob_length;
2562         int column_size;
2563         char *lob_buffer = (char *)0;
2564         int lob_fetch_status;
2565 
2566         if (column->indicator == -1) { /* column is NULL */
2567                 ZVAL_NULL(value);
2568                 return 0;
2569         }
2570 
2571         if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */
2572                 ZVAL_RES(value, column->stmtid);
2573                 ++GC_REFCOUNT(column->stmtid);
2574         } else if (column->is_descr) {
2575 
2576                 if (column->data_type != SQLT_RDD) {
2577 
2578                         /* reset descriptor's length */
2579                         descriptor = (php_oci_descriptor *) column->descid->ptr;
2580 
2581                         if (!descriptor) {
2582                                 php_error_docref(NULL, E_WARNING, "Unable to find LOB descriptor #%d", column->descid);
2583                                 return 1;
2584                         }
2585 
2586                         descriptor->lob_size = -1;
2587                         descriptor->lob_current_position = 0;
2588                         descriptor->buffering = 0;
2589                 }
2590 
2591                 if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
2592                         /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
2593 
2594                         if (column->chunk_size)
2595                                 descriptor->chunk_size = column->chunk_size;
2596                         lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length);
2597                         if (descriptor->chunk_size)  /* Cache the chunk_size to avoid recalling OCILobGetChunkSize */
2598                                 column->chunk_size = descriptor->chunk_size;
2599                         php_oci_temp_lob_close(descriptor);
2600                         if (lob_fetch_status) {
2601                                 ZVAL_FALSE(value);
2602                                 return 1;
2603                         } else {
2604                                 if (lob_length > 0) {
2605                                         ZVAL_STRINGL(value, lob_buffer, lob_length);
2606                                 } else {
2607                                         ZVAL_EMPTY_STRING(value);
2608                                 }
2609                                 if (lob_buffer)
2610                                         efree(lob_buffer);
2611                                 return 0;
2612                         }
2613                 } else {
2614                         /* return the locator */
2615                         object_init_ex(value, oci_lob_class_entry_ptr);
2616                         add_property_resource(value, "descriptor", column->descid);
2617                         ++GC_REFCOUNT(column->descid);
2618                 }
2619         } else {
2620                 switch (column->retcode) {
2621                         case 0:
2622                                 /* intact value */
2623                                 if (column->piecewise) {
2624                                         column_size = column->retlen4;
2625                                 } else {
2626                                         column_size = column->retlen;
2627                                 }
2628                                 break;
2629 
2630                         default:
2631                                 ZVAL_FALSE(value);
2632                                 return 0;
2633                 }
2634 
2635                 ZVAL_STRINGL(value, column->data, column_size);
2636         }
2637         return 0;
2638 }
2639 /* }}} */
2640 
2641 
2642 /* {{{ php_oci_fetch_row()
2643  *
2644  * Fetch the next row from the given statement
2645  * Has logic for Oracle 12c Implicit Result Sets
2646  */
2647 void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args)
2648 {
2649         zval *z_statement, *array;
2650         zval *placeholder = (zval*) NULL;
2651 /*      zend_array *temp_array = (zend_array *) NULL;*/
2652         php_oci_statement *statement;             /* statement that will be fetched from */
2653 #if (OCI_MAJOR_VERSION >= 12)
2654         php_oci_statement *invokedstatement;  /* statement this function was invoked with */
2655 #endif /* OCI_MAJOR_VERSION */
2656         php_oci_out_column *column;
2657         ub4 nrows = 1;
2658         int i;
2659         zend_long fetch_mode = 0;
2660 
2661         if (expected_args > 2) {
2662                 /* only for ocifetchinto BC */
2663 
2664                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|l", &z_statement, &array, &fetch_mode) == FAILURE) {
2665                         return;
2666                 }
2667 
2668                 if (ZEND_NUM_ARGS() == 2) {
2669                         fetch_mode = mode;
2670                 }
2671 
2672                 if (Z_ISREF_P(array))
2673                         placeholder = Z_REFVAL_P(array);
2674                 else
2675                         placeholder = array;
2676 
2677         } else if (expected_args == 2) {
2678                 /* only for oci_fetch_array() */
2679 
2680                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &z_statement, &fetch_mode) == FAILURE) {
2681                         return;
2682                 }
2683 
2684                 if (ZEND_NUM_ARGS() == 1) {
2685                         fetch_mode = mode;
2686                 }
2687         } else {
2688                 /* for all oci_fetch_*() */
2689 
2690                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_statement) == FAILURE) {
2691                         return;
2692                 }
2693 
2694                 fetch_mode = mode;
2695         }
2696 
2697         if (!(fetch_mode & PHP_OCI_NUM) && !(fetch_mode & PHP_OCI_ASSOC)) {
2698                 /* none of the modes present, use the default one */
2699                 if (mode & PHP_OCI_ASSOC) {
2700                         fetch_mode |= PHP_OCI_ASSOC;
2701                 }
2702                 if (mode & PHP_OCI_NUM) {
2703                         fetch_mode |= PHP_OCI_NUM;
2704                 }
2705         }
2706 
2707 #if (OCI_MAJOR_VERSION < 12)
2708         PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
2709 
2710         if (php_oci_statement_fetch(statement, nrows)) {
2711                 RETURN_FALSE;                   /* end of fetch */
2712         }
2713 #else /* OCI_MAJOR_VERSION */
2714         PHP_OCI_ZVAL_TO_STATEMENT(z_statement, invokedstatement);
2715 
2716         if (invokedstatement->impres_flag == PHP_OCI_IMPRES_NO_CHILDREN) {
2717                 /* Already know there are no Implicit Result Sets */
2718             statement = invokedstatement;
2719         } else if (invokedstatement->impres_flag == PHP_OCI_IMPRES_HAS_CHILDREN) {
2720                 /* Previously saw an Implicit Result Set in an earlier invocation of php_oci_fetch_row */
2721                 statement = (php_oci_statement *)invokedstatement->impres_child_stmt;
2722         } else {
2723                 sword errstatus;
2724 
2725                 /* Check for an Implicit Result Set on this statement handle */
2726                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)invokedstatement->stmt, OCI_HTYPE_STMT,
2727                                                     (dvoid *) &invokedstatement->impres_count,
2728                                                     (ub4 *)NULL, OCI_ATTR_IMPLICIT_RESULT_COUNT, invokedstatement->err));
2729                 if (errstatus) {
2730                         RETURN_FALSE;
2731                 }
2732                 if (invokedstatement->impres_count > 0) {
2733                         /* Make it so the fetch occurs on the first Implicit Result Set */
2734                         statement = php_oci_get_implicit_resultset(invokedstatement);
2735                         if (!statement || php_oci_statement_execute(statement, (ub4)OCI_DEFAULT))
2736                                 RETURN_FALSE;
2737                         invokedstatement->impres_count--;
2738                         invokedstatement->impres_child_stmt = (struct php_oci_statement *)statement;
2739                         invokedstatement->impres_flag = PHP_OCI_IMPRES_HAS_CHILDREN;
2740                 } else {
2741                         statement = invokedstatement; /* didn't find Implicit Result Sets */
2742                         invokedstatement->impres_flag = PHP_OCI_IMPRES_NO_CHILDREN;  /* Don't bother checking again */
2743                 }
2744         }
2745 
2746         if (php_oci_statement_fetch(statement, nrows)) {
2747                 /* End of fetch */
2748                 if (invokedstatement->impres_count > 0) {
2749                         /* Check next Implicit Result Set */
2750                 statement = php_oci_get_implicit_resultset(invokedstatement);
2751                         if (!statement || php_oci_statement_execute(statement, (ub4)OCI_DEFAULT))
2752                                 RETURN_FALSE;
2753                         invokedstatement->impres_count--;
2754                         invokedstatement->impres_child_stmt = (struct php_oci_statement *)statement;
2755                         if (php_oci_statement_fetch(statement, nrows)) {
2756                                 /* End of all fetches */
2757                     RETURN_FALSE;
2758                         }
2759                 } else {
2760                         RETURN_FALSE;
2761                 }
2762     }
2763 #endif /* OCI_MAJOR_VERSION */
2764 
2765         if (placeholder == NULL) {
2766                 placeholder = return_value;
2767         } else {
2768                 zval_dtor(placeholder);
2769         }
2770 
2771         array_init(placeholder);
2772 
2773         for (i = 0; i < statement->ncolumns; i++) {
2774 
2775                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
2776 
2777                 if (column == NULL) {
2778                         continue;
2779                 }
2780                 if ((column->indicator == -1) && ((fetch_mode & PHP_OCI_RETURN_NULLS) == 0)) {
2781                         continue;
2782                 }
2783 
2784                 if (!(column->indicator == -1)) {
2785                         zval element;
2786 
2787                         php_oci_column_to_zval(column, &element, (int) fetch_mode);
2788 
2789                         if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) {
2790                                 add_index_zval(placeholder, i, &element);
2791                         }
2792                         if (fetch_mode & PHP_OCI_ASSOC) {
2793                                 if (fetch_mode & PHP_OCI_NUM) {
2794                                         Z_TRY_ADDREF_P(&element);
2795                                 }
2796                                 add_assoc_zval(placeholder, column->name, &element);
2797                         }
2798 
2799                 } else {
2800                         if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) {
2801                                 add_index_null(placeholder, i);
2802                         }
2803                         if (fetch_mode & PHP_OCI_ASSOC) {
2804                                 add_assoc_null(placeholder, column->name);
2805                         }
2806                 }
2807         }
2808 
2809         if (expected_args > 2) {
2810                 RETURN_LONG(statement->ncolumns);
2811         }
2812 }
2813 /* }}} */
2814 
2815 /* {{{ php_oci_persistent_helper()
2816  *
2817  * Helper function to close/rollback persistent connections at the end of request. A return value of
2818  * 1 indicates that the connection is to be destroyed
2819  */
2820 static int php_oci_persistent_helper(zval *zv)
2821 {
2822         zend_resource *le = Z_RES_P(zv);
2823         time_t timestamp;
2824         php_oci_connection *connection;
2825 
2826         timestamp = time(NULL);
2827 
2828         /* Persistent connection stubs are also counted as they have private session pools */
2829         if (le->type == le_pconnection) {
2830                 connection = (php_oci_connection *)le->ptr;
2831 
2832                 if (!connection->used_this_request && OCI_G(persistent_timeout) != -1) {
2833 #ifdef HAVE_OCI8_DTRACE
2834                         if (DTRACE_OCI8_CONNECT_EXPIRY_ENABLED()) {
2835                                 DTRACE_OCI8_CONNECT_EXPIRY(connection, connection->is_stub ? 1 : 0, (long)connection->idle_expiry, (long)timestamp);
2836                         }
2837 #endif /* HAVE_OCI8_DTRACE */
2838                         if (connection->idle_expiry < timestamp) {
2839                                 /* connection has timed out */
2840                                 return ZEND_HASH_APPLY_REMOVE;
2841                         }
2842                 }
2843         }
2844         return ZEND_HASH_APPLY_KEEP;
2845 }
2846 /* }}} */
2847 
2848 /* {{{ php_oci_create_spool()
2849  *
2850  *       Create(alloc + Init) Session pool for the given dbname and charsetid
2851  */
2852 static php_oci_spool *php_oci_create_spool(char *username, int username_len, char *password, int password_len, char *dbname, int dbname_len, zend_string *hash_key, int charsetid)
2853 {
2854         php_oci_spool *session_pool = NULL;
2855         zend_bool iserror = 0;
2856         ub4 poolmode = OCI_DEFAULT;     /* Mode to be passed to OCISessionPoolCreate */
2857         OCIAuthInfo *spoolAuth = NULL;
2858         sword errstatus;
2859 
2860         /* Allocate sessionpool out of persistent memory */
2861         session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool));
2862         if (session_pool == NULL) {
2863                 iserror = 1;
2864                 goto exit_create_spool;
2865         }
2866 
2867         /* Populate key if passed */
2868         if (hash_key && (ZSTR_LEN(hash_key) > 0)) {
2869                 session_pool->spool_hash_key = zend_string_dup(hash_key, 1);
2870                 if (session_pool->spool_hash_key == NULL) {
2871                         iserror = 1;
2872                         goto exit_create_spool;
2873                 }
2874         }
2875 
2876         /* Create the session pool's env */
2877         if (!(session_pool->env = php_oci_create_env(charsetid))) {
2878                 iserror = 1;
2879                 goto exit_create_spool;
2880         }
2881 
2882         /* Allocate the pool handle */
2883         PHP_OCI_CALL_RETURN(errstatus, OCIHandleAlloc, (session_pool->env, (dvoid **) &session_pool->poolh, OCI_HTYPE_SPOOL, (size_t) 0, (dvoid **) 0));
2884 
2885         if (errstatus != OCI_SUCCESS) {
2886                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2887                 iserror = 1;
2888                 goto exit_create_spool;
2889         }
2890 
2891         /* Allocate the session pool error handle - This only for use in the destructor, as there is a
2892          * generic bug which can free up the OCI_G(err) variable before destroying connections. We
2893          * cannot use this for other roundtrip calls as there is no way the user can access this error
2894          */
2895         PHP_OCI_CALL_RETURN(errstatus, OCIHandleAlloc, ((dvoid *) session_pool->env, (dvoid **)&(session_pool->err), (ub4) OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0));
2896 
2897         if (errstatus != OCI_SUCCESS) {
2898                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2899                 iserror = 1;
2900                 goto exit_create_spool;
2901         }
2902 
2903 /* Disable RLB as we mostly have single-connection pools */
2904 #if (OCI_MAJOR_VERSION > 10)
2905         poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS;
2906 #else
2907         poolmode = OCI_SPC_HOMOGENEOUS;
2908 #endif
2909 
2910 #if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2)))
2911         /* {{{ Allocate auth handle for session pool */
2912         PHP_OCI_CALL_RETURN(errstatus, OCIHandleAlloc, (session_pool->env, (dvoid **)&(spoolAuth), OCI_HTYPE_AUTHINFO, 0, NULL));
2913 
2914         if (errstatus != OCI_SUCCESS) {
2915                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2916                 iserror = 1;
2917                 goto exit_create_spool;
2918         }
2919         /* }}} */
2920 
2921         /* {{{ Set the edition attribute on the auth handle */
2922         if (OCI_G(edition)) {
2923                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, ((dvoid *) spoolAuth, (ub4) OCI_HTYPE_AUTHINFO, (dvoid *) OCI_G(edition), (ub4)(strlen(OCI_G(edition))), (ub4)OCI_ATTR_EDITION, OCI_G(err)));
2924 
2925                 if (errstatus != OCI_SUCCESS) {
2926                         OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2927                         iserror = 1;
2928                         goto exit_create_spool;
2929                 }
2930         }
2931         /* }}} */
2932 
2933         /* {{{ Set the driver name attribute on the auth handle */
2934         PHP_OCI_CALL_RETURN(errstatus, 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)));
2935 
2936         if (errstatus != OCI_SUCCESS) {
2937                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2938                 iserror = 1;
2939                 goto exit_create_spool;
2940         }
2941         /* }}} */
2942 
2943         /* {{{ Set the auth handle on the session pool */
2944         PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, ((dvoid *) (session_pool->poolh),(ub4) OCI_HTYPE_SPOOL, (dvoid *) spoolAuth, (ub4)0, (ub4)OCI_ATTR_SPOOL_AUTH, OCI_G(err)));
2945 
2946         if (errstatus != OCI_SUCCESS) {
2947                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2948                 iserror = 1;
2949                 goto exit_create_spool;
2950         }
2951         /* }}} */
2952 #endif
2953 
2954         /* Create the homogeneous session pool - We have different session pools for every different
2955          * username, password, charset and dbname.
2956          */
2957         PHP_OCI_CALL_RETURN(errstatus, 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));
2958 
2959         if (errstatus != OCI_SUCCESS) {
2960                 OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
2961                 iserror = 1;
2962         }
2963 
2964 exit_create_spool:
2965         if (iserror && session_pool) {
2966                 php_oci_spool_close(session_pool);
2967                 session_pool = NULL;
2968         }
2969 
2970         if (spoolAuth) {
2971                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) spoolAuth, (ub4) OCI_HTYPE_AUTHINFO));
2972         }
2973 
2974 #ifdef HAVE_OCI8_DTRACE
2975         if (DTRACE_OCI8_SESSPOOL_CREATE_ENABLED()) {
2976                 DTRACE_OCI8_SESSPOOL_CREATE(session_pool);
2977         }
2978 #endif /* HAVE_OCI8_DTRACE */
2979 
2980         return session_pool;
2981 }
2982 /* }}} */
2983 
2984 /* {{{ php_oci_get_spool()
2985  *
2986  * Get Session pool for the given dbname and charsetid from the persistent list. Function called for
2987  * non-persistent connections.
2988  */
2989 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)
2990 {
2991         smart_str spool_hashed_details = {0};
2992         php_oci_spool *session_pool = NULL;
2993         zend_resource spool_le = {{0}};
2994         zend_resource *spool_out_le = NULL;
2995         zend_bool iserror = 0;
2996         zval *spool_out_zv = NULL;
2997 
2998         /* {{{ Create the spool hash key */
2999         smart_str_appendl_ex(&spool_hashed_details, "oci8spool***", sizeof("oci8spool***") - 1, 0);
3000         smart_str_appendl_ex(&spool_hashed_details, username, username_len, 0);
3001         smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
3002         /* Add edition attribute to the hash */
3003         if (OCI_G(edition)){
3004                 smart_str_appendl_ex(&spool_hashed_details, OCI_G(edition), strlen(OCI_G(edition)), 0);
3005         }
3006         smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
3007         if (password_len) {
3008                 zend_ulong password_hash;
3009                 password_hash = zend_inline_hash_func(password, password_len);
3010                 smart_str_append_unsigned_ex(&spool_hashed_details, password_hash, 0);
3011         }
3012         smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
3013 
3014         if (dbname_len) {
3015                 smart_str_appendl_ex(&spool_hashed_details, dbname, dbname_len, 0);
3016         }
3017         smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
3018 
3019         smart_str_append_unsigned_ex(&spool_hashed_details, charsetid, 0);
3020 
3021         /* Session Pool Hash Key : oci8spool***username**edition**hashedpassword**dbname**charset */
3022 
3023         smart_str_0(&spool_hashed_details);
3024         php_strtolower(ZSTR_VAL(spool_hashed_details.s), ZSTR_LEN(spool_hashed_details.s));
3025         /* }}} */
3026 
3027         spool_out_zv = zend_hash_find(&EG(persistent_list), spool_hashed_details.s);
3028         if (spool_out_zv != NULL) {
3029                 spool_out_le = Z_RES_P(spool_out_zv);
3030         }
3031 
3032         if (spool_out_le == NULL) {
3033 
3034                 session_pool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, spool_hashed_details.s, charsetid);
3035 
3036                 if (session_pool == NULL) {
3037                         iserror = 1;
3038                         goto exit_get_spool;
3039                 }
3040                 spool_le.ptr  = session_pool;
3041                 spool_le.type = le_psessionpool;
3042                 PHP_OCI_REGISTER_RESOURCE(session_pool, le_psessionpool);
3043                 zend_hash_update_mem(&EG(persistent_list), session_pool->spool_hash_key, (void *)&spool_le, sizeof(zend_resource));
3044         } else if (spool_out_le->type == le_psessionpool &&
3045                 ZSTR_LEN(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key) == ZSTR_LEN(spool_hashed_details.s) &&
3046                 memcmp(ZSTR_VAL(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key), ZSTR_VAL(spool_hashed_details.s), ZSTR_LEN(spool_hashed_details.s)) == 0) {
3047                 /* retrieve the cached session pool */
3048                 session_pool = (php_oci_spool *)(spool_out_le->ptr);
3049         }
3050 
3051 exit_get_spool:
3052         smart_str_free(&spool_hashed_details);
3053         if (iserror && session_pool) {
3054                 php_oci_spool_close(session_pool);
3055                 session_pool = NULL;
3056         }
3057 
3058         return session_pool;
3059 
3060 }
3061 /* }}} */
3062 
3063 /* {{{ php_oci_create_env()
3064  *
3065  * Create the OCI environment choosing the correct function for the OCI version
3066  */
3067 static OCIEnv *php_oci_create_env(ub2 charsetid)
3068 {
3069         OCIEnv *retenv = NULL;
3070 
3071         /* create an environment using the character set id */
3072         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));
3073 
3074         if (OCI_G(errcode) != OCI_SUCCESS) {
3075                 sb4   ora_error_code = 0;
3076                 text  ora_msg_buf[PHP_OCI_ERRBUF_LEN];  /* Use traditional smaller size: non-PL/SQL errors should fit and it keeps the stack smaller */
3077 
3078 #ifdef HAVE_OCI_INSTANT_CLIENT
3079                 php_error_docref(NULL, 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");
3080 #else
3081                 php_error_docref(NULL, 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");
3082 #endif
3083                 if (retenv
3084                         && OCIErrorGet(retenv, (ub4)1, NULL, &ora_error_code, ora_msg_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ENV) == OCI_SUCCESS
3085                         && *ora_msg_buf) {
3086                         php_error_docref(NULL, E_WARNING, "%s", ora_msg_buf);
3087                 }
3088 
3089                 return NULL;
3090         }
3091         return retenv;
3092 }
3093 /* }}} */
3094 
3095 /* {{{ php_oci_old_create_session()
3096  *
3097  * This function is to be deprecated in future in favour of OCISessionGet which is used in
3098  * php_oci_do_connect_ex
3099  */
3100 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)
3101 {
3102         ub4 statement_cache_size = 0;
3103 
3104         if (OCI_G(statement_cache_size) > 0) {
3105                 if (OCI_G(statement_cache_size) > SB4MAXVAL)
3106                         statement_cache_size = (ub4) SB4MAXVAL;
3107                 else
3108                         statement_cache_size = (ub4) OCI_G(statement_cache_size);
3109         }
3110 
3111         /* Create the OCI environment separate for each connection */
3112         if (!(connection->env = php_oci_create_env(connection->charset))) {
3113                 return 1;
3114         }
3115 
3116         /* {{{ Allocate our server handle */
3117         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->server), OCI_HTYPE_SERVER, 0, NULL));
3118 
3119         if (OCI_G(errcode) != OCI_SUCCESS) {
3120                 php_oci_error(OCI_G(err), OCI_G(errcode));
3121                 return 1;
3122         }
3123         /* }}} */
3124 
3125         /* {{{ Attach to the server */
3126         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text *)dbname, dbname_len, (ub4) OCI_DEFAULT));
3127 
3128         if (OCI_G(errcode) != OCI_SUCCESS) {
3129                 php_oci_error(OCI_G(err), OCI_G(errcode));
3130                 return 1;
3131         }
3132         /* }}} */
3133         connection->is_attached = 1;
3134 
3135         /* {{{ Allocate our session handle */
3136         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->session), OCI_HTYPE_SESSION, 0, NULL));
3137 
3138         if (OCI_G(errcode) != OCI_SUCCESS) {
3139                 php_oci_error(OCI_G(err), OCI_G(errcode));
3140                 return 1;
3141         }
3142         /* }}} */
3143 
3144         /* {{{ Allocate our private error-handle */
3145         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));
3146 
3147         if (OCI_G(errcode) != OCI_SUCCESS) {
3148                 php_oci_error(OCI_G(err), OCI_G(errcode));
3149                 return 1;
3150         }
3151         /* }}} */
3152 
3153         /* {{{ Allocate our service-context */
3154         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->svc), OCI_HTYPE_SVCCTX, 0, NULL));
3155 
3156         if (OCI_G(errcode) != OCI_SUCCESS) {
3157                 php_oci_error(OCI_G(err), OCI_G(errcode));
3158                 return 1;
3159         }
3160         /* }}} */
3161 
3162         /* {{{ Set the username */
3163         if (username) {
3164                 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)));
3165 
3166                 if (OCI_G(errcode) != OCI_SUCCESS) {
3167                         php_oci_error(OCI_G(err), OCI_G(errcode));
3168                         return 1;
3169                 }
3170         }
3171         /* }}} */
3172 
3173         /* {{{ Set the password */
3174         if (password) {
3175                 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)));
3176 
3177                 if (OCI_G(errcode) != OCI_SUCCESS) {
3178                         php_oci_error(OCI_G(err), OCI_G(errcode));
3179                         return 1;
3180                 }
3181         }
3182         /* }}} */
3183 
3184         /* {{{ Set the edition attribute on the session handle */
3185 #if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2)))
3186         if (OCI_G(edition)) {
3187                 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)));
3188 
3189                 if (OCI_G(errcode) != OCI_SUCCESS) {
3190                         php_oci_error(OCI_G(err), OCI_G(errcode));
3191                         return 1;
3192                 }
3193         }
3194 #endif
3195 /* }}} */
3196 
3197         /* {{{ Set the driver name attribute on the session handle */
3198 #if (OCI_MAJOR_VERSION >= 11)
3199         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)));
3200 
3201         if (OCI_G(errcode) != OCI_SUCCESS) {
3202                 php_oci_error(OCI_G(err), OCI_G(errcode));
3203                 return 1;
3204         }
3205 #endif
3206 /* }}} */
3207 
3208         /* {{{ Set the server handle in the service handle */
3209         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err)));
3210 
3211         if (OCI_G(errcode) != OCI_SUCCESS) {
3212                 php_oci_error(OCI_G(err), OCI_G(errcode));
3213                 return 1;
3214         }
3215         /* }}} */
3216 
3217         /* {{{ Set the authentication handle in the service handle */
3218         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->session, 0, OCI_ATTR_SESSION, OCI_G(err)));
3219 
3220         if (OCI_G(errcode) != OCI_SUCCESS) {
3221                 php_oci_error(OCI_G(err), OCI_G(errcode));
3222                 return 1;
3223         }
3224         /* }}} */
3225 
3226         if (new_password) {
3227                 /* {{{ Try to change password if new one was provided */
3228                 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));
3229 
3230                 if (OCI_G(errcode) != OCI_SUCCESS) {
3231                         php_oci_error(OCI_G(err), OCI_G(errcode));
3232                         return 1;
3233                 }
3234 
3235                 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)));
3236 
3237                 if (OCI_G(errcode) != OCI_SUCCESS) {
3238                         php_oci_error(OCI_G(err), OCI_G(errcode));
3239                         return 1;
3240                 }
3241                 /* }}} */
3242         } else {
3243                 /* {{{ start the session */
3244                 ub4 cred_type = OCI_CRED_RDBMS;
3245 
3246                 /* Extract the overloaded session_mode parameter into valid Oracle credential and session mode values */
3247                 if (session_mode & PHP_OCI_CRED_EXT) {
3248                         cred_type = OCI_CRED_EXT;
3249                         session_mode ^= PHP_OCI_CRED_EXT;
3250                 }
3251 
3252                 session_mode |= OCI_STMT_CACHE;
3253 
3254                 PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) cred_type, (ub4) session_mode));
3255 
3256                 if (OCI_G(errcode) != OCI_SUCCESS) {
3257                         php_oci_error(OCI_G(err), OCI_G(errcode));
3258                         /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when
3259                          * user's password has expired, but is still usable.
3260                          */
3261                         if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
3262                                 return 1;
3263                         }
3264                 }
3265                 /* }}} */
3266         }
3267 
3268         /* Brand new connection: Init and update the next_ping in the connection */
3269         if (php_oci_ping_init(connection, OCI_G(err)) != OCI_SUCCESS) {
3270                 php_oci_error(OCI_G(err), OCI_G(errcode));
3271                 return 1;
3272         }
3273 
3274         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)));
3275 
3276         if (OCI_G(errcode) != OCI_SUCCESS) {
3277                 php_oci_error(OCI_G(err), OCI_G(errcode));
3278                 return 1;
3279         }
3280 
3281         /* Successfully created session */
3282         return 0;
3283 }
3284 /* }}} */
3285 
3286 /* {{{ php_oci_create_session()
3287  *
3288  * Create session using client-side session pool - new norm
3289  */
3290 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)
3291 {
3292         php_oci_spool *actual_spool = NULL;
3293 #if (OCI_MAJOR_VERSION > 10)
3294         ub4 purity = -2;                                /* Illegal value to initialize */
3295 #endif
3296         time_t timestamp = time(NULL);
3297         ub4 statement_cache_size = 0;
3298 
3299         if (OCI_G(statement_cache_size) > 0) {
3300                 if (OCI_G(statement_cache_size) > SB4MAXVAL)
3301                         statement_cache_size = (ub4) SB4MAXVAL;
3302                 else
3303                         statement_cache_size = (ub4) OCI_G(statement_cache_size);
3304         }
3305 
3306         /* Persistent connections have private session pools */
3307         if (connection->is_persistent && !connection->private_spool &&
3308                 !(connection->private_spool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, NULL, connection->charset))) {
3309                         return 1;
3310         }
3311         actual_spool = (connection->is_persistent) ? (connection->private_spool) : (session_pool);
3312 
3313         connection->env = actual_spool->env;
3314 
3315         /* Do this upfront so that connection close on an error would know that this is a session pool
3316          * connection. Failure to do this would result in crashes in error scenarios
3317          */
3318         if (!connection->using_spool) {
3319                 connection->using_spool = 1;
3320         }
3321 
3322 #ifdef HAVE_OCI8_DTRACE
3323         if (DTRACE_OCI8_SESSPOOL_TYPE_ENABLED()) {
3324                 DTRACE_OCI8_SESSPOOL_TYPE(session_pool ? 1 : 0, session_pool ? session_pool : connection->private_spool);
3325         }
3326 #endif /* HAVE_OCI8_DTRACE */
3327 
3328         /* The passed in "connection" can be a cached stub from plist or freshly created. In the former
3329          * case, we do not have to allocate any handles
3330          */
3331 
3332         if (!connection->err) {
3333                 PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));
3334 
3335                 if (OCI_G(errcode) != OCI_SUCCESS) {
3336                         php_oci_error(OCI_G(err), OCI_G(errcode));
3337                         return 1;
3338                 }
3339         }
3340 
3341         /* {{{ Allocate and initialize the connection-private authinfo handle if not allocated yet */
3342         if (!connection->authinfo) {
3343                 PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL));
3344 
3345                 if (OCI_G(errcode) != OCI_SUCCESS) {
3346                         php_oci_error(OCI_G(err), OCI_G(errcode));
3347                         return 1;
3348                 }
3349 
3350                 /* Set the Connection class and purity if OCI client version >= 11g */
3351 #if (OCI_MAJOR_VERSION > 10)
3352                 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)));
3353 
3354                 if (OCI_G(errcode) != OCI_SUCCESS) {
3355                         php_oci_error(OCI_G(err), OCI_G(errcode));
3356                         return 1;
3357                 }
3358 
3359                 if (connection->is_persistent)
3360                         purity = OCI_ATTR_PURITY_SELF;
3361                 else
3362                         purity = OCI_ATTR_PURITY_NEW;
3363 
3364                 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)));
3365 
3366                 if (OCI_G(errcode) != OCI_SUCCESS) {
3367                         php_oci_error(OCI_G(err), OCI_G(errcode));
3368                         return 1;
3369                 }
3370 #endif
3371         }
3372         /* }}} */
3373 
3374         /* {{{ Debug statements */
3375 #ifdef HAVE_OCI8_DTRACE
3376         if (DTRACE_OCI8_SESSPOOL_STATS_ENABLED()) {
3377                 ub4 numfree = 0, numbusy = 0, numopen = 0;
3378                 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)));
3379                 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)));
3380                 numfree = numopen - numbusy;    /* number of free connections in the pool */
3381                 DTRACE_OCI8_SESSPOOL_STATS(numfree, numbusy, numopen);
3382         }
3383 #endif /* HAVE_OCI8_DTRACE */
3384         /* }}} */
3385 
3386                 /* Ping loop: Ping and loop till we get a good connection. When a database instance goes
3387                  * down, it can leave several bad connections that need to be flushed out before getting a
3388                  * good one. In non-RAC, we always get a brand new connection at the end of the loop and in
3389                  * RAC, we can get a good connection from a different instance before flushing out all bad
3390                  * ones. We do not need to ping brand new connections.
3391                  */
3392         do {
3393                 /* Continue to use the global error handle as the connection is closed when an error occurs */
3394                 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));
3395 
3396                 if (OCI_G(errcode) != OCI_SUCCESS) {
3397                         php_oci_error(OCI_G(err), OCI_G(errcode));
3398 
3399                         /* Session creation returns OCI_SUCCESS_WITH_INFO when user's password has expired, but
3400                          * is still usable.
3401                          */
3402 
3403                         if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
3404                                 return 1;
3405                         }
3406                 }
3407 
3408                 /* {{{ Populate the session and server fields of the connection */
3409                 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)));
3410 
3411                 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)));
3412                 /* }}} */
3413 
3414                 PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, OCI_G(err), (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&(connection->next_pingp)));
3415                 if (OCI_G(errcode) != OCI_SUCCESS) {
3416                         php_oci_error(OCI_G(err), OCI_G(errcode));
3417                         return 1;
3418                 }
3419 
3420                 if (!(connection->next_pingp)){
3421                         /* This is a brand new connection, we need not ping, but have to initialize ping */
3422                         if (php_oci_ping_init(connection, OCI_G(err)) != OCI_SUCCESS) {
3423                                 php_oci_error(OCI_G(err), OCI_G(errcode));
3424                                 return 1;
3425                         }
3426                 } else if ((*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp))) {
3427                         if (php_oci_connection_ping(connection)) {
3428                                 /* Got a good connection - update next_ping and get out of ping loop */
3429                                 *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
3430                         } else {
3431                                 /* Bad connection - remove from pool */
3432                                 PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) OCI_SESSRLS_DROPSESS));
3433                                 connection->svc = NULL;
3434                                 connection->server = NULL;
3435                                 connection->session = NULL;
3436                         }
3437                 }       /* If ping applicable */
3438         } while (!(connection->svc));
3439 
3440         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)));
3441 
3442         if (OCI_G(errcode) != OCI_SUCCESS) {
3443                 php_oci_error(OCI_G(err), OCI_G(errcode));
3444                 return 1;
3445         }
3446 
3447         /* Session is now taken from the session pool and attached and open */
3448         connection->is_stub = 0;
3449         connection->is_attached = connection->is_open = 1;
3450 
3451         return 0;
3452 }
3453 /* }}} */
3454 
3455 /* {{{ php_oci_spool_list_dtor()
3456  *
3457  * Session pool destructor function
3458  */
3459 static void php_oci_spool_list_dtor(zend_resource *entry)
3460 {
3461         php_oci_spool *session_pool = (php_oci_spool *)entry->ptr;
3462 
3463         if (session_pool) {
3464                 php_oci_spool_close(session_pool);
3465         }
3466 
3467         return;
3468 }
3469 /* }}} */
3470 
3471 /* {{{  php_oci_spool_close()
3472  *
3473  * Destroys the OCI Session Pool
3474  */
3475 static void php_oci_spool_close(php_oci_spool *session_pool)
3476 {
3477         if (session_pool->poolname_len) {
3478                 PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh,
3479                         (dvoid *) session_pool->err, OCI_SPD_FORCE));
3480         }
3481 
3482         if (session_pool->poolh) {
3483                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL));
3484         }
3485 
3486         if (session_pool->err) {
3487                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR));
3488         }
3489 
3490         if (session_pool->env) {
3491                 PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->env, OCI_HTYPE_ENV));
3492         }
3493 
3494         if (session_pool->spool_hash_key) {
3495                 free(session_pool->spool_hash_key);
3496         }
3497 
3498         free(session_pool);
3499 }
3500 /* }}} */
3501 
3502 /* {{{ php_oci_ping_init()
3503  *
3504  * Initializes the next_ping time as a context value in the connection.  We now use
3505  * OCIContext{Get,Set}Value to store the next_ping because we need to support ping for
3506  * non-persistent DRCP connections
3507  */
3508 static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh)
3509 {
3510         time_t *next_pingp = NULL;
3511 
3512         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, errh, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&next_pingp));
3513         if (OCI_G(errcode) != OCI_SUCCESS) {
3514                 return OCI_G(errcode);
3515         }
3516 
3517         /* This must be a brand-new connection. Allocate memory for the ping */
3518         if (!next_pingp) {
3519                 PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIMemoryAlloc, (connection->session, errh, (void **)&next_pingp, OCI_DURATION_SESSION, sizeof(time_t), OCI_MEMORY_CLEARED));
3520                 if (OCI_G(errcode) != OCI_SUCCESS) {
3521                         return OCI_G(errcode);
3522                 }
3523         }
3524 
3525         if (OCI_G(ping_interval) >= 0) {
3526                 time_t timestamp = time(NULL);
3527                 *next_pingp = timestamp + OCI_G(ping_interval);
3528         } else {
3529                 *next_pingp = 0;
3530         }
3531 
3532         /* Set the new ping value into the connection */
3533         PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextSetValue, (connection->session, errh, OCI_DURATION_SESSION, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), next_pingp));
3534         if (OCI_G(errcode) != OCI_SUCCESS) {
3535                 OCIMemoryFree(connection->session, errh, next_pingp);
3536                 return OCI_G(errcode);
3537         }
3538 
3539         /* Cache the pointer so we do not have to do OCIContextGetValue repeatedly */
3540         connection->next_pingp = next_pingp;
3541 
3542         return OCI_SUCCESS;
3543 }
3544 /* }}} */
3545 
3546 /* {{{ php_oci_dtrace_check_connection()
3547  *
3548  * DTrace output for connections that may have become invalid and marked for reopening
3549  */
3550 void php_oci_dtrace_check_connection(php_oci_connection *connection, sb4 errcode, ub4 serverStatus)
3551 {
3552 #ifdef HAVE_OCI8_DTRACE
3553         if (DTRACE_OCI8_CHECK_CONNECTION_ENABLED()) {
3554                 DTRACE_OCI8_CHECK_CONNECTION(connection, connection->client_id, connection->is_open ? 1 : 0, (long)errcode, (unsigned long)serverStatus);
3555         }
3556 #endif /* HAVE_OCI8_DTRACE */
3557 }
3558 /* }}} */
3559 
3560 #endif /* HAVE_OCI8 */
3561 
3562 /*
3563  * Local variables:
3564  * tab-width: 4
3565  * c-basic-offset: 4
3566  * End:
3567  * vim600: noet sw=4 ts=4 fdm=marker
3568  * vim<600: noet sw=4 ts=4
3569  */

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