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