cvs: php-src /ext/oci8 README oci8.c php_oci8_int.h /ext/oci8/tests drcp_cclass1.phpt
| From: | Christopher Jones | Date: | Wed, 12 Mar 2008 01:25:13 +0000 |
| Subject: | cvs: php-src /ext/oci8 README oci8.c php_oci8_int.h /ext/oci8/tests drcp_cclass1.phpt | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-49065@lists.php.net to get a copy of this message | ||
sixd Wed Mar 12 01:25:13 2008 UTC
Added files:
/php-src/ext/oci8/tests drcp_cclass1.phpt
Modified files:
/php-src/ext/oci8 oci8.c php_oci8_int.h README
Log:
Cleaned up whitespace
Fixed bug #44372 (compilation with Oracle 10gR1 libraries)
http://bugs.php.net/bug.php?id=44372
Updated updated error number list to improve re-connection
behavior after a database restart.
Guard against potential internal list corruption after ping
removes old oci_pconnect() information.
Fix ini_set("oci8.connection_class", "abc") to get an appropriate
persistent connection.
Ping at oci8.ping_interval for oci_connect() and oci_new_connect()
when DRCP connections are used. This improves non-persistent
connection reliability if a database gets restarted.
http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/oci8.c?r1=1.344&r2=1.345&diff_format=u Index: php-src/ext/oci8/oci8.c diff -u php-src/ext/oci8/oci8.c:1.344 php-src/ext/oci8/oci8.c:1.345 --- php-src/ext/oci8/oci8.c:1.344 Tue Feb 26 02:18:16 2008 +++ php-src/ext/oci8/oci8.c Wed Mar 12 01:25:13 2008 @@ -26,14 +26,14 @@ +----------------------------------------------------------------------+ */ -/* $Id: oci8.c,v 1.344 2008/02/26 02:18:16 sixd Exp $ */ +/* $Id: oci8.c,v 1.345 2008/03/12 01:25:13 sixd Exp $ */ /* TODO * * file://localhost/www/docs/oci10/ociaahan.htm#423823 - implement lob_empty() with OCI_ATTR_LOBEMPTY * * get OCI_ATTR_CHARSET_ID attr of column to detect UTF string and multiply buffer in 4 times * - * */ + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -59,7 +59,7 @@ int le_statement; int le_descriptor; int le_psessionpool; -#ifdef PHP_OCI8_HAVE_COLLECTIONS +#ifdef PHP_OCI8_HAVE_COLLECTIONS int le_collection; #endif @@ -86,6 +86,7 @@ /* static protos {{{ */ static void php_oci_connection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_pconnection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); +static void php_oci_pconnection_list_np_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_statement_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_descriptor_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC); @@ -107,6 +108,7 @@ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC); static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC); static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, char *hash_key, int hash_key_len, int charsetid, zend_uchar type TSRMLS_DC); +static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC); /* }}} */ /* {{{ dynamically loadable module stuff */ @@ -211,184 +213,184 @@ /* {{{ extension definition structures */ static const zend_function_entry php_oci_functions[] = { - PHP_FE(oci_define_by_name, oci_third_arg_force_ref) - PHP_FE(oci_bind_by_name, oci_third_arg_force_ref) - PHP_FE(oci_bind_array_by_name, oci_third_arg_force_ref) - PHP_FE(oci_field_is_null, NULL) - PHP_FE(oci_field_name, NULL) - PHP_FE(oci_field_size, NULL) - PHP_FE(oci_field_scale, NULL) - PHP_FE(oci_field_precision, NULL) - PHP_FE(oci_field_type, NULL) - PHP_FE(oci_field_type_raw, NULL) - PHP_FE(oci_execute, NULL) - PHP_FE(oci_cancel, NULL) - PHP_FE(oci_fetch, NULL) - PHP_FE(oci_fetch_object, NULL) - PHP_FE(oci_fetch_row, NULL) - PHP_FE(oci_fetch_assoc, NULL) - PHP_FE(oci_fetch_array, NULL) - PHP_FE(ocifetchinto, oci_second_arg_force_ref) - PHP_FE(oci_fetch_all, oci_second_arg_force_ref) - PHP_FE(oci_free_statement, NULL) - PHP_FE(oci_internal_debug, NULL) - PHP_FE(oci_num_fields, NULL) - PHP_FE(oci_parse, NULL) - PHP_FE(oci_new_cursor, NULL) - PHP_FE(oci_result, NULL) - PHP_FE(oci_server_version, NULL) - PHP_FE(oci_statement_type, NULL) - PHP_FE(oci_num_rows, NULL) - PHP_FE(oci_close, NULL) - PHP_FE(oci_connect, NULL) - PHP_FE(oci_new_connect, NULL) - PHP_FE(oci_pconnect, NULL) - PHP_FE(oci_error, NULL) - PHP_FE(oci_free_descriptor, NULL) - PHP_FE(oci_lob_save, NULL) - PHP_FE(oci_lob_import, NULL) - PHP_FE(oci_lob_size, NULL) - PHP_FE(oci_lob_load, NULL) - PHP_FE(oci_lob_read, NULL) - PHP_FE(oci_lob_eof, NULL) - PHP_FE(oci_lob_tell, NULL) - PHP_FE(oci_lob_truncate, NULL) - PHP_FE(oci_lob_erase, NULL) - PHP_FE(oci_lob_flush, NULL) - PHP_FE(ocisetbufferinglob, NULL) - PHP_FE(ocigetbufferinglob, NULL) - PHP_FE(oci_lob_is_equal, NULL) - PHP_FE(oci_lob_rewind, NULL) - PHP_FE(oci_lob_write, NULL) - PHP_FE(oci_lob_append, NULL) - PHP_FE(oci_lob_copy, NULL) - PHP_FE(oci_lob_export, NULL) - PHP_FE(oci_lob_seek, NULL) - PHP_FE(oci_commit, NULL) - PHP_FE(oci_rollback, NULL) - PHP_FE(oci_new_descriptor, NULL) - PHP_FE(oci_set_prefetch, NULL) - PHP_FE(oci_password_change, NULL) + PHP_FE(oci_define_by_name, oci_third_arg_force_ref) + PHP_FE(oci_bind_by_name, oci_third_arg_force_ref) + PHP_FE(oci_bind_array_by_name, oci_third_arg_force_ref) + PHP_FE(oci_field_is_null, NULL) + PHP_FE(oci_field_name, NULL) + PHP_FE(oci_field_size, NULL) + PHP_FE(oci_field_scale, NULL) + PHP_FE(oci_field_precision, NULL) + PHP_FE(oci_field_type, NULL) + PHP_FE(oci_field_type_raw, NULL) + PHP_FE(oci_execute, NULL) + PHP_FE(oci_cancel, NULL) + PHP_FE(oci_fetch, NULL) + PHP_FE(oci_fetch_object, NULL) + PHP_FE(oci_fetch_row, NULL) + PHP_FE(oci_fetch_assoc, NULL) + PHP_FE(oci_fetch_array, NULL) + PHP_FE(ocifetchinto, oci_second_arg_force_ref) + PHP_FE(oci_fetch_all, oci_second_arg_force_ref) + PHP_FE(oci_free_statement, NULL) + PHP_FE(oci_internal_debug, NULL) + PHP_FE(oci_num_fields, NULL) + PHP_FE(oci_parse, NULL) + PHP_FE(oci_new_cursor, NULL) + PHP_FE(oci_result, NULL) + PHP_FE(oci_server_version, NULL) + PHP_FE(oci_statement_type, NULL) + PHP_FE(oci_num_rows, NULL) + PHP_FE(oci_close, NULL) + PHP_FE(oci_connect, NULL) + PHP_FE(oci_new_connect, NULL) + PHP_FE(oci_pconnect, NULL) + PHP_FE(oci_error, NULL) + PHP_FE(oci_free_descriptor, NULL) + PHP_FE(oci_lob_save, NULL) + PHP_FE(oci_lob_import, NULL) + PHP_FE(oci_lob_size, NULL) + PHP_FE(oci_lob_load, NULL) + PHP_FE(oci_lob_read, NULL) + PHP_FE(oci_lob_eof, NULL) + PHP_FE(oci_lob_tell, NULL) + PHP_FE(oci_lob_truncate, NULL) + PHP_FE(oci_lob_erase, NULL) + PHP_FE(oci_lob_flush, NULL) + PHP_FE(ocisetbufferinglob, NULL) + PHP_FE(ocigetbufferinglob, NULL) + PHP_FE(oci_lob_is_equal, NULL) + PHP_FE(oci_lob_rewind, NULL) + PHP_FE(oci_lob_write, NULL) + PHP_FE(oci_lob_append, NULL) + PHP_FE(oci_lob_copy, NULL) + PHP_FE(oci_lob_export, NULL) + PHP_FE(oci_lob_seek, NULL) + PHP_FE(oci_commit, NULL) + PHP_FE(oci_rollback, NULL) + PHP_FE(oci_new_descriptor, NULL) + PHP_FE(oci_set_prefetch, NULL) + PHP_FE(oci_password_change, NULL) #ifdef PHP_OCI8_HAVE_COLLECTIONS - PHP_FE(oci_free_collection, NULL) - PHP_FE(oci_collection_append, NULL) - PHP_FE(oci_collection_element_get, NULL) - PHP_FE(oci_collection_element_assign, NULL) - PHP_FE(oci_collection_assign, NULL) - PHP_FE(oci_collection_size, NULL) - PHP_FE(oci_collection_max, NULL) - PHP_FE(oci_collection_trim, NULL) - PHP_FE(oci_new_collection, NULL) -#endif - - PHP_FALIAS(oci_free_cursor, oci_free_statement, NULL) - PHP_FALIAS(ocifreecursor, oci_free_statement, NULL) - PHP_FALIAS(ocibindbyname, oci_bind_by_name, oci_third_arg_force_ref) - PHP_FALIAS(ocidefinebyname, oci_define_by_name, oci_third_arg_force_ref) - PHP_FALIAS(ocicolumnisnull, oci_field_is_null, NULL) - PHP_FALIAS(ocicolumnname, oci_field_name, NULL) - PHP_FALIAS(ocicolumnsize, oci_field_size, NULL) - PHP_FALIAS(ocicolumnscale, oci_field_scale, NULL) - PHP_FALIAS(ocicolumnprecision, oci_field_precision, NULL) - PHP_FALIAS(ocicolumntype, oci_field_type, NULL) - PHP_FALIAS(ocicolumntyperaw, oci_field_type_raw, NULL) - PHP_FALIAS(ociexecute, oci_execute, NULL) - PHP_FALIAS(ocicancel, oci_cancel, NULL) - PHP_FALIAS(ocifetch, oci_fetch, NULL) - PHP_FALIAS(ocifetchstatement, oci_fetch_all, oci_second_arg_force_ref) - PHP_FALIAS(ocifreestatement, oci_free_statement, NULL) - PHP_FALIAS(ociinternaldebug, oci_internal_debug, NULL) - PHP_FALIAS(ocinumcols, oci_num_fields, NULL) - PHP_FALIAS(ociparse, oci_parse, NULL) - PHP_FALIAS(ocinewcursor, oci_new_cursor, NULL) - PHP_FALIAS(ociresult, oci_result, NULL) - PHP_FALIAS(ociserverversion, oci_server_version, NULL) - PHP_FALIAS(ocistatementtype, oci_statement_type, NULL) - PHP_FALIAS(ocirowcount, oci_num_rows, NULL) - PHP_FALIAS(ocilogoff, oci_close, NULL) - PHP_FALIAS(ocilogon, oci_connect, NULL) - PHP_FALIAS(ocinlogon, oci_new_connect, NULL) - PHP_FALIAS(ociplogon, oci_pconnect, NULL) - PHP_FALIAS(ocierror, oci_error, NULL) - PHP_FALIAS(ocifreedesc, oci_free_descriptor, NULL) - PHP_FALIAS(ocisavelob, oci_lob_save, NULL) - PHP_FALIAS(ocisavelobfile, oci_lob_import, NULL) - PHP_FALIAS(ociwritelobtofile, oci_lob_export, NULL) - PHP_FALIAS(ociloadlob, oci_lob_load, NULL) - PHP_FALIAS(ocicommit, oci_commit, NULL) - PHP_FALIAS(ocirollback, oci_rollback, NULL) - PHP_FALIAS(ocinewdescriptor, oci_new_descriptor, NULL) - PHP_FALIAS(ocisetprefetch, oci_set_prefetch, NULL) - PHP_FALIAS(ocipasswordchange, oci_password_change, NULL) + PHP_FE(oci_free_collection, NULL) + PHP_FE(oci_collection_append, NULL) + PHP_FE(oci_collection_element_get, NULL) + PHP_FE(oci_collection_element_assign, NULL) + PHP_FE(oci_collection_assign, NULL) + PHP_FE(oci_collection_size, NULL) + PHP_FE(oci_collection_max, NULL) + PHP_FE(oci_collection_trim, NULL) + PHP_FE(oci_new_collection, NULL) +#endif + + PHP_FALIAS(oci_free_cursor, oci_free_statement, NULL) + PHP_FALIAS(ocifreecursor, oci_free_statement, NULL) + PHP_FALIAS(ocibindbyname, oci_bind_by_name, oci_third_arg_force_ref) + PHP_FALIAS(ocidefinebyname, oci_define_by_name, oci_third_arg_force_ref) + PHP_FALIAS(ocicolumnisnull, oci_field_is_null, NULL) + PHP_FALIAS(ocicolumnname, oci_field_name, NULL) + PHP_FALIAS(ocicolumnsize, oci_field_size, NULL) + PHP_FALIAS(ocicolumnscale, oci_field_scale, NULL) + PHP_FALIAS(ocicolumnprecision, oci_field_precision, NULL) + PHP_FALIAS(ocicolumntype, oci_field_type, NULL) + PHP_FALIAS(ocicolumntyperaw, oci_field_type_raw, NULL) + PHP_FALIAS(ociexecute, oci_execute, NULL) + PHP_FALIAS(ocicancel, oci_cancel, NULL) + PHP_FALIAS(ocifetch, oci_fetch, NULL) + PHP_FALIAS(ocifetchstatement, oci_fetch_all, oci_second_arg_force_ref) + PHP_FALIAS(ocifreestatement, oci_free_statement, NULL) + PHP_FALIAS(ociinternaldebug, oci_internal_debug, NULL) + PHP_FALIAS(ocinumcols, oci_num_fields, NULL) + PHP_FALIAS(ociparse, oci_parse, NULL) + PHP_FALIAS(ocinewcursor, oci_new_cursor, NULL) + PHP_FALIAS(ociresult, oci_result, NULL) + PHP_FALIAS(ociserverversion, oci_server_version, NULL) + PHP_FALIAS(ocistatementtype, oci_statement_type, NULL) + PHP_FALIAS(ocirowcount, oci_num_rows, NULL) + PHP_FALIAS(ocilogoff, oci_close, NULL) + PHP_FALIAS(ocilogon, oci_connect, NULL) + PHP_FALIAS(ocinlogon, oci_new_connect, NULL) + PHP_FALIAS(ociplogon, oci_pconnect, NULL) + PHP_FALIAS(ocierror, oci_error, NULL) + PHP_FALIAS(ocifreedesc, oci_free_descriptor, NULL) + PHP_FALIAS(ocisavelob, oci_lob_save, NULL) + PHP_FALIAS(ocisavelobfile, oci_lob_import, NULL) + PHP_FALIAS(ociwritelobtofile, oci_lob_export, NULL) + PHP_FALIAS(ociloadlob, oci_lob_load, NULL) + PHP_FALIAS(ocicommit, oci_commit, NULL) + PHP_FALIAS(ocirollback, oci_rollback, NULL) + PHP_FALIAS(ocinewdescriptor, oci_new_descriptor, NULL) + PHP_FALIAS(ocisetprefetch, oci_set_prefetch, NULL) + PHP_FALIAS(ocipasswordchange, oci_password_change, NULL) #ifdef PHP_OCI8_HAVE_COLLECTIONS - PHP_FALIAS(ocifreecollection, oci_free_collection, NULL) - PHP_FALIAS(ocinewcollection, oci_new_collection, NULL) - PHP_FALIAS(ocicollappend, oci_collection_append, NULL) - PHP_FALIAS(ocicollgetelem, oci_collection_element_get, NULL) - PHP_FALIAS(ocicollassignelem, oci_collection_element_assign, NULL) - PHP_FALIAS(ocicollsize, oci_collection_size, NULL) - PHP_FALIAS(ocicollmax, oci_collection_max, NULL) - PHP_FALIAS(ocicolltrim, oci_collection_trim, NULL) + PHP_FALIAS(ocifreecollection, oci_free_collection, NULL) + PHP_FALIAS(ocinewcollection, oci_new_collection, NULL) + PHP_FALIAS(ocicollappend, oci_collection_append, NULL) + PHP_FALIAS(ocicollgetelem, oci_collection_element_get, NULL) + PHP_FALIAS(ocicollassignelem, oci_collection_element_assign, NULL) + PHP_FALIAS(ocicollsize, oci_collection_size, NULL) + PHP_FALIAS(ocicollmax, oci_collection_max, NULL) + PHP_FALIAS(ocicolltrim, oci_collection_trim, NULL) #endif {NULL,NULL,NULL} }; static const zend_function_entry php_oci_lob_class_functions[] = { - PHP_FALIAS(load, oci_lob_load, NULL) - PHP_FALIAS(tell, oci_lob_tell, NULL) - PHP_FALIAS(truncate, oci_lob_truncate, NULL) - PHP_FALIAS(erase, oci_lob_erase, NULL) - PHP_FALIAS(flush, oci_lob_flush, NULL) - PHP_FALIAS(setbuffering,ocisetbufferinglob, NULL) - PHP_FALIAS(getbuffering,ocigetbufferinglob, NULL) - PHP_FALIAS(rewind, oci_lob_rewind, NULL) - PHP_FALIAS(read, oci_lob_read, NULL) - PHP_FALIAS(eof, oci_lob_eof, NULL) - PHP_FALIAS(seek, oci_lob_seek, NULL) - PHP_FALIAS(write, oci_lob_write, NULL) - PHP_FALIAS(append, oci_lob_append, NULL) - PHP_FALIAS(size, oci_lob_size, NULL) - PHP_FALIAS(writetofile, oci_lob_export, NULL) - PHP_FALIAS(export, oci_lob_export, NULL) - PHP_FALIAS(import, oci_lob_import, NULL) + PHP_FALIAS(load, oci_lob_load, NULL) + PHP_FALIAS(tell, oci_lob_tell, NULL) + PHP_FALIAS(truncate, oci_lob_truncate, NULL) + PHP_FALIAS(erase, oci_lob_erase, NULL) + PHP_FALIAS(flush, oci_lob_flush, NULL) + PHP_FALIAS(setbuffering,ocisetbufferinglob, NULL) + PHP_FALIAS(getbuffering,ocigetbufferinglob, NULL) + PHP_FALIAS(rewind, oci_lob_rewind, NULL) + PHP_FALIAS(read, oci_lob_read, NULL) + PHP_FALIAS(eof, oci_lob_eof, NULL) + PHP_FALIAS(seek, oci_lob_seek, NULL) + PHP_FALIAS(write, oci_lob_write, NULL) + PHP_FALIAS(append, oci_lob_append, NULL) + PHP_FALIAS(size, oci_lob_size, NULL) + PHP_FALIAS(writetofile, oci_lob_export, NULL) + PHP_FALIAS(export, oci_lob_export, NULL) + PHP_FALIAS(import, oci_lob_import, NULL) #ifdef HAVE_OCI8_TEMP_LOB - PHP_FALIAS(writetemporary, oci_lob_write_temporary, NULL) - PHP_FALIAS(close, oci_lob_close, NULL) + PHP_FALIAS(writetemporary, oci_lob_write_temporary, NULL) + PHP_FALIAS(close, oci_lob_close, NULL) #endif - PHP_FALIAS(save, oci_lob_save, NULL) - PHP_FALIAS(savefile, oci_lob_import, NULL) - PHP_FALIAS(free, oci_free_descriptor, NULL) + PHP_FALIAS(save, oci_lob_save, NULL) + PHP_FALIAS(savefile, oci_lob_import, NULL) + PHP_FALIAS(free, oci_free_descriptor, NULL) {NULL,NULL,NULL} }; #ifdef PHP_OCI8_HAVE_COLLECTIONS static const zend_function_entry php_oci_coll_class_functions[] = { - PHP_FALIAS(append, oci_collection_append, NULL) - PHP_FALIAS(getelem, oci_collection_element_get, NULL) - PHP_FALIAS(assignelem, oci_collection_element_assign, NULL) - PHP_FALIAS(assign, oci_collection_assign, NULL) - PHP_FALIAS(size, oci_collection_size, NULL) - PHP_FALIAS(max, oci_collection_max, NULL) - PHP_FALIAS(trim, oci_collection_trim, NULL) - PHP_FALIAS(free, oci_free_collection, NULL) + PHP_FALIAS(append, oci_collection_append, NULL) + PHP_FALIAS(getelem, oci_collection_element_get, NULL) + PHP_FALIAS(assignelem, oci_collection_element_assign, NULL) + PHP_FALIAS(assign, oci_collection_assign, NULL) + PHP_FALIAS(size, oci_collection_size, NULL) + PHP_FALIAS(max, oci_collection_max, NULL) + PHP_FALIAS(trim, oci_collection_trim, NULL) + PHP_FALIAS(free, oci_free_collection, NULL) {NULL,NULL,NULL} }; #endif zend_module_entry oci8_module_entry = { STANDARD_MODULE_HEADER, - "oci8", /* extension name */ - php_oci_functions, /* extension function list */ - PHP_MINIT(oci), /* extension-wide startup function */ - PHP_MSHUTDOWN(oci), /* extension-wide shutdown function */ - PHP_RINIT(oci), /* per-request startup function */ - PHP_RSHUTDOWN(oci), /* per-request shutdown function */ - PHP_MINFO(oci), /* information function */ + "oci8", /* extension name */ + php_oci_functions, /* extension function list */ + PHP_MINIT(oci), /* extension-wide startup function */ + PHP_MSHUTDOWN(oci), /* extension-wide shutdown function */ + PHP_RINIT(oci), /* per-request startup function */ + PHP_RSHUTDOWN(oci), /* per-request shutdown function */ + PHP_MINFO(oci), /* information function */ "1.3.1", PHP_MODULE_GLOBALS(oci), /* globals descriptor */ - PHP_GINIT(oci), /* globals ctor */ - NULL, /* globals dtor */ - NULL, /* post deactivate */ + PHP_GINIT(oci), /* globals ctor */ + NULL, /* globals dtor */ + NULL, /* post deactivate */ STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ @@ -411,7 +413,7 @@ */ /* {{{ php_oci_init_global_handles() - Initialize global handles only when they are needed + Initialize global handles only when they are needed */ static void php_oci_init_global_handles(TSRMLS_D) { @@ -420,21 +422,21 @@ text tmp_buf[PHP_OCI_ERRBUF_LEN]; errcode = OCIEnvInit (&OCI_G(env), OCI_DEFAULT, 0, NULL); - + if (errcode == OCI_ERROR) { goto oci_error; } - + errcode = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL); - + if (errcode == OCI_ERROR || errcode == OCI_SUCCESS_WITH_INFO) { goto oci_error; } return; - + oci_error: - + OCIErrorGet(OCI_G(env), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR); if (error_code) { @@ -443,12 +445,12 @@ if (tmp_buf_len > 0 && tmp_buf[tmp_buf_len - 1] == '\n') { tmp_buf[tmp_buf_len - 1] = '\0'; } - + if (errcode != OCI_SUCCESS_WITH_INFO) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_ERROR: %s", tmp_buf); - + OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV); - + OCI_G(env) = NULL; OCI_G(err) = NULL; } else { @@ -466,7 +468,7 @@ PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR)); OCI_G(err) = NULL; } - + if (OCI_G(env)) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV)); OCI_G(env) = NULL; @@ -509,7 +511,7 @@ le_statement = zend_register_list_destructors_ex(php_oci_statement_list_dtor, NULL, "oci8 statement", module_number); le_connection = zend_register_list_destructors_ex(php_oci_connection_list_dtor, NULL, "oci8 connection", module_number); - le_pconnection = zend_register_list_destructors_ex(NULL, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number); + le_pconnection = zend_register_list_destructors_ex(php_oci_pconnection_list_np_dtor, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number); le_psessionpool = zend_register_list_destructors_ex(NULL, php_oci_spool_list_dtor, "oci8 persistent session pool", module_number); le_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number); #ifdef PHP_OCI8_HAVE_COLLECTIONS @@ -541,15 +543,15 @@ /* for $LOB->flush() */ REGISTER_LONG_CONSTANT("OCI_LOB_BUFFER_FREE",OCI_LOB_BUFFER_FREE, CONST_CS | CONST_PERSISTENT); - -/* for OCIBindByName (real "oci" names + short "php" names*/ + +/* for OCIBindByName (real "oci" names + short "php" names */ REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_AFC",SQLT_AFC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CHR",SQLT_CHR, CONST_CS | CONST_PERSISTENT); @@ -570,7 +572,7 @@ #ifdef PHP_OCI8_HAVE_COLLECTIONS REGISTER_LONG_CONSTANT("OCI_B_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE", CONST_CS | CONST_PERSISTENT); #endif @@ -595,7 +597,7 @@ REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",PHP_OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",PHP_OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT); -/* for OCINewDescriptor (real "oci" names + short "php" names*/ +/* for OCINewDescriptor (real "oci" names + short "php" names */ REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT); @@ -627,7 +629,7 @@ PHP_MSHUTDOWN_FUNCTION(oci) { OCI_G(shutdown) = 1; - + UNREGISTER_INI_ENTRIES(); #ifndef ZTS @@ -648,7 +650,7 @@ #ifdef PHP_OCI8_HAVE_COLLECTIONS zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_collection TSRMLS_CC); #endif - while (OCI_G(num_statements)) { + while (OCI_G(num_statements)) { zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_statement TSRMLS_CC); } #endif @@ -671,7 +673,7 @@ php_info_print_table_start(); php_info_print_table_row(2, "OCI8 Support", "enabled"); php_info_print_table_row(2, "Version", "1.3.1 Beta"); - php_info_print_table_row(2, "Revision", "$Revision: 1.344 $"); + php_info_print_table_row(2, "Revision", "$Revision: 1.345 $"); snprintf(buf, sizeof(buf), "%ld", OCI_G(num_persistent)); php_info_print_table_row(2, "Active Persistent Connections", buf); @@ -682,8 +684,8 @@ php_info_print_table_row(2, "Oracle Version", PHP_OCI8_VERSION ); php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DIR ); php_info_print_table_row(2, "Libraries Used", PHP_OCI8_SHARED_LIBADD ); -#else -# if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) +#else +# if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION); php_info_print_table_row(2, "Oracle Instant Client Version", buf); # endif @@ -702,7 +704,7 @@ #endif php_info_print_table_end(); - + DISPLAY_INI_ENTRIES(); } /* }}} */ @@ -714,8 +716,11 @@ static void php_oci_connection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) { php_oci_connection *connection = (php_oci_connection *)entry->ptr; - php_oci_connection_close(connection TSRMLS_CC); - OCI_G(num_links)--; + + if (connection) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_links)--; + } } /* }}} */ /* {{{ php_oci_pconnection_list_dtor() @@ -723,8 +728,25 @@ static void php_oci_pconnection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) { php_oci_connection *connection = (php_oci_connection *)entry->ptr; - php_oci_connection_close(connection TSRMLS_CC); - OCI_G(num_persistent)--; + + if (connection) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_persistent)--; + } +} /* }}} */ + +/* {{{ php_oci_pconnection_list_np_dtor() + Non-Persistent destructor for persistent connection - This gets invoked when + the refcount of this goes to zero in the regular list */ +static void php_oci_pconnection_list_np_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) +{ + php_oci_connection *connection = (php_oci_connection *)entry->ptr; + + /* If it is a bad connection, clean it up. This is the sole purpose of this dtor. We should ideally do a hash_del also, but this scenario is currently not possible. */ + if (connection && !connection->is_open && !connection->is_stub) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_persistent)--; + } } /* }}} */ /* {{{ php_oci_statement_list_dtor() @@ -790,12 +812,6 @@ efree(bind->array.indicators); } -/* - if (bind->array.retcodes) { - efree(bind->array.retcodes); - } -*/ - zval_ptr_dtor(&bind->zval); } /* }}} */ @@ -831,7 +847,7 @@ { php_oci_descriptor *descriptor = *(php_oci_descriptor **)data; TSRMLS_FETCH(); - + if (descriptor && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) { php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC); descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED; @@ -846,7 +862,7 @@ { php_oci_descriptor *descriptor = *(php_oci_descriptor **)data; int *desc_id = (int *) id; - + if (descriptor && desc_id && descriptor->id == *desc_id) { return 1; } @@ -881,7 +897,7 @@ case OCI_NO_DATA: php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NO_DATA"); break; - case OCI_ERROR: + case OCI_ERROR: errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC); if (errbuf) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "%R", (UG(unicode) ? IS_UNICODE : IS_STRING), errbuf); @@ -950,7 +966,7 @@ err_buf[err_buf_len - 1] = '\0'; } } - + if (err_buf_len && error_buf) { *error_buf = (text *)estrndup((char *)err_buf, TEXT_BYTES(err_buf_len)); } @@ -962,7 +978,7 @@ #ifdef HAVE_OCI8_ATTR_STATEMENT /* {{{ php_oci_fetch_sqltext_offset() Compute offset in the SQL statement */ -int php_oci_fetch_sqltext_offset(php_oci_statement *statement, zstr *sqltext, ub2 *error_offset TSRMLS_DC) +int php_oci_fetch_sqltext_offset(php_oci_statement *statement, zstr *sqltext, ub2 *error_offset TSRMLS_DC) { ub4 sqltext_len = 0; @@ -974,15 +990,15 @@ } else { PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *) &(sqltext->s), (ub4 *)&sqltext_len, OCI_ATTR_STATEMENT, statement->err)); } - - if (statement->errcode != OCI_SUCCESS) { + + if (statement->errcode != OCI_SUCCESS) { php_oci_error(statement->err, statement->errcode TSRMLS_CC); return 1; } PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err)); - - if (statement->errcode != OCI_SUCCESS) { + + if (statement->errcode != OCI_SUCCESS) { php_oci_error(statement->err, statement->errcode TSRMLS_CC); return 1; } @@ -990,7 +1006,7 @@ } /* }}} */ #endif -/* {{{ php_oci_do_connect() +/* {{{ php_oci_do_connect() Connect wrapper */ void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive) { @@ -1006,7 +1022,7 @@ /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "TT|TTl", &username, &username_len, &username_type, &password, &password_len, &password_type, &dbname, &dbname_len, &dbname_type, &charset, &charset_len, &charset_type, &session_mode) == FAILURE) { return; - } + } connection = php_oci_do_connect_ex(username, username_len, password, password_len, NULL_ZSTR, 0, dbname, dbname_len, charset, session_mode, persistent, exclusive, username_type TSRMLS_CC); @@ -1014,12 +1030,12 @@ RETURN_FALSE; } RETURN_RESOURCE(connection->rsrc_id); - + } /* }}} */ /* {{{ php_oci_do_connect_ex() * The real connect function. Allocates all the resources needed, establishes the connection and returns the result handle (or NULL) */ -php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC) +php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC) { zend_rsrc_list_entry *le; zend_rsrc_list_entry new_le; @@ -1027,13 +1043,14 @@ smart_str hashed_details = {0}; time_t timestamp; php_oci_spool *session_pool = NULL; - zend_bool use_spool = 1; /* Default is to use client-side session pool */ + zend_bool use_spool = 1; /* Default is to use client-side session pool */ + zend_bool ping_done = 0; #if HAVE_OCI_ENV_NLS_CREATE ub2 charsetid = 0; ub2 charsetid_nls_lang = 0; #endif - + switch (session_mode) { case OCI_DEFAULT: break; @@ -1058,34 +1075,40 @@ /* We cannot use the new session create logic (OCISessionGet from * client-side session pool) when privileged connect or password * change is attempted. TODO: Remove this once OCI provides - * capability + * capability */ - if ((session_mode==OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) { + if ((session_mode == OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) { use_spool = 0; - } - else if (UG(unicode)) { + } else if (UG(unicode)) { /* Pre 10.1 session pool does not support unicode - bypass pool */ -#ifndef HAVE_OCI_LOB_READ2 /* For finding 10.1+ client */ +#ifndef HAVE_OCI_LOB_READ2 /* For finding 10.1+ client */ use_spool = 0; #endif } - smart_str_appendl_ex(&hashed_details, "oci8___", sizeof("oci8___") - 1, 0); + smart_str_appendl_ex(&hashed_details, "oci8***", sizeof("oci8***") - 1, 0); smart_str_appendl_ex(&hashed_details, username.s, USTR_BYTES(type, username_len), 0); - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); + + /* DRCP: connection_class is an attribute of a connection */ + if (OCI_G(connection_class)){ + smart_str_appendl_ex(&hashed_details, OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), 0); + } + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); + if (password_len) { ulong password_hash; password_hash = zend_u_inline_hash_func(type, password, password_len); smart_str_append_unsigned_ex(&hashed_details, password_hash, 0); } - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); if (dbname_len) { smart_str_appendl_ex(&hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0); } - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); - /* Initialize global handles if the weren't initialized before */ + /* Initialize global handles if they weren't initialized before */ if (OCI_G(env) == NULL) { php_oci_init_global_handles(TSRMLS_C); } @@ -1112,8 +1135,7 @@ } smart_str_append_unsigned_ex(&hashed_details, charsetid_nls_lang, 0); } - } - else { + } else { charsetid = OCI_UTF16ID; smart_str_append_unsigned_ex(&hashed_details, charsetid, 0); } @@ -1125,13 +1147,13 @@ #endif timestamp = time(NULL); - + smart_str_append_unsigned_ex(&hashed_details, session_mode, 0); smart_str_0(&hashed_details); /* make it lowercase */ php_strtolower(hashed_details.c, hashed_details.len); - + if (!exclusive && !new_password.v) { zend_bool found = 0; @@ -1139,7 +1161,7 @@ found = 1; /* found */ if (le->type == le_pconnection) { - connection = (php_oci_connection *)le->ptr; + connection = (php_oci_connection *)le->ptr; } } else if (!persistent && zend_hash_find(&EG(regular_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) { found = 1; @@ -1156,21 +1178,19 @@ } /* Debug statements {{{ */ - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (connection && connection->is_stub) { php_printf ("OCI8 DEBUG L1: Got a cached stub: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else if (connection) { + } else if (connection) { php_printf ("OCI8 DEBUG L1: Got a cached connection: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: Got NO cached connection at (%s:%d) \n", __FILE__, __LINE__); } } /* }}} */ - /* If we got a pconnection stub, then 'load'(OCISessionGet) the + /* If we got a pconnection stub, then 'load'(OCISessionGet) the * real connection from its private spool - * A connection is a stub if it is only a cached structure and the + * A connection is a stub if it is only a cached structure and the * real connection is released to its underlying private session pool. * We currently do not have stub support for non-persistent conns. * @@ -1183,26 +1203,29 @@ return NULL; } + /* We do the ping in php_oci_create_session, no need to ping again below */ + ping_done = 1; } - + if (connection) { if (connection->is_open) { /* found an open connection. now ping it */ if (connection->is_persistent) { + int rsrc_type; + /* check connection liveness in the following order: * 1) always check OCI_ATTR_SERVER_STATUS * 2) see if it's time to ping it - * 3) ping it if needed - * */ + * 3) ping it if needed + */ if (php_oci_connection_status(connection TSRMLS_CC)) { - /* only ping if: + /* only ping if: * 1) next_ping > 0, which means that ping_interval is not -1 (aka "Off") * 2) current_timestamp > next_ping, which means "it's time to check if it's still alive" - * */ - if ( (connection->next_ping > 0) && (timestamp >= connection->next_ping) && !php_oci_connection_ping(connection TSRMLS_CC)) { + */ + if ( !ping_done && (*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp)) && !php_oci_connection_ping(connection TSRMLS_CC) ) { /* server died */ } else { - int rsrc_type; php_oci_connection *tmp; /* okay, the connection is open and the server is still alive */ @@ -1221,6 +1244,18 @@ } /* server died */ connection->is_open = 0; + connection->used_this_request = 1; + + /* Connection is no more part of the persistent list */ + free(connection->hash_key); + connection->hash_key = NULL; + connection->hash_key_len = 0; + + /* We have to do a hash_del but need to preserve the resource if there is a positive refcount. Set the data pointer in the list entry to NULL */ + if (zend_list_find(connection->rsrc_id, &rsrc_type)) { + le->ptr = NULL; + } + zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1); connection = NULL; goto open; @@ -1247,22 +1282,22 @@ open: /* Check if we have reached max_persistent. If so, try to remove a few - * timeout out connections. As last resort, return a non-persistent conn + * timed-out connections. As a last resort, return a non-persistent connection. */ if (persistent) { zend_bool alloc_non_persistent = 0; - + if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) { /* try to find an idle connection and kill it */ zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC); - + if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) { /* all persistent connactions are in use, fallback to non-persistent connection creation */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Too many open persistent connections (%ld)", OCI_G(num_persistent)); alloc_non_persistent = 1; } } - + if (alloc_non_persistent) { connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection)); connection->hash_key = estrndup(hashed_details.c, hashed_details.len); @@ -1282,9 +1317,9 @@ } /* {{{ Get the session pool that suits this connection request from the - * persistent list. This step is only for non-persistent connections as + * persistent list. This step is only for non-persistent connections as * persistent connections have private session pools. Non-persistent conns - * use shared session pool to allow for optimizations such as caching the + * use shared session pool to allow for optimizations such as caching the * physical connection (for DRCP) even when the non-persistent php connection * is destroyed. * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability */ @@ -1294,20 +1329,14 @@ php_oci_connection_close(connection TSRMLS_CC); smart_str_free_ex(&hashed_details, 0); return NULL; - } + } } /* }}} */ connection->idle_expiry = (OCI_G(persistent_timeout) > 0) ? (timestamp + OCI_G(persistent_timeout)) : 0; - if (OCI_G(ping_interval) >= 0) { - connection->next_ping = timestamp + OCI_G(ping_interval); - } else { - /* -1 means "Off" */ - connection->next_ping = 0; - } - + /* mark password as unchanged by PHP during the duration of the database session */ connection->passwd_changed = 0; - + smart_str_free_ex(&hashed_details, 0); #if HAVE_OCI_ENV_NLS_CREATE @@ -1318,21 +1347,20 @@ } #endif - /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change {{{*/ + /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change */ if ( !use_spool) { if (php_oci_old_create_session(connection, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) { php_oci_connection_close(connection TSRMLS_CC); return NULL; } - } /* }}} */ - else { + } else { /* create using the client-side session pool */ if (php_oci_create_session(connection, session_pool, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) { php_oci_connection_close(connection TSRMLS_CC); return NULL; - } + } } - + /* mark it as open */ connection->is_open = 1; @@ -1351,16 +1379,15 @@ zend_hash_update(&EG(regular_list), connection->hash_key, connection->hash_key_len+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL); OCI_G(num_links)++; } else { - connection->rsrc_id = zend_list_insert(connection, le_connection); + connection->rsrc_id = zend_list_insert(connection, le_connection); OCI_G(num_links)++; } /* Debug statements {{{ */ - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (connection->is_persistent) { php_printf ("OCI8 DEBUG L1: New Persistent Connection address:(%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: New Non-Persistent Connection address: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); } php_printf ("OCI8 DEBUG L1: num_persistent=(%ld), num_links=(%ld) at (%s:%d) \n", OCI_G(num_persistent), OCI_G(num_links), __FILE__, __LINE__); @@ -1378,20 +1405,19 @@ * ORA-1010 (invalid OCI operation) such as from Pre-10.1 servers, * the error is still from the server and we would have * successfully performed a roundtrip and validated the - * connection. Use OCIServerVersion for Pre-10.1 clients + * connection. Use OCIServerVersion for Pre-10.2 clients */ -#if HAVE_OCI_LOB_READ2 /* 10.1 and greater client - OCIPing was first available in 10.1 */ +#if ( (OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION > 2)) ) /* OCIPing available 10.2 onwards */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT)); #else char version[256]; /* use good old OCIServerVersion() */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text*)version, sizeof(version), OCI_HTYPE_SVCCTX)); + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX)); #endif - + if (OCI_G(errcode) == OCI_SUCCESS) { return 1; - } - else { + } else { sb4 error_code = 0; text tmp_buf[PHP_OCI_ERRBUF_LEN]; @@ -1402,7 +1428,7 @@ } } - /* ignore errors here, just return failure + /* ignore errors here, just return failure * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */ return 0; } @@ -1416,12 +1442,12 @@ /* get OCI_ATTR_SERVER_STATUS */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err))); - + if (OCI_G(errcode) == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) { return 1; } - /* ignore errors here, just return failure + /* ignore errors here, just return failure * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */ return 0; } @@ -1457,7 +1483,7 @@ return 0; } /* }}} */ -/* {{{ php_oci_connection_close() +/* {{{ php_oci_connection_close() Close the connection and free all its resources */ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC) { @@ -1469,7 +1495,7 @@ efree(connection->descriptors); } - if (connection->svc) { + if (connection->svc) { /* rollback outstanding transactions */ if (connection->needs_commit) { if (php_oci_connection_rollback(connection TSRMLS_CC)) { @@ -1480,11 +1506,18 @@ } if (!connection->is_stub && connection->svc && connection->is_open) { + /* Update the next_ping in the connection. Needed also for non-peristent because non-persistent DRCP caches connection underneath */ + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + /* Use OCISessionRelease for session pool connections */ if (connection->using_spool) { PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) 0)); - } - else { + } else { PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0)); } } @@ -1495,31 +1528,30 @@ if (connection->authinfo) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO)); } - - /* No Handlefrees for session pool connections {{{ */ + + /* No Handlefrees for session pool connections */ if (!connection->using_spool) { if (connection->session) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION)); } - + if (connection->is_attached) { PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT)); } - + if (connection->svc) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX)); } - + if (connection->server) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER)); } - + if (connection->env) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV)); } - } /* }}} */ - else if (connection->private_spool) { - /* Keep this as the last member to be freed, as there are dependencies + } else if (connection->private_spool) { + /* Keep this as the last member to be freed, as there are dependencies * (like env) on the session pool */ php_oci_spool_close(connection->private_spool TSRMLS_CC); @@ -1541,7 +1573,7 @@ return result; } /* }}} */ -/* {{{ php_oci_connection_release() +/* {{{ php_oci_connection_release() Release the connection to its session pool. This looks similar to php_oci_connection_close, but the latter is used for connections that are to be terminated. The latter was not overloaded for "release" because of too many callers */ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC) { @@ -1558,7 +1590,7 @@ connection->descriptors = NULL; } - if (connection->svc) { + if (connection->svc) { /* rollback outstanding transactions */ if (connection->needs_commit) { if (php_oci_connection_rollback(connection TSRMLS_CC)) { @@ -1570,8 +1602,15 @@ /* Release the session */ if (connection->svc) { - PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL, - 0, OCI_DEFAULT)); + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + + PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL, + 0, result ? OCI_SESSRLS_DROPSESS : OCI_DEFAULT)); } /* It no longer has relation with the database session. However authinfo and env are cached */ @@ -1582,9 +1621,11 @@ connection->is_attached = connection->is_open = connection->needs_commit = 0; connection->is_stub = 1; - /* now a stub, so don't count it in the number of connnections */ + /* Cut the link between the connection structure and the time_t structure allocated within the OCI session */ + connection->next_pingp = NULL; + if (!connection->is_persistent) { - OCI_G(num_links)--; /* Support for "connection" stubs - future use */ + OCI_G(num_links)--; /* Support for "connection" stubs - future use */ } OCI_G(in_call) = in_call_save; @@ -1606,14 +1647,14 @@ return 0; } /* }}} */ -/* {{{ php_oci_server_get_version() +/* {{{ php_oci_server_get_version() Get Oracle server version */ -int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC) +int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC) { char version_buff[512]; - PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text*)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX)); - + PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text *)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX)); + if (connection->errcode != OCI_SUCCESS) { php_oci_error(connection->err, connection->errcode TSRMLS_CC); PHP_OCI_HANDLE_ERROR(connection, connection->errcode); @@ -1628,7 +1669,7 @@ return 0; } /* }}} */ -/* {{{ php_oci_column_to_zval() +/* {{{ php_oci_column_to_zval() Convert php_oci_out_column struct into zval */ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSRMLS_DC) { @@ -1639,20 +1680,20 @@ zstr lob_buffer; zstr zstr_data = ZSTR(column->data); php_oci_lob_type lob_type; - - if (column->indicator == -1) { /* column is NULL */ - ZVAL_NULL(value); + + if (column->indicator == -1) { /* column is NULL */ + ZVAL_NULL(value); return 0; } - + if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */ ZVAL_RESOURCE(value, column->stmtid); zend_list_addref(column->stmtid); } else if (column->is_descr) { - + if (column->data_type != SQLT_RDD) { int rsrc_type; - + /* reset descriptor's length */ descriptor = (php_oci_descriptor *) zend_list_find(column->descid, &rsrc_type); @@ -1660,7 +1701,7 @@ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find LOB descriptor #%d", column->descid); return 1; } - + descriptor->lob_size = -1; descriptor->lob_current_position = 0; descriptor->buffering = 0; @@ -1668,7 +1709,7 @@ if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) { /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */ - + lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC); lob_fetch_status |= (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0); #ifdef HAVE_OCI8_TEMP_LOB @@ -1696,7 +1737,7 @@ break; } return 0; - } else { + } else { /* return the locator */ object_init_ex(value, oci_lob_class_entry_ptr); add_property_resource(value, "descriptor", column->descid); @@ -1704,7 +1745,7 @@ } } else { switch (column->retcode) { - case 0: + case 0: /* intact value */ if (column->piecewise) { column_size = column->retlen4; @@ -1712,19 +1753,19 @@ column_size = column->retlen; } break; - - default: - ZVAL_FALSE(value); + + default: + ZVAL_FALSE(value); return 0; } - + ZVAL_TEXTL(value, zstr_data, TEXT_CHARS(column_size), 1); } return 0; } /* }}} */ -/* {{{ php_oci_fetch_row() +/* {{{ php_oci_fetch_row() Fetch the next row from the given statement */ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args) { @@ -1741,7 +1782,7 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|l", &z_statement, &array, &fetch_mode) == FAILURE) { return; } - + if (ZEND_NUM_ARGS() == 2) { fetch_mode = mode; } @@ -1751,17 +1792,17 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &fetch_mode) == FAILURE) { return; } - + if (ZEND_NUM_ARGS() == 1) { fetch_mode = mode; } } else { /* for all oci_fetch_*() */ - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) { return; } - + fetch_mode = mode; } @@ -1769,7 +1810,7 @@ /* none of the modes present, use the default one */ if (mode & PHP_OCI_ASSOC) { fetch_mode |= PHP_OCI_ASSOC; - } + } if (mode & PHP_OCI_NUM) { fetch_mode |= PHP_OCI_NUM; } @@ -1784,9 +1825,9 @@ array_init(return_value); for (i = 0; i < statement->ncolumns; i++) { - + column = php_oci_statement_get_column(statement, i + 1, NULL_ZSTR, 0 TSRMLS_CC); - + if (column == NULL) { continue; } @@ -1796,7 +1837,7 @@ if (!(column->indicator == -1)) { zval *element; - + MAKE_STD_ZVAL(element); php_oci_column_to_zval(column, element, fetch_mode TSRMLS_CC); @@ -1809,7 +1850,7 @@ } add_u_assoc_zval(return_value, (UG(unicode) ? IS_UNICODE : IS_STRING), column->name, element); } - + } else { if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) { add_index_null(return_value, i); @@ -1831,7 +1872,7 @@ } /* }}} */ -/* {{{ php_oci_persistent_helper() +/* {{{ php_oci_persistent_helper() Helper function to close/rollback persistent connections at the end of request. A return value of 1 indicates that the connection is to be destroyed */ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC) { @@ -1839,7 +1880,7 @@ php_oci_connection *connection; timestamp = time(NULL); - + /* pconnection stubs are also counted as they have private session pools */ if (le->type == le_pconnection) { connection = (php_oci_connection *)le->ptr; @@ -1849,19 +1890,24 @@ return ZEND_HASH_APPLY_REMOVE; } + /* Helps remove bad connections from the persistent list */ + if (!connection->is_open && !connection->is_stub) { + return ZEND_HASH_APPLY_REMOVE; + } + if (connection->descriptors) { zend_hash_destroy(connection->descriptors); efree(connection->descriptors); connection->descriptors = NULL; } - + if (connection->needs_commit) { php_oci_connection_rollback(connection TSRMLS_CC); } - + /* If oci_password_change() changed the password of a * persistent connection, close the connection and remove - * it from the persistent connection cache. This means + * it from the persistent connection cache. This means * subsequent scripts will be prevented from being able to * present the old (now invalid) password to a usable * connection to the database; they must use the new @@ -1874,17 +1920,19 @@ if (OCI_G(persistent_timeout) > 0) { connection->idle_expiry = timestamp + OCI_G(persistent_timeout); } - - if (OCI_G(ping_interval) >= 0) { - connection->next_ping = timestamp + OCI_G(ping_interval); - } else { - /* ping_interval is -1 */ - connection->next_ping = 0; - } - /* Release all persistent connections at the end of the request */ - if (connection->using_spool && !connection->is_stub && php_oci_connection_release(connection TSRMLS_CC)) { - return ZEND_HASH_APPLY_REMOVE; + if (!connection->is_stub) { + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = timestamp + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + + /* Release all session pool-using persistent connections at the end of the request */ + if (connection->using_spool && php_oci_connection_release(connection TSRMLS_CC)) { + return ZEND_HASH_APPLY_REMOVE; + } } connection->used_this_request = 0; @@ -1904,16 +1952,17 @@ { php_oci_spool *session_pool = NULL; zend_bool iserror = 0; + ub4 poolmode = OCI_DEFAULT; /* Mode to be passed to OCISessionPoolCreate */ /*Allocate sessionpool out of persistent memory */ session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool)); - /* Populate key if passed */ + /* Populate key if passed */ if (hash_key_len) { session_pool->spool_hash_key = zend_strndup(hash_key, hash_key_len); session_pool->spool_hash_key_len = hash_key_len; } - + /* Create the session pool's env */ if (!(session_pool->env = php_oci_create_env(charsetid TSRMLS_CC))) { iserror = 1; @@ -1932,7 +1981,7 @@ /* allocate the session pool error handle - This only for use in the * destructor, as there is a generic bug which can free up the OCI_G(err) * variable before destroying connections. We cannot use this for other - * roundtrip calls as there is no way the user can access this error + * roundtrip calls as there is no way the user can access this error */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, ((dvoid *) session_pool->env, (dvoid **)&(session_pool->err), (ub4) OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0)); @@ -1940,13 +1989,20 @@ php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; goto exit_create_spool; - } + } + +/* Disable RLB as we'd mostly have single-connection pools */ +#if (OCI_MAJOR_VERSION > 10 ) + poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS; +#else + poolmode = OCI_SPC_HOMOGENEOUS; +#endif /* Create the homogeneous session pool - We have different session pools * for every different username, password, charset and dbname. */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 1, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), OCI_SPC_HOMOGENEOUS)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 0, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), poolmode)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; @@ -1958,20 +2014,21 @@ ub4 timeout = OCI_G(persistent_timeout); PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) session_pool->poolh, (ub4) OCI_HTYPE_SPOOL, (void *) &timeout, (ub4) sizeof(timeout), (ub4) OCI_ATTR_SPOOL_TIMEOUT, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; goto exit_create_spool; } } + exit_create_spool: if (iserror && session_pool) { php_oci_spool_close(session_pool TSRMLS_CC); session_pool = NULL; } - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { php_printf ("OCI8 DEBUG L1: create_spool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__); } @@ -1979,7 +2036,7 @@ } /* }}} */ /* {{{ php_oci_get_spool() - Get Session pool for the given dbname and charsetid from the persistent + Get Session pool for the given dbname and charsetid from the persistent list. Function called for non-persistent connections. */ static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC) @@ -1989,26 +2046,26 @@ zend_rsrc_list_entry spool_le = {0}; zend_rsrc_list_entry *spool_out_le = NULL; zend_bool iserror = 0; - + /* Create the spool hash key {{{ */ - smart_str_appendl_ex(&spool_hashed_details, "oci8__spool__", sizeof("oci8__spool__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "oci8spool***", sizeof("oci8spool***") - 1, 0); smart_str_appendl_ex(&spool_hashed_details, username.s, USTR_BYTES(type, username_len), 0); - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); if (password_len) { ulong password_hash; password_hash = zend_u_inline_hash_func(type, password, password_len); smart_str_append_unsigned_ex(&spool_hashed_details, password_hash, 0); } - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); if (dbname_len) { smart_str_appendl_ex(&spool_hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0); } - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); - + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); + smart_str_append_unsigned_ex(&spool_hashed_details, charsetid, 0); - /* Session Pool Hash Key : oci8__spool__dbname__charset */ + /* Session Pool Hash Key : oci8spool***username**hashedpassword**dbname**charset */ smart_str_0(&spool_hashed_details); php_strtolower(spool_hashed_details.c, spool_hashed_details.len); @@ -2018,16 +2075,15 @@ session_pool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, spool_hashed_details.c, spool_hashed_details.len, charsetid, type TSRMLS_CC); - if (session_pool == NULL) { + if (session_pool == NULL) { iserror = 1; - goto exit_get_spool; - } + goto exit_get_spool; + } spool_le.ptr = session_pool; spool_le.type = le_psessionpool; zend_list_insert(session_pool, le_psessionpool); zend_hash_update(&EG(persistent_list), session_pool->spool_hash_key, session_pool->spool_hash_key_len + 1, (void *)&spool_le, sizeof(zend_rsrc_list_entry),NULL); - } - else if (spool_out_le->type == le_psessionpool && + } else if (spool_out_le->type == le_psessionpool && (((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key_len) == spool_hashed_details.len && memcmp(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key, spool_hashed_details.c, spool_hashed_details.len) == 0 ) { /* retrieve the cached session pool */ @@ -2047,25 +2103,25 @@ /* {{{ php_oci_create_env() Create the OCI environment choosing the correct function for the OCI version */ -static OCIEnv* php_oci_create_env(ub2 charsetid TSRMLS_DC) +static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC) { OCIEnv *retenv = NULL; /* allocate environment handle */ #if HAVE_OCI_ENV_NLS_CREATE #define PHP_OCI_INIT_FUNC_NAME "OCIEnvNlsCreate" - + /* create an environment using the character set id, Oracle 9i+ ONLY */ 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)); #elif HAVE_OCI_ENV_CREATE #define PHP_OCI_INIT_FUNC_NAME "OCIEnvCreate" - + /* allocate env handle without NLS support */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvCreate, (&retenv, PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL)); #else #define PHP_OCI_INIT_FUNC_NAME "OCIEnvInit" - + /* the simpliest way */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvInit, (&retenv, OCI_DEFAULT, 0, NULL)); #endif @@ -2089,26 +2145,26 @@ This function is to be deprecated in future in favour of OCISessionGet which is used in php_oci_do_connect_ex */ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC) { - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { php_printf ("OCI8 DEBUG: Bypassing client-side session pool for session create at (%s:%d) \n", __FILE__, __LINE__); } /* Create the OCI environment separate for each connection */ - if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) { - return 1; + if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) { + return 1; } - /* Allocate our server handle {{{ */ + /* Allocate our server handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->server), OCI_HTYPE_SERVER, 0, NULL)); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } /* }}} */ /* Attach to the server {{{ */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text*)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text *)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2117,7 +2173,7 @@ /* Allocate our session handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->session), OCI_HTYPE_SESSION, 0, NULL)); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2142,24 +2198,24 @@ /* Set the username {{{ */ if (username_len) { PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) username.s, (ub4) USTR_BYTES(type, username_len), (ub4) OCI_ATTR_USERNAME, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } }/* }}} */ /* Set the password {{{ */ if (password_len) { PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) password.s, (ub4) USTR_BYTES(type, password_len), (ub4) OCI_ATTR_PASSWORD, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } }/* }}} */ - /* Set the server handle in the service handle {{{ */ + /* Set the server handle in the service handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err))); if (OCI_G(errcode) != OCI_SUCCESS) { @@ -2217,23 +2273,29 @@ php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when * user's password has expired, but is still usable. - * */ + */ if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { return 1; } } /* }}} */ } + /* Brand new connection: Init and update the next_ping in the connection */ + if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + return 1; + } + #if HAVE_OCI_STMT_PREPARE2 { ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0; PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } } #endif @@ -2249,6 +2311,7 @@ #if (OCI_MAJOR_VERSION > 10 ) ub4 purity = -2; /* Illegal value to initialize */ #endif + time_t timestamp = time(NULL); /* Persistent connections have private session pools */ if (connection->is_persistent && !connection->private_spool && @@ -2266,22 +2329,21 @@ connection->using_spool = 1; } - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (session_pool) { php_printf ("OCI8 DEBUG L1: using shared pool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: using private pool: (%p) at (%s:%d) \n", connection->private_spool, __FILE__, __LINE__); } } - /* The passed in "connection" can be a cached stub from plist or a + /* The passed in "connection" can be a cached stub from plist or * freshly created. In the former case, we do not have to allocate * any handles */ if (!connection->err) { - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2290,14 +2352,14 @@ /* {{{ Allocate and initialize the connection-private authinfo handle if not allocated yet */ if (!connection->authinfo) { - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } - /* Set the Connection class and purity if OCI client version >=11g */ + /* Set the Connection class and purity if OCI client version >= 11g */ #if (OCI_MAJOR_VERSION > 10 ) PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), (ub4)OCI_ATTR_CONNECTION_CLASS, OCI_G(err))); @@ -2310,7 +2372,6 @@ purity = OCI_ATTR_PURITY_SELF; else purity = OCI_ATTR_PURITY_NEW; - PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_AUTHINFO, (dvoid *) &purity, (ub4)0, (ub4)OCI_ATTR_PURITY, OCI_G(err))); @@ -2321,39 +2382,84 @@ #endif } /* }}} */ - /* Continue to use the global error handle as the connection is closed when an error occurs */ - PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)); - - if (OCI_G(errcode) != OCI_SUCCESS) { - php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + /* Debug statements {{{ */ + if (OCI_G(debug_mode)) { + ub4 numfree = 0, numbusy = 0, numopen = 0; + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numopen, (ub4 *)0, OCI_ATTR_SPOOL_OPEN_COUNT, OCI_G(err))); + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numbusy, (ub4 *)0, OCI_ATTR_SPOOL_BUSY_COUNT, OCI_G(err))); + numfree = numopen - numbusy; /* number of free connections in the pool */ + php_printf ("OCI8 DEBUG L1: (numopen=%d)(numbusy=%d) at (%s:%d) \n", numopen, numbusy, __FILE__, __LINE__); + } /* }}} */ + + /* Ping loop: Ping and loop till we get a good + * connection. When a database instance goes down, it can + * leave several bad connections that need to be flushed out + * before getting a good one. In non-RAC, we always get a + * brand new connection at the end of the loop and in RAC, we + * can get a good connection from a different instance before + * flushing out all bad ones. We do not need to ping brand new + * connections. + */ + do { + /* Continue to use the global error handle as the connection is closed when an error occurs */ + PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)); + + if (OCI_G(errcode) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + + /* Session creation returns OCI_SUCCESS_WITH_INFO when + * user's password has expired, but is still usable. + */ - /* Session creation returns OCI_SUCCESS_WITH_INFO when - * user's password has expired, but is still usable. - * */ + if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { + return 1; + } + } - if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { + /* {{{ Populate the session and server fields of the connection */ + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err))); + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */ + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, OCI_G(err), (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&(connection->next_pingp))); + if (OCI_G(errcode) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } - } - + + if (!(connection->next_pingp)){ + /* This is a brand new connection, we need not ping, but have to initialize ping */ + if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + return 1; + } + } else if ((*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp))) { + if (php_oci_connection_ping(connection TSRMLS_CC)) { + /* Got a good connection - update next_ping and get out of ping loop */ + *(connection->next_pingp) = timestamp + OCI_G(ping_interval); + } else { + /* Bad connection - remove from pool */ + PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) OCI_SESSRLS_DROPSESS)); + connection->svc = NULL; + connection->server = NULL; + connection->session = NULL; + } + } /* If ping applicable */ + } while (!(connection->svc)); + #if HAVE_OCI_STMT_PREPARE2 { ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0; PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } } #endif - /* {{{ Populate the session and server fields of the connection */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err))); - - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */ - /* Session is now taken from the session pool and attached and open */ connection->is_stub = 0; connection->is_attached = connection->is_open = 1; @@ -2374,12 +2480,12 @@ return; } /* }}} */ -/* {{{ php_oci_spool_close() +/* {{{ php_oci_spool_close() Destroys the OCI Session Pool */ static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC) { - if (session_pool->poolname_len) { - PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh, + if (session_pool->poolname_len) { + PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh, (dvoid *) session_pool->err, OCI_SPD_FORCE)); } @@ -2387,23 +2493,65 @@ PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL)); } - if (session_pool->err) { + if (session_pool->err) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR)); } - if (session_pool->env) { + if (session_pool->env) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->env, OCI_HTYPE_ENV)); } if (session_pool->spool_hash_key) { - free(session_pool->spool_hash_key); + free(session_pool->spool_hash_key); } free(session_pool); } /* }}} */ +/* {{{ php_oci_ping_init() + Initializes the next_ping time as a context value in the + connection. We now use OCIContext{Get,Set}Value to store the + next_ping because we need to support ping for non-persistent DRCP + connections */ +static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC) +{ + time_t *next_pingp = NULL; + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, errh, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&next_pingp)); + if (OCI_G(errcode) != OCI_SUCCESS) { + return OCI_G(errcode); + } + + /* This must be a brand-new connection. Allocate memory for the ping */ + if (!next_pingp) { + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIMemoryAlloc, (connection->session, errh, (void **)&next_pingp, OCI_DURATION_SESSION, sizeof(time_t), OCI_MEMORY_CLEARED)); + if (OCI_G(errcode) != OCI_SUCCESS) { + return OCI_G(errcode); + } + } + + if (OCI_G(ping_interval) >= 0) { + time_t timestamp = time(NULL); + *next_pingp = timestamp + OCI_G(ping_interval); + } else { + *next_pingp = 0; + } + + /* Set the new ping value into the connection */ + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextSetValue, (connection->session, errh, OCI_DURATION_SESSION, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), next_pingp)); + if (OCI_G(errcode) != OCI_SUCCESS) { + OCIMemoryFree(connection->session, errh, next_pingp); + return OCI_G(errcode); + } + + /* Cache the pointer so we do not have to do OCIContextGetValue repeatedly */ + connection->next_pingp = next_pingp; + + return OCI_SUCCESS; +} /* }}} */ + #ifdef ZTS -/* {{{ php_oci_list_helper() +/* {{{ php_oci_list_helper() Helper function to destroy data on thread shutdown in ZTS mode */ static int php_oci_list_helper(zend_rsrc_list_entry *le, void *le_type TSRMLS_DC) { http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/php_oci8_int.h?r1=1.41&r2=1.42&diff_format=u Index: php-src/ext/oci8/php_oci8_int.h diff -u php-src/ext/oci8/php_oci8_int.h:1.41 php-src/ext/oci8/php_oci8_int.h:1.42 --- php-src/ext/oci8/php_oci8_int.h:1.41 Mon Feb 25 23:49:51 2008 +++ php-src/ext/oci8/php_oci8_int.h Wed Mar 12 01:25:13 2008 @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 6 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2008 The PHP Group | +----------------------------------------------------------------------+ @@ -25,7 +25,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_oci8_int.h,v 1.41 2008/02/25 23:49:51 sixd Exp $ */ +/* $Id: php_oci8_int.h,v 1.42 2008/03/12 01:25:13 sixd Exp $ */ #if HAVE_OCI8 # ifndef PHP_OCI8_INT_H @@ -34,13 +34,13 @@ /* misc defines {{{ */ # if (defined(__osf__) && defined(__alpha)) # ifndef A_OSF -# define A_OSF +# define A_OSF # endif # ifndef OSF1 -# define OSF1 +# define OSF1 # endif # ifndef _INTRINSICS -# define _INTRINSICS +# define _INTRINSICS # endif # endif /* osf alpha */ @@ -59,7 +59,7 @@ extern int le_pconnection; extern int le_statement; extern int le_descriptor; -#ifdef PHP_OCI8_HAVE_COLLECTIONS +#ifdef PHP_OCI8_HAVE_COLLECTIONS extern int le_collection; #endif extern int le_server; @@ -77,19 +77,19 @@ #define PHP_OCI_MAX_NAME_LEN 64 #define PHP_OCI_MAX_DATA_SIZE INT_MAX -#define PHP_OCI_PIECE_SIZE (64*1024)-1 +#define PHP_OCI_PIECE_SIZE (64*1024)-1 #define PHP_OCI_LOB_BUFFER_SIZE 1048576l /* 1Mb seems to be the most reasonable buffer size for LOB reading */ -#define PHP_OCI_ASSOC 1<<0 -#define PHP_OCI_NUM 1<<1 -#define PHP_OCI_BOTH (PHP_OCI_ASSOC|PHP_OCI_NUM) - -#define PHP_OCI_RETURN_NULLS 1<<2 -#define PHP_OCI_RETURN_LOBS 1<<3 - -#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN 1<<4 -#define PHP_OCI_FETCHSTATEMENT_BY_ROW 1<<5 -#define PHP_OCI_FETCHSTATEMENT_BY (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW) +#define PHP_OCI_ASSOC 1<<0 +#define PHP_OCI_NUM 1<<1 +#define PHP_OCI_BOTH (PHP_OCI_ASSOC|PHP_OCI_NUM) + +#define PHP_OCI_RETURN_NULLS 1<<2 +#define PHP_OCI_RETURN_LOBS 1<<3 + +#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN 1<<4 +#define PHP_OCI_FETCHSTATEMENT_BY_ROW 1<<5 +#define PHP_OCI_FETCHSTATEMENT_BY (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW) #define PHP_OCI_LOB_BUFFER_DISABLED 0 #define PHP_OCI_LOB_BUFFER_ENABLED 1 @@ -103,147 +103,146 @@ } php_oci_lob_type; typedef struct { /* php_oci_spool {{{ */ - OCIEnv *env; /*env of this session pool */ - OCIError *err; /* pool's error handle */ - OCISPool *poolh; /* pool handle */ - void *poolname; /* session pool name */ - unsigned int poolname_len; /* length of session pool name */ - char *spool_hash_key; /* Hash key for session pool in plist */ - int spool_hash_key_len; /* Hash key length */ + OCIEnv *env; /*env of this session pool */ + OCIError *err; /* pool's error handle */ + OCISPool *poolh; /* pool handle */ + void *poolname; /* session pool name */ + unsigned int poolname_len; /* length of session pool name */ + char *spool_hash_key; /* Hash key for session pool in plist */ + int spool_hash_key_len; /* Hash key length */ } php_oci_spool; /* }}} */ typedef struct { /* php_oci_connection {{{ */ - OCIEnv *env; /* private env handle */ - ub2 charset; /* charset ID */ - OCIServer *server; /* private server handle */ - OCISvcCtx *svc; /* private service context handle */ - OCISession *session; /* private session handle */ - OCIAuthInfo *authinfo; /* Cached authinfo handle for OCISessionGet */ - OCIError *err; /* private error handle */ - php_oci_spool *private_spool; /* private session pool (for persistent) */ - sword errcode; /* last errcode */ - - HashTable *descriptors; /* descriptors hash, used to flush all the LOBs using this connection on commit */ - unsigned is_open:1; /* hels to determine if the connection is dead or not */ - unsigned is_attached:1; /* hels to determine if we should detach from the server when closing/freeing the connection */ - unsigned is_persistent:1; /* self-descriptive */ - unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */ - unsigned needs_commit:1; /* helps to determine if we should rollback this connection on close/shutdown */ - unsigned passwd_changed:1; /* helps determine if a persistent connection hash should be invalidated after a password change */ - unsigned is_stub:1; /* flag to keep track whether the connection structure has a real OCI connection associated */ - unsigned using_spool:1; /* Is this connection from session pool? */ - int rsrc_id; /* resource ID */ - time_t idle_expiry; /* time when the connection will be considered as expired */ - time_t next_ping; /* time of the next ping */ - char *hash_key; /* hashed details of the connection */ - int hash_key_len; + OCIEnv *env; /* private env handle */ + ub2 charset; /* charset ID */ + OCIServer *server; /* private server handle */ + OCISvcCtx *svc; /* private service context handle */ + OCISession *session; /* private session handle */ + OCIAuthInfo *authinfo; /* Cached authinfo handle for OCISessionGet */ + OCIError *err; /* private error handle */ + php_oci_spool *private_spool; /* private session pool (for persistent) */ + sword errcode; /* last errcode */ + + HashTable *descriptors; /* descriptors hash, used to flush all the LOBs using this connection on commit */ + unsigned is_open:1; /* hels to determine if the connection is dead or not */ + unsigned is_attached:1; /* hels to determine if we should detach from the server when closing/freeing the connection */ + unsigned is_persistent:1; /* self-descriptive */ + unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */ + unsigned needs_commit:1; /* helps to determine if we should rollback this connection on close/shutdown */ + unsigned passwd_changed:1; /* helps determine if a persistent connection hash should be invalidated after a password change */ + unsigned is_stub:1; /* flag to keep track whether the connection structure has a real OCI connection associated */ + unsigned using_spool:1; /* Is this connection from session pool? */ + int rsrc_id; /* resource ID */ + time_t idle_expiry; /* time when the connection will be considered as expired */ + time_t *next_pingp; /* (pointer to) time of the next ping */ + char *hash_key; /* hashed details of the connection */ + int hash_key_len; } php_oci_connection; /* }}} */ typedef struct { /* php_oci_descriptor {{{ */ - int id; - php_oci_connection *connection; /* parent connection handle */ - dvoid *descriptor; /* OCI descriptor handle */ - ub4 type; /* descriptor type (FILE/LOB) */ - int lob_current_position; /* LOB internal pointer */ - int lob_size; /* cached LOB size. -1 = Lob wasn't initialized yet */ - int buffering; /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */ - ub4 chunk_size; /* chunk size of the LOB. 0 - unknown */ - ub1 charset_form; /* charset form, required for NCLOBs */ - ub2 charset_id; /* charset ID */ - unsigned is_open:1; /* helps to determine if lob is open or not */ - php_oci_lob_type lob_type; /* CLOB/BLOB */ + int id; + php_oci_connection *connection; /* parent connection handle */ + dvoid *descriptor; /* OCI descriptor handle */ + ub4 type; /* descriptor type (FILE/LOB) */ + int lob_current_position; /* LOB internal pointer */ + int lob_size; /* cached LOB size. -1 = Lob wasn't initialized yet */ + int buffering; /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */ + ub4 chunk_size; /* chunk size of the LOB. 0 - unknown */ + ub1 charset_form; /* charset form, required for NCLOBs */ + ub2 charset_id; /* charset ID */ + unsigned is_open:1; /* helps to determine if lob is open or not */ + php_oci_lob_type lob_type; /* CLOB/BLOB */ } php_oci_descriptor; /* }}} */ typedef struct { /* php_oci_lob_ctx {{{ */ - char **lob_data; /* address of pointer to LOB data */ - ub4 *lob_len; /* address of LOB length variable (bytes) */ - ub4 alloc_len; + char **lob_data; /* address of pointer to LOB data */ + ub4 *lob_len; /* address of LOB length variable (bytes) */ + ub4 alloc_len; } php_oci_lob_ctx; /* }}} */ typedef struct { /* php_oci_collection {{{ */ - int id; - php_oci_connection *connection; /* parent connection handle */ - OCIType *tdo; /* collection's type handle */ - OCITypeCode coll_typecode; /* collection's typecode handle */ - OCIRef *elem_ref; /* element's reference handle */ - OCIType *element_type; /* element's type handle */ - OCITypeCode element_typecode; /* element's typecode handle */ - OCIColl *collection; /* collection handle */ + int id; + php_oci_connection *connection; /* parent connection handle */ + OCIType *tdo; /* collection's type handle */ + OCITypeCode coll_typecode; /* collection's typecode handle */ + OCIRef *elem_ref; /* element's reference handle */ + OCIType *element_type; /* element's type handle */ + OCITypeCode element_typecode; /* element's typecode handle */ + OCIColl *collection; /* collection handle */ } php_oci_collection; /* }}} */ typedef struct { /* php_oci_define {{{ */ - zval *zval; /* zval used in define */ - zstr name; /* placeholder's name */ - zend_uchar name_type; /* unicode or not */ - ub4 name_len; /* placeholder's name length */ - ub4 type; /* define type */ + zval *zval; /* zval used in define */ + zstr name; /* placeholder's name */ + zend_uchar name_type; /* unicode or not */ + ub4 name_len; /* placeholder's name length */ + ub4 type; /* define type */ } php_oci_define; /* }}} */ typedef struct { /* php_oci_statement {{{ */ - int id; - int parent_stmtid; /* parent statement id */ - php_oci_connection *connection; /* parent connection handle */ - sword errcode; /* last errcode*/ - OCIError *err; /* private error handle */ - OCIStmt *stmt; /* statement handle */ - char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */ - long last_query_len; /* last query length */ - HashTable *columns; /* hash containing all the result columns */ - HashTable *binds; /* binds hash */ - HashTable *defines; /* defines hash */ - int ncolumns; /* number of columns in the result */ - unsigned executed:1; /* statement executed flag */ - unsigned has_data:1; /* statement has more data flag */ - ub2 stmttype; /* statement type */ + int id; + int parent_stmtid; /* parent statement id */ + php_oci_connection *connection; /* parent connection handle */ + sword errcode; /* last errcode*/ + OCIError *err; /* private error handle */ + OCIStmt *stmt; /* statement handle */ + char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */ + long last_query_len; /* last query length */ + HashTable *columns; /* hash containing all the result columns */ + HashTable *binds; /* binds hash */ + HashTable *defines; /* defines hash */ + int ncolumns; /* number of columns in the result */ + unsigned executed:1; /* statement executed flag */ + unsigned has_data:1; /* statement has more data flag */ + ub2 stmttype; /* statement type */ } php_oci_statement; /* }}} */ typedef struct { /* php_oci_bind {{{ */ - OCIBind *bind; /* bind handle */ - zval *zval; /* value */ - dvoid *descriptor; /* used for binding of LOBS etc */ - OCIStmt *statement; /* used for binding REFCURSORs */ - php_oci_statement *parent_statement; /* pointer to the parent statement */ + OCIBind *bind; /* bind handle */ + zval *zval; /* value */ + dvoid *descriptor; /* used for binding of LOBS etc */ + OCIStmt *statement; /* used for binding REFCURSORs */ + php_oci_statement *parent_statement; /* pointer to the parent statement */ struct { - void *elements; - sb2 *indicators; - ub2 *element_lengths; -/* ub2 *retcodes; */ - ub4 current_length; - ub4 old_length; - ub4 max_length; - long type; + void *elements; + sb2 *indicators; + ub2 *element_lengths; + ub4 current_length; + ub4 old_length; + ub4 max_length; + long type; } array; - sb2 indicator; /* -1 means NULL */ - ub2 retcode; /* */ - zend_bool out; /* OUT bind or not */ - ub4 dummy_len; /* a dummy var to store alenpp value in bind OUT callback */ + sb2 indicator; /* -1 means NULL */ + ub2 retcode; + zend_bool out; /* OUT bind or not */ + ub4 dummy_len; /* a dummy var to store alenpp value in bind OUT callback */ } php_oci_bind; /* }}} */ typedef struct { /* php_oci_out_column {{{ */ - php_oci_statement *statement; /* statement handle. used when fetching REFCURSORS */ - php_oci_statement *nested_statement; /* statement handle. used when fetching REFCURSORS */ - OCIDefine *oci_define; /* define handle */ - zstr name; /* column name */ - ub4 name_len; /* column name length */ - ub2 data_type; /* column data type */ - ub2 data_size; /* data size */ - ub4 storage_size4; /* size used when allocating buffers */ - sb2 indicator; /* */ - ub2 retcode; /* code returned when fetching this particular column */ - ub2 retlen; /* */ - ub4 retlen4; /* */ - ub2 is_descr; /* column contains a descriptor */ - ub2 is_cursor; /* column contains a cursor */ - int stmtid; /* statement id for cursors */ - int descid; /* descriptor id for descriptors */ - void *data; /* */ - php_oci_define *define; /* define handle */ - int piecewise; /* column is fetched piece-by-piece */ - ub4 cb_retlen; /* */ - sb1 scale; /* column scale */ - sb2 precision; /* column precision */ - ub1 charset_form; /* charset form, required for NCLOBs */ - ub2 charset_id; /* charset ID */ + php_oci_statement *statement; /* statement handle. used when fetching REFCURSORS */ + php_oci_statement *nested_statement; /* statement handle. used when fetching REFCURSORS */ + OCIDefine *oci_define; /* define handle */ + zstr name; /* column name */ + ub4 name_len; /* column name length */ + ub2 data_type; /* column data type */ + ub2 data_size; /* data size */ + ub4 storage_size4; /* size used when allocating buffers */ + sb2 indicator; + ub2 retcode; /* code returned when fetching this particular column */ + ub2 retlen; + ub4 retlen4; + ub2 is_descr; /* column contains a descriptor */ + ub2 is_cursor; /* column contains a cursor */ + int stmtid; /* statement id for cursors */ + int descid; /* descriptor id for descriptors */ + void *data; + php_oci_define *define; /* define handle */ + int piecewise; /* column is fetched piece-by-piece */ + ub4 cb_retlen; + sb1 scale; /* column scale */ + sb2 precision; /* column precision */ + ub1 charset_form; /* charset form, required for NCLOBs */ + ub2 charset_id; /* charset ID */ } php_oci_out_column; /* }}} */ /* {{{ macros */ @@ -271,17 +270,31 @@ #define PHP_OCI_HANDLE_ERROR(connection, errcode) \ do { \ switch (errcode) { \ - case 1013: \ - zend_bailout(); \ - break; \ - case 22: \ - case 1012: \ - case 3113: \ - case 604: \ - case 1041: \ - case 3114: \ - connection->is_open = 0; \ - break; \ + case 1013: \ + zend_bailout(); \ + break; \ + case 22: \ + case 378: \ + case 602: \ + case 603: \ + case 604: \ + case 609: \ + case 1012: \ + case 1033: \ + case 1041: \ + case 1043: \ + case 1089: \ + case 1090: \ + case 1092: \ + case 3113: \ + case 3114: \ + case 3122: \ + case 3135: \ + case 12153: \ + case 27146: \ + case 28511: \ + connection->is_open = 0; \ + break; \ } \ } while (0) @@ -302,14 +315,14 @@ #define PHP_OCI_ZVAL_TO_COLLECTION(zval, collection) \ ZEND_FETCH_RESOURCE(collection, php_oci_collection *, &zval, -1, "oci8 collection", le_collection) -#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type) \ +#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type) \ do { \ var = (type) zend_fetch_resource(&zval TSRMLS_CC, -1, name, NULL, 1, resource_type); \ - if (!var) { \ - return 1; \ + if (!var) { \ + return 1; \ } \ } while (0) - + #define PHP_OCI_ZVAL_TO_CONNECTION_EX(zval, connection) \ PHP_OCI_FETCH_RESOURCE_EX(zval, connection, php_oci_connection *, "oci8 connection", le_connection) @@ -339,7 +352,7 @@ #ifdef HAVE_OCI8_ATTR_STATEMENT int php_oci_fetch_sqltext_offset(php_oci_statement *, zstr *, ub2 * TSRMLS_DC); #endif - + void php_oci_do_connect (INTERNAL_FUNCTION_PARAMETERS, int , int); php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC); @@ -348,7 +361,7 @@ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC); int php_oci_password_change(php_oci_connection *, zstr, int, zstr, int, zstr, int, zend_uchar TSRMLS_DC); -int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC); +int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC); void php_oci_fetch_row(INTERNAL_FUNCTION_PARAMETERS, int, int); int php_oci_column_to_zval(php_oci_out_column *, zval *, int TSRMLS_DC); @@ -434,36 +447,30 @@ /* }}} */ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ */ - sword errcode; /* global last error code (used when connect fails, for example) */ - OCIError *err; /* global error handle */ - - /* - char *default_username; - char *default_password; - char *default_dbname; - */ - - zend_bool debug_mode; /* debug mode flag */ - - long max_persistent; /* maximum number of persistent connections per process */ - long num_persistent; /* number of existing persistent connections */ - long num_links; /* non-persistent + persistent connections */ - long num_statements; /* number of statements open */ - long ping_interval; /* time interval between pings */ - long persistent_timeout; /* time period after which idle persistent connection is considered expired */ - long statement_cache_size; /* statement cache size. used with 9i+ clients only*/ - long default_prefetch; /* default prefetch setting */ - zend_bool privileged_connect; /* privileged connect flag (On/Off) */ - zend_bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */ - - int shutdown; /* in shutdown flag */ - - OCIEnv *env; /* global environment handle */ - - zend_bool in_call; - char *connection_class; - zend_bool events; -ZEND_END_MODULE_GLOBALS(oci) /* }}} */ + sword errcode; /* global last error code (used when connect fails, for example) */ + OCIError *err; /* global error handle */ + + zend_bool debug_mode; /* debug mode flag */ + + long max_persistent; /* maximum number of persistent connections per process */ + long num_persistent; /* number of existing persistent connections */ + long num_links; /* non-persistent + persistent connections */ + long num_statements; /* number of statements open */ + long ping_interval; /* time interval between pings */ + long persistent_timeout; /* time period after which idle persistent connection is considered expired */ + long statement_cache_size; /* statement cache size. used with 9i+ clients only*/ + long default_prefetch; /* default prefetch setting */ + zend_bool privileged_connect; /* privileged connect flag (On/Off) */ + zend_bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */ + + int shutdown; /* in shutdown flag */ + + OCIEnv *env; /* global environment handle */ + + zend_bool in_call; + char *connection_class; + zend_bool events; +ZEND_END_MODULE_GLOBALS(oci) /* }}} */ #ifdef ZTS #define OCI_G(v) TSRMG(oci_globals_id, zend_oci_globals *, v) @@ -486,5 +493,3 @@ * c-basic-offset: 4 * End: */ - - http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/README?r1=1.3&r2=1.4&diff_format=u Index: php-src/ext/oci8/README diff -u php-src/ext/oci8/README:1.3 php-src/ext/oci8/README:1.4 --- php-src/ext/oci8/README:1.3 Tue Feb 19 01:44:29 2008 +++ php-src/ext/oci8/README Wed Mar 12 01:25:13 2008 @@ -166,7 +166,7 @@ 6. DRCP and FAN Support ----------------------- -The PHP OCI8 Beta extension has support for the Oracle Database +The PHP 6 OCI8 Beta extension has support for the Oracle Database Resident Connection Pool (DRCP) and Fast Application Notification (FAN). @@ -205,6 +205,25 @@ After building PHP with the OCI8 extension and 11g libraries, follow these steps: +6.2.0 Important: if Oracle Database 11.1.0.6 with DRCP connections is + used, then the Oracle database patch for bug 6474441 must be + applied (see section 6.5) or a workaround below used. Without + this patch, "ORA-01000: maximum open cursors exceeded", "ORA-01001 + invalid cursor" or "ORA-01002 fetch out of sequence" errors may + occur. + + If the Oracle 11.1.0.6 database patch cannot be applied, one of + the following three workarounds can be used to disable statement + caching instead: + + (i) Connect using Oracle dedicated or shared servers instead of DRCP. + + (ii) Set PHP's oci8.statement_cache_size to 0. + + (iii) Set an event in the database initialization parameter file: + event="56699 trace name context forever, level 128". + + 6.2.1. As a privileged database administrator, use a program like SQL*Plus to start the connection pool in the database: @@ -298,55 +317,15 @@ 6.3.4. Run your application, connecting to a 10gR2 or 11g database. -6.4. Changes in this release from PECL OCI8 1.3.0 Beta - -The initial release of OCI8 with DRCP and FAN support was PECL OCI8 -1.3.0 Beta. This section documents differences from that release. - -6.4.1 Statement caching has been re-enabled. - -Important: if Oracle Database 11.1.0.6 with DRCP connections is used, -then the Oracle database patch for bug 6474441 must be applied (see -section 6.5) or a workaround below used. Without this patch, -"ORA-01000: maximum open cursors exceeded", "ORA-01001 invalid cursor" -or "ORA-01002 fetch out of sequence" errors may occur. - -If the Oracle 11.1.0.6 database patch cannot be applied, one of the -following three workarounds can be used to disable statement caching -instead: - -(i) Connect using Oracle dedicated or shared servers instead of DRCP. - -(ii) Set PHP's oci8.statement_cache_size to 0. - -(iii) Set an event in the database initialization parameter file: -event="56699 trace name context forever, level 128". - -6.4.2 Changing Password for non-DRCP connections has been re-enabled. - -When oci_password_change() is successfully performed for non-DRCP -connections in a PHP script, subsequent connections with the new -password from this PHP instance no longer fail with "ORA-1017 invalid -username/password". - -Changing a password over DRCP connections will continue to fail with -the error "ORA-56609: Usage not supported with DRCP". This is an -documented restriction of Oracle Database 11g. - -6.4.3 Oci8.max_persistent setting is re-enabled. - -The php.ini parameter oci8.max_persistent will limit the number of -persistent connections that each PHP process will keep open between -HTTP requests. Any further oci_pconnect() calls once this limit is -reached will be treated as oci_connect() calls. +6.4. Recommendations and Known Limitations -It is still recommended that DRCP users modify the connection pool -settings of the database to control resource usage. Non-DRCP users -should consider setting oci8.persistent_timeout to close idle -connections. +6.4.1 Changing Password for DRCP connections +Changing a password over DRCP connections will fail with the error +"ORA-56609: Usage not supported with DRCP". This is an documented +restriction of Oracle Database 11g. -6.4.4 LOGON Triggers can be used to set session properties +6.4.2 LOGON Triggers can be used to set session properties The patch for Oracle Database 11.1.0.6 bug 6474441 (see section 6.5) allows PHP applications with DRCP connection to use a database LOGON @@ -364,9 +343,9 @@ With DRCP there is an connection management relationship between (i) DRCP's automatic pool expansion and reduction, (ii) PHP's persistent connection caching, (iii) with the way LOGON triggers fire with DRCP -authentication. Because of this interplay, LOGON triggers in PHP when -DRCP is used are only recommended for setting session attributes and -not for per-PHP connection events. +authentication. Because of this interplay, LOGON triggers in PHP +(when DRCP is used) are only recommended for setting session +attributes and not for per-PHP connection events. 6.5. Patching Oracle Database 11g http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/tests/drcp_cclass1.phpt?view=markup&rev=1.1 Index: php-src/ext/oci8/tests/drcp_cclass1.phpt +++ php-src/ext/oci8/tests/drcp_cclass1.phpt --TEST-- DRCP: Test setting connection class inline --SKIPIF-- <?php if (!extension_loaded('oci8')) die ("skip no oci8 extension"); require(__DIR__."/details.inc"); if (!$test_drcp) die("skip testing DRCP connection class only works in DRCP mode"); if (strcasecmp($user, "system") && strcasecmp($user, "sys")) die("skip needs to be run as a DBA user"); ?> --FILE-- <?php require(__DIR__."/details.inc"); // Initialization $t = time(); $cc1 = 'cc1_'.$t; $cc2 = 'cc2_'.$t; // Run Test echo "Test 1\n"; ini_set('oci8.connection_class', $cc1); $c = oci_pconnect($user, $password, $dbase); $s = oci_parse($c, "select * from dual"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); echo "Test 2\n"; ini_set('oci8.connection_class', $cc2); $c = oci_pconnect($user, $password, $dbase); $s = oci_parse($c, "select * from dual"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); echo "Test 3\n"; $s = oci_parse($c, "select cclass_name from v\$cpool_cc_stats where cclass_name like '%.cc__$t'"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); // Cleanup echo "Done\n"; ?> --EXPECTF-- Test 1 array(1) { ["DUMMY"]=> array(1) { [0]=> string(1) "X" } } Test 2 array(1) { ["DUMMY"]=> array(1) { [0]=> string(1) "X" } } Test 3 array(1) { ["CCLASS_NAME"]=> array(2) { [0]=> string(21) "%s.cc1_%d" [1]=> string(21) "%s.cc2_%d" } } Done --UEXPECTF-- Test 1 array(1) { [u"DUMMY"]=> array(1) { [0]=> unicode(1) "X" } } Test 2 array(1) { [u"DUMMY"]=> array(1) { [0]=> unicode(1) "X" } } Test 3 array(1) { [u"CCLASS_NAME"]=> array(2) { [0]=> unicode(21) "%s.cc1_%d" [1]=> unicode(21) "%s.cc2_%d" } } Done
http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/oci8.c?r1=1.344&r2=1.345&diff_format=u Index: php-src/ext/oci8/oci8.c diff -u php-src/ext/oci8/oci8.c:1.344 php-src/ext/oci8/oci8.c:1.345 --- php-src/ext/oci8/oci8.c:1.344 Tue Feb 26 02:18:16 2008 +++ php-src/ext/oci8/oci8.c Wed Mar 12 01:25:13 2008 @@ -26,14 +26,14 @@ +----------------------------------------------------------------------+ */ -/* $Id: oci8.c,v 1.344 2008/02/26 02:18:16 sixd Exp $ */ +/* $Id: oci8.c,v 1.345 2008/03/12 01:25:13 sixd Exp $ */ /* TODO * * file://localhost/www/docs/oci10/ociaahan.htm#423823 - implement lob_empty() with OCI_ATTR_LOBEMPTY * * get OCI_ATTR_CHARSET_ID attr of column to detect UTF string and multiply buffer in 4 times * - * */ + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -59,7 +59,7 @@ int le_statement; int le_descriptor; int le_psessionpool; -#ifdef PHP_OCI8_HAVE_COLLECTIONS +#ifdef PHP_OCI8_HAVE_COLLECTIONS int le_collection; #endif @@ -86,6 +86,7 @@ /* static protos {{{ */ static void php_oci_connection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_pconnection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); +static void php_oci_pconnection_list_np_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_statement_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_descriptor_list_dtor (zend_rsrc_list_entry * TSRMLS_DC); static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC); @@ -107,6 +108,7 @@ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC); static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC); static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, char *hash_key, int hash_key_len, int charsetid, zend_uchar type TSRMLS_DC); +static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC); /* }}} */ /* {{{ dynamically loadable module stuff */ @@ -211,184 +213,184 @@ /* {{{ extension definition structures */ static const zend_function_entry php_oci_functions[] = { - PHP_FE(oci_define_by_name, oci_third_arg_force_ref) - PHP_FE(oci_bind_by_name, oci_third_arg_force_ref) - PHP_FE(oci_bind_array_by_name, oci_third_arg_force_ref) - PHP_FE(oci_field_is_null, NULL) - PHP_FE(oci_field_name, NULL) - PHP_FE(oci_field_size, NULL) - PHP_FE(oci_field_scale, NULL) - PHP_FE(oci_field_precision, NULL) - PHP_FE(oci_field_type, NULL) - PHP_FE(oci_field_type_raw, NULL) - PHP_FE(oci_execute, NULL) - PHP_FE(oci_cancel, NULL) - PHP_FE(oci_fetch, NULL) - PHP_FE(oci_fetch_object, NULL) - PHP_FE(oci_fetch_row, NULL) - PHP_FE(oci_fetch_assoc, NULL) - PHP_FE(oci_fetch_array, NULL) - PHP_FE(ocifetchinto, oci_second_arg_force_ref) - PHP_FE(oci_fetch_all, oci_second_arg_force_ref) - PHP_FE(oci_free_statement, NULL) - PHP_FE(oci_internal_debug, NULL) - PHP_FE(oci_num_fields, NULL) - PHP_FE(oci_parse, NULL) - PHP_FE(oci_new_cursor, NULL) - PHP_FE(oci_result, NULL) - PHP_FE(oci_server_version, NULL) - PHP_FE(oci_statement_type, NULL) - PHP_FE(oci_num_rows, NULL) - PHP_FE(oci_close, NULL) - PHP_FE(oci_connect, NULL) - PHP_FE(oci_new_connect, NULL) - PHP_FE(oci_pconnect, NULL) - PHP_FE(oci_error, NULL) - PHP_FE(oci_free_descriptor, NULL) - PHP_FE(oci_lob_save, NULL) - PHP_FE(oci_lob_import, NULL) - PHP_FE(oci_lob_size, NULL) - PHP_FE(oci_lob_load, NULL) - PHP_FE(oci_lob_read, NULL) - PHP_FE(oci_lob_eof, NULL) - PHP_FE(oci_lob_tell, NULL) - PHP_FE(oci_lob_truncate, NULL) - PHP_FE(oci_lob_erase, NULL) - PHP_FE(oci_lob_flush, NULL) - PHP_FE(ocisetbufferinglob, NULL) - PHP_FE(ocigetbufferinglob, NULL) - PHP_FE(oci_lob_is_equal, NULL) - PHP_FE(oci_lob_rewind, NULL) - PHP_FE(oci_lob_write, NULL) - PHP_FE(oci_lob_append, NULL) - PHP_FE(oci_lob_copy, NULL) - PHP_FE(oci_lob_export, NULL) - PHP_FE(oci_lob_seek, NULL) - PHP_FE(oci_commit, NULL) - PHP_FE(oci_rollback, NULL) - PHP_FE(oci_new_descriptor, NULL) - PHP_FE(oci_set_prefetch, NULL) - PHP_FE(oci_password_change, NULL) + PHP_FE(oci_define_by_name, oci_third_arg_force_ref) + PHP_FE(oci_bind_by_name, oci_third_arg_force_ref) + PHP_FE(oci_bind_array_by_name, oci_third_arg_force_ref) + PHP_FE(oci_field_is_null, NULL) + PHP_FE(oci_field_name, NULL) + PHP_FE(oci_field_size, NULL) + PHP_FE(oci_field_scale, NULL) + PHP_FE(oci_field_precision, NULL) + PHP_FE(oci_field_type, NULL) + PHP_FE(oci_field_type_raw, NULL) + PHP_FE(oci_execute, NULL) + PHP_FE(oci_cancel, NULL) + PHP_FE(oci_fetch, NULL) + PHP_FE(oci_fetch_object, NULL) + PHP_FE(oci_fetch_row, NULL) + PHP_FE(oci_fetch_assoc, NULL) + PHP_FE(oci_fetch_array, NULL) + PHP_FE(ocifetchinto, oci_second_arg_force_ref) + PHP_FE(oci_fetch_all, oci_second_arg_force_ref) + PHP_FE(oci_free_statement, NULL) + PHP_FE(oci_internal_debug, NULL) + PHP_FE(oci_num_fields, NULL) + PHP_FE(oci_parse, NULL) + PHP_FE(oci_new_cursor, NULL) + PHP_FE(oci_result, NULL) + PHP_FE(oci_server_version, NULL) + PHP_FE(oci_statement_type, NULL) + PHP_FE(oci_num_rows, NULL) + PHP_FE(oci_close, NULL) + PHP_FE(oci_connect, NULL) + PHP_FE(oci_new_connect, NULL) + PHP_FE(oci_pconnect, NULL) + PHP_FE(oci_error, NULL) + PHP_FE(oci_free_descriptor, NULL) + PHP_FE(oci_lob_save, NULL) + PHP_FE(oci_lob_import, NULL) + PHP_FE(oci_lob_size, NULL) + PHP_FE(oci_lob_load, NULL) + PHP_FE(oci_lob_read, NULL) + PHP_FE(oci_lob_eof, NULL) + PHP_FE(oci_lob_tell, NULL) + PHP_FE(oci_lob_truncate, NULL) + PHP_FE(oci_lob_erase, NULL) + PHP_FE(oci_lob_flush, NULL) + PHP_FE(ocisetbufferinglob, NULL) + PHP_FE(ocigetbufferinglob, NULL) + PHP_FE(oci_lob_is_equal, NULL) + PHP_FE(oci_lob_rewind, NULL) + PHP_FE(oci_lob_write, NULL) + PHP_FE(oci_lob_append, NULL) + PHP_FE(oci_lob_copy, NULL) + PHP_FE(oci_lob_export, NULL) + PHP_FE(oci_lob_seek, NULL) + PHP_FE(oci_commit, NULL) + PHP_FE(oci_rollback, NULL) + PHP_FE(oci_new_descriptor, NULL) + PHP_FE(oci_set_prefetch, NULL) + PHP_FE(oci_password_change, NULL) #ifdef PHP_OCI8_HAVE_COLLECTIONS - PHP_FE(oci_free_collection, NULL) - PHP_FE(oci_collection_append, NULL) - PHP_FE(oci_collection_element_get, NULL) - PHP_FE(oci_collection_element_assign, NULL) - PHP_FE(oci_collection_assign, NULL) - PHP_FE(oci_collection_size, NULL) - PHP_FE(oci_collection_max, NULL) - PHP_FE(oci_collection_trim, NULL) - PHP_FE(oci_new_collection, NULL) -#endif - - PHP_FALIAS(oci_free_cursor, oci_free_statement, NULL) - PHP_FALIAS(ocifreecursor, oci_free_statement, NULL) - PHP_FALIAS(ocibindbyname, oci_bind_by_name, oci_third_arg_force_ref) - PHP_FALIAS(ocidefinebyname, oci_define_by_name, oci_third_arg_force_ref) - PHP_FALIAS(ocicolumnisnull, oci_field_is_null, NULL) - PHP_FALIAS(ocicolumnname, oci_field_name, NULL) - PHP_FALIAS(ocicolumnsize, oci_field_size, NULL) - PHP_FALIAS(ocicolumnscale, oci_field_scale, NULL) - PHP_FALIAS(ocicolumnprecision, oci_field_precision, NULL) - PHP_FALIAS(ocicolumntype, oci_field_type, NULL) - PHP_FALIAS(ocicolumntyperaw, oci_field_type_raw, NULL) - PHP_FALIAS(ociexecute, oci_execute, NULL) - PHP_FALIAS(ocicancel, oci_cancel, NULL) - PHP_FALIAS(ocifetch, oci_fetch, NULL) - PHP_FALIAS(ocifetchstatement, oci_fetch_all, oci_second_arg_force_ref) - PHP_FALIAS(ocifreestatement, oci_free_statement, NULL) - PHP_FALIAS(ociinternaldebug, oci_internal_debug, NULL) - PHP_FALIAS(ocinumcols, oci_num_fields, NULL) - PHP_FALIAS(ociparse, oci_parse, NULL) - PHP_FALIAS(ocinewcursor, oci_new_cursor, NULL) - PHP_FALIAS(ociresult, oci_result, NULL) - PHP_FALIAS(ociserverversion, oci_server_version, NULL) - PHP_FALIAS(ocistatementtype, oci_statement_type, NULL) - PHP_FALIAS(ocirowcount, oci_num_rows, NULL) - PHP_FALIAS(ocilogoff, oci_close, NULL) - PHP_FALIAS(ocilogon, oci_connect, NULL) - PHP_FALIAS(ocinlogon, oci_new_connect, NULL) - PHP_FALIAS(ociplogon, oci_pconnect, NULL) - PHP_FALIAS(ocierror, oci_error, NULL) - PHP_FALIAS(ocifreedesc, oci_free_descriptor, NULL) - PHP_FALIAS(ocisavelob, oci_lob_save, NULL) - PHP_FALIAS(ocisavelobfile, oci_lob_import, NULL) - PHP_FALIAS(ociwritelobtofile, oci_lob_export, NULL) - PHP_FALIAS(ociloadlob, oci_lob_load, NULL) - PHP_FALIAS(ocicommit, oci_commit, NULL) - PHP_FALIAS(ocirollback, oci_rollback, NULL) - PHP_FALIAS(ocinewdescriptor, oci_new_descriptor, NULL) - PHP_FALIAS(ocisetprefetch, oci_set_prefetch, NULL) - PHP_FALIAS(ocipasswordchange, oci_password_change, NULL) + PHP_FE(oci_free_collection, NULL) + PHP_FE(oci_collection_append, NULL) + PHP_FE(oci_collection_element_get, NULL) + PHP_FE(oci_collection_element_assign, NULL) + PHP_FE(oci_collection_assign, NULL) + PHP_FE(oci_collection_size, NULL) + PHP_FE(oci_collection_max, NULL) + PHP_FE(oci_collection_trim, NULL) + PHP_FE(oci_new_collection, NULL) +#endif + + PHP_FALIAS(oci_free_cursor, oci_free_statement, NULL) + PHP_FALIAS(ocifreecursor, oci_free_statement, NULL) + PHP_FALIAS(ocibindbyname, oci_bind_by_name, oci_third_arg_force_ref) + PHP_FALIAS(ocidefinebyname, oci_define_by_name, oci_third_arg_force_ref) + PHP_FALIAS(ocicolumnisnull, oci_field_is_null, NULL) + PHP_FALIAS(ocicolumnname, oci_field_name, NULL) + PHP_FALIAS(ocicolumnsize, oci_field_size, NULL) + PHP_FALIAS(ocicolumnscale, oci_field_scale, NULL) + PHP_FALIAS(ocicolumnprecision, oci_field_precision, NULL) + PHP_FALIAS(ocicolumntype, oci_field_type, NULL) + PHP_FALIAS(ocicolumntyperaw, oci_field_type_raw, NULL) + PHP_FALIAS(ociexecute, oci_execute, NULL) + PHP_FALIAS(ocicancel, oci_cancel, NULL) + PHP_FALIAS(ocifetch, oci_fetch, NULL) + PHP_FALIAS(ocifetchstatement, oci_fetch_all, oci_second_arg_force_ref) + PHP_FALIAS(ocifreestatement, oci_free_statement, NULL) + PHP_FALIAS(ociinternaldebug, oci_internal_debug, NULL) + PHP_FALIAS(ocinumcols, oci_num_fields, NULL) + PHP_FALIAS(ociparse, oci_parse, NULL) + PHP_FALIAS(ocinewcursor, oci_new_cursor, NULL) + PHP_FALIAS(ociresult, oci_result, NULL) + PHP_FALIAS(ociserverversion, oci_server_version, NULL) + PHP_FALIAS(ocistatementtype, oci_statement_type, NULL) + PHP_FALIAS(ocirowcount, oci_num_rows, NULL) + PHP_FALIAS(ocilogoff, oci_close, NULL) + PHP_FALIAS(ocilogon, oci_connect, NULL) + PHP_FALIAS(ocinlogon, oci_new_connect, NULL) + PHP_FALIAS(ociplogon, oci_pconnect, NULL) + PHP_FALIAS(ocierror, oci_error, NULL) + PHP_FALIAS(ocifreedesc, oci_free_descriptor, NULL) + PHP_FALIAS(ocisavelob, oci_lob_save, NULL) + PHP_FALIAS(ocisavelobfile, oci_lob_import, NULL) + PHP_FALIAS(ociwritelobtofile, oci_lob_export, NULL) + PHP_FALIAS(ociloadlob, oci_lob_load, NULL) + PHP_FALIAS(ocicommit, oci_commit, NULL) + PHP_FALIAS(ocirollback, oci_rollback, NULL) + PHP_FALIAS(ocinewdescriptor, oci_new_descriptor, NULL) + PHP_FALIAS(ocisetprefetch, oci_set_prefetch, NULL) + PHP_FALIAS(ocipasswordchange, oci_password_change, NULL) #ifdef PHP_OCI8_HAVE_COLLECTIONS - PHP_FALIAS(ocifreecollection, oci_free_collection, NULL) - PHP_FALIAS(ocinewcollection, oci_new_collection, NULL) - PHP_FALIAS(ocicollappend, oci_collection_append, NULL) - PHP_FALIAS(ocicollgetelem, oci_collection_element_get, NULL) - PHP_FALIAS(ocicollassignelem, oci_collection_element_assign, NULL) - PHP_FALIAS(ocicollsize, oci_collection_size, NULL) - PHP_FALIAS(ocicollmax, oci_collection_max, NULL) - PHP_FALIAS(ocicolltrim, oci_collection_trim, NULL) + PHP_FALIAS(ocifreecollection, oci_free_collection, NULL) + PHP_FALIAS(ocinewcollection, oci_new_collection, NULL) + PHP_FALIAS(ocicollappend, oci_collection_append, NULL) + PHP_FALIAS(ocicollgetelem, oci_collection_element_get, NULL) + PHP_FALIAS(ocicollassignelem, oci_collection_element_assign, NULL) + PHP_FALIAS(ocicollsize, oci_collection_size, NULL) + PHP_FALIAS(ocicollmax, oci_collection_max, NULL) + PHP_FALIAS(ocicolltrim, oci_collection_trim, NULL) #endif {NULL,NULL,NULL} }; static const zend_function_entry php_oci_lob_class_functions[] = { - PHP_FALIAS(load, oci_lob_load, NULL) - PHP_FALIAS(tell, oci_lob_tell, NULL) - PHP_FALIAS(truncate, oci_lob_truncate, NULL) - PHP_FALIAS(erase, oci_lob_erase, NULL) - PHP_FALIAS(flush, oci_lob_flush, NULL) - PHP_FALIAS(setbuffering,ocisetbufferinglob, NULL) - PHP_FALIAS(getbuffering,ocigetbufferinglob, NULL) - PHP_FALIAS(rewind, oci_lob_rewind, NULL) - PHP_FALIAS(read, oci_lob_read, NULL) - PHP_FALIAS(eof, oci_lob_eof, NULL) - PHP_FALIAS(seek, oci_lob_seek, NULL) - PHP_FALIAS(write, oci_lob_write, NULL) - PHP_FALIAS(append, oci_lob_append, NULL) - PHP_FALIAS(size, oci_lob_size, NULL) - PHP_FALIAS(writetofile, oci_lob_export, NULL) - PHP_FALIAS(export, oci_lob_export, NULL) - PHP_FALIAS(import, oci_lob_import, NULL) + PHP_FALIAS(load, oci_lob_load, NULL) + PHP_FALIAS(tell, oci_lob_tell, NULL) + PHP_FALIAS(truncate, oci_lob_truncate, NULL) + PHP_FALIAS(erase, oci_lob_erase, NULL) + PHP_FALIAS(flush, oci_lob_flush, NULL) + PHP_FALIAS(setbuffering,ocisetbufferinglob, NULL) + PHP_FALIAS(getbuffering,ocigetbufferinglob, NULL) + PHP_FALIAS(rewind, oci_lob_rewind, NULL) + PHP_FALIAS(read, oci_lob_read, NULL) + PHP_FALIAS(eof, oci_lob_eof, NULL) + PHP_FALIAS(seek, oci_lob_seek, NULL) + PHP_FALIAS(write, oci_lob_write, NULL) + PHP_FALIAS(append, oci_lob_append, NULL) + PHP_FALIAS(size, oci_lob_size, NULL) + PHP_FALIAS(writetofile, oci_lob_export, NULL) + PHP_FALIAS(export, oci_lob_export, NULL) + PHP_FALIAS(import, oci_lob_import, NULL) #ifdef HAVE_OCI8_TEMP_LOB - PHP_FALIAS(writetemporary, oci_lob_write_temporary, NULL) - PHP_FALIAS(close, oci_lob_close, NULL) + PHP_FALIAS(writetemporary, oci_lob_write_temporary, NULL) + PHP_FALIAS(close, oci_lob_close, NULL) #endif - PHP_FALIAS(save, oci_lob_save, NULL) - PHP_FALIAS(savefile, oci_lob_import, NULL) - PHP_FALIAS(free, oci_free_descriptor, NULL) + PHP_FALIAS(save, oci_lob_save, NULL) + PHP_FALIAS(savefile, oci_lob_import, NULL) + PHP_FALIAS(free, oci_free_descriptor, NULL) {NULL,NULL,NULL} }; #ifdef PHP_OCI8_HAVE_COLLECTIONS static const zend_function_entry php_oci_coll_class_functions[] = { - PHP_FALIAS(append, oci_collection_append, NULL) - PHP_FALIAS(getelem, oci_collection_element_get, NULL) - PHP_FALIAS(assignelem, oci_collection_element_assign, NULL) - PHP_FALIAS(assign, oci_collection_assign, NULL) - PHP_FALIAS(size, oci_collection_size, NULL) - PHP_FALIAS(max, oci_collection_max, NULL) - PHP_FALIAS(trim, oci_collection_trim, NULL) - PHP_FALIAS(free, oci_free_collection, NULL) + PHP_FALIAS(append, oci_collection_append, NULL) + PHP_FALIAS(getelem, oci_collection_element_get, NULL) + PHP_FALIAS(assignelem, oci_collection_element_assign, NULL) + PHP_FALIAS(assign, oci_collection_assign, NULL) + PHP_FALIAS(size, oci_collection_size, NULL) + PHP_FALIAS(max, oci_collection_max, NULL) + PHP_FALIAS(trim, oci_collection_trim, NULL) + PHP_FALIAS(free, oci_free_collection, NULL) {NULL,NULL,NULL} }; #endif zend_module_entry oci8_module_entry = { STANDARD_MODULE_HEADER, - "oci8", /* extension name */ - php_oci_functions, /* extension function list */ - PHP_MINIT(oci), /* extension-wide startup function */ - PHP_MSHUTDOWN(oci), /* extension-wide shutdown function */ - PHP_RINIT(oci), /* per-request startup function */ - PHP_RSHUTDOWN(oci), /* per-request shutdown function */ - PHP_MINFO(oci), /* information function */ + "oci8", /* extension name */ + php_oci_functions, /* extension function list */ + PHP_MINIT(oci), /* extension-wide startup function */ + PHP_MSHUTDOWN(oci), /* extension-wide shutdown function */ + PHP_RINIT(oci), /* per-request startup function */ + PHP_RSHUTDOWN(oci), /* per-request shutdown function */ + PHP_MINFO(oci), /* information function */ "1.3.1", PHP_MODULE_GLOBALS(oci), /* globals descriptor */ - PHP_GINIT(oci), /* globals ctor */ - NULL, /* globals dtor */ - NULL, /* post deactivate */ + PHP_GINIT(oci), /* globals ctor */ + NULL, /* globals dtor */ + NULL, /* post deactivate */ STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ @@ -411,7 +413,7 @@ */ /* {{{ php_oci_init_global_handles() - Initialize global handles only when they are needed + Initialize global handles only when they are needed */ static void php_oci_init_global_handles(TSRMLS_D) { @@ -420,21 +422,21 @@ text tmp_buf[PHP_OCI_ERRBUF_LEN]; errcode = OCIEnvInit (&OCI_G(env), OCI_DEFAULT, 0, NULL); - + if (errcode == OCI_ERROR) { goto oci_error; } - + errcode = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL); - + if (errcode == OCI_ERROR || errcode == OCI_SUCCESS_WITH_INFO) { goto oci_error; } return; - + oci_error: - + OCIErrorGet(OCI_G(env), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR); if (error_code) { @@ -443,12 +445,12 @@ if (tmp_buf_len > 0 && tmp_buf[tmp_buf_len - 1] == '\n') { tmp_buf[tmp_buf_len - 1] = '\0'; } - + if (errcode != OCI_SUCCESS_WITH_INFO) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_ERROR: %s", tmp_buf); - + OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV); - + OCI_G(env) = NULL; OCI_G(err) = NULL; } else { @@ -466,7 +468,7 @@ PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR)); OCI_G(err) = NULL; } - + if (OCI_G(env)) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV)); OCI_G(env) = NULL; @@ -509,7 +511,7 @@ le_statement = zend_register_list_destructors_ex(php_oci_statement_list_dtor, NULL, "oci8 statement", module_number); le_connection = zend_register_list_destructors_ex(php_oci_connection_list_dtor, NULL, "oci8 connection", module_number); - le_pconnection = zend_register_list_destructors_ex(NULL, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number); + le_pconnection = zend_register_list_destructors_ex(php_oci_pconnection_list_np_dtor, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number); le_psessionpool = zend_register_list_destructors_ex(NULL, php_oci_spool_list_dtor, "oci8 persistent session pool", module_number); le_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number); #ifdef PHP_OCI8_HAVE_COLLECTIONS @@ -541,15 +543,15 @@ /* for $LOB->flush() */ REGISTER_LONG_CONSTANT("OCI_LOB_BUFFER_FREE",OCI_LOB_BUFFER_FREE, CONST_CS | CONST_PERSISTENT); - -/* for OCIBindByName (real "oci" names + short "php" names*/ + +/* for OCIBindByName (real "oci" names + short "php" names */ REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_AFC",SQLT_AFC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_CHR",SQLT_CHR, CONST_CS | CONST_PERSISTENT); @@ -570,7 +572,7 @@ #ifdef PHP_OCI8_HAVE_COLLECTIONS REGISTER_LONG_CONSTANT("OCI_B_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE", CONST_CS | CONST_PERSISTENT); #endif @@ -595,7 +597,7 @@ REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",PHP_OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",PHP_OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT); -/* for OCINewDescriptor (real "oci" names + short "php" names*/ +/* for OCINewDescriptor (real "oci" names + short "php" names */ REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT); @@ -627,7 +629,7 @@ PHP_MSHUTDOWN_FUNCTION(oci) { OCI_G(shutdown) = 1; - + UNREGISTER_INI_ENTRIES(); #ifndef ZTS @@ -648,7 +650,7 @@ #ifdef PHP_OCI8_HAVE_COLLECTIONS zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_collection TSRMLS_CC); #endif - while (OCI_G(num_statements)) { + while (OCI_G(num_statements)) { zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_statement TSRMLS_CC); } #endif @@ -671,7 +673,7 @@ php_info_print_table_start(); php_info_print_table_row(2, "OCI8 Support", "enabled"); php_info_print_table_row(2, "Version", "1.3.1 Beta"); - php_info_print_table_row(2, "Revision", "$Revision: 1.344 $"); + php_info_print_table_row(2, "Revision", "$Revision: 1.345 $"); snprintf(buf, sizeof(buf), "%ld", OCI_G(num_persistent)); php_info_print_table_row(2, "Active Persistent Connections", buf); @@ -682,8 +684,8 @@ php_info_print_table_row(2, "Oracle Version", PHP_OCI8_VERSION ); php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DIR ); php_info_print_table_row(2, "Libraries Used", PHP_OCI8_SHARED_LIBADD ); -#else -# if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) +#else +# if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION); php_info_print_table_row(2, "Oracle Instant Client Version", buf); # endif @@ -702,7 +704,7 @@ #endif php_info_print_table_end(); - + DISPLAY_INI_ENTRIES(); } /* }}} */ @@ -714,8 +716,11 @@ static void php_oci_connection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) { php_oci_connection *connection = (php_oci_connection *)entry->ptr; - php_oci_connection_close(connection TSRMLS_CC); - OCI_G(num_links)--; + + if (connection) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_links)--; + } } /* }}} */ /* {{{ php_oci_pconnection_list_dtor() @@ -723,8 +728,25 @@ static void php_oci_pconnection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) { php_oci_connection *connection = (php_oci_connection *)entry->ptr; - php_oci_connection_close(connection TSRMLS_CC); - OCI_G(num_persistent)--; + + if (connection) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_persistent)--; + } +} /* }}} */ + +/* {{{ php_oci_pconnection_list_np_dtor() + Non-Persistent destructor for persistent connection - This gets invoked when + the refcount of this goes to zero in the regular list */ +static void php_oci_pconnection_list_np_dtor(zend_rsrc_list_entry *entry TSRMLS_DC) +{ + php_oci_connection *connection = (php_oci_connection *)entry->ptr; + + /* If it is a bad connection, clean it up. This is the sole purpose of this dtor. We should ideally do a hash_del also, but this scenario is currently not possible. */ + if (connection && !connection->is_open && !connection->is_stub) { + php_oci_connection_close(connection TSRMLS_CC); + OCI_G(num_persistent)--; + } } /* }}} */ /* {{{ php_oci_statement_list_dtor() @@ -790,12 +812,6 @@ efree(bind->array.indicators); } -/* - if (bind->array.retcodes) { - efree(bind->array.retcodes); - } -*/ - zval_ptr_dtor(&bind->zval); } /* }}} */ @@ -831,7 +847,7 @@ { php_oci_descriptor *descriptor = *(php_oci_descriptor **)data; TSRMLS_FETCH(); - + if (descriptor && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) { php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC); descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED; @@ -846,7 +862,7 @@ { php_oci_descriptor *descriptor = *(php_oci_descriptor **)data; int *desc_id = (int *) id; - + if (descriptor && desc_id && descriptor->id == *desc_id) { return 1; } @@ -881,7 +897,7 @@ case OCI_NO_DATA: php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NO_DATA"); break; - case OCI_ERROR: + case OCI_ERROR: errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC); if (errbuf) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "%R", (UG(unicode) ? IS_UNICODE : IS_STRING), errbuf); @@ -950,7 +966,7 @@ err_buf[err_buf_len - 1] = '\0'; } } - + if (err_buf_len && error_buf) { *error_buf = (text *)estrndup((char *)err_buf, TEXT_BYTES(err_buf_len)); } @@ -962,7 +978,7 @@ #ifdef HAVE_OCI8_ATTR_STATEMENT /* {{{ php_oci_fetch_sqltext_offset() Compute offset in the SQL statement */ -int php_oci_fetch_sqltext_offset(php_oci_statement *statement, zstr *sqltext, ub2 *error_offset TSRMLS_DC) +int php_oci_fetch_sqltext_offset(php_oci_statement *statement, zstr *sqltext, ub2 *error_offset TSRMLS_DC) { ub4 sqltext_len = 0; @@ -974,15 +990,15 @@ } else { PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *) &(sqltext->s), (ub4 *)&sqltext_len, OCI_ATTR_STATEMENT, statement->err)); } - - if (statement->errcode != OCI_SUCCESS) { + + if (statement->errcode != OCI_SUCCESS) { php_oci_error(statement->err, statement->errcode TSRMLS_CC); return 1; } PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err)); - - if (statement->errcode != OCI_SUCCESS) { + + if (statement->errcode != OCI_SUCCESS) { php_oci_error(statement->err, statement->errcode TSRMLS_CC); return 1; } @@ -990,7 +1006,7 @@ } /* }}} */ #endif -/* {{{ php_oci_do_connect() +/* {{{ php_oci_do_connect() Connect wrapper */ void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive) { @@ -1006,7 +1022,7 @@ /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "TT|TTl", &username, &username_len, &username_type, &password, &password_len, &password_type, &dbname, &dbname_len, &dbname_type, &charset, &charset_len, &charset_type, &session_mode) == FAILURE) { return; - } + } connection = php_oci_do_connect_ex(username, username_len, password, password_len, NULL_ZSTR, 0, dbname, dbname_len, charset, session_mode, persistent, exclusive, username_type TSRMLS_CC); @@ -1014,12 +1030,12 @@ RETURN_FALSE; } RETURN_RESOURCE(connection->rsrc_id); - + } /* }}} */ /* {{{ php_oci_do_connect_ex() * The real connect function. Allocates all the resources needed, establishes the connection and returns the result handle (or NULL) */ -php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC) +php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC) { zend_rsrc_list_entry *le; zend_rsrc_list_entry new_le; @@ -1027,13 +1043,14 @@ smart_str hashed_details = {0}; time_t timestamp; php_oci_spool *session_pool = NULL; - zend_bool use_spool = 1; /* Default is to use client-side session pool */ + zend_bool use_spool = 1; /* Default is to use client-side session pool */ + zend_bool ping_done = 0; #if HAVE_OCI_ENV_NLS_CREATE ub2 charsetid = 0; ub2 charsetid_nls_lang = 0; #endif - + switch (session_mode) { case OCI_DEFAULT: break; @@ -1058,34 +1075,40 @@ /* We cannot use the new session create logic (OCISessionGet from * client-side session pool) when privileged connect or password * change is attempted. TODO: Remove this once OCI provides - * capability + * capability */ - if ((session_mode==OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) { + if ((session_mode == OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) { use_spool = 0; - } - else if (UG(unicode)) { + } else if (UG(unicode)) { /* Pre 10.1 session pool does not support unicode - bypass pool */ -#ifndef HAVE_OCI_LOB_READ2 /* For finding 10.1+ client */ +#ifndef HAVE_OCI_LOB_READ2 /* For finding 10.1+ client */ use_spool = 0; #endif } - smart_str_appendl_ex(&hashed_details, "oci8___", sizeof("oci8___") - 1, 0); + smart_str_appendl_ex(&hashed_details, "oci8***", sizeof("oci8***") - 1, 0); smart_str_appendl_ex(&hashed_details, username.s, USTR_BYTES(type, username_len), 0); - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); + + /* DRCP: connection_class is an attribute of a connection */ + if (OCI_G(connection_class)){ + smart_str_appendl_ex(&hashed_details, OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), 0); + } + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); + if (password_len) { ulong password_hash; password_hash = zend_u_inline_hash_func(type, password, password_len); smart_str_append_unsigned_ex(&hashed_details, password_hash, 0); } - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); if (dbname_len) { smart_str_appendl_ex(&hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0); } - smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0); - /* Initialize global handles if the weren't initialized before */ + /* Initialize global handles if they weren't initialized before */ if (OCI_G(env) == NULL) { php_oci_init_global_handles(TSRMLS_C); } @@ -1112,8 +1135,7 @@ } smart_str_append_unsigned_ex(&hashed_details, charsetid_nls_lang, 0); } - } - else { + } else { charsetid = OCI_UTF16ID; smart_str_append_unsigned_ex(&hashed_details, charsetid, 0); } @@ -1125,13 +1147,13 @@ #endif timestamp = time(NULL); - + smart_str_append_unsigned_ex(&hashed_details, session_mode, 0); smart_str_0(&hashed_details); /* make it lowercase */ php_strtolower(hashed_details.c, hashed_details.len); - + if (!exclusive && !new_password.v) { zend_bool found = 0; @@ -1139,7 +1161,7 @@ found = 1; /* found */ if (le->type == le_pconnection) { - connection = (php_oci_connection *)le->ptr; + connection = (php_oci_connection *)le->ptr; } } else if (!persistent && zend_hash_find(&EG(regular_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) { found = 1; @@ -1156,21 +1178,19 @@ } /* Debug statements {{{ */ - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (connection && connection->is_stub) { php_printf ("OCI8 DEBUG L1: Got a cached stub: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else if (connection) { + } else if (connection) { php_printf ("OCI8 DEBUG L1: Got a cached connection: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: Got NO cached connection at (%s:%d) \n", __FILE__, __LINE__); } } /* }}} */ - /* If we got a pconnection stub, then 'load'(OCISessionGet) the + /* If we got a pconnection stub, then 'load'(OCISessionGet) the * real connection from its private spool - * A connection is a stub if it is only a cached structure and the + * A connection is a stub if it is only a cached structure and the * real connection is released to its underlying private session pool. * We currently do not have stub support for non-persistent conns. * @@ -1183,26 +1203,29 @@ return NULL; } + /* We do the ping in php_oci_create_session, no need to ping again below */ + ping_done = 1; } - + if (connection) { if (connection->is_open) { /* found an open connection. now ping it */ if (connection->is_persistent) { + int rsrc_type; + /* check connection liveness in the following order: * 1) always check OCI_ATTR_SERVER_STATUS * 2) see if it's time to ping it - * 3) ping it if needed - * */ + * 3) ping it if needed + */ if (php_oci_connection_status(connection TSRMLS_CC)) { - /* only ping if: + /* only ping if: * 1) next_ping > 0, which means that ping_interval is not -1 (aka "Off") * 2) current_timestamp > next_ping, which means "it's time to check if it's still alive" - * */ - if ( (connection->next_ping > 0) && (timestamp >= connection->next_ping) && !php_oci_connection_ping(connection TSRMLS_CC)) { + */ + if ( !ping_done && (*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp)) && !php_oci_connection_ping(connection TSRMLS_CC) ) { /* server died */ } else { - int rsrc_type; php_oci_connection *tmp; /* okay, the connection is open and the server is still alive */ @@ -1221,6 +1244,18 @@ } /* server died */ connection->is_open = 0; + connection->used_this_request = 1; + + /* Connection is no more part of the persistent list */ + free(connection->hash_key); + connection->hash_key = NULL; + connection->hash_key_len = 0; + + /* We have to do a hash_del but need to preserve the resource if there is a positive refcount. Set the data pointer in the list entry to NULL */ + if (zend_list_find(connection->rsrc_id, &rsrc_type)) { + le->ptr = NULL; + } + zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1); connection = NULL; goto open; @@ -1247,22 +1282,22 @@ open: /* Check if we have reached max_persistent. If so, try to remove a few - * timeout out connections. As last resort, return a non-persistent conn + * timed-out connections. As a last resort, return a non-persistent connection. */ if (persistent) { zend_bool alloc_non_persistent = 0; - + if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) { /* try to find an idle connection and kill it */ zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC); - + if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) { /* all persistent connactions are in use, fallback to non-persistent connection creation */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Too many open persistent connections (%ld)", OCI_G(num_persistent)); alloc_non_persistent = 1; } } - + if (alloc_non_persistent) { connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection)); connection->hash_key = estrndup(hashed_details.c, hashed_details.len); @@ -1282,9 +1317,9 @@ } /* {{{ Get the session pool that suits this connection request from the - * persistent list. This step is only for non-persistent connections as + * persistent list. This step is only for non-persistent connections as * persistent connections have private session pools. Non-persistent conns - * use shared session pool to allow for optimizations such as caching the + * use shared session pool to allow for optimizations such as caching the * physical connection (for DRCP) even when the non-persistent php connection * is destroyed. * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability */ @@ -1294,20 +1329,14 @@ php_oci_connection_close(connection TSRMLS_CC); smart_str_free_ex(&hashed_details, 0); return NULL; - } + } } /* }}} */ connection->idle_expiry = (OCI_G(persistent_timeout) > 0) ? (timestamp + OCI_G(persistent_timeout)) : 0; - if (OCI_G(ping_interval) >= 0) { - connection->next_ping = timestamp + OCI_G(ping_interval); - } else { - /* -1 means "Off" */ - connection->next_ping = 0; - } - + /* mark password as unchanged by PHP during the duration of the database session */ connection->passwd_changed = 0; - + smart_str_free_ex(&hashed_details, 0); #if HAVE_OCI_ENV_NLS_CREATE @@ -1318,21 +1347,20 @@ } #endif - /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change {{{*/ + /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change */ if ( !use_spool) { if (php_oci_old_create_session(connection, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) { php_oci_connection_close(connection TSRMLS_CC); return NULL; } - } /* }}} */ - else { + } else { /* create using the client-side session pool */ if (php_oci_create_session(connection, session_pool, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) { php_oci_connection_close(connection TSRMLS_CC); return NULL; - } + } } - + /* mark it as open */ connection->is_open = 1; @@ -1351,16 +1379,15 @@ zend_hash_update(&EG(regular_list), connection->hash_key, connection->hash_key_len+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL); OCI_G(num_links)++; } else { - connection->rsrc_id = zend_list_insert(connection, le_connection); + connection->rsrc_id = zend_list_insert(connection, le_connection); OCI_G(num_links)++; } /* Debug statements {{{ */ - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (connection->is_persistent) { php_printf ("OCI8 DEBUG L1: New Persistent Connection address:(%p) at (%s:%d) \n", connection, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: New Non-Persistent Connection address: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__); } php_printf ("OCI8 DEBUG L1: num_persistent=(%ld), num_links=(%ld) at (%s:%d) \n", OCI_G(num_persistent), OCI_G(num_links), __FILE__, __LINE__); @@ -1378,20 +1405,19 @@ * ORA-1010 (invalid OCI operation) such as from Pre-10.1 servers, * the error is still from the server and we would have * successfully performed a roundtrip and validated the - * connection. Use OCIServerVersion for Pre-10.1 clients + * connection. Use OCIServerVersion for Pre-10.2 clients */ -#if HAVE_OCI_LOB_READ2 /* 10.1 and greater client - OCIPing was first available in 10.1 */ +#if ( (OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION > 2)) ) /* OCIPing available 10.2 onwards */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT)); #else char version[256]; /* use good old OCIServerVersion() */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text*)version, sizeof(version), OCI_HTYPE_SVCCTX)); + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX)); #endif - + if (OCI_G(errcode) == OCI_SUCCESS) { return 1; - } - else { + } else { sb4 error_code = 0; text tmp_buf[PHP_OCI_ERRBUF_LEN]; @@ -1402,7 +1428,7 @@ } } - /* ignore errors here, just return failure + /* ignore errors here, just return failure * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */ return 0; } @@ -1416,12 +1442,12 @@ /* get OCI_ATTR_SERVER_STATUS */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err))); - + if (OCI_G(errcode) == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) { return 1; } - /* ignore errors here, just return failure + /* ignore errors here, just return failure * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */ return 0; } @@ -1457,7 +1483,7 @@ return 0; } /* }}} */ -/* {{{ php_oci_connection_close() +/* {{{ php_oci_connection_close() Close the connection and free all its resources */ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC) { @@ -1469,7 +1495,7 @@ efree(connection->descriptors); } - if (connection->svc) { + if (connection->svc) { /* rollback outstanding transactions */ if (connection->needs_commit) { if (php_oci_connection_rollback(connection TSRMLS_CC)) { @@ -1480,11 +1506,18 @@ } if (!connection->is_stub && connection->svc && connection->is_open) { + /* Update the next_ping in the connection. Needed also for non-peristent because non-persistent DRCP caches connection underneath */ + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + /* Use OCISessionRelease for session pool connections */ if (connection->using_spool) { PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) 0)); - } - else { + } else { PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0)); } } @@ -1495,31 +1528,30 @@ if (connection->authinfo) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO)); } - - /* No Handlefrees for session pool connections {{{ */ + + /* No Handlefrees for session pool connections */ if (!connection->using_spool) { if (connection->session) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION)); } - + if (connection->is_attached) { PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT)); } - + if (connection->svc) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX)); } - + if (connection->server) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER)); } - + if (connection->env) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV)); } - } /* }}} */ - else if (connection->private_spool) { - /* Keep this as the last member to be freed, as there are dependencies + } else if (connection->private_spool) { + /* Keep this as the last member to be freed, as there are dependencies * (like env) on the session pool */ php_oci_spool_close(connection->private_spool TSRMLS_CC); @@ -1541,7 +1573,7 @@ return result; } /* }}} */ -/* {{{ php_oci_connection_release() +/* {{{ php_oci_connection_release() Release the connection to its session pool. This looks similar to php_oci_connection_close, but the latter is used for connections that are to be terminated. The latter was not overloaded for "release" because of too many callers */ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC) { @@ -1558,7 +1590,7 @@ connection->descriptors = NULL; } - if (connection->svc) { + if (connection->svc) { /* rollback outstanding transactions */ if (connection->needs_commit) { if (php_oci_connection_rollback(connection TSRMLS_CC)) { @@ -1570,8 +1602,15 @@ /* Release the session */ if (connection->svc) { - PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL, - 0, OCI_DEFAULT)); + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + + PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL, + 0, result ? OCI_SESSRLS_DROPSESS : OCI_DEFAULT)); } /* It no longer has relation with the database session. However authinfo and env are cached */ @@ -1582,9 +1621,11 @@ connection->is_attached = connection->is_open = connection->needs_commit = 0; connection->is_stub = 1; - /* now a stub, so don't count it in the number of connnections */ + /* Cut the link between the connection structure and the time_t structure allocated within the OCI session */ + connection->next_pingp = NULL; + if (!connection->is_persistent) { - OCI_G(num_links)--; /* Support for "connection" stubs - future use */ + OCI_G(num_links)--; /* Support for "connection" stubs - future use */ } OCI_G(in_call) = in_call_save; @@ -1606,14 +1647,14 @@ return 0; } /* }}} */ -/* {{{ php_oci_server_get_version() +/* {{{ php_oci_server_get_version() Get Oracle server version */ -int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC) +int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC) { char version_buff[512]; - PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text*)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX)); - + PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text *)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX)); + if (connection->errcode != OCI_SUCCESS) { php_oci_error(connection->err, connection->errcode TSRMLS_CC); PHP_OCI_HANDLE_ERROR(connection, connection->errcode); @@ -1628,7 +1669,7 @@ return 0; } /* }}} */ -/* {{{ php_oci_column_to_zval() +/* {{{ php_oci_column_to_zval() Convert php_oci_out_column struct into zval */ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSRMLS_DC) { @@ -1639,20 +1680,20 @@ zstr lob_buffer; zstr zstr_data = ZSTR(column->data); php_oci_lob_type lob_type; - - if (column->indicator == -1) { /* column is NULL */ - ZVAL_NULL(value); + + if (column->indicator == -1) { /* column is NULL */ + ZVAL_NULL(value); return 0; } - + if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */ ZVAL_RESOURCE(value, column->stmtid); zend_list_addref(column->stmtid); } else if (column->is_descr) { - + if (column->data_type != SQLT_RDD) { int rsrc_type; - + /* reset descriptor's length */ descriptor = (php_oci_descriptor *) zend_list_find(column->descid, &rsrc_type); @@ -1660,7 +1701,7 @@ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find LOB descriptor #%d", column->descid); return 1; } - + descriptor->lob_size = -1; descriptor->lob_current_position = 0; descriptor->buffering = 0; @@ -1668,7 +1709,7 @@ if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) { /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */ - + lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC); lob_fetch_status |= (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0); #ifdef HAVE_OCI8_TEMP_LOB @@ -1696,7 +1737,7 @@ break; } return 0; - } else { + } else { /* return the locator */ object_init_ex(value, oci_lob_class_entry_ptr); add_property_resource(value, "descriptor", column->descid); @@ -1704,7 +1745,7 @@ } } else { switch (column->retcode) { - case 0: + case 0: /* intact value */ if (column->piecewise) { column_size = column->retlen4; @@ -1712,19 +1753,19 @@ column_size = column->retlen; } break; - - default: - ZVAL_FALSE(value); + + default: + ZVAL_FALSE(value); return 0; } - + ZVAL_TEXTL(value, zstr_data, TEXT_CHARS(column_size), 1); } return 0; } /* }}} */ -/* {{{ php_oci_fetch_row() +/* {{{ php_oci_fetch_row() Fetch the next row from the given statement */ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args) { @@ -1741,7 +1782,7 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|l", &z_statement, &array, &fetch_mode) == FAILURE) { return; } - + if (ZEND_NUM_ARGS() == 2) { fetch_mode = mode; } @@ -1751,17 +1792,17 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &fetch_mode) == FAILURE) { return; } - + if (ZEND_NUM_ARGS() == 1) { fetch_mode = mode; } } else { /* for all oci_fetch_*() */ - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) { return; } - + fetch_mode = mode; } @@ -1769,7 +1810,7 @@ /* none of the modes present, use the default one */ if (mode & PHP_OCI_ASSOC) { fetch_mode |= PHP_OCI_ASSOC; - } + } if (mode & PHP_OCI_NUM) { fetch_mode |= PHP_OCI_NUM; } @@ -1784,9 +1825,9 @@ array_init(return_value); for (i = 0; i < statement->ncolumns; i++) { - + column = php_oci_statement_get_column(statement, i + 1, NULL_ZSTR, 0 TSRMLS_CC); - + if (column == NULL) { continue; } @@ -1796,7 +1837,7 @@ if (!(column->indicator == -1)) { zval *element; - + MAKE_STD_ZVAL(element); php_oci_column_to_zval(column, element, fetch_mode TSRMLS_CC); @@ -1809,7 +1850,7 @@ } add_u_assoc_zval(return_value, (UG(unicode) ? IS_UNICODE : IS_STRING), column->name, element); } - + } else { if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) { add_index_null(return_value, i); @@ -1831,7 +1872,7 @@ } /* }}} */ -/* {{{ php_oci_persistent_helper() +/* {{{ php_oci_persistent_helper() Helper function to close/rollback persistent connections at the end of request. A return value of 1 indicates that the connection is to be destroyed */ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC) { @@ -1839,7 +1880,7 @@ php_oci_connection *connection; timestamp = time(NULL); - + /* pconnection stubs are also counted as they have private session pools */ if (le->type == le_pconnection) { connection = (php_oci_connection *)le->ptr; @@ -1849,19 +1890,24 @@ return ZEND_HASH_APPLY_REMOVE; } + /* Helps remove bad connections from the persistent list */ + if (!connection->is_open && !connection->is_stub) { + return ZEND_HASH_APPLY_REMOVE; + } + if (connection->descriptors) { zend_hash_destroy(connection->descriptors); efree(connection->descriptors); connection->descriptors = NULL; } - + if (connection->needs_commit) { php_oci_connection_rollback(connection TSRMLS_CC); } - + /* If oci_password_change() changed the password of a * persistent connection, close the connection and remove - * it from the persistent connection cache. This means + * it from the persistent connection cache. This means * subsequent scripts will be prevented from being able to * present the old (now invalid) password to a usable * connection to the database; they must use the new @@ -1874,17 +1920,19 @@ if (OCI_G(persistent_timeout) > 0) { connection->idle_expiry = timestamp + OCI_G(persistent_timeout); } - - if (OCI_G(ping_interval) >= 0) { - connection->next_ping = timestamp + OCI_G(ping_interval); - } else { - /* ping_interval is -1 */ - connection->next_ping = 0; - } - /* Release all persistent connections at the end of the request */ - if (connection->using_spool && !connection->is_stub && php_oci_connection_release(connection TSRMLS_CC)) { - return ZEND_HASH_APPLY_REMOVE; + if (!connection->is_stub) { + if (OCI_G(ping_interval) >= 0) { + *(connection->next_pingp) = timestamp + OCI_G(ping_interval); + } else { + /* ping_interval is -1 */ + *(connection->next_pingp) = 0; + } + + /* Release all session pool-using persistent connections at the end of the request */ + if (connection->using_spool && php_oci_connection_release(connection TSRMLS_CC)) { + return ZEND_HASH_APPLY_REMOVE; + } } connection->used_this_request = 0; @@ -1904,16 +1952,17 @@ { php_oci_spool *session_pool = NULL; zend_bool iserror = 0; + ub4 poolmode = OCI_DEFAULT; /* Mode to be passed to OCISessionPoolCreate */ /*Allocate sessionpool out of persistent memory */ session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool)); - /* Populate key if passed */ + /* Populate key if passed */ if (hash_key_len) { session_pool->spool_hash_key = zend_strndup(hash_key, hash_key_len); session_pool->spool_hash_key_len = hash_key_len; } - + /* Create the session pool's env */ if (!(session_pool->env = php_oci_create_env(charsetid TSRMLS_CC))) { iserror = 1; @@ -1932,7 +1981,7 @@ /* allocate the session pool error handle - This only for use in the * destructor, as there is a generic bug which can free up the OCI_G(err) * variable before destroying connections. We cannot use this for other - * roundtrip calls as there is no way the user can access this error + * roundtrip calls as there is no way the user can access this error */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, ((dvoid *) session_pool->env, (dvoid **)&(session_pool->err), (ub4) OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0)); @@ -1940,13 +1989,20 @@ php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; goto exit_create_spool; - } + } + +/* Disable RLB as we'd mostly have single-connection pools */ +#if (OCI_MAJOR_VERSION > 10 ) + poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS; +#else + poolmode = OCI_SPC_HOMOGENEOUS; +#endif /* Create the homogeneous session pool - We have different session pools * for every different username, password, charset and dbname. */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 1, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), OCI_SPC_HOMOGENEOUS)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 0, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), poolmode)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; @@ -1958,20 +2014,21 @@ ub4 timeout = OCI_G(persistent_timeout); PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) session_pool->poolh, (ub4) OCI_HTYPE_SPOOL, (void *) &timeout, (ub4) sizeof(timeout), (ub4) OCI_ATTR_SPOOL_TIMEOUT, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); iserror = 1; goto exit_create_spool; } } + exit_create_spool: if (iserror && session_pool) { php_oci_spool_close(session_pool TSRMLS_CC); session_pool = NULL; } - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { php_printf ("OCI8 DEBUG L1: create_spool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__); } @@ -1979,7 +2036,7 @@ } /* }}} */ /* {{{ php_oci_get_spool() - Get Session pool for the given dbname and charsetid from the persistent + Get Session pool for the given dbname and charsetid from the persistent list. Function called for non-persistent connections. */ static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC) @@ -1989,26 +2046,26 @@ zend_rsrc_list_entry spool_le = {0}; zend_rsrc_list_entry *spool_out_le = NULL; zend_bool iserror = 0; - + /* Create the spool hash key {{{ */ - smart_str_appendl_ex(&spool_hashed_details, "oci8__spool__", sizeof("oci8__spool__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "oci8spool***", sizeof("oci8spool***") - 1, 0); smart_str_appendl_ex(&spool_hashed_details, username.s, USTR_BYTES(type, username_len), 0); - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); if (password_len) { ulong password_hash; password_hash = zend_u_inline_hash_func(type, password, password_len); smart_str_append_unsigned_ex(&spool_hashed_details, password_hash, 0); } - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); if (dbname_len) { smart_str_appendl_ex(&spool_hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0); } - smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0); - + smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0); + smart_str_append_unsigned_ex(&spool_hashed_details, charsetid, 0); - /* Session Pool Hash Key : oci8__spool__dbname__charset */ + /* Session Pool Hash Key : oci8spool***username**hashedpassword**dbname**charset */ smart_str_0(&spool_hashed_details); php_strtolower(spool_hashed_details.c, spool_hashed_details.len); @@ -2018,16 +2075,15 @@ session_pool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, spool_hashed_details.c, spool_hashed_details.len, charsetid, type TSRMLS_CC); - if (session_pool == NULL) { + if (session_pool == NULL) { iserror = 1; - goto exit_get_spool; - } + goto exit_get_spool; + } spool_le.ptr = session_pool; spool_le.type = le_psessionpool; zend_list_insert(session_pool, le_psessionpool); zend_hash_update(&EG(persistent_list), session_pool->spool_hash_key, session_pool->spool_hash_key_len + 1, (void *)&spool_le, sizeof(zend_rsrc_list_entry),NULL); - } - else if (spool_out_le->type == le_psessionpool && + } else if (spool_out_le->type == le_psessionpool && (((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key_len) == spool_hashed_details.len && memcmp(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key, spool_hashed_details.c, spool_hashed_details.len) == 0 ) { /* retrieve the cached session pool */ @@ -2047,25 +2103,25 @@ /* {{{ php_oci_create_env() Create the OCI environment choosing the correct function for the OCI version */ -static OCIEnv* php_oci_create_env(ub2 charsetid TSRMLS_DC) +static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC) { OCIEnv *retenv = NULL; /* allocate environment handle */ #if HAVE_OCI_ENV_NLS_CREATE #define PHP_OCI_INIT_FUNC_NAME "OCIEnvNlsCreate" - + /* create an environment using the character set id, Oracle 9i+ ONLY */ 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)); #elif HAVE_OCI_ENV_CREATE #define PHP_OCI_INIT_FUNC_NAME "OCIEnvCreate" - + /* allocate env handle without NLS support */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvCreate, (&retenv, PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL)); #else #define PHP_OCI_INIT_FUNC_NAME "OCIEnvInit" - + /* the simpliest way */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvInit, (&retenv, OCI_DEFAULT, 0, NULL)); #endif @@ -2089,26 +2145,26 @@ This function is to be deprecated in future in favour of OCISessionGet which is used in php_oci_do_connect_ex */ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC) { - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { php_printf ("OCI8 DEBUG: Bypassing client-side session pool for session create at (%s:%d) \n", __FILE__, __LINE__); } /* Create the OCI environment separate for each connection */ - if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) { - return 1; + if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) { + return 1; } - /* Allocate our server handle {{{ */ + /* Allocate our server handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->server), OCI_HTYPE_SERVER, 0, NULL)); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } /* }}} */ /* Attach to the server {{{ */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text*)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text *)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2117,7 +2173,7 @@ /* Allocate our session handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->session), OCI_HTYPE_SESSION, 0, NULL)); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2142,24 +2198,24 @@ /* Set the username {{{ */ if (username_len) { PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) username.s, (ub4) USTR_BYTES(type, username_len), (ub4) OCI_ATTR_USERNAME, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } }/* }}} */ /* Set the password {{{ */ if (password_len) { PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) password.s, (ub4) USTR_BYTES(type, password_len), (ub4) OCI_ATTR_PASSWORD, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } }/* }}} */ - /* Set the server handle in the service handle {{{ */ + /* Set the server handle in the service handle {{{ */ PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err))); if (OCI_G(errcode) != OCI_SUCCESS) { @@ -2217,23 +2273,29 @@ php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when * user's password has expired, but is still usable. - * */ + */ if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { return 1; } } /* }}} */ } + /* Brand new connection: Init and update the next_ping in the connection */ + if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + return 1; + } + #if HAVE_OCI_STMT_PREPARE2 { ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0; PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } } #endif @@ -2249,6 +2311,7 @@ #if (OCI_MAJOR_VERSION > 10 ) ub4 purity = -2; /* Illegal value to initialize */ #endif + time_t timestamp = time(NULL); /* Persistent connections have private session pools */ if (connection->is_persistent && !connection->private_spool && @@ -2266,22 +2329,21 @@ connection->using_spool = 1; } - if (OCI_G(debug_mode)) { + if (OCI_G(debug_mode)) { if (session_pool) { php_printf ("OCI8 DEBUG L1: using shared pool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__); - } - else { + } else { php_printf ("OCI8 DEBUG L1: using private pool: (%p) at (%s:%d) \n", connection->private_spool, __FILE__, __LINE__); } } - /* The passed in "connection" can be a cached stub from plist or a + /* The passed in "connection" can be a cached stub from plist or * freshly created. In the former case, we do not have to allocate * any handles */ if (!connection->err) { - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; @@ -2290,14 +2352,14 @@ /* {{{ Allocate and initialize the connection-private authinfo handle if not allocated yet */ if (!connection->authinfo) { - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL)); - + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL)); + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } - /* Set the Connection class and purity if OCI client version >=11g */ + /* Set the Connection class and purity if OCI client version >= 11g */ #if (OCI_MAJOR_VERSION > 10 ) PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), (ub4)OCI_ATTR_CONNECTION_CLASS, OCI_G(err))); @@ -2310,7 +2372,6 @@ purity = OCI_ATTR_PURITY_SELF; else purity = OCI_ATTR_PURITY_NEW; - PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_AUTHINFO, (dvoid *) &purity, (ub4)0, (ub4)OCI_ATTR_PURITY, OCI_G(err))); @@ -2321,39 +2382,84 @@ #endif } /* }}} */ - /* Continue to use the global error handle as the connection is closed when an error occurs */ - PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)); - - if (OCI_G(errcode) != OCI_SUCCESS) { - php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + /* Debug statements {{{ */ + if (OCI_G(debug_mode)) { + ub4 numfree = 0, numbusy = 0, numopen = 0; + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numopen, (ub4 *)0, OCI_ATTR_SPOOL_OPEN_COUNT, OCI_G(err))); + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numbusy, (ub4 *)0, OCI_ATTR_SPOOL_BUSY_COUNT, OCI_G(err))); + numfree = numopen - numbusy; /* number of free connections in the pool */ + php_printf ("OCI8 DEBUG L1: (numopen=%d)(numbusy=%d) at (%s:%d) \n", numopen, numbusy, __FILE__, __LINE__); + } /* }}} */ + + /* Ping loop: Ping and loop till we get a good + * connection. When a database instance goes down, it can + * leave several bad connections that need to be flushed out + * before getting a good one. In non-RAC, we always get a + * brand new connection at the end of the loop and in RAC, we + * can get a good connection from a different instance before + * flushing out all bad ones. We do not need to ping brand new + * connections. + */ + do { + /* Continue to use the global error handle as the connection is closed when an error occurs */ + PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)); + + if (OCI_G(errcode) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + + /* Session creation returns OCI_SUCCESS_WITH_INFO when + * user's password has expired, but is still usable. + */ - /* Session creation returns OCI_SUCCESS_WITH_INFO when - * user's password has expired, but is still usable. - * */ + if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { + return 1; + } + } - if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) { + /* {{{ Populate the session and server fields of the connection */ + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err))); + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */ + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, OCI_G(err), (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&(connection->next_pingp))); + if (OCI_G(errcode) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; } - } - + + if (!(connection->next_pingp)){ + /* This is a brand new connection, we need not ping, but have to initialize ping */ + if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) { + php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); + return 1; + } + } else if ((*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp))) { + if (php_oci_connection_ping(connection TSRMLS_CC)) { + /* Got a good connection - update next_ping and get out of ping loop */ + *(connection->next_pingp) = timestamp + OCI_G(ping_interval); + } else { + /* Bad connection - remove from pool */ + PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) OCI_SESSRLS_DROPSESS)); + connection->svc = NULL; + connection->server = NULL; + connection->session = NULL; + } + } /* If ping applicable */ + } while (!(connection->svc)); + #if HAVE_OCI_STMT_PREPARE2 { ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0; PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err))); - + if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); return 1; - } + } } #endif - /* {{{ Populate the session and server fields of the connection */ - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err))); - - PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */ - /* Session is now taken from the session pool and attached and open */ connection->is_stub = 0; connection->is_attached = connection->is_open = 1; @@ -2374,12 +2480,12 @@ return; } /* }}} */ -/* {{{ php_oci_spool_close() +/* {{{ php_oci_spool_close() Destroys the OCI Session Pool */ static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC) { - if (session_pool->poolname_len) { - PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh, + if (session_pool->poolname_len) { + PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh, (dvoid *) session_pool->err, OCI_SPD_FORCE)); } @@ -2387,23 +2493,65 @@ PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL)); } - if (session_pool->err) { + if (session_pool->err) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR)); } - if (session_pool->env) { + if (session_pool->env) { PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->env, OCI_HTYPE_ENV)); } if (session_pool->spool_hash_key) { - free(session_pool->spool_hash_key); + free(session_pool->spool_hash_key); } free(session_pool); } /* }}} */ +/* {{{ php_oci_ping_init() + Initializes the next_ping time as a context value in the + connection. We now use OCIContext{Get,Set}Value to store the + next_ping because we need to support ping for non-persistent DRCP + connections */ +static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC) +{ + time_t *next_pingp = NULL; + + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, errh, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&next_pingp)); + if (OCI_G(errcode) != OCI_SUCCESS) { + return OCI_G(errcode); + } + + /* This must be a brand-new connection. Allocate memory for the ping */ + if (!next_pingp) { + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIMemoryAlloc, (connection->session, errh, (void **)&next_pingp, OCI_DURATION_SESSION, sizeof(time_t), OCI_MEMORY_CLEARED)); + if (OCI_G(errcode) != OCI_SUCCESS) { + return OCI_G(errcode); + } + } + + if (OCI_G(ping_interval) >= 0) { + time_t timestamp = time(NULL); + *next_pingp = timestamp + OCI_G(ping_interval); + } else { + *next_pingp = 0; + } + + /* Set the new ping value into the connection */ + PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextSetValue, (connection->session, errh, OCI_DURATION_SESSION, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), next_pingp)); + if (OCI_G(errcode) != OCI_SUCCESS) { + OCIMemoryFree(connection->session, errh, next_pingp); + return OCI_G(errcode); + } + + /* Cache the pointer so we do not have to do OCIContextGetValue repeatedly */ + connection->next_pingp = next_pingp; + + return OCI_SUCCESS; +} /* }}} */ + #ifdef ZTS -/* {{{ php_oci_list_helper() +/* {{{ php_oci_list_helper() Helper function to destroy data on thread shutdown in ZTS mode */ static int php_oci_list_helper(zend_rsrc_list_entry *le, void *le_type TSRMLS_DC) { http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/php_oci8_int.h?r1=1.41&r2=1.42&diff_format=u Index: php-src/ext/oci8/php_oci8_int.h diff -u php-src/ext/oci8/php_oci8_int.h:1.41 php-src/ext/oci8/php_oci8_int.h:1.42 --- php-src/ext/oci8/php_oci8_int.h:1.41 Mon Feb 25 23:49:51 2008 +++ php-src/ext/oci8/php_oci8_int.h Wed Mar 12 01:25:13 2008 @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 6 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2008 The PHP Group | +----------------------------------------------------------------------+ @@ -25,7 +25,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_oci8_int.h,v 1.41 2008/02/25 23:49:51 sixd Exp $ */ +/* $Id: php_oci8_int.h,v 1.42 2008/03/12 01:25:13 sixd Exp $ */ #if HAVE_OCI8 # ifndef PHP_OCI8_INT_H @@ -34,13 +34,13 @@ /* misc defines {{{ */ # if (defined(__osf__) && defined(__alpha)) # ifndef A_OSF -# define A_OSF +# define A_OSF # endif # ifndef OSF1 -# define OSF1 +# define OSF1 # endif # ifndef _INTRINSICS -# define _INTRINSICS +# define _INTRINSICS # endif # endif /* osf alpha */ @@ -59,7 +59,7 @@ extern int le_pconnection; extern int le_statement; extern int le_descriptor; -#ifdef PHP_OCI8_HAVE_COLLECTIONS +#ifdef PHP_OCI8_HAVE_COLLECTIONS extern int le_collection; #endif extern int le_server; @@ -77,19 +77,19 @@ #define PHP_OCI_MAX_NAME_LEN 64 #define PHP_OCI_MAX_DATA_SIZE INT_MAX -#define PHP_OCI_PIECE_SIZE (64*1024)-1 +#define PHP_OCI_PIECE_SIZE (64*1024)-1 #define PHP_OCI_LOB_BUFFER_SIZE 1048576l /* 1Mb seems to be the most reasonable buffer size for LOB reading */ -#define PHP_OCI_ASSOC 1<<0 -#define PHP_OCI_NUM 1<<1 -#define PHP_OCI_BOTH (PHP_OCI_ASSOC|PHP_OCI_NUM) - -#define PHP_OCI_RETURN_NULLS 1<<2 -#define PHP_OCI_RETURN_LOBS 1<<3 - -#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN 1<<4 -#define PHP_OCI_FETCHSTATEMENT_BY_ROW 1<<5 -#define PHP_OCI_FETCHSTATEMENT_BY (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW) +#define PHP_OCI_ASSOC 1<<0 +#define PHP_OCI_NUM 1<<1 +#define PHP_OCI_BOTH (PHP_OCI_ASSOC|PHP_OCI_NUM) + +#define PHP_OCI_RETURN_NULLS 1<<2 +#define PHP_OCI_RETURN_LOBS 1<<3 + +#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN 1<<4 +#define PHP_OCI_FETCHSTATEMENT_BY_ROW 1<<5 +#define PHP_OCI_FETCHSTATEMENT_BY (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW) #define PHP_OCI_LOB_BUFFER_DISABLED 0 #define PHP_OCI_LOB_BUFFER_ENABLED 1 @@ -103,147 +103,146 @@ } php_oci_lob_type; typedef struct { /* php_oci_spool {{{ */ - OCIEnv *env; /*env of this session pool */ - OCIError *err; /* pool's error handle */ - OCISPool *poolh; /* pool handle */ - void *poolname; /* session pool name */ - unsigned int poolname_len; /* length of session pool name */ - char *spool_hash_key; /* Hash key for session pool in plist */ - int spool_hash_key_len; /* Hash key length */ + OCIEnv *env; /*env of this session pool */ + OCIError *err; /* pool's error handle */ + OCISPool *poolh; /* pool handle */ + void *poolname; /* session pool name */ + unsigned int poolname_len; /* length of session pool name */ + char *spool_hash_key; /* Hash key for session pool in plist */ + int spool_hash_key_len; /* Hash key length */ } php_oci_spool; /* }}} */ typedef struct { /* php_oci_connection {{{ */ - OCIEnv *env; /* private env handle */ - ub2 charset; /* charset ID */ - OCIServer *server; /* private server handle */ - OCISvcCtx *svc; /* private service context handle */ - OCISession *session; /* private session handle */ - OCIAuthInfo *authinfo; /* Cached authinfo handle for OCISessionGet */ - OCIError *err; /* private error handle */ - php_oci_spool *private_spool; /* private session pool (for persistent) */ - sword errcode; /* last errcode */ - - HashTable *descriptors; /* descriptors hash, used to flush all the LOBs using this connection on commit */ - unsigned is_open:1; /* hels to determine if the connection is dead or not */ - unsigned is_attached:1; /* hels to determine if we should detach from the server when closing/freeing the connection */ - unsigned is_persistent:1; /* self-descriptive */ - unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */ - unsigned needs_commit:1; /* helps to determine if we should rollback this connection on close/shutdown */ - unsigned passwd_changed:1; /* helps determine if a persistent connection hash should be invalidated after a password change */ - unsigned is_stub:1; /* flag to keep track whether the connection structure has a real OCI connection associated */ - unsigned using_spool:1; /* Is this connection from session pool? */ - int rsrc_id; /* resource ID */ - time_t idle_expiry; /* time when the connection will be considered as expired */ - time_t next_ping; /* time of the next ping */ - char *hash_key; /* hashed details of the connection */ - int hash_key_len; + OCIEnv *env; /* private env handle */ + ub2 charset; /* charset ID */ + OCIServer *server; /* private server handle */ + OCISvcCtx *svc; /* private service context handle */ + OCISession *session; /* private session handle */ + OCIAuthInfo *authinfo; /* Cached authinfo handle for OCISessionGet */ + OCIError *err; /* private error handle */ + php_oci_spool *private_spool; /* private session pool (for persistent) */ + sword errcode; /* last errcode */ + + HashTable *descriptors; /* descriptors hash, used to flush all the LOBs using this connection on commit */ + unsigned is_open:1; /* hels to determine if the connection is dead or not */ + unsigned is_attached:1; /* hels to determine if we should detach from the server when closing/freeing the connection */ + unsigned is_persistent:1; /* self-descriptive */ + unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */ + unsigned needs_commit:1; /* helps to determine if we should rollback this connection on close/shutdown */ + unsigned passwd_changed:1; /* helps determine if a persistent connection hash should be invalidated after a password change */ + unsigned is_stub:1; /* flag to keep track whether the connection structure has a real OCI connection associated */ + unsigned using_spool:1; /* Is this connection from session pool? */ + int rsrc_id; /* resource ID */ + time_t idle_expiry; /* time when the connection will be considered as expired */ + time_t *next_pingp; /* (pointer to) time of the next ping */ + char *hash_key; /* hashed details of the connection */ + int hash_key_len; } php_oci_connection; /* }}} */ typedef struct { /* php_oci_descriptor {{{ */ - int id; - php_oci_connection *connection; /* parent connection handle */ - dvoid *descriptor; /* OCI descriptor handle */ - ub4 type; /* descriptor type (FILE/LOB) */ - int lob_current_position; /* LOB internal pointer */ - int lob_size; /* cached LOB size. -1 = Lob wasn't initialized yet */ - int buffering; /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */ - ub4 chunk_size; /* chunk size of the LOB. 0 - unknown */ - ub1 charset_form; /* charset form, required for NCLOBs */ - ub2 charset_id; /* charset ID */ - unsigned is_open:1; /* helps to determine if lob is open or not */ - php_oci_lob_type lob_type; /* CLOB/BLOB */ + int id; + php_oci_connection *connection; /* parent connection handle */ + dvoid *descriptor; /* OCI descriptor handle */ + ub4 type; /* descriptor type (FILE/LOB) */ + int lob_current_position; /* LOB internal pointer */ + int lob_size; /* cached LOB size. -1 = Lob wasn't initialized yet */ + int buffering; /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */ + ub4 chunk_size; /* chunk size of the LOB. 0 - unknown */ + ub1 charset_form; /* charset form, required for NCLOBs */ + ub2 charset_id; /* charset ID */ + unsigned is_open:1; /* helps to determine if lob is open or not */ + php_oci_lob_type lob_type; /* CLOB/BLOB */ } php_oci_descriptor; /* }}} */ typedef struct { /* php_oci_lob_ctx {{{ */ - char **lob_data; /* address of pointer to LOB data */ - ub4 *lob_len; /* address of LOB length variable (bytes) */ - ub4 alloc_len; + char **lob_data; /* address of pointer to LOB data */ + ub4 *lob_len; /* address of LOB length variable (bytes) */ + ub4 alloc_len; } php_oci_lob_ctx; /* }}} */ typedef struct { /* php_oci_collection {{{ */ - int id; - php_oci_connection *connection; /* parent connection handle */ - OCIType *tdo; /* collection's type handle */ - OCITypeCode coll_typecode; /* collection's typecode handle */ - OCIRef *elem_ref; /* element's reference handle */ - OCIType *element_type; /* element's type handle */ - OCITypeCode element_typecode; /* element's typecode handle */ - OCIColl *collection; /* collection handle */ + int id; + php_oci_connection *connection; /* parent connection handle */ + OCIType *tdo; /* collection's type handle */ + OCITypeCode coll_typecode; /* collection's typecode handle */ + OCIRef *elem_ref; /* element's reference handle */ + OCIType *element_type; /* element's type handle */ + OCITypeCode element_typecode; /* element's typecode handle */ + OCIColl *collection; /* collection handle */ } php_oci_collection; /* }}} */ typedef struct { /* php_oci_define {{{ */ - zval *zval; /* zval used in define */ - zstr name; /* placeholder's name */ - zend_uchar name_type; /* unicode or not */ - ub4 name_len; /* placeholder's name length */ - ub4 type; /* define type */ + zval *zval; /* zval used in define */ + zstr name; /* placeholder's name */ + zend_uchar name_type; /* unicode or not */ + ub4 name_len; /* placeholder's name length */ + ub4 type; /* define type */ } php_oci_define; /* }}} */ typedef struct { /* php_oci_statement {{{ */ - int id; - int parent_stmtid; /* parent statement id */ - php_oci_connection *connection; /* parent connection handle */ - sword errcode; /* last errcode*/ - OCIError *err; /* private error handle */ - OCIStmt *stmt; /* statement handle */ - char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */ - long last_query_len; /* last query length */ - HashTable *columns; /* hash containing all the result columns */ - HashTable *binds; /* binds hash */ - HashTable *defines; /* defines hash */ - int ncolumns; /* number of columns in the result */ - unsigned executed:1; /* statement executed flag */ - unsigned has_data:1; /* statement has more data flag */ - ub2 stmttype; /* statement type */ + int id; + int parent_stmtid; /* parent statement id */ + php_oci_connection *connection; /* parent connection handle */ + sword errcode; /* last errcode*/ + OCIError *err; /* private error handle */ + OCIStmt *stmt; /* statement handle */ + char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */ + long last_query_len; /* last query length */ + HashTable *columns; /* hash containing all the result columns */ + HashTable *binds; /* binds hash */ + HashTable *defines; /* defines hash */ + int ncolumns; /* number of columns in the result */ + unsigned executed:1; /* statement executed flag */ + unsigned has_data:1; /* statement has more data flag */ + ub2 stmttype; /* statement type */ } php_oci_statement; /* }}} */ typedef struct { /* php_oci_bind {{{ */ - OCIBind *bind; /* bind handle */ - zval *zval; /* value */ - dvoid *descriptor; /* used for binding of LOBS etc */ - OCIStmt *statement; /* used for binding REFCURSORs */ - php_oci_statement *parent_statement; /* pointer to the parent statement */ + OCIBind *bind; /* bind handle */ + zval *zval; /* value */ + dvoid *descriptor; /* used for binding of LOBS etc */ + OCIStmt *statement; /* used for binding REFCURSORs */ + php_oci_statement *parent_statement; /* pointer to the parent statement */ struct { - void *elements; - sb2 *indicators; - ub2 *element_lengths; -/* ub2 *retcodes; */ - ub4 current_length; - ub4 old_length; - ub4 max_length; - long type; + void *elements; + sb2 *indicators; + ub2 *element_lengths; + ub4 current_length; + ub4 old_length; + ub4 max_length; + long type; } array; - sb2 indicator; /* -1 means NULL */ - ub2 retcode; /* */ - zend_bool out; /* OUT bind or not */ - ub4 dummy_len; /* a dummy var to store alenpp value in bind OUT callback */ + sb2 indicator; /* -1 means NULL */ + ub2 retcode; + zend_bool out; /* OUT bind or not */ + ub4 dummy_len; /* a dummy var to store alenpp value in bind OUT callback */ } php_oci_bind; /* }}} */ typedef struct { /* php_oci_out_column {{{ */ - php_oci_statement *statement; /* statement handle. used when fetching REFCURSORS */ - php_oci_statement *nested_statement; /* statement handle. used when fetching REFCURSORS */ - OCIDefine *oci_define; /* define handle */ - zstr name; /* column name */ - ub4 name_len; /* column name length */ - ub2 data_type; /* column data type */ - ub2 data_size; /* data size */ - ub4 storage_size4; /* size used when allocating buffers */ - sb2 indicator; /* */ - ub2 retcode; /* code returned when fetching this particular column */ - ub2 retlen; /* */ - ub4 retlen4; /* */ - ub2 is_descr; /* column contains a descriptor */ - ub2 is_cursor; /* column contains a cursor */ - int stmtid; /* statement id for cursors */ - int descid; /* descriptor id for descriptors */ - void *data; /* */ - php_oci_define *define; /* define handle */ - int piecewise; /* column is fetched piece-by-piece */ - ub4 cb_retlen; /* */ - sb1 scale; /* column scale */ - sb2 precision; /* column precision */ - ub1 charset_form; /* charset form, required for NCLOBs */ - ub2 charset_id; /* charset ID */ + php_oci_statement *statement; /* statement handle. used when fetching REFCURSORS */ + php_oci_statement *nested_statement; /* statement handle. used when fetching REFCURSORS */ + OCIDefine *oci_define; /* define handle */ + zstr name; /* column name */ + ub4 name_len; /* column name length */ + ub2 data_type; /* column data type */ + ub2 data_size; /* data size */ + ub4 storage_size4; /* size used when allocating buffers */ + sb2 indicator; + ub2 retcode; /* code returned when fetching this particular column */ + ub2 retlen; + ub4 retlen4; + ub2 is_descr; /* column contains a descriptor */ + ub2 is_cursor; /* column contains a cursor */ + int stmtid; /* statement id for cursors */ + int descid; /* descriptor id for descriptors */ + void *data; + php_oci_define *define; /* define handle */ + int piecewise; /* column is fetched piece-by-piece */ + ub4 cb_retlen; + sb1 scale; /* column scale */ + sb2 precision; /* column precision */ + ub1 charset_form; /* charset form, required for NCLOBs */ + ub2 charset_id; /* charset ID */ } php_oci_out_column; /* }}} */ /* {{{ macros */ @@ -271,17 +270,31 @@ #define PHP_OCI_HANDLE_ERROR(connection, errcode) \ do { \ switch (errcode) { \ - case 1013: \ - zend_bailout(); \ - break; \ - case 22: \ - case 1012: \ - case 3113: \ - case 604: \ - case 1041: \ - case 3114: \ - connection->is_open = 0; \ - break; \ + case 1013: \ + zend_bailout(); \ + break; \ + case 22: \ + case 378: \ + case 602: \ + case 603: \ + case 604: \ + case 609: \ + case 1012: \ + case 1033: \ + case 1041: \ + case 1043: \ + case 1089: \ + case 1090: \ + case 1092: \ + case 3113: \ + case 3114: \ + case 3122: \ + case 3135: \ + case 12153: \ + case 27146: \ + case 28511: \ + connection->is_open = 0; \ + break; \ } \ } while (0) @@ -302,14 +315,14 @@ #define PHP_OCI_ZVAL_TO_COLLECTION(zval, collection) \ ZEND_FETCH_RESOURCE(collection, php_oci_collection *, &zval, -1, "oci8 collection", le_collection) -#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type) \ +#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type) \ do { \ var = (type) zend_fetch_resource(&zval TSRMLS_CC, -1, name, NULL, 1, resource_type); \ - if (!var) { \ - return 1; \ + if (!var) { \ + return 1; \ } \ } while (0) - + #define PHP_OCI_ZVAL_TO_CONNECTION_EX(zval, connection) \ PHP_OCI_FETCH_RESOURCE_EX(zval, connection, php_oci_connection *, "oci8 connection", le_connection) @@ -339,7 +352,7 @@ #ifdef HAVE_OCI8_ATTR_STATEMENT int php_oci_fetch_sqltext_offset(php_oci_statement *, zstr *, ub2 * TSRMLS_DC); #endif - + void php_oci_do_connect (INTERNAL_FUNCTION_PARAMETERS, int , int); php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC); @@ -348,7 +361,7 @@ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC); int php_oci_password_change(php_oci_connection *, zstr, int, zstr, int, zstr, int, zend_uchar TSRMLS_DC); -int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC); +int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC); void php_oci_fetch_row(INTERNAL_FUNCTION_PARAMETERS, int, int); int php_oci_column_to_zval(php_oci_out_column *, zval *, int TSRMLS_DC); @@ -434,36 +447,30 @@ /* }}} */ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ */ - sword errcode; /* global last error code (used when connect fails, for example) */ - OCIError *err; /* global error handle */ - - /* - char *default_username; - char *default_password; - char *default_dbname; - */ - - zend_bool debug_mode; /* debug mode flag */ - - long max_persistent; /* maximum number of persistent connections per process */ - long num_persistent; /* number of existing persistent connections */ - long num_links; /* non-persistent + persistent connections */ - long num_statements; /* number of statements open */ - long ping_interval; /* time interval between pings */ - long persistent_timeout; /* time period after which idle persistent connection is considered expired */ - long statement_cache_size; /* statement cache size. used with 9i+ clients only*/ - long default_prefetch; /* default prefetch setting */ - zend_bool privileged_connect; /* privileged connect flag (On/Off) */ - zend_bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */ - - int shutdown; /* in shutdown flag */ - - OCIEnv *env; /* global environment handle */ - - zend_bool in_call; - char *connection_class; - zend_bool events; -ZEND_END_MODULE_GLOBALS(oci) /* }}} */ + sword errcode; /* global last error code (used when connect fails, for example) */ + OCIError *err; /* global error handle */ + + zend_bool debug_mode; /* debug mode flag */ + + long max_persistent; /* maximum number of persistent connections per process */ + long num_persistent; /* number of existing persistent connections */ + long num_links; /* non-persistent + persistent connections */ + long num_statements; /* number of statements open */ + long ping_interval; /* time interval between pings */ + long persistent_timeout; /* time period after which idle persistent connection is considered expired */ + long statement_cache_size; /* statement cache size. used with 9i+ clients only*/ + long default_prefetch; /* default prefetch setting */ + zend_bool privileged_connect; /* privileged connect flag (On/Off) */ + zend_bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */ + + int shutdown; /* in shutdown flag */ + + OCIEnv *env; /* global environment handle */ + + zend_bool in_call; + char *connection_class; + zend_bool events; +ZEND_END_MODULE_GLOBALS(oci) /* }}} */ #ifdef ZTS #define OCI_G(v) TSRMG(oci_globals_id, zend_oci_globals *, v) @@ -486,5 +493,3 @@ * c-basic-offset: 4 * End: */ - - http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/README?r1=1.3&r2=1.4&diff_format=u Index: php-src/ext/oci8/README diff -u php-src/ext/oci8/README:1.3 php-src/ext/oci8/README:1.4 --- php-src/ext/oci8/README:1.3 Tue Feb 19 01:44:29 2008 +++ php-src/ext/oci8/README Wed Mar 12 01:25:13 2008 @@ -166,7 +166,7 @@ 6. DRCP and FAN Support ----------------------- -The PHP OCI8 Beta extension has support for the Oracle Database +The PHP 6 OCI8 Beta extension has support for the Oracle Database Resident Connection Pool (DRCP) and Fast Application Notification (FAN). @@ -205,6 +205,25 @@ After building PHP with the OCI8 extension and 11g libraries, follow these steps: +6.2.0 Important: if Oracle Database 11.1.0.6 with DRCP connections is + used, then the Oracle database patch for bug 6474441 must be + applied (see section 6.5) or a workaround below used. Without + this patch, "ORA-01000: maximum open cursors exceeded", "ORA-01001 + invalid cursor" or "ORA-01002 fetch out of sequence" errors may + occur. + + If the Oracle 11.1.0.6 database patch cannot be applied, one of + the following three workarounds can be used to disable statement + caching instead: + + (i) Connect using Oracle dedicated or shared servers instead of DRCP. + + (ii) Set PHP's oci8.statement_cache_size to 0. + + (iii) Set an event in the database initialization parameter file: + event="56699 trace name context forever, level 128". + + 6.2.1. As a privileged database administrator, use a program like SQL*Plus to start the connection pool in the database: @@ -298,55 +317,15 @@ 6.3.4. Run your application, connecting to a 10gR2 or 11g database. -6.4. Changes in this release from PECL OCI8 1.3.0 Beta - -The initial release of OCI8 with DRCP and FAN support was PECL OCI8 -1.3.0 Beta. This section documents differences from that release. - -6.4.1 Statement caching has been re-enabled. - -Important: if Oracle Database 11.1.0.6 with DRCP connections is used, -then the Oracle database patch for bug 6474441 must be applied (see -section 6.5) or a workaround below used. Without this patch, -"ORA-01000: maximum open cursors exceeded", "ORA-01001 invalid cursor" -or "ORA-01002 fetch out of sequence" errors may occur. - -If the Oracle 11.1.0.6 database patch cannot be applied, one of the -following three workarounds can be used to disable statement caching -instead: - -(i) Connect using Oracle dedicated or shared servers instead of DRCP. - -(ii) Set PHP's oci8.statement_cache_size to 0. - -(iii) Set an event in the database initialization parameter file: -event="56699 trace name context forever, level 128". - -6.4.2 Changing Password for non-DRCP connections has been re-enabled. - -When oci_password_change() is successfully performed for non-DRCP -connections in a PHP script, subsequent connections with the new -password from this PHP instance no longer fail with "ORA-1017 invalid -username/password". - -Changing a password over DRCP connections will continue to fail with -the error "ORA-56609: Usage not supported with DRCP". This is an -documented restriction of Oracle Database 11g. - -6.4.3 Oci8.max_persistent setting is re-enabled. - -The php.ini parameter oci8.max_persistent will limit the number of -persistent connections that each PHP process will keep open between -HTTP requests. Any further oci_pconnect() calls once this limit is -reached will be treated as oci_connect() calls. +6.4. Recommendations and Known Limitations -It is still recommended that DRCP users modify the connection pool -settings of the database to control resource usage. Non-DRCP users -should consider setting oci8.persistent_timeout to close idle -connections. +6.4.1 Changing Password for DRCP connections +Changing a password over DRCP connections will fail with the error +"ORA-56609: Usage not supported with DRCP". This is an documented +restriction of Oracle Database 11g. -6.4.4 LOGON Triggers can be used to set session properties +6.4.2 LOGON Triggers can be used to set session properties The patch for Oracle Database 11.1.0.6 bug 6474441 (see section 6.5) allows PHP applications with DRCP connection to use a database LOGON @@ -364,9 +343,9 @@ With DRCP there is an connection management relationship between (i) DRCP's automatic pool expansion and reduction, (ii) PHP's persistent connection caching, (iii) with the way LOGON triggers fire with DRCP -authentication. Because of this interplay, LOGON triggers in PHP when -DRCP is used are only recommended for setting session attributes and -not for per-PHP connection events. +authentication. Because of this interplay, LOGON triggers in PHP +(when DRCP is used) are only recommended for setting session +attributes and not for per-PHP connection events. 6.5. Patching Oracle Database 11g http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/tests/drcp_cclass1.phpt?view=markup&rev=1.1 Index: php-src/ext/oci8/tests/drcp_cclass1.phpt +++ php-src/ext/oci8/tests/drcp_cclass1.phpt --TEST-- DRCP: Test setting connection class inline --SKIPIF-- <?php if (!extension_loaded('oci8')) die ("skip no oci8 extension"); require(__DIR__."/details.inc"); if (!$test_drcp) die("skip testing DRCP connection class only works in DRCP mode"); if (strcasecmp($user, "system") && strcasecmp($user, "sys")) die("skip needs to be run as a DBA user"); ?> --FILE-- <?php require(__DIR__."/details.inc"); // Initialization $t = time(); $cc1 = 'cc1_'.$t; $cc2 = 'cc2_'.$t; // Run Test echo "Test 1\n"; ini_set('oci8.connection_class', $cc1); $c = oci_pconnect($user, $password, $dbase); $s = oci_parse($c, "select * from dual"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); echo "Test 2\n"; ini_set('oci8.connection_class', $cc2); $c = oci_pconnect($user, $password, $dbase); $s = oci_parse($c, "select * from dual"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); echo "Test 3\n"; $s = oci_parse($c, "select cclass_name from v\$cpool_cc_stats where cclass_name like '%.cc__$t'"); oci_execute($s); oci_fetch_all($s, $r); var_dump($r); // Cleanup echo "Done\n"; ?> --EXPECTF-- Test 1 array(1) { ["DUMMY"]=> array(1) { [0]=> string(1) "X" } } Test 2 array(1) { ["DUMMY"]=> array(1) { [0]=> string(1) "X" } } Test 3 array(1) { ["CCLASS_NAME"]=> array(2) { [0]=> string(21) "%s.cc1_%d" [1]=> string(21) "%s.cc2_%d" } } Done --UEXPECTF-- Test 1 array(1) { [u"DUMMY"]=> array(1) { [0]=> unicode(1) "X" } } Test 2 array(1) { [u"DUMMY"]=> array(1) { [0]=> unicode(1) "X" } } Test 3 array(1) { [u"CCLASS_NAME"]=> array(2) { [0]=> unicode(21) "%s.cc1_%d" [1]=> unicode(21) "%s.cc2_%d" } } Done