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

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