php-src/ext/oracle/oci8.c
Zeev Suraski bc415d5a88 * Finalizing the PHP version of SAPI. Support POST and cookies among other things.
* Fully implement ISAPI support - POST and cookies among other things.
* Almost completely rewrote phpinfo().  Allow modules to easily display their
  information in phpinfo() without modifying phpinfo() itself (prototype for
  the module info function was changed, thus the large amount of updated module
  files).
* Initial extended SAPI support for Apache, completely untested.
* CGI now uses SAPI fully as well.
1999-05-09 08:48:05 +00:00

3594 lines
92 KiB
C

/*
+----------------------------------------------------------------------+
| PHP HTML Embedded Scripting Language Version 3.0 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-1999 PHP Development Team (See Credits file) |
+----------------------------------------------------------------------+
| This program is free software; you can redistribute it and/or modify |
| it under the terms of one of the following licenses: |
| |
| A) the GNU General Public License as published by the Free Software |
| Foundation; either version 2 of the License, or (at your option) |
| any later version. |
| |
| B) the PHP License as published by the PHP Development Team and |
| included in the distribution in the file: LICENSE |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of both licenses referred to here. |
| If you did not, or have any questions about PHP licensing, please |
| contact core@php.net. |
+----------------------------------------------------------------------+
| Authors: Stig Sæther Bakken <ssb@fast.no> |
| Thies C. Arntzen <thies@digicol.de> |
| |
| Initial work sponsored by |
| Digital Collections, http://www.digicol.de/ |
+----------------------------------------------------------------------+
*/
#define OCI8_USE_EMALLOC 0 /* set this to 1 if you want to use the php memory manager! */
/* $Id$ */
/* TODO list:
*
* - better oracle-error handling.
* - Commit/Rollback testing.....
* - php.ini flags
* - Error mode (print or shut up?)
* - returning refcursors as statement handles
* - OCIPasswordChange()
* - Prefetching control
* - LONG, LONG RAW, RAW is now limited to 2MB (should be user-settable);
* - binding of arrays
* - Truncate input values to the bind size
* - Character sets for NCLOBS
* - piecewise operation for longs, lobs etc
* - split the module into an upper (php-callable) and lower (c-callable) layer!
* - make_pval needs some cleanup....
* - NULLS (retcode/indicator) needs some more work for describing & binding
* - remove all XXXs
* - clean up and documentation
* - there seems to be a bug in OCI where it returns ORA-01406 (value truncated) - whereby it isn't (search for 01406 in the source)
* this seems to happen for NUMBER values only...
* - make OCIInternalDebug accept a mask of flags....
* - better NULL handling
* - add some flags to OCIFetchStatement (maxrows etc...)
*/
/* {{{ includes & stuff */
#if defined(COMPILE_DL)
# ifdef THREAD_SAFE
# undef THREAD_SAFE /* XXX no need in 3.0 */
# endif
# include "dl/phpdl.h"
#endif
#include "php.h"
#if PHP_API_VERSION < 19990421
#include "internal_functions.h"
#include "php3_list.h"
#include "head.h"
#endif
#include "php3_oci8.h"
#if HAVE_OCI8
/* XXXXXXXXXXXXXXXXXXXXXXXx
this is needed due to a brain-dead change in the ocidfn.h header
somewhere between 8.0.3 and 8.0.5 - sorry no consistend way to
do it. (thies@digicol.de)
*/
#ifndef SQLT_BFILEE
#define SQLT_BFILEE 114
#endif
#ifndef SQLT_CFILEE
#define SQLT_CFILEE 115
#endif
#define SAFE_STRING(s) ((s)?(s):"")
#if !(WIN32|WINNT)
# include "build-defs.h"
#endif
#include "snprintf.h"
/* }}} */
/* {{{ thread safety stuff */
#ifdef THREAD_SAFE
# define OCI8_GLOBAL(a) oci8_globals->a
# define OCI8_TLS_VARS oci8_global_struct *oci8_globals = TlsGetValue(OCI8Tls);
void *oci8_mutex;
DWORD OCI8Tls;
static int numthreads=0;
typedef struct oci8_global_struct {
oci8_module php3_oci8_module;
} oci8_global_struct;
#else /* !defined(THREAD_SAFE) */
# define OCI8_GLOBAL(a) a
# define OCI8_TLS_VARS
oci8_module php3_oci8_module;
#endif /* defined(THREAD_SAFE) */
/* }}} */
/* {{{ dynamically loadable module stuff */
#if COMPILE_DL
DLEXPORT php3_module_entry *get_module() { return &oci8_module_entry; };
# if (WIN32|WINNT) && defined(THREAD_SAFE)
/* NOTE: You should have an oci8.def file where you export DllMain */
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
if ((OCI8Tls = TlsAlloc()) == 0xFFFFFFFF){
return 0;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (!TlsFree(OCI8Tls)) {
return 0;
}
break;
}
return 1;
}
# endif /* thread safe on Windows */
#endif /* COMPILE_DL */
/* }}} */
/* {{{ startup/shutdown/info/internal function prototypes */
int php3_minit_oci8(INIT_FUNC_ARGS);
int php3_rinit_oci8(INIT_FUNC_ARGS);
int php3_mshutdown_oci8(SHUTDOWN_FUNC_ARGS);
int php3_rshutdown_oci8(SHUTDOWN_FUNC_ARGS);
void php3_info_oci8(ZEND_MODULE_INFO_FUNC_ARGS);
static ub4 oci8_error(OCIError *err_p, char *what, sword status);
/* static int oci8_ping(oci8_connection *conn); XXX NYI */
static void oci8_debug(const char *format,...);
static void _oci8_close_conn(oci8_connection *connection);
static void _oci8_free_stmt(oci8_statement *statement);
static void _oci8_free_column(oci8_out_column *column);
static void _oci8_free_descr(oci8_descriptor *descr);
static oci8_connection *oci8_get_conn(int, const char *, HashTable *);
static oci8_statement *oci8_get_stmt(int, const char *, HashTable *);
static oci8_out_column *oci8_get_col(oci8_statement *, int, pval *, char *);
static int oci8_make_pval(pval *,oci8_statement *,oci8_out_column *, char *,HashTable *, int mode);
static int oci8_parse(oci8_connection *, text *, ub4, HashTable *);
static int oci8_execute(oci8_statement *, char *,ub4 mode);
static int oci8_fetch(oci8_statement *, ub4, char *);
static ub4 oci8_loaddesc(oci8_connection *, oci8_descriptor *, char **);
static void oci8_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent);
/* ServerAttach/Detach */
static oci8_server *oci8_open_server(char *dbname,int persistent);
static void _oci8_close_server(oci8_server *server);
/* SessionBegin/End */
static oci8_session *oci8_open_user(oci8_server* server,char *username,char *password,int persistent);
static void _oci8_close_user(oci8_session *session);
/* bind callback functions */
static sb4 oci8_bind_in_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 *, ub1 *, dvoid **);
static sb4 oci8_bind_out_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **);
/* define callback function */
static sb4 oci8_define_callback(dvoid *, OCIDefine *, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **);
/* failover callback function */
static sb4 oci8_failover_callback(dvoid *svchp,dvoid* envhp,dvoid *fo_ctx,ub4 fo_type, ub4 fo_event);
/* }}} */
/* {{{ extension function prototypes */
void php3_oci8_bindbyname(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_definebyname(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_columnisnull(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_columnname(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_columnsize(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_columntype(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_execute(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_fetch(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_fetchinto(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_fetchstatement(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_freestatement(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_internaldebug(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_logout(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_logon(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_plogon(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_error(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_freedesc(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_savedesc(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_loaddesc(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_commit(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_rollback(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_newtrans(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_settrans(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_newdescriptor(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_numcols(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_parse(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_result(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_serverversion(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_statementtype(INTERNAL_FUNCTION_PARAMETERS);
void php3_oci8_rowcount(INTERNAL_FUNCTION_PARAMETERS);
/* }}} */
/* {{{ extension definition structures */
#define OCI_ASSOC 1<<0
#define OCI_NUM 1<<1
#define OCI_BOTH (OCI_ASSOC|OCI_NUM)
#define OCI_RETURN_NULLS 1<<2
#define OCI_RETURN_LOBS 1<<3
static unsigned char a3_arg_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
static unsigned char a2_arg_force_ref[] = { 2, BYREF_NONE, BYREF_FORCE };
function_entry oci8_functions[] = {
{"ocidefinebyname", php3_oci8_definebyname, a3_arg_force_ref},
{"ocibindbyname", php3_oci8_bindbyname, a3_arg_force_ref},
{"ocicolumnisnull", php3_oci8_columnisnull, NULL},
{"ocicolumnname", php3_oci8_columnname, NULL},
{"ocicolumnsize", php3_oci8_columnsize, NULL},
{"ocicolumntype", php3_oci8_columntype, NULL},
{"ociexecute", php3_oci8_execute, NULL},
{"ocifetch", php3_oci8_fetch, NULL},
{"ocifetchinto", php3_oci8_fetchinto, a2_arg_force_ref},
{"ocifetchstatement",php3_oci8_fetchstatement,a2_arg_force_ref},
{"ocifreestatement", php3_oci8_freestatement, NULL},
{"ociinternaldebug", php3_oci8_internaldebug, NULL},
{"ocinumcols", php3_oci8_numcols, NULL},
{"ociparse", php3_oci8_parse, NULL},
{"ociresult", php3_oci8_result, NULL},
{"ociserverversion", php3_oci8_serverversion, NULL},
{"ocistatementtype", php3_oci8_statementtype, NULL},
{"ocirowcount", php3_oci8_rowcount, NULL},
{"ocilogoff", php3_oci8_logout, NULL},
{"ocilogon", php3_oci8_logon, NULL},
{"ociplogon", php3_oci8_plogon, NULL},
{"ocierror", php3_oci8_error, NULL},
{"ocifreedescriptor",php3_oci8_freedesc, NULL},
{"ocisavedesc", php3_oci8_savedesc, NULL},
{"ociloaddesc", php3_oci8_loaddesc, NULL},
{"ocicommit", php3_oci8_commit, NULL},
{"ocirollback", php3_oci8_rollback, NULL},
{"ocinewtransaction",php3_oci8_newtrans, NULL},
{"ocisettransaction",php3_oci8_settrans, NULL},
{"ocinewdescriptor", php3_oci8_newdescriptor, NULL},
{NULL, NULL, NULL}
};
php3_module_entry oci8_module_entry = {
"OCI8", /* extension name */
oci8_functions, /* extension function list */
php3_minit_oci8, /* extension-wide startup function */
php3_mshutdown_oci8, /* extension-wide shutdown function */
php3_rinit_oci8, /* per-request startup function */
php3_rshutdown_oci8, /* per-request shutdown function */
php3_info_oci8, /* information function */
STANDARD_MODULE_PROPERTIES
};
/* }}} */
/* {{{ debug malloc/realloc/free */
#if OCI8_USE_EMALLOC
CONST dvoid *ocimalloc(dvoid *ctx, size_t size)
{
dvoid *ret;
ret = (dvoid *)malloc(size);
oci8_debug("ocimalloc(%d) = %08x", size,ret);
return ret;
}
CONST dvoid *ocirealloc(dvoid *ctx, dvoid *ptr, size_t size)
{
dvoid *ret;
oci8_debug("ocirealloc(%08x, %d)", ptr, size);
ret = (dvoid *)realloc(ptr, size);
return ptr;
}
CONST void ocifree(dvoid *ctx, dvoid *ptr)
{
oci8_debug("ocifree(%08x)", ptr);
free(ptr);
}
#endif
/* }}} */
/* {{{ startup, shutdown and info functions */
int php3_minit_oci8(INIT_FUNC_ARGS)
{
#ifdef THREAD_SAFE
oci8_global_struct *oci8_globals;
# if !COMPILE_DL
# if WIN32|WINNT
CREATE_MUTEX(oci8_mutex,"OCI8_TLS");
# endif
SET_MUTEX(oci8_mutex);
numthreads++;
if (numthreads == 1) {
if ((OCI8Tls = TlsAlloc()) == 0xFFFFFFFF){
FREE_MUTEX(oci8_mutex);
return 0;
}
}
FREE_MUTEX(oci8_mutex);
# endif /* !COMPILE_DL */
oci8_globals =
(oci8_global_struct *) LocalAlloc(LPTR, sizeof(oci8_global_struct));
TlsSetValue(OCI8Tls, (void *) oci8_globals);
#endif /* THREAD_SAFE */
/* XXX NYI
if (cfg_get_long("oci8.allow_persistent",
&OCI8_GLOBAL(php3_oci8_module).allow_persistent)
== FAILURE) {
OCI8_GLOBAL(php3_oci8_module).allow_persistent = -1;
}
if (cfg_get_long("oci8.max_persistent",
&OCI8_GLOBAL(php3_oci8_module).max_persistent)
== FAILURE) {
OCI8_GLOBAL(php3_oci8_module).max_persistent = -1;
}
if (cfg_get_long("oci8.max_links",
&OCI8_GLOBAL(php3_oci8_module).max_links)
== FAILURE) {
OCI8_GLOBAL(php3_oci8_module).max_links = -1;
}
OCI8_GLOBAL(php3_oci8_module).num_persistent = 0;
*/
OCI8_GLOBAL(php3_oci8_module).user_num = 1000;
OCI8_GLOBAL(php3_oci8_module).server_num = 2000;
OCI8_GLOBAL(php3_oci8_module).le_conn = register_list_destructors(_oci8_close_conn, NULL);
OCI8_GLOBAL(php3_oci8_module).le_stmt = register_list_destructors(_oci8_free_stmt, NULL);
OCI8_GLOBAL(php3_oci8_module).user = malloc(sizeof(HashTable));
_php3_hash_init(OCI8_GLOBAL(php3_oci8_module).user, 13, NULL, NULL, 1);
OCI8_GLOBAL(php3_oci8_module).server = malloc(sizeof(HashTable));
_php3_hash_init(OCI8_GLOBAL(php3_oci8_module).server, 13, NULL, NULL, 1);
if (cfg_get_long("oci8.debug_mode",
&OCI8_GLOBAL(php3_oci8_module).debug_mode) == FAILURE) {
OCI8_GLOBAL(php3_oci8_module).debug_mode = 0;
}
/* thies@digicol.de 990203 i do not think that we will need all of them - just in here for completeness for now! */
REGISTER_LONG_CONSTANT("OCI_DEFAULT",OCI_DEFAULT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_DESCRIBE_ONLY",OCI_DESCRIBE_ONLY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_COMMIT_ON_SUCCESS",OCI_COMMIT_ON_SUCCESS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_EXACT_FETCH",OCI_EXACT_FETCH, CONST_CS | CONST_PERSISTENT);
/* 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("OCI_B_BFILE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_B_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_B_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_B_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_B_ROWID",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
/* for OCIFetchInto & OCIResult */
REGISTER_LONG_CONSTANT("OCI_ASSOC",OCI_ASSOC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_NUM",OCI_NUM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_BOTH",OCI_BOTH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT);
/* 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);
REGISTER_LONG_CONSTANT("OCI_D_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_D_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OCI_D_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);
#if OCI8_USE_EMALLOC
OCIInitialize(OCI_DEFAULT, NULL, ocimalloc, ocirealloc, ocifree);
#else
OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL);
#endif
OCIEnvInit(&OCI8_GLOBAL(php3_oci8_module).pEnv, OCI_DEFAULT, 0, NULL);
return SUCCESS;
}
/* ----------------------------------------------------------------- */
int php3_rinit_oci8(INIT_FUNC_ARGS)
{
OCI8_TLS_VARS;
/* XXX NYI
OCI8_GLOBAL(php3_oci8_module).num_links =
OCI8_GLOBAL(php3_oci8_module).num_persistent;
*/
OCI8_GLOBAL(php3_oci8_module).debug_mode = 0; /* start "fresh" */
oci8_debug("php3_rinit_oci8");
return SUCCESS;
}
static int _user_pcleanup(oci8_session *session)
{
_oci8_close_user(session);
return 0;
}
static int _server_pcleanup(oci8_server *server)
{
_oci8_close_server(server);
return 0;
}
int php3_mshutdown_oci8(SHUTDOWN_FUNC_ARGS)
{
oci8_debug("php3_mshutdown_oci8");
_php3_hash_apply(OCI8_GLOBAL(php3_oci8_module).user,(int (*)(void *))_user_pcleanup);
_php3_hash_apply(OCI8_GLOBAL(php3_oci8_module).server,(int (*)(void *))_server_pcleanup);
_php3_hash_destroy(OCI8_GLOBAL(php3_oci8_module).user);
_php3_hash_destroy(OCI8_GLOBAL(php3_oci8_module).server);
free(OCI8_GLOBAL(php3_oci8_module).user);
free(OCI8_GLOBAL(php3_oci8_module).server);
OCIHandleFree((dvoid *) &OCI8_GLOBAL(php3_oci8_module).pEnv, OCI_HTYPE_ENV);
#ifdef THREAD_SAFE
oci8_global_struct *oci8_globals;
oci8_globals = TlsGetValue(OCI8Tls);
if (oci8_globals != 0) {
LocalFree((HLOCAL) oci8_globals);
}
#if !COMPILE_DL
SET_MUTEX(oci8_mutex);
numthreads--;
if (!numthreads) {
if (!TlsFree(OCI8Tls)) {
FREE_MUTEX(oci8_mutex);
return 0;
}
}
FREE_MUTEX(oci8_mutex);
#endif
#endif
return SUCCESS;
}
static int _user_cleanup(oci8_session *session)
{
if (session->persistent)
return 0;
_oci8_close_user(session);
return 0;
}
static int _server_cleanup(oci8_server *server)
{
if (server->persistent)
return 0;
_oci8_close_server(server);
return 0;
}
int php3_rshutdown_oci8(SHUTDOWN_FUNC_ARGS)
{
OCI8_TLS_VARS;
oci8_debug("php3_rshutdown_oci8");
_php3_hash_apply(OCI8_GLOBAL(php3_oci8_module).user,(int (*)(void *))_user_cleanup);
_php3_hash_apply(OCI8_GLOBAL(php3_oci8_module).server,(int (*)(void *))_server_cleanup);
/* XXX free all statements, rollback all outstanding transactions */
return SUCCESS;
}
void php3_info_oci8(ZEND_MODULE_INFO_FUNC_ARGS)
{
#if !(WIN32|WINNT)
php3_printf("Oracle version: %s<br>\n"
"Compile-time ORACLE_HOME: %s<br>\n"
"Libraries used: %s",
PHP_ORACLE_VERSION, PHP_ORACLE_HOME, PHP_ORACLE_LIBS);
#endif
}
/* }}} */
/* {{{ oci8_free_define() */
static int
oci8_free_define(oci8_define *define)
{
oci8_debug("oci8_free_define: %s",define->name);
if (define->name) {
efree(define->name);
define->name = 0;
}
return 0;
}
/* }}} */
/* {{{ _oci8_free_column() */
static void
_oci8_free_column(oci8_out_column *column)
{
if (! column) {
return;
}
oci8_debug("_oci8_free_column: %s",column->name);
if (column->data) {
if (column->is_descr) {
_php3_hash_index_del(column->statement->conn->descriptors,(int) column->data);
} else {
if ((! column->define) && column->data) {
efree(column->data);
}
}
}
if (column->name) {
efree(column->name);
}
/* efree(column); XXX php cleares this for us */
}
/* }}} */
/* {{{ _oci8_free_stmt() */
static void
_oci8_free_stmt(oci8_statement *statement)
{
OCI8_TLS_VARS;
if (! statement) {
return;
}
oci8_debug("_oci8_free_stmt: id=%d last_query=\"%s\"",
statement->id,
(statement->last_query?(char*)statement->last_query:"???"));
if (statement->pStmt) {
OCIHandleFree(statement->pStmt, OCI_HTYPE_STMT);
statement->pStmt = 0;
}
if (statement->pError) {
OCIHandleFree(statement->pError, OCI_HTYPE_ERROR);
statement->pError = 0;
}
if (statement->last_query) {
efree(statement->last_query);
}
if (statement->columns) {
_php3_hash_destroy(statement->columns);
efree(statement->columns);
}
if (statement->binds) {
_php3_hash_destroy(statement->binds);
efree(statement->binds);
}
if (statement->defines) {
_php3_hash_destroy(statement->defines);
efree(statement->defines);
}
efree(statement);
}
/* }}} */
/* {{{ _oci8_close_conn() */
static void
_oci8_close_conn(oci8_connection *connection)
{
OCI8_TLS_VARS;
if (! connection) {
return;
}
/*
as the connection is "only" a in memory service context we do not disconnect from oracle.
*/
oci8_debug("_oci8_close_conn: id=%d",connection->id);
if (connection->descriptors) {
_php3_hash_destroy(connection->descriptors);
efree(connection->descriptors);
}
if (connection->pServiceContext) {
OCIHandleFree((dvoid *) connection->pServiceContext, (ub4) OCI_HTYPE_SVCCTX);
}
if (connection->pError) {
OCIHandleFree((dvoid *) connection->pError, (ub4) OCI_HTYPE_ERROR);
}
efree(connection);
}
/* }}} */
/* {{{ oci8_error() */
static ub4
oci8_error(OCIError *err_p, char *what, sword status)
{
text errbuf[512];
ub4 errcode = 0;
switch (status) {
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
php3_error(E_WARNING, "%s: OCI_SUCCESS_WITH_INFO", what);
break;
case OCI_NEED_DATA:
php3_error(E_WARNING, "%s: OCI_NEED_DATA", what);
break;
case OCI_NO_DATA:
php3_error(E_WARNING, "%s: OCI_NO_DATA", what);
break;
case OCI_ERROR:
OCIErrorGet(err_p, (ub4)1, NULL, &errcode, errbuf,
(ub4)sizeof(errbuf), (ub4)OCI_HTYPE_ERROR);
php3_error(E_WARNING, "%s: %s", what, errbuf);
break;
case OCI_INVALID_HANDLE:
php3_error(E_WARNING, "%s: OCI_INVALID_HANDLE", what);
break;
case OCI_STILL_EXECUTING:
php3_error(E_WARNING, "%s: OCI_STILL_EXECUTING", what);
break;
case OCI_CONTINUE:
php3_error(E_WARNING, "%s: OCI_CONTINUE", what);
break;
default:
break;
}
return errcode;
}
/* }}} */
/* {{{ NYI oci8_ping() */
#if 0 /* XXX NYI */
/* test if a connection is still alive and return 1 if it is */
static int oci8_ping(oci8_connection *conn)
{
/* XXX FIXME not yet implemented */
return 1;
}
#endif
/* }}} */
/************************* INTERNAL FUNCTIONS *************************/
/* {{{ oci8_debugcol() */
#if 0
static void oci8_debugcol(oci8_out_column *column,const char *format,...)
{
OCI8_TLS_VARS;
if (OCI8_GLOBAL(php3_oci8_module).debug_mode) {
char buffer[1024];
char colbuffer[1024];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer)-1, format, args);
va_end(args);
buffer[sizeof(buffer)-1] = '\0';
sprintf(colbuffer,"name=%s,type=%d,size4=%ld,size2=%d,storage_size4=%ld,indicator=%d,retcode=%d,rlen=%ld",
column->name,column->type,column->size4,column->size2,column->storage_size4,column->indicator,column->retcode,column->rlen);
if (php3_header()) {
php3_printf("OCIDebug:%s - %s<br>\n",buffer,colbuffer);
}
}
}
#endif
/* }}} */
/* {{{ oci8_debug() */
static void oci8_debug(const char *format,...)
{
OCI8_TLS_VARS;
if (OCI8_GLOBAL(php3_oci8_module).debug_mode) {
char buffer[1024];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer)-1, format, args);
va_end(args);
buffer[sizeof(buffer)-1] = '\0';
if (php3_header()) {
php3_printf("OCIDebug: %s<br>\n", buffer);
}
}
}
/* }}} */
/* {{{ oci8_get_conn() */
static oci8_connection *
oci8_get_conn(int conn_ind, const char *func, HashTable *list)
{
int type;
oci8_connection *connection;
OCI8_TLS_VARS;
connection = (oci8_connection *)php3_list_find(conn_ind, &type);
if (!connection || !OCI8_CONN_TYPE(type)) {
php3_error(E_WARNING, "%s: invalid connection %d", func, conn_ind);
return (oci8_connection *)NULL;
}
if (connection->open) {
return connection;
} else {
/* _oci8_close_conn(connection); be careful with this!! */
return (oci8_connection *)NULL;
}
}
/* }}} */
/* {{{ oci8_get_stmt() */
static oci8_statement *
oci8_get_stmt(int stmt_ind, const char *func, HashTable *list)
{
int type;
oci8_statement *statement;
OCI8_TLS_VARS;
statement = (oci8_statement *)php3_list_find(stmt_ind, &type);
if (!statement || !OCI8_STMT_TYPE(type)) {
php3_error(E_WARNING, "%s: invalid statement %d", func, stmt_ind);
return (oci8_statement *)NULL;
}
if (statement->conn->open) {
return statement;
} else {
/* _oci8_free_stmt(statement); be careful with this!! */
return (oci8_statement *)NULL;
}
}
/* }}} */
/* {{{ oci8_get_col() */
static oci8_out_column *
oci8_get_col(oci8_statement *statement, int col, pval *pval, char *func)
{
oci8_out_column *outcol = NULL;
int i;
OCI8_TLS_VARS;
if (pval) {
if (pval->type == IS_STRING) {
for (i = 0; i < statement->ncolumns; i++) {
outcol = oci8_get_col(statement, i + 1, 0, func);
if (outcol == NULL) {
continue;
} else if (((int) outcol->name_len == pval->value.str.len)
&& (! strncmp(outcol->name,pval->value.str.val,pval->value.str.len))) {
return outcol;
}
}
} else {
convert_to_long(pval);
return oci8_get_col(statement,pval->value.lval,0,func);
}
} else if (col != -1) {
if (_php3_hash_index_find(statement->columns, col, (void **)&outcol) == FAILURE) {
php3_error(E_WARNING, "%s: invalid column %d", func, col);
return NULL;
}
return outcol;
}
return NULL;
}
/* }}} */
/* {{{ oci8_make_pval() */
static int
oci8_make_pval(pval *value,oci8_statement *statement,oci8_out_column *column, char *func,HashTable *list, int mode)
{
size_t size;
oci8_descriptor *descr;
ub4 loblen;
char *buffer;
/*
oci8_debug("oci8_make_pval: %16s,rlen = %4d,storage_size4 = %4d,size2 = %4d,indicator %4d, retcode = %4d",
column->name,column->rlen,column->storage_size4,column->size2,column->indicator,column->retcode);
*/
memset(value,0,sizeof(pval));
if (column->indicator == -1) { /* column is NULL */
var_reset(value); /* XXX we NEED to make sure that there's no data attached to this yet!!! */
return 0;
}
if (column->is_descr) {
if ((column->type != SQLT_RDD) && (mode & OCI_RETURN_LOBS)) {
/* OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
if (_php3_hash_index_find(statement->conn->descriptors,(int) column->data, (void **)&descr) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor %d",column->data);
return -1;
}
loblen = oci8_loaddesc(statement->conn,descr,&buffer);
if (loblen > 0) {
value->type = IS_STRING;
value->value.str.len = loblen;
value->value.str.val = buffer;
#if PHP_API_VERSION >= 19990421
value->refcount = 1;
value->is_ref = 0;
#endif
} else {
var_reset(value);
}
} else { /* return the locator */
object_init(value);
add_property_long(value, "connection", statement->conn->id);
add_property_long(value, "descriptor", (long) column->data);
if (column->type != SQLT_RDD) { /* ROWIDs don't have any user-callable methods */
if ((column->type != SQLT_BFILEE) && (column->type != SQLT_CFILEE)) {
add_method(value, "save", php3_oci8_savedesc); /* oracle does not support writing of files as of now */
}
add_method(value, "load", php3_oci8_loaddesc);
}
/* there is NO free call here, 'cause the memory gets deallocated together with the statement! */
}
} else {
switch (column->retcode) {
case 1406: /* ORA-01406 XXX truncated value */
/* this seems to be a BUG in oracle with 1-digit numbers */
/*
oci8_debugcol(column,"truncated");
*/
size = column->indicator - 1; /* when value is truncated indicator contains the lenght */
break;
case 0: /* intact value */
/*
oci8_debugcol(column,"OK");
*/
size = column->rlen;
break;
default: /* XXX we SHOULD maybe have a different behaviour for unknown results! */
var_reset(value);
return 0;
}
value->type = IS_STRING;
value->value.str.len = size;
value->value.str.val = estrndup(column->data,size);
#if PHP_API_VERSION >= 19990421
value->refcount = 1;
value->is_ref = 0;
#endif
}
return 0;
}
/* }}} */
/* {{{ oci8_parse() */
static int
oci8_parse(oci8_connection *connection, text *query, ub4 len, HashTable *list)
{
oci8_statement *statement;
sword error;
OCI8_TLS_VARS;
statement = ecalloc(1,sizeof(oci8_statement));
OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&statement->pStmt,
OCI_HTYPE_STMT,
0,
NULL);
OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&statement->pError,
OCI_HTYPE_ERROR,
0,
NULL);
error = oci8_error(statement->pError, "OCIParse",
OCIStmtPrepare(statement->pStmt, connection->pError,
query, len,
OCI_NTV_SYNTAX, OCI_DEFAULT));
if (error) {
return 0;
}
#if 0 /* testing */
{ ub4 prefetch = 10*1024;
error = oci8_error(statement->pError, "OCIAttrSet OCI_ATTR_PREFETCH_ROWS",
OCIAttrSet(statement->pStmt,OCI_HTYPE_STMT,&prefetch,0,OCI_ATTR_PREFETCH_MEMORY,&statement->pError));
}
#endif
statement->last_query = estrdup(query);
statement->conn = connection;
statement->id = php3_list_insert(statement, OCI8_GLOBAL(php3_oci8_module).le_stmt);
oci8_debug("oci8_parse \"%s\" id=%d conn=%d",
query,
statement->id,
statement->conn->id);
return statement->id;
}
/* }}} */
/* {{{ oci8_execute() */
static int
oci8_execute(oci8_statement *statement, char *func,ub4 mode)
{
oci8_out_column *outcol;
oci8_out_column column;
OCIParam *param = 0;
text *colname;
ub4 counter;
sword error;
ub2 define_type;
ub2 stmttype;
ub4 iters;
ub4 colcount;
ub2 storage_size2;
OCI8_TLS_VARS;
error = oci8_error(
statement->pError,
"OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_STMT_TYPE",
OCIAttrGet(
(dvoid *)statement->pStmt,
OCI_HTYPE_STMT,
(ub2 *)&stmttype,
(ub4 *)0,
OCI_ATTR_STMT_TYPE,
statement->pError));
if (error) {
return 0;
}
if (stmttype == OCI_STMT_SELECT) {
iters = 0;
} else {
iters = 1;
}
error = oci8_error(
statement->pError,
"OCIStmtExecute",
OCIStmtExecute(
statement->conn->pServiceContext,
statement->pStmt,
statement->pError,
iters,
0,
NULL,
NULL,
mode));
switch (error) {
case 0:
break;
case 3113: /* ORA-03113: end-of-file on communication channel */
statement->conn->open = 0;
statement->conn->session->open = 0;
statement->conn->session->server->open = 0;
return 0;
break;
}
if (stmttype == OCI_STMT_SELECT && (statement->executed == 0)) {
/* we only need to do the define step is this very statement is executed the first time! */
statement->executed++;
statement->columns = emalloc(sizeof(HashTable));
if (!statement->columns ||
_php3_hash_init(statement->columns, 13, NULL,(void (*)(void *))_oci8_free_column, 0) == FAILURE) {
/* out of memory */
return 0;
}
OCIHandleAlloc(
OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&param,
OCI_DTYPE_PARAM,
0,
NULL);
counter = 1;
error = oci8_error(
statement->pError,
"OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_PARAM_COUNT",
OCIAttrGet(
(dvoid *)statement->pStmt,
OCI_HTYPE_STMT,
(dvoid *)&colcount,
(ub4 *)0,
OCI_ATTR_PARAM_COUNT,
statement->pError));
if (error) {
return 0; /* XXX we loose memory!!! */
}
statement->ncolumns = colcount;
for (counter = 1; counter <= colcount; counter++) {
memset(&column,0,sizeof(oci8_out_column));
if (_php3_hash_index_update(statement->columns, counter, &column,
sizeof(oci8_out_column), (void**) &outcol) == FAILURE) {
efree(statement->columns);
/* out of memory */
return 0;
}
outcol->statement = statement;
error = oci8_error(
statement->pError,
"OCIParamGet OCI_HTYPE_STMT",
OCIParamGet(
(dvoid *)statement->pStmt,
OCI_HTYPE_STMT,
statement->pError,
(dvoid*)&param,
counter));
if (error) {
return 0; /* XXX we loose memory!!! */
}
error = oci8_error(
statement->pError,
"OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_TYPE",
OCIAttrGet(
(dvoid *)param,
OCI_DTYPE_PARAM,
(dvoid *)&outcol->type,
(ub4 *)0,
OCI_ATTR_DATA_TYPE,
statement->pError));
if (error) {
return 0; /* XXX we loose memory!!! */
}
error = oci8_error(
statement->pError,
"OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_SIZE",
OCIAttrGet(
(dvoid *)param,
OCI_DTYPE_PARAM,
(dvoid *)&storage_size2,
(dvoid *)0,
OCI_ATTR_DATA_SIZE,
statement->pError));
if (error) {
return 0; /* XXX we loose memory!!! */
}
outcol->storage_size4 = storage_size2;
error = oci8_error(
statement->pError,
"OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_NAME",
OCIAttrGet(
(dvoid *)param,
OCI_DTYPE_PARAM,
(dvoid **)&colname, /* XXX this string is NOT zero terminated!!!! */
(ub4 *)&outcol->name_len,
(ub4)OCI_ATTR_NAME,
statement->pError));
if (error) {
return 0; /* XXX we loose memory!!! */
}
outcol->name = estrndup(colname,outcol->name_len);
/* Remember the size Oracle told us, we have to increase the
* storage size for some types.
*/
outcol->size4 = outcol->storage_size4;
/* find a user-setted define */
if (statement->defines) {
_php3_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define);
}
switch (outcol->type) {
case SQLT_RSET: /* ref. cursor XXX NYI */
define_type = -1;
break;
case SQLT_RDD: /* ROWID */
case SQLT_BLOB: /* binary LOB */
case SQLT_CLOB: /* character LOB */
case SQLT_BFILE: /* binary file LOB */
define_type = outcol->type;
outcol->is_descr = 1;
outcol->storage_size4 = -1;
break;
case SQLT_LBI:
case SQLT_LNG:
case SQLT_BIN:
define_type = SQLT_STR;
/* XXX this should be user-settable!! */
outcol->storage_size4 = OCI8_MAX_DATA_SIZE; /* 2MB */
break;
default:
define_type = SQLT_STR;
if ((outcol->type == SQLT_DAT) || (outcol->type == SQLT_NUM)) {
outcol->storage_size4 = 256; /* XXX this should fit "most" NLS date-formats and Numbers */
} else {
outcol->storage_size4++; /* add one for string terminator */
}
break;
}
error = oci8_error(
statement->pError,
"OCIDefineByPos",
OCIDefineByPos(
statement->pStmt, /* IN/OUT handle to the requested SQL query */
(OCIDefine **)&outcol->pDefine, /* IN/OUT pointer to a pointer to a define handle */
statement->pError, /* IN/OUT An error handle */
counter, /* IN position in the select list */
(dvoid *)0, /* IN/OUT pointer to a buffer */
outcol->storage_size4, /* IN The size of each valuep buffer in bytes */
define_type, /* IN The data type */
(dvoid *)&outcol->indicator, /* IN pointer to an indicator variable or arr */
(ub2 *)&outcol->size2, /* IN/OUT Pointer to array of length of data fetched */
(ub2 *)&outcol->retcode, /* OUT Pointer to array of column-level return codes */
OCI_DYNAMIC_FETCH)); /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
if (error) {
return 0; /* XXX we loose memory!!! */
}
error = oci8_error(
statement->pError,
"OCIDefineDynamic",
OCIDefineDynamic(
outcol->pDefine,
statement->pError,
outcol,
oci8_define_callback));
if (error) {
return 0; /* XXX we loose memory!!! */
}
}
}
return 1;
}
/* }}} */
/* {{{ oci8_fetch() */
static int
oci8_fetch(oci8_statement *statement, ub4 nrows, char *func)
{
sword error;
int i;
oci8_out_column *column;
pval *pval;
OCI8_TLS_VARS;
error = OCIStmtFetch(statement->pStmt, statement->pError, nrows,
OCI_FETCH_NEXT, OCI_DEFAULT);
if (error == OCI_NO_DATA) {
return 0;
}
if (error == OCI_SUCCESS_WITH_INFO || error == OCI_SUCCESS) {
/* do the stuff needed for OCIDefineByName */
for (i = 0; i < statement->ncolumns; i++) {
column = oci8_get_col(statement, i + 1, 0, "OCIFetch");
if (column == NULL) { /* should not happen... */
continue;
}
if ((column->define) && (! column->is_descr)) {
pval = column->define->pval;
if (! column->define->data) { /* oracle has NOT called our define_callback (column value is NULL) */
pval->value.str.val = emalloc(column->storage_size4);
column->define->data = pval->value.str.val;
}
if (column->indicator == -1) { /* NULL */
pval->value.str.len = 0;
} else {
if (column->retcode == 1406) { /*XXX ORA-01406 truncated value */
/* this seems to be a BUG in oracle with 1-digit numbers */
/*
oci8_debugcol(column,"truncated");
*/
pval->value.str.len = column->indicator - 1; /* when value is truncated indicator contains the lenght */
} else {
pval->value.str.len = column->rlen;
}
}
pval->value.str.val[ pval->value.str.len ] = 0;
}
}
return 1;
}
oci8_error(statement->pError, func, error);
return 0;
}
/* }}} */
/* {{{ oci8_loaddesc() */
static ub4
oci8_loaddesc(oci8_connection *connection, oci8_descriptor *mydescr, char **buffer)
{
sword ociresult;
ub4 loblen;
OCI8_TLS_VARS;
ociresult = OCILobGetLength(connection->pServiceContext, connection->pError, mydescr->ocidescr, &loblen);
if (ociresult) {
oci8_error(connection->pError, "OCILobGetLength", ociresult);
return 0;
}
*buffer = emalloc(loblen + 1);
if (! buffer) {
return 0;
}
if (mydescr->type == OCI_DTYPE_FILE) {
ociresult = OCILobFileOpen(connection->pServiceContext,
connection->pError,
mydescr->ocidescr,
OCI_FILE_READONLY);
if (ociresult) {
oci8_error(connection->pError, "OCILobFileOpen", ociresult);
efree(buffer);
return 0;
}
}
ociresult = OCILobRead(connection->pServiceContext,
connection->pError,
mydescr->ocidescr,
&loblen, /* IN/OUT bytes toread/read */
1, /* offset (starts with 1) */
(dvoid *) *buffer,
loblen, /* size of buffer */
(dvoid *)0,
(OCICallbackLobRead) 0, /* callback... */
(ub2) 0, /* The character set ID of the buffer data. */
(ub1) SQLCS_IMPLICIT); /* The character set form of the buffer data. */
if (ociresult) {
oci8_error(connection->pError, "OCILobRead", ociresult);
efree(buffer);
return 0;
}
if (mydescr->type == OCI_DTYPE_FILE) {
ociresult = OCILobFileClose(connection->pServiceContext,
connection->pError,
mydescr->ocidescr);
if (ociresult) {
oci8_error(connection->pError, "OCILobFileClose", ociresult);
efree(buffer);
return 0;
}
}
(*buffer)[ loblen ] = 0;
oci8_debug("OCIloaddesc: size=%d",loblen);
return loblen;
}
/* }}} */
/* {{{ oci8_failover_callback() */
static sb4
oci8_failover_callback(dvoid *svchp,
dvoid* envhp,
dvoid *fo_ctx,
ub4 fo_type,
ub4 fo_event)
{
/*
this stuff is from an oci sample - it will get cleaned up as soon as i understand it!!! (thies@digicol.de 990420)
right now i cant get oracle to even call it;-(((((((((((
*/
switch (fo_event)
{
case OCI_FO_BEGIN:
{
printf(" Failing Over ... Please stand by \n");
printf(" Failover type was found to be %s \n",
((fo_type==OCI_FO_NONE) ? "NONE"
:(fo_type==OCI_FO_SESSION) ? "SESSION"
:(fo_type==OCI_FO_SELECT) ? "SELECT"
: "UNKNOWN!"));
printf(" Failover Context is :%s\n",
(fo_ctx?(char *)fo_ctx:"NULL POINTER!"));
break;
}
case OCI_FO_ABORT:
{
printf(" Failover aborted. Failover will not take place.\n");
break;
}
case OCI_FO_END:
{
printf(" Failover ended ...resuming services\n");
break;
}
case OCI_FO_REAUTH:
{
printf(" Failed over user. Resuming services\n");
/* Application can check the OCI_ATTR_SESSION attribute of
the service handle to find out the user being
re-authenticated.
After this, the application can replay any ALTER SESSION
commands associated with this session. These must have
been saved by the application in the fo_ctx
*/
break;
}
case OCI_FO_ERROR:
{
printf(" Failover error gotten. Sleeping...\n");
sleep(3);
/* cannot find this blody define !!! return OCI_FO_RETRY; */
break;
}
default:
{
printf("Bad Failover Event: %ld.\n", fo_event);
break;
}
}
return 0;
}
/* }}} */
/* {{{ oci8_define_callback() */
static sb4
oci8_define_callback(dvoid *octxp,
OCIDefine *defnp,
ub4 iter, /* 0-based execute iteration value */
dvoid **bufpp, /* pointer to data */
ub4 **alenp, /* size after value/piece has been read */
ub1 *piecep, /* which piece */
dvoid **indpp, /* indicator value */
ub2 **rcodep)
{
oci8_out_column *outcol;
oci8_define *define;
pval *pval, *tmp;
oci8_descriptor *pdescr, descr;
outcol = (oci8_out_column *)octxp;
define = outcol->define;
if (outcol->is_descr) {
if (define && (! outcol->pdescr)) { /* column has been user-defined */
if (_php3_hash_find(define->pval->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor property");
return OCI_ERROR;
} else if (_php3_hash_index_find(outcol->statement->conn->descriptors, tmp->value.lval, (void **)&pdescr) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor");
return OCI_ERROR;
}
outcol->pdescr = pdescr;
} else if (! outcol->pdescr) { /* we got no define value and teh descriptor hasn't been allocated yet */
if (outcol->type == SQLT_BFILE) {
descr.type = OCI_DTYPE_FILE;
} else if (outcol->type == SQLT_RDD ) {
descr.type = OCI_DTYPE_ROWID;
} else {
descr.type = OCI_DTYPE_LOB;
}
OCIDescriptorAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,(dvoid *)&(descr.ocidescr), descr.type, (size_t) 0, (dvoid **) 0);
_php3_hash_index_update(outcol->statement->conn->descriptors,
outcol->statement->conn->descriptors_count,&descr,sizeof(oci8_descriptor),(void **)&pdescr);
outcol->data = (void *) outcol->statement->conn->descriptors_count++;
outcol->pdescr = pdescr;
oci8_debug("OCIExecute: new descriptor for %d -> %x",outcol->data,descr.ocidescr);
}
if (! outcol->pdescr) {
php3_error(E_WARNING, "unable to find my descriptor");
return OCI_ERROR;
}
outcol->rlen = -1;
*bufpp = outcol->pdescr->ocidescr;
} else { /* "normal variable" */
if (define) {
pval = define->pval;
convert_to_string(pval);
if (pval->value.str.val) {
if ((pval->value.str.val==undefined_variable_string) || (pval->value.str.val==empty_string)) {
/* value was empty -> allocate it... */
pval->value.str.val = 0;
} else if (pval->value.str.val != define->data) {
/* value has changed - and is maybe too small -> reallocate it! */
efree(pval->value.str.val);
pval->value.str.val = 0;
}
}
if (pval->value.str.val == 0) {
pval->value.str.val = emalloc(outcol->storage_size4);
define->data = pval->value.str.val;
}
outcol->data = pval->value.str.val;
} else if (! outcol->data) {
outcol->data = (text *) emalloc(outcol->storage_size4);
}
if (! outcol->data) {
php3_error(E_WARNING, "OCIFetch: cannot allocate %d bytes!",outcol->storage_size4);
return OCI_ERROR;
}
outcol->rlen = outcol->storage_size4;
*bufpp = outcol->data;
}
outcol->indicator = 0;
outcol->retcode = 0;
*alenp = &outcol->rlen;
*indpp = &outcol->indicator;
*rcodep = &outcol->retcode;
*piecep = OCI_ONE_PIECE;
/*
oci8_debug("oci8_define_callback: %s,*bufpp = %x,**alenp = %d,**indpp = %d, **rcodep= %d, *piecep = %d",
outcol->name,*bufpp,**alenp,**(ub2**)indpp,**rcodep,*piecep);
*/
return OCI_CONTINUE;
}
/* }}} */
/* {{{ oci8_bind_in_callback() */
static sb4
oci8_bind_in_callback(dvoid *ictxp, /* context pointer */
OCIBind *bindp, /* bind handle */
ub4 iter, /* 0-based execute iteration value */
ub4 index, /* index of current array for PL/SQL or
row index for SQL */
dvoid **bufpp, /* pointer to data */
ub4 *alenp, /* size after value/piece has been read */
ub1 *piecep, /* which piece */
dvoid **indpp) /* indicator value */
{
oci8_bind *phpbind;
pval *val;
phpbind = (oci8_bind *)ictxp;
if (!phpbind || !(val = phpbind->value)) {
php3_error(E_WARNING, "!phpbind || !phpbind->val");
return OCI_ERROR;
}
if (phpbind->descr == 0) { /* "normal string bind */
convert_to_string(val);
*bufpp = val->value.str.val;
*alenp = phpbind->maxsize;
*indpp = (dvoid *)&phpbind->indicator;
} else { /* descriptor bind */
*bufpp = phpbind->descr;
*alenp = -1; /* seems to be allright */
*indpp = (dvoid *)&phpbind->indicator;
}
*piecep = OCI_ONE_PIECE; /* pass all data in one go */
return OCI_CONTINUE;
}
/* }}} */
/* {{{ oci8_bind_out_callback() */
static sb4
oci8_bind_out_callback(dvoid *ctxp, /* context pointer */
OCIBind *bindp, /* bind handle */
ub4 iter, /* 0-based execute iteration value */
ub4 index, /* index of current array for PL/SQL or
row index for SQL */
dvoid **bufpp, /* pointer to data */
ub4 **alenpp, /* size after value/piece has been read */
ub1 *piecep, /* which piece */
dvoid **indpp, /* indicator value */
ub2 **rcodepp) /* return code */
{
oci8_bind *phpbind;
pval *val;
phpbind = (oci8_bind *)ctxp;
if (!phpbind) {
oci8_debug("oci8_bind_out_callback: phpbind = NULL");
return OCI_ERROR;
}
val = phpbind->value;
if (val == NULL) {
oci8_debug("oci8_bind_out_callback: phpbind->value = NULL");
return OCI_ERROR;
}
/* XXX risky, if the variable has been freed, nasty things
* could happen here.
*/
if (val->type == IS_OBJECT) {
} else if (val->type == IS_STRING) {
STR_FREE(val->value.str.val);
phpbind->value->value.str.len = phpbind->maxsize;
phpbind->value->value.str.val = emalloc(phpbind->maxsize);
oci8_debug("oci8_bind_out_callback: maxlen=%d",phpbind->maxsize);
*alenpp = (ub4*) &phpbind->value->value.str.len; /* XXX we assume that php-pval len has 4 bytes */
*bufpp = phpbind->value->value.str.val;
*piecep = OCI_ONE_PIECE;
*rcodepp = &phpbind->retcode;
*indpp = &phpbind->indicator;
}
return OCI_CONTINUE;
}
/* }}} */
/* {{{ oci8_open_user()
*/
static oci8_session *oci8_open_user(oci8_server* server,char *username,char *password,int persistent)
{
sword error;
oci8_session *session = 0;
OCISvcCtx *svchp = 0;
char *hashed_details = 0;
int hashed_details_length;
OCI8_TLS_VARS;
/*
check if we already have this user authenticated
we will reuse authenticated users within a request no matter if the user requested a persistent
connections or not!
but only as pesistent requested connections will be kept between requests!
*/
hashed_details_length = strlen(SAFE_STRING(username))+
strlen(SAFE_STRING(password))+
strlen(SAFE_STRING(server->dbname));
hashed_details = (char *) malloc(hashed_details_length+1);
sprintf(hashed_details,"%s%s%s",
SAFE_STRING(username),
SAFE_STRING(password),
SAFE_STRING(server->dbname));
_php3_hash_find(OCI8_GLOBAL(php3_oci8_module).user, hashed_details, hashed_details_length+1, (void **) &session);
if (session) {
if (session->open) {
free(hashed_details);
return session;
} else {
_oci8_close_user(session);
/* breakthru to open */
}
}
session = calloc(1,sizeof(oci8_session));
if (! session) {
goto CLEANUP;
}
session->persistent = persistent;
session->server = server;
session->hashed_details = hashed_details;
session->hashed_details_length = hashed_details_length;
/* allocate temporary Service Context */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&svchp,
OCI_HTYPE_SVCCTX,
0,
NULL);
if (error != OCI_SUCCESS) {
oci8_error(server->pError, "oci8_open_user: OCIHandleAlloc OCI_HTYPE_SVCCTX", error);
goto CLEANUP;
}
/* allocate private error-handle */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&session->pError,
OCI_HTYPE_ERROR,
0,
NULL);
if (error != OCI_SUCCESS) {
oci8_error(server->pError, "oci8_open_user: OCIHandleAlloc OCI_HTYPE_ERROR", error);
goto CLEANUP;
}
/* allocate private session-handle */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&session->pSession,
OCI_HTYPE_SESSION,
0,
NULL);
if (error != OCI_SUCCESS) {
oci8_error(server->pError, "oci8_open_user: OCIHandleAlloc OCI_HTYPE_SESSION", error);
goto CLEANUP;
}
/* Set the server handle in service handle */
error = OCIAttrSet(svchp,
OCI_HTYPE_SVCCTX,
server->pServer,
0,
OCI_ATTR_SERVER,
session->pError);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "oci8_open_user: OCIAttrSet OCI_ATTR_SERVER", error);
goto CLEANUP;
}
/* set the username in user handle */
error = OCIAttrSet((dvoid *) session->pSession,
(ub4) OCI_HTYPE_SESSION,
(dvoid *) username,
(ub4) strlen(username),
(ub4) OCI_ATTR_USERNAME,
session->pError);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "OCIAttrSet OCI_ATTR_USERNAME", error);
goto CLEANUP;
}
/* set the password in user handle */
error = OCIAttrSet((dvoid *) session->pSession,
(ub4) OCI_HTYPE_SESSION,
(dvoid *) password,
(ub4) strlen(password),
(ub4) OCI_ATTR_PASSWORD,
session->pError);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "OCIAttrSet OCI_ATTR_PASSWORD", error);
goto CLEANUP;
}
error = OCISessionBegin(svchp,
session->pError,
session->pSession,
(ub4) OCI_CRED_RDBMS,
(ub4) OCI_DEFAULT);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "OCISessionBegin", error);
goto CLEANUP;
}
/* Free Temporary Service Context */
OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX);
session->num = OCI8_GLOBAL(php3_oci8_module).user_num++;
_php3_hash_update(OCI8_GLOBAL(php3_oci8_module).user,
hashed_details,
hashed_details_length+1,
(void *) session,
sizeof(oci8_session),
(void **) &session);
oci8_debug("oci8_open_user new sess=%d user=%s",session->num,session->hashed_details);
session->open = 1;
return session;
CLEANUP:
oci8_debug("oci8_open_user: FAILURE -> CLEANUP called");
_oci8_close_user(session);
return 0;
}
/* }}} */
/* {{{ _oci8_close_user()
*/
static void
_oci8_close_user(oci8_session *session)
{
OCISvcCtx *svchp;
sword error;
if (! session) {
return;
}
oci8_debug("_oci8_close_user: logging-off sess=%d user=%s",session->num,session->hashed_details);
if (session->open) {
/* Temporary Service Context */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **) &svchp,
(ub4) OCI_HTYPE_SVCCTX,
(size_t) 0,
(dvoid **) 0);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "_oci8_close_user OCIHandleAlloc OCI_HTYPE_SVCCTX", error);
}
/* Set the server handle in service handle */
error = OCIAttrSet(svchp,
OCI_HTYPE_SVCCTX,
session->server->pServer,
0,
OCI_ATTR_SERVER,
session->pError);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "_oci8_close_user: OCIAttrSet OCI_ATTR_SERVER", error);
}
/* Set the Authentication handle in the service handle */
error = OCIAttrSet(svchp,
OCI_HTYPE_SVCCTX,
session->pSession,
0,
OCI_ATTR_SESSION,
session->pError);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "_oci8_close_user: OCIAttrSet OCI_ATTR_SESSION", error);
}
error = OCISessionEnd(svchp,
session->pError,
session->pSession,
(ub4) 0);
if (error != OCI_SUCCESS) {
oci8_error(session->pError, "_oci8_close_user: OCISessionEnd", error);
}
} else {
oci8_debug("_oci8_close_user: logging-off DEAD session");
}
OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX);
if (session->pSession)
OCIHandleFree((dvoid *) session->pSession, (ub4) OCI_HTYPE_SESSION);
if (session->pError)
OCIHandleFree((dvoid *) session->pError, (ub4) OCI_HTYPE_ERROR);
_php3_hash_del(OCI8_GLOBAL(php3_oci8_module).user,session->hashed_details,session->hashed_details_length+1);
if (session->hashed_details) {
free(session->hashed_details);
}
free(session);
}
/* }}} */
/* {{{ _oci8_free_descr()
*/
static void
_oci8_free_descr(oci8_descriptor *descr)
{
OCI8_TLS_VARS;
oci8_debug("oci8_free_descr: %x",descr->ocidescr);
OCIDescriptorFree(descr->ocidescr, descr->type);
}
/* }}} */
/* {{{ oci8_open_server()
*/
static oci8_server *oci8_open_server(char *dbname,int persistent)
{
oci8_server *server = 0;
sword error;
char *hashed_details = 0;
int hashed_details_length;
OCI8_TLS_VARS;
/*
check if we already have this server open
we will reuse servers within a request no matter if the usere requested persistent
connections or not!
but only as pesistent requested connections will be kept between requests!
*/
hashed_details_length = strlen(SAFE_STRING((char *)dbname));
hashed_details = (char *) malloc(hashed_details_length+1);
sprintf(hashed_details,"%s",SAFE_STRING((char *)dbname));
_php3_hash_find(OCI8_GLOBAL(php3_oci8_module).server, hashed_details, hashed_details_length+1, (void **) &server);
if (server) {
if (server->open) {
free(hashed_details);
/* if our new users uses this connection persistent, we're keeping it! */
if (persistent) {
server->persistent = persistent;
}
return server;
} else { /* server "died" in the meantime - try to reconnect! */
_oci8_close_server(server);
/* breakthru to open */
}
}
server = calloc(1,sizeof(oci8_server));
if (! server) {
goto CLEANUP;
}
server->persistent = persistent;
server->hashed_details = hashed_details;
server->hashed_details_length = hashed_details_length;
strcpy(server->dbname,dbname);
OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&server->pError,
OCI_HTYPE_ERROR,
0,
NULL);
OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&server->pServer,
OCI_HTYPE_SERVER,
0,
NULL);
error = OCIServerAttach(server->pServer,
server->pError,
dbname,
strlen(dbname),
(ub4) OCI_DEFAULT);
if (error) {
oci8_error(server->pError, "oci8_open_server", error);
goto CLEANUP;
}
server->num = OCI8_GLOBAL(php3_oci8_module).server_num++;
_php3_hash_update(OCI8_GLOBAL(php3_oci8_module).server,
hashed_details,
hashed_details_length+1,
(void *) server,
sizeof(oci8_server),
(void **) &server);
server->failover.fo_ctx = (dvoid *) server;
server->failover.callback_function = oci8_failover_callback;
error = OCIAttrSet((dvoid *)server->pServer,
(ub4) OCI_HTYPE_SERVER,
(dvoid *) &server->failover,
(ub4) 0,
(ub4) OCI_ATTR_FOCBK,
server->pError);
if (error) {
oci8_error(server->pError, "oci8_open_server OCIAttrSet OCI_ATTR_FOCBK", error);
goto CLEANUP;
}
oci8_debug("oci8_open_server new conn=%d dname=%s",server->num,server->dbname);
server->open = 1;
return server;
CLEANUP:
oci8_debug("oci8_open_server: FAILURE -> CLEANUP called");
_oci8_close_server(server);
return 0;
}
/* }}} */
/* {{{ _oci8_close_server()
*/
static void
_oci8_close_server(oci8_server *server)
{
sword error;
OCI8_TLS_VARS;
if (! server) {
return;
}
oci8_debug("_oci8_close_server: detaching conn=%d dbname=%s",server->num,server->dbname);
/* XXX close server here */
if (server->open) {
if (server->pServer && server->pError) {
error = OCIServerDetach(server->pServer,
server->pError,
OCI_DEFAULT);
if (error) {
oci8_error(server->pError, "oci8_close_server OCIServerDetach", error);
}
}
} else {
oci8_debug("_oci8_close_server: closind DEAD server");
}
if (server->pServer)
OCIHandleFree((dvoid *) server->pServer, (ub4) OCI_HTYPE_SERVER);
if (server->pError)
OCIHandleFree((dvoid *) server->pError, (ub4) OCI_HTYPE_ERROR);
_php3_hash_del(OCI8_GLOBAL(php3_oci8_module).server,server->hashed_details,server->hashed_details_length+1);
if (server->hashed_details) {
free(server->hashed_details);
}
free(server);
}
/* }}} */
/* {{{ oci8_do_connect()
Connect to an Oracle database and log on. returns a new session.
*/
static void oci8_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)
{
text *username, *password, *dbname;
pval *userParam, *passParam, *dbParam;
oci8_server *server = 0;
oci8_session *session = 0;
oci8_connection *connection = 0;
sword error;
OCI8_TLS_VARS;
if (getParameters(ht, 3, &userParam, &passParam, &dbParam) == SUCCESS) {
convert_to_string(userParam);
convert_to_string(passParam);
convert_to_string(dbParam);
username = userParam->value.str.val;
password = passParam->value.str.val;
dbname = dbParam->value.str.val;
} else if (getParameters(ht, 2, &userParam, &passParam) == SUCCESS) {
convert_to_string(userParam);
convert_to_string(passParam);
username = userParam->value.str.val;
password = passParam->value.str.val;
dbname = (text *)"";
} else {
WRONG_PARAM_COUNT;
}
connection = (oci8_connection *) ecalloc(1,sizeof(oci8_connection));
if (! connection) {
goto CLEANUP;
}
server = oci8_open_server(dbname,persistent);
if (! server) {
goto CLEANUP;
}
persistent = server->persistent; /* if our server-context is not persistent we can't */
session = oci8_open_user(server,username,password,persistent);
if (! session) {
goto CLEANUP;
}
persistent = session->persistent; /* if our session-context is not persistent we can't */
/* set our session */
connection->session = session;
/* allocate our private error-handle */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&connection->pError,
OCI_HTYPE_ERROR,
0,
NULL);
if (error != OCI_SUCCESS) {
oci8_error(server->pError, "oci8_do_connect: OCIHandleAlloc OCI_HTYPE_ERROR", error);
goto CLEANUP;
}
/* allocate our service-context */
error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **)&connection->pServiceContext,
OCI_HTYPE_SVCCTX,
0,
NULL);
if (error != OCI_SUCCESS) {
oci8_error(connection->pError, "oci8_do_connect: OCIHandleAlloc OCI_HTYPE_SVCCTX", error);
goto CLEANUP;
}
/* Set the server handle in service handle */
error = OCIAttrSet(connection->pServiceContext,
OCI_HTYPE_SVCCTX,
server->pServer,
0,
OCI_ATTR_SERVER,
connection->pError);
if (error != OCI_SUCCESS) {
oci8_error(connection->pError, "oci8_do_connect: OCIAttrSet OCI_ATTR_SERVER", error);
goto CLEANUP;
}
/* Set the Authentication handle in the service handle */
error = OCIAttrSet(connection->pServiceContext,
OCI_HTYPE_SVCCTX,
session->pSession,
0,
OCI_ATTR_SESSION,
connection->pError);
if (error != OCI_SUCCESS) {
oci8_error(connection->pError, "oci8_do_connect: OCIAttrSet OCI_ATTR_SESSION", error);
goto CLEANUP;
}
/*
OCIAttrSet((dvoid *)session->server->pServer,
OCI_HTYPE_SERVER,
(dvoid *) "demo",
0,
OCI_ATTR_EXTERNAL_NAME,
connection->pError);
OCIAttrSet((dvoid *)session->server->pServer,
OCI_HTYPE_SERVER,
(dvoid *) "txn demo2",
0,
OCI_ATTR_INTERNAL_NAME,
connection->pError);
*/
connection->id = php3_list_insert(connection, OCI8_GLOBAL(php3_oci8_module).le_conn);
connection->descriptors = emalloc(sizeof(HashTable));
if (!connection->descriptors ||
_php3_hash_init(connection->descriptors, 13, NULL,(void (*)(void *))_oci8_free_descr, 0) == FAILURE) {
goto CLEANUP;
}
connection->open = 1;
oci8_debug("oci8_do_connect: id=%d",connection->id);
RETURN_LONG(connection->id);
CLEANUP:
oci8_debug("oci8_do_connect: FAILURE -> CLEANUP called");
if (connection->id) {
php3_list_delete(connection->id);
} else {
_oci8_close_conn(connection);
}
RETURN_FALSE;
}
/* }}} */
/************************* EXTENSION FUNCTIONS *************************/
/* {{{ proto int OCIDefineByName(int stmt, string name, mixed &var [,int type])
Define a PHP variable to an Oracle column by name.
if you want to define a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE defining!!!
*/
void php3_oci8_definebyname(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *name, *var, *type;
oci8_statement *statement;
oci8_define *define, *tmp_define;
ub2 ocitype;
ocitype = SQLT_STR; /* zero terminated string */
if (getParameters(ht, 4, &stmt, &name, &var, &type) == SUCCESS) {
convert_to_long(type);
ocitype = (ub2) type->value.lval;
} else if (getParameters(ht, 3, &stmt, &name, &var) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIDefineByName", list);
if (statement == NULL) {
RETURN_FALSE;
}
convert_to_string(name);
define = ecalloc(1,sizeof(oci8_define));
if (!define) {
/* out of memory */
RETURN_FALSE;
}
if (statement->defines == NULL) {
statement->defines = emalloc(sizeof(HashTable));
if (statement->defines == NULL ||
_php3_hash_init(statement->defines, 13, NULL, (void (*)(void *))oci8_free_define, 0) == FAILURE) {
/* out of memory */
RETURN_FALSE;
}
}
if (_php3_hash_add(statement->defines,
name->value.str.val,
name->value.str.len,
define,
sizeof(oci8_define),
(void **)&tmp_define) == SUCCESS) {
efree(define);
define = tmp_define;
} else {
RETURN_FALSE;
}
define->name = estrndup(name->value.str.val,name->value.str.len);
define->name_len = name->value.str.len;
define->type = ocitype;
define->pval = var;
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int OCIBindByName(int stmt, string name, mixed &var, int maxlength [,int type])
Bind a PHP variable to an Oracle placeholder by name.
if you want to bind a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE binding!!!
*/
void php3_oci8_bindbyname(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *name, *var, *maxlen, *tmp,*type;
oci8_statement *statement;
oci8_bind *bind, *tmp_bind;
oci8_descriptor *descr;
sword error;
ub2 ocitype;
sb4 ocimaxlen;
dvoid *mydescr = 0;
ocitype = SQLT_STR; /* zero terminated string */
if (getParameters(ht, 5, &stmt, &name, &var, &maxlen,&type) == SUCCESS) {
convert_to_long(type);
ocitype = (ub2) type->value.lval;
convert_to_long(maxlen);
ocimaxlen = maxlen->value.lval;
} else if (getParameters(ht, 4, &stmt, &name, &var, &maxlen) == SUCCESS) {
convert_to_long(maxlen); ocimaxlen = maxlen->value.lval;
} else {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIBindByName", list);
if (statement == NULL) {
RETURN_FALSE;
}
switch (var->type) {
case IS_OBJECT :
if (_php3_hash_find(var->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor property");
RETURN_FALSE;
}
if (_php3_hash_index_find(statement->conn->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor");
RETURN_FALSE;
}
mydescr = (dvoid *) descr->ocidescr;
if (! mydescr) {
RETURN_FALSE;
}
break;
default:
convert_to_string(var);
if (ocimaxlen == -1) {
if (var->value.str.len == 0) {
php3_error(E_WARNING, "OCIBindByName bindlength is 0");
}
ocimaxlen = var->value.str.len + 1; /* SQLT_STR needs a trailing 0 - maybe we need to resize the var buffers????? */
}
break;
}
convert_to_string(name);
bind = ecalloc(1,sizeof(oci8_bind));
if (!bind) {
/* out of memory */
RETURN_FALSE;
}
if (statement->binds == NULL) {
statement->binds = emalloc(sizeof(HashTable));
if (statement->binds == NULL ||
_php3_hash_init(statement->binds, 13, NULL, NULL, 0) == FAILURE) {
/* out of memory */
RETURN_FALSE;
}
}
if (_php3_hash_next_index_insert(statement->binds, bind,
sizeof(oci8_bind),
(void **)&tmp_bind) == SUCCESS) {
efree(bind);
bind = tmp_bind;
}
bind->value = var;
bind->descr = mydescr;
bind->maxsize = ocimaxlen;
error = OCIBindByName(statement->pStmt, /* statement handle */
(OCIBind **)&bind->pBind, /* bind hdl (will alloc) */
statement->pError, /* error handle */
name->value.str.val, /* placeholder name */
name->value.str.len, /* placeholder length */
(dvoid *)0, /* in/out data */
ocimaxlen, /* max size of input/output data */
(ub2)ocitype, /* in/out data type */
(dvoid *)&bind->indicator, /* indicator (ignored) */
(ub2 *)0, /* size array (ignored) */
(ub2 *)&bind->retcode, /* return code (ignored) */
(ub4)0, /* maxarr_len (PL/SQL only?) */
(ub4 *)0, /* actual array size (PL/SQL only?) */
OCI_DATA_AT_EXEC /* mode */);
if (error != OCI_SUCCESS) {
oci8_error(statement->pError, "OCIBindByName", error);
RETURN_FALSE;
}
error = OCIBindDynamic(bind->pBind,
statement->pError,
(dvoid *)bind,
oci8_bind_in_callback,
(dvoid *)bind,
oci8_bind_out_callback);
if (error != OCI_SUCCESS) {
oci8_error(statement->pError, "OCIBindDynamic", error);
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string ocifreedesc(object lob)
*/
void php3_oci8_freedesc(INTERNAL_FUNCTION_PARAMETERS)
{
pval *id, *conn, *desc;
oci8_connection *connection;
OCI8_TLS_VARS;
if (getThis(&id) == SUCCESS) {
if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) {
php3_error(E_WARNING, "unable to find my statement property");
RETURN_FALSE;
}
connection = oci8_get_conn(conn->value.lval, "OCIfreedesc", list);
if (connection == NULL) {
RETURN_FALSE;
}
if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&desc) == FAILURE) {
php3_error(E_WARNING, "unable to find my locator property");
RETURN_FALSE;
}
oci8_debug("OCOfreedesc: descr=%d",desc->value.lval);
_php3_hash_index_del(connection->descriptors,desc->value.lval);
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string ocisavedesc(object lob)
*/
void php3_oci8_savedesc(INTERNAL_FUNCTION_PARAMETERS)
{
pval *id, *tmp, *conn, *arg;
OCILobLocator *mylob;
oci8_connection *connection;
oci8_descriptor *descr;
sword ociresult;
ub4 loblen;
OCI8_TLS_VARS;
if (getThis(&id) == SUCCESS) {
if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) {
php3_error(E_WARNING, "unable to find my statement property");
RETURN_FALSE;
}
connection = oci8_get_conn(conn->value.lval, "OCIsavedesc", list);
if (connection == NULL) {
RETURN_FALSE;
}
if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
php3_error(E_WARNING, "unable to find my locator property");
RETURN_FALSE;
}
if (_php3_hash_index_find(connection->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor %d",tmp->value.lval);
RETURN_FALSE;
}
mylob = (OCILobLocator *) descr->ocidescr;
if (! mylob) {
RETURN_FALSE;
}
if (getParameters(ht, 1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
loblen = arg->value.str.len;
if (loblen < 1) {
php3_error(E_WARNING, "Cannot save a lob wich size is less than 1 byte");
RETURN_FALSE;
}
ociresult = OCILobWrite(connection->pServiceContext,
connection->pError,
mylob,
&loblen,
(ub4) 1,
(dvoid *) arg->value.str.val,
(ub4) loblen,
OCI_ONE_PIECE,
(dvoid *)0,
(OCICallbackLobWrite) 0,
(ub2) 0,
(ub1) SQLCS_IMPLICIT );
oci8_debug("OCIsavedesc: size=%d",loblen);
if (ociresult) {
oci8_error(connection->pError, "OCILobWrite", ociresult);
RETURN_FALSE;
}
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string ociloaddesc(object lob)
*/
void php3_oci8_loaddesc(INTERNAL_FUNCTION_PARAMETERS)
{
pval *id, *tmp, *conn;
oci8_connection *connection;
oci8_descriptor *descr;
char *buffer;
ub4 loblen;
OCI8_TLS_VARS;
if (getThis(&id) == SUCCESS) {
if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) {
php3_error(E_WARNING, "unable to find my statement property");
RETURN_FALSE;
}
connection = oci8_get_conn(conn->value.lval, "OCIsavedesc", list);
if (connection == NULL) {
RETURN_FALSE;
}
if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
php3_error(E_WARNING, "unable to find my locator property");
RETURN_FALSE;
}
if (_php3_hash_index_find(connection->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) {
php3_error(E_WARNING, "unable to find my descriptor %d",tmp->value.lval);
RETURN_FALSE;
}
loblen = oci8_loaddesc(connection,descr,&buffer);
if (loblen > 0) {
RETURN_STRINGL(buffer,loblen,0);
}
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string OCINewDescriptor(int connection [,int type ])
initialize a new empty descriptor LOB/FILE (LOB is default)
*/
void php3_oci8_newdescriptor(INTERNAL_FUNCTION_PARAMETERS)
{
pval *conn, *type;
sword ociresult;
oci8_connection *connection;
oci8_descriptor descr;
int mylob;
OCI8_TLS_VARS;
descr.type = OCI_DTYPE_LOB;
if (getParameters(ht, 2, &conn, &type) == SUCCESS) {
descr.type = type->value.lval;
} else if (getParameters(ht, 1, &conn) == FAILURE) {
WRONG_PARAM_COUNT;
}
switch (descr.type) {
case OCI_DTYPE_FILE:
case OCI_DTYPE_LOB:
case OCI_DTYPE_ROWID:
break;
default:
php3_error(E_WARNING, "Unknown descriptor type %d.",descr.type);
RETURN_FALSE;
}
convert_to_long(conn);
connection = oci8_get_conn(conn->value.lval, "OCINewDescriptor", list);
if (connection == NULL) {
RETURN_FALSE;
}
ociresult = OCIDescriptorAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,(dvoid*)&(descr.ocidescr), descr.type, (size_t) 0, (dvoid **) 0);
if (ociresult) {
oci8_error(connection->pError,"OCIDescriptorAlloc %d",ociresult);
RETURN_FALSE;
}
_php3_hash_index_update(connection->descriptors, connection->descriptors_count,&descr,sizeof(oci8_descriptor),NULL);
mylob = connection->descriptors_count++;
oci8_debug("OCINewDescriptor: new descriptor for %d -> %x",mylob,descr.ocidescr);
object_init(return_value);
add_property_long(return_value, "descriptor", (long) mylob);
add_property_long(return_value, "connection", conn->value.lval);
add_method(return_value, "free", php3_oci8_freedesc);
switch (descr.type) {
case OCI_DTYPE_LOB :
add_method(return_value, "save", php3_oci8_savedesc);
/* breaktruh */
case OCI_DTYPE_FILE :
add_method(return_value, "load", php3_oci8_loaddesc);
break;
}
add_method(return_value, "free", php3_oci8_freedesc);
}
/* }}} */
/* {{{ proto string OCINewTrans(int conn, string name)
*/
void php3_oci8_settrans(INTERNAL_FUNCTION_PARAMETERS)
{
}
/* }}} */
/* {{{ proto string OCINewTrans(int conn, string name)
*/
void php3_oci8_newtrans(INTERNAL_FUNCTION_PARAMETERS)
{
pval *conn;
oci8_connection *connection;
oci8_xa *trans;
sword ociresult;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &conn) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(conn);
connection = oci8_get_conn(conn->value.lval, "OCINewTrans", list);
if (connection == NULL) {
RETURN_FALSE;
}
trans = (oci8_xa *) ecalloc(1,sizeof(oci8_xa));
ociresult = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,
(dvoid **) &trans->pTrans,
OCI_HTYPE_TRANS,
0,
0);
if (ociresult) {
oci8_error(connection->pError, "php3_oci8_newtrans OCIHandleAlloc OCI_HTYPE_TRANS", ociresult);
RETURN_FALSE;
}
ociresult = OCIAttrSet((dvoid *) connection->pServiceContext,
OCI_HTYPE_SVCCTX,
(dvoid *)trans->pTrans,
0,
OCI_ATTR_TRANS,
connection->pError);
if (ociresult) {
oci8_error(connection->pError, "php3_oci8_newtrans OCIAttrSet OCI_ATTR_TRANS", ociresult);
RETURN_FALSE;
}
#if 0
trans->xid.formatID = -1; /* format id = 1000 */
trans->xid.gtrid_length = 1; /* gtrid = 123 */
trans->xid.data[0] = 0;
trans->xid.data[1] = 2;
trans->xid.data[2] = 3;
trans->xid.bqual_length = 1; /* bqual = 2 */
trans->xid.data[3] = 0;
ociresult = OCIAttrSet((dvoid *)trans->pTrans,
OCI_HTYPE_TRANS,
(dvoid *)&trans->xid,
sizeof(XID),
OCI_ATTR_XID,
connection->pError);
if (ociresult) {
oci8_error(connection->pError, "php3_oci8_newtrans OCIAttrSet OCI_ATTR_XID", ociresult);
RETURN_FALSE;
}
strcpy(trans->xname,"hallo");
ociresult = OCIAttrSet((dvoid *)trans->pTrans,
OCI_HTYPE_TRANS,
(dvoid *)&trans->xname,
strlen(trans->xname),
OCI_ATTR_TRANS_NAME,
connection->pError);
if (ociresult) {
oci8_error(connection->pError, "php3_oci8_newtrans OCIAttrSet OCI_ATTR_XID", ociresult);
RETURN_FALSE;
}
#endif
/*
Specifies whether a new transaction is being started or an existing transaction is being resumed. Also specifies serializiability or read-only status. More than a single value can be specified.
By default, a read/write transaction is started. The flag values are:
OCI_TRANS_NEW - starts a new transaction branch. By default starts a tightly coupled and migratable branch.
OCI_TRANS_TIGHT - explicitly specifies a tightly coupled branch
OCI_TRANS_LOOSE - specifies a loosely coupled branch
OCI_TRANS_RESUME - resumes an existing transaction branch.
OCI_TRANS_READONLY - start a read-only transaction
OCI_TRANS_SERIALIZABLE - start a serializable transaction
*/
ociresult = OCITransStart(connection->pServiceContext,
connection->pError,
(uword) 60,
(ub4) OCI_TRANS_NEW);
oci8_debug("OCITransStart=%d",ociresult);
if (ociresult) {
oci8_error(connection->pError, "OCITransStart", ociresult);
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string OCIRollback(int conn)
rollback the current context
*/
void php3_oci8_rollback(INTERNAL_FUNCTION_PARAMETERS)
{
pval *conn;
oci8_connection *connection;
sword ociresult;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &conn) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(conn);
connection = oci8_get_conn(conn->value.lval, "OCIRollback", list);
if (connection == NULL) {
RETURN_FALSE;
}
ociresult = OCITransRollback(connection->pServiceContext,connection->pError, (ub4)0);
oci8_debug("OCITransRollback=%d",ociresult);
if (ociresult) {
oci8_error(connection->pError, "OCIRollback", ociresult);
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string OCICommit(int conn)
commit the current context
*/
void php3_oci8_commit(INTERNAL_FUNCTION_PARAMETERS)
{
pval *conn;
oci8_connection *connection;
sword ociresult;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &conn) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(conn);
connection = oci8_get_conn(conn->value.lval, "OCICommit", list);
if (connection == NULL) {
RETURN_FALSE;
}
ociresult = OCITransCommit(connection->pServiceContext,connection->pError, (ub4)0);
if (ociresult) {
oci8_error(connection->pError, "OCICommit", ociresult);
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string OCIColumnName(int stmt, int col)
Tell the name of a column.
*/
void php3_oci8_columnname(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *col;
oci8_statement *statement;
oci8_out_column *outcol;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &col) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIColumnName", list);
if (statement == NULL) {
RETURN_FALSE;
}
outcol = oci8_get_col(statement, -1, col, "OCIColumnName");
if (outcol == NULL) {
RETURN_FALSE;
}
RETURN_STRINGL(outcol->name, outcol->name_len, 1);
}
/* }}} */
/* {{{ proto int OCIColumnSize(int stmt, int col)
Tell the maximum data size of a column.
*/
void php3_oci8_columnsize(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *col;
oci8_statement *statement;
oci8_out_column *outcol;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &col) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIColumnSize", list);
if (statement == NULL) {
RETURN_FALSE;
}
outcol = oci8_get_col(statement, -1, col, "OCIColumnSize");
if (outcol == NULL) {
RETURN_FALSE;
}
RETURN_LONG(outcol->size4);
}
/* }}} */
/* {{{ proto mixed OCIColumnType(int stmt, int col)
Tell the data type of a column.
*/
void php3_oci8_columntype(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *col;
oci8_statement *statement;
oci8_out_column *outcol;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &col) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIColumnType", list);
if (statement == NULL) {
RETURN_FALSE;
}
outcol = oci8_get_col(statement, -1, col, "OCIColumnType");
if (outcol == NULL) {
RETURN_FALSE;
}
switch (outcol->type) {
case SQLT_DAT:
RETVAL_STRING("DATE",1);
break;
case SQLT_NUM:
RETVAL_STRING("NUMBER",1);
break;
case SQLT_LNG:
RETVAL_STRING("LONG",1);
break;
case SQLT_BIN:
RETVAL_STRING("RAW",1);
break;
case SQLT_LBI:
RETVAL_STRING("LONG RAW",1);
break;
case SQLT_CHR:
RETVAL_STRING("VARCHAR",1);
break;
case SQLT_AFC:
RETVAL_STRING("CHAR",1);
break;
case SQLT_BLOB:
RETVAL_STRING("BLOB",1);
break;
case SQLT_CLOB:
RETVAL_STRING("CLOB",1);
break;
case SQLT_BFILE:
RETVAL_STRING("BFILE",1);
break;
case SQLT_RDD:
RETVAL_STRING("ROWID",1);
break;
default:
RETVAL_LONG(outcol->type);
}
}
/* }}} */
/* {{{ proto int OCIColumnIsNULL(int stmt, int col)
Tell whether a column is NULL.
*/
void php3_oci8_columnisnull(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *col;
oci8_statement *statement;
oci8_out_column *outcol;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &col) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIColumnIsNULL", list);
if (statement == NULL) {
RETURN_FALSE;
}
outcol = oci8_get_col(statement, -1, col, "OCIColumnIsNULL");
if (outcol == NULL) {
RETURN_FALSE;
}
if (outcol->indicator == -1) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Proto void OCIDebug(int onoff)
Toggle internal debugging output for the OCI extension.
*/
/* Disables or enables the internal debug output.
* By default it is disabled.
*/
void php3_oci8_internaldebug(INTERNAL_FUNCTION_PARAMETERS)
{
pval *arg;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(arg);
OCI8_GLOBAL(php3_oci8_module).debug_mode = arg->value.lval;
}
/* }}} */
/* {{{ proto int OCIExecute(int stmt [,int mode])
Execute a parsed statement.
*/
void php3_oci8_execute(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt,*mode;
oci8_statement *statement;
ub4 execmode;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &mode) == SUCCESS) {
convert_to_long(mode);
execmode = mode->value.lval;
} else if (getParameters(ht, 1, &stmt) == SUCCESS) {
execmode = OCI_COMMIT_ON_SUCCESS;
} else {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIExecute", list);
if (statement == NULL) {
RETURN_FALSE;
}
if (oci8_execute(statement, "OCIExecute",execmode)) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int OCIFetch(int stmt)
Prepare a new row of data for reading.
*/
void php3_oci8_fetch(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt;
oci8_statement *statement;
ub4 nrows = 1; /* only one row at a time is supported for now */
OCI8_TLS_VARS;
if (getParameters(ht, 1, &stmt) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIFetch", list);
if (statement == NULL) {
RETURN_FALSE;
}
if (oci8_fetch(statement, nrows, "OCIFetch")) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int OCIFetchInto(int stmt, array &output [, int mode])
Fetch a row of result data into an array.
*/
void php3_oci8_fetchinto(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *array, *element, *fmode;
oci8_statement *statement;
oci8_out_column *column;
ub4 nrows = 1;
int i;
int mode = OCI_NUM;
OCI8_TLS_VARS;
if (getParameters(ht, 3, &stmt, &array, &fmode) == SUCCESS) {
convert_to_long(fmode);
mode = fmode->value.lval;
} else if (getParameters(ht, 2, &stmt, &array) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIFetchInto", list);
if (statement == NULL) {
RETURN_FALSE;
}
if (!oci8_fetch(statement, nrows, "OCIFetchInto")) {
RETURN_FALSE;
}
/*
if we don't want NULL columns back, we need to recreate the array
as it could have a different number of enties for each fetched row
*/
if (! (mode & OCI_RETURN_NULLS)) {
if (array->type == IS_ARRAY) {
/* XXX is that right?? */
_php3_hash_destroy(array->value.ht);
efree(array->value.ht);
var_reset(array);
}
}
if (array->type != IS_ARRAY) {
if (array_init(array) == FAILURE) {
php3_error(E_WARNING, "OCIFetchInto: unable to convert arg 2 to array");
RETURN_FALSE;
}
}
#if PHP_API_VERSION < 19990421
element = emalloc(sizeof(pval));
#endif
for (i = 0; i < statement->ncolumns; i++) {
column = oci8_get_col(statement, i + 1, 0, "OCIFetchInto");
if (column == NULL) { /* should not happen... */
continue;
}
if ((column->indicator == -1) && ((mode & OCI_RETURN_NULLS) == 0)) {
continue;
}
#if PHP_API_VERSION >= 19990421
element = emalloc(sizeof(pval));
#endif
if ((mode & OCI_NUM) || (! (mode & OCI_ASSOC))) { /* OCI_NUM is default */
oci8_make_pval(element,statement,column, "OCIFetchInto",list,mode);
#if PHP_API_VERSION >= 19990421
_php3_hash_index_update(array->value.ht, i, (void *)&element, sizeof(pval*), NULL);
#else
_php3_hash_index_update(array->value.ht, i, (void *)element, sizeof(pval), NULL);
#endif
}
if (mode & OCI_ASSOC) {
oci8_make_pval(element,statement,column, "OCIFetchInto",list,mode);
#if PHP_API_VERSION >= 19990421
_php3_hash_update(array->value.ht, column->name, column->name_len+1, (void *)&element, sizeof(pval*), NULL);
#else
_php3_hash_update(array->value.ht, column->name, column->name_len+1, (void *)element, sizeof(pval), NULL);
#endif
}
}
#if PHP_API_VERSION < 19990421
efree(element);
#endif
RETURN_LONG(statement->ncolumns);
}
/* }}} */
/* {{{ proto int OCIFetchStatement(int stmt, array &output)
Fetch all rows of result data into an array.
*/
void php3_oci8_fetchstatement(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *array, element, *fmode;
oci8_statement *statement;
oci8_out_column **columns;
pval **outarrs;
pval tmp;
ub4 nrows = 1;
int i;
int mode = OCI_NUM;
int rows = 0;
char namebuf[ 128 ];
OCI8_TLS_VARS;
if (getParameters(ht, 3, &stmt, &array, &fmode) == SUCCESS) {
convert_to_long(fmode);
mode = fmode->value.lval;
} else if (getParameters(ht, 2, &stmt, &array) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIFetchStatement", list);
if (statement == NULL) {
RETURN_FALSE;
}
if (array->type != IS_ARRAY) {
if (array_init(array) == FAILURE) {
php3_error(E_WARNING, "OCIFetchStatement: unable to convert arg 2 to array");
RETURN_FALSE;
}
}
columns = emalloc(statement->ncolumns * sizeof(oci8_out_column *));
outarrs = emalloc(statement->ncolumns * sizeof(pval));
for (i = 0; i < statement->ncolumns; i++) {
columns[ i ] = oci8_get_col(statement, i + 1, 0, "OCIFetchStatement");
array_init(&tmp);
memcpy(namebuf,columns[ i ]->name, columns[ i ]->name_len);
namebuf[ columns[ i ]->name_len ] = 0;
_php3_hash_update(array->value.ht, namebuf, columns[ i ]->name_len+1, (void *) &tmp, sizeof(pval), (void **) &(outarrs[ i ]));
}
while (oci8_fetch(statement, nrows, "OCIFetchStatement")) {
for (i = 0; i < statement->ncolumns; i++) {
oci8_make_pval(&element,statement,columns[ i ], "OCIFetchStatement",list,OCI_RETURN_LOBS);
_php3_hash_index_update(outarrs[ i ]->value.ht, rows, (void *)&element, sizeof(pval), NULL);
}
rows++;
}
efree(columns);
efree(outarrs);
RETURN_LONG(rows);
}
/* }}} */
/* {{{ proto int OCIFreeStatement(int stmt)
Free all resources associated with a statement.
*/
void php3_oci8_freestatement(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt;
oci8_statement *statement;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &stmt) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIFreeStatement", list);
if (statement == NULL) {
RETURN_FALSE;
}
php3_list_delete(stmt->value.lval);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int OCILogoff(int conn)
Disconnect from database.
*/
/* Logs off and disconnects.
*/
void php3_oci8_logout(INTERNAL_FUNCTION_PARAMETERS)
{
oci8_connection *connection;
pval *arg;
int index, index_t;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(arg);
index = arg->value.lval;
connection = (oci8_connection *)php3_list_find(index, &index_t);
if (!connection) {
oci8_debug("OCILogoff: connection == NULL.");
RETURN_FALSE;
}
if (! OCI8_CONN_TYPE(index_t)) {
oci8_debug("OCILogoff: connection not found...");
RETURN_FALSE;
}
if (php3_list_delete(index) == SUCCESS) {
RETURN_TRUE;
} else {
oci8_debug("OCILogoff: php3_list_delete failed.");
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int OCILogon(string user, string pass[, string db])
Connect to an Oracle database and log on. returns a new session.
*/
/* Connects to an Oracle 8 database and logs on. If the
* optional third parameter is not specified, PHP uses the environment
* variable ORACLE_SID to determine which database to connect to.
*/
void php3_oci8_logon(INTERNAL_FUNCTION_PARAMETERS)
{
oci8_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
}
/* }}} */
/* {{{ proto int OCIPLogon(string user, string pass[, string db])
Connect to an Oracle database and log on. returns a new session.
*/
/* Connects to an Oracle 8 database and logs on. If the
* optional third parameter is not specified, PHP uses the environment
* variable ORACLE_SID to determine which database to connect to.
*/
void php3_oci8_plogon(INTERNAL_FUNCTION_PARAMETERS)
{
oci8_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
}
/* }}} */
/* {{{ proto int OCIError(int stmt|conn)
Return the last error of stmt|conn. If no error happened returns false.
*/
void php3_oci8_error(INTERNAL_FUNCTION_PARAMETERS)
{
pval *mixed;
oci8_statement *statement;
oci8_connection *connection;
text errbuf[512];
ub4 errcode = 0;
int type;
dvoid *errh = NULL;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &mixed) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(mixed);
statement = (oci8_statement *)php3_list_find(mixed->value.lval, &type);
if (statement && OCI8_STMT_TYPE(type)) {
errh = statement->pError;
} else {
connection = (oci8_connection *)php3_list_find(mixed->value.lval, &type);
if (connection && OCI8_CONN_TYPE(type)) {
errh = connection->pError;
}
}
if (! errh) {
php3_error(E_WARNING, "OCIError: unable to find Error handle");
RETURN_FALSE;
}
OCIErrorGet(errh,1,NULL,&errcode,errbuf,(ub4)sizeof(errbuf),(ub4)OCI_HTYPE_ERROR);
if (errcode) {
array_init(return_value);
add_assoc_long(return_value, "code", errcode);
add_assoc_string(return_value, "message", errbuf, 1);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int OCINumCols(int stmt)
Return the number of result columns in a statement.
*/
void php3_oci8_numcols(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt;
oci8_statement *statement;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &stmt) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCINumCols", list);
if (statement == NULL) {
RETURN_FALSE;
}
RETURN_LONG(statement->ncolumns);
}
/* }}} */
/* {{{ proto int OCIParse(int conn, string query)
Parse a query and return a statement.
*/
void php3_oci8_parse(INTERNAL_FUNCTION_PARAMETERS)
{
pval *conn, *query;
oci8_connection *connection;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &conn, &query) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(conn);
convert_to_string(query);
connection = oci8_get_conn(conn->value.lval, "OCIParse", list);
if (connection == NULL) {
RETURN_FALSE;
}
RETURN_LONG(oci8_parse(connection,
query->value.str.val,
query->value.str.len,
list));
}
/* }}} */
/* {{{ proto string OCIResult(int stmt, mixed column)
Return a single column of result data.
*/
void php3_oci8_result(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt, *col;
oci8_statement *statement;
oci8_out_column *outcol = NULL;
OCI8_TLS_VARS;
if (getParameters(ht, 2, &stmt, &col) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIResult", list);
if (statement == NULL) {
RETURN_FALSE;
}
outcol = oci8_get_col(statement, -1, col, "OCIResult");
if (outcol == NULL) {
RETURN_FALSE;
}
oci8_make_pval(return_value,statement,outcol, "OCIResult",list,0);
}
/* }}} */
/* {{{ proto string OCIServerVersion(int conn)
Return a string containing server version information.
*/
void php3_oci8_serverversion(INTERNAL_FUNCTION_PARAMETERS)
{
oci8_connection *connection;
pval *arg;
int index, index_t;
sword error;
char version[256];
OCI8_TLS_VARS;
if (getParameters(ht, 1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(arg);
index = arg->value.lval;
connection = (oci8_connection *)php3_list_find(index, &index_t);
if (!connection || !OCI8_CONN_TYPE(index_t)) {
RETURN_FALSE;
}
error = OCIServerVersion(connection->pServiceContext,
connection->pError, version, sizeof(version),
OCI_HTYPE_SVCCTX);
if (error != OCI_SUCCESS) {
oci8_error(connection->pError, "OCIServerVersion", error);
RETURN_FALSE;
}
RETURN_STRING(version,1);
}
/* }}} */
/* {{{ proto int OCIStatementType(int stmt)
Return the query type of an OCI statement.
*/
/* XXX it would be better with a general interface to OCIAttrGet() */
void php3_oci8_statementtype(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt;
oci8_statement *statement;
ub2 stmttype;
sword error;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &stmt) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIStatementType", list);
if (statement == NULL) {
RETURN_FALSE;
}
error = OCIAttrGet((dvoid *)statement->pStmt, OCI_HTYPE_STMT,
(ub2 *)&stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE,
statement->pError);
if (error != OCI_SUCCESS) {
oci8_error(statement->pError, "OCIStatementType", error);
RETURN_FALSE;
}
switch (stmttype) {
case OCI_STMT_SELECT:
RETVAL_STRING("SELECT",1);
break;
case OCI_STMT_UPDATE:
RETVAL_STRING("UPDATE",1);
break;
case OCI_STMT_DELETE:
RETVAL_STRING("DELETE",1);
break;
case OCI_STMT_INSERT:
RETVAL_STRING("INSERT",1);
break;
case OCI_STMT_CREATE:
RETVAL_STRING("CREATE",1);
break;
case OCI_STMT_DROP:
RETVAL_STRING("DROP",1);
break;
case OCI_STMT_ALTER:
RETVAL_STRING("ALTER",1);
break;
case OCI_STMT_BEGIN:
RETVAL_STRING("BEGIN",1);
break;
case OCI_STMT_DECLARE:
RETVAL_STRING("DECLARE",1);
break;
default:
RETVAL_STRING("UNKNOWN",1);
}
}
void php3_oci8_rowcount(INTERNAL_FUNCTION_PARAMETERS)
{
pval *stmt;
oci8_statement *statement;
ub4 rowcount;
sword error;
OCI8_TLS_VARS;
if (getParameters(ht, 1, &stmt) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long(stmt);
statement = oci8_get_stmt(stmt->value.lval, "OCIStatementType", list);
if (statement == NULL) {
RETURN_FALSE;
}
error = OCIAttrGet((dvoid *)statement->pStmt, OCI_HTYPE_STMT,
(ub2 *)&rowcount, (ub4 *)0, OCI_ATTR_ROW_COUNT,
statement->pError);
if (error != OCI_SUCCESS) {
oci8_error(statement->pError, "OCIRowCount", error);
RETURN_FALSE;
}
RETURN_LONG(rowcount);
}
/* }}} */
#endif /* HAVE_OCI8 */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/