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