232 lines
8.3 KiB
C
232 lines
8.3 KiB
C
//-----------------------------------------------------------------------------
|
|
// Environment.c
|
|
// Environment handling.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// structure for the Python type
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
OCIEnv *handle;
|
|
OCIError *errorHandle;
|
|
int maxBytesPerCharacter;
|
|
int fixedWidth;
|
|
ub4 maxStringBytes;
|
|
} udt_Environment;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// maximum number of characters/bytes applicable to strings/binaries
|
|
//-----------------------------------------------------------------------------
|
|
#define MAX_STRING_CHARS 4000
|
|
#define MAX_BINARY_BYTES 4000
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// forward declarations
|
|
//-----------------------------------------------------------------------------
|
|
static void Environment_Free(udt_Environment*);
|
|
static int Environment_CheckForError(udt_Environment*, sword, const char*);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of Python type
|
|
//-----------------------------------------------------------------------------
|
|
static PyTypeObject g_EnvironmentType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"OracleEnvironment", // tp_name
|
|
sizeof(udt_Environment), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) Environment_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
0, // tp_repr
|
|
0, // tp_as_number
|
|
0, // tp_as_sequence
|
|
0, // tp_as_mapping
|
|
0, // tp_hash
|
|
0, // tp_call
|
|
0, // tp_str
|
|
0, // tp_getattro
|
|
0, // tp_setattro
|
|
0, // tp_as_buffer
|
|
Py_TPFLAGS_DEFAULT, // tp_flags
|
|
0 // tp_doc
|
|
};
|
|
|
|
|
|
#include "Error.c"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Environment_New()
|
|
// Create a new environment object.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Environment *Environment_New(
|
|
int threaded, // use threaded mode?
|
|
int events) // use events mode?
|
|
{
|
|
udt_Environment *environment;
|
|
sword status;
|
|
ub4 mode;
|
|
|
|
// create a new object for the Oracle environment
|
|
environment = PyObject_NEW(udt_Environment, &g_EnvironmentType);
|
|
if (!environment)
|
|
return NULL;
|
|
environment->handle = NULL;
|
|
environment->errorHandle = NULL;
|
|
environment->fixedWidth = 1;
|
|
environment->maxBytesPerCharacter = CXORA_BYTES_PER_CHAR;
|
|
environment->maxStringBytes = MAX_STRING_CHARS * CXORA_BYTES_PER_CHAR;
|
|
|
|
// turn threading mode on, if desired
|
|
mode = OCI_OBJECT;
|
|
if (threaded)
|
|
mode |= OCI_THREADED;
|
|
#ifdef ORACLE_11G
|
|
if (events)
|
|
mode |= OCI_EVENTS;
|
|
#endif
|
|
|
|
// create the environment handle
|
|
status = OCIEnvNlsCreate(&environment->handle, mode, NULL, NULL, NULL,
|
|
NULL, 0, NULL, CXORA_CHARSETID, CXORA_CHARSETID);
|
|
if (!environment->handle) {
|
|
Py_DECREF(environment);
|
|
PyErr_SetString(g_InterfaceErrorException,
|
|
"Unable to acquire Oracle environment handle");
|
|
return NULL;
|
|
}
|
|
if (Environment_CheckForError(environment, status,
|
|
"Environment_New(): create env handle") < 0) {
|
|
environment->handle = NULL;
|
|
Py_DECREF(environment);
|
|
return NULL;
|
|
}
|
|
|
|
// create the error handle
|
|
status = OCIHandleAlloc(environment->handle,
|
|
(dvoid**) &environment->errorHandle, OCI_HTYPE_ERROR, 0, 0);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Environment_New(): create error handle") < 0) {
|
|
Py_DECREF(environment);
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef WITH_UNICODE
|
|
// acquire max bytes per character
|
|
status = OCINlsNumericInfoGet(environment->handle,
|
|
environment->errorHandle, &environment->maxBytesPerCharacter,
|
|
OCI_NLS_CHARSET_MAXBYTESZ);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Environment_New(): get max bytes per character") < 0) {
|
|
Py_DECREF(environment);
|
|
return NULL;
|
|
}
|
|
environment->maxStringBytes =
|
|
MAX_STRING_CHARS * environment->maxBytesPerCharacter;
|
|
|
|
// acquire whether character set is fixed width
|
|
status = OCINlsNumericInfoGet(environment->handle,
|
|
environment->errorHandle, &environment->fixedWidth,
|
|
OCI_NLS_CHARSET_FIXEDWIDTH);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Environment_New(): determine if charset is fixed width") < 0) {
|
|
Py_DECREF(environment);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
return environment;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Environment_Free()
|
|
// Deallocate the environment. Note that destroying the environment handle
|
|
// will automatically destroy any child handles that were created.
|
|
//-----------------------------------------------------------------------------
|
|
static void Environment_Free(
|
|
udt_Environment *environment) // environment object
|
|
{
|
|
if (environment->handle)
|
|
OCIHandleFree(environment->handle, OCI_HTYPE_ENV);
|
|
PyObject_DEL(environment);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Environment_RaiseError()
|
|
// Reads the error that was caused by the last Oracle statement and raise an
|
|
// exception for Python. At this point it is assumed that the Oracle
|
|
// environment is fully initialized.
|
|
//-----------------------------------------------------------------------------
|
|
static int Environment_RaiseError(
|
|
udt_Environment *environment, // environment to raise error for
|
|
const char *context) // context in which error occurred
|
|
{
|
|
PyObject *exceptionType;
|
|
udt_Error *error;
|
|
|
|
error = Error_New(environment, context, 1);
|
|
if (error) {
|
|
switch (error->code) {
|
|
case 1:
|
|
case 1400:
|
|
case 2290:
|
|
case 2291:
|
|
case 2292:
|
|
exceptionType = g_IntegrityErrorException;
|
|
break;
|
|
case 1012:
|
|
case 1033:
|
|
case 1034:
|
|
case 1089:
|
|
case 3113:
|
|
case 3114:
|
|
case 12203:
|
|
case 12500:
|
|
case 12571:
|
|
exceptionType = g_OperationalErrorException;
|
|
break;
|
|
default:
|
|
exceptionType = g_DatabaseErrorException;
|
|
break;
|
|
}
|
|
PyErr_SetObject(exceptionType, (PyObject*) error);
|
|
Py_DECREF(error);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Environment_CheckForError()
|
|
// Check for an error in the last call and if an error has occurred, raise a
|
|
// Python exception.
|
|
//-----------------------------------------------------------------------------
|
|
static int Environment_CheckForError(
|
|
udt_Environment *environment, // environment to raise error in
|
|
sword status, // status of last call
|
|
const char *context) // context
|
|
{
|
|
udt_Error *error;
|
|
|
|
if (status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO) {
|
|
if (status != OCI_INVALID_HANDLE)
|
|
return Environment_RaiseError(environment, context);
|
|
error = Error_New(environment, context, 0);
|
|
if (!error)
|
|
return -1;
|
|
error->code = 0;
|
|
error->message = cxString_FromAscii("Invalid handle!");
|
|
if (!error->message)
|
|
Py_DECREF(error);
|
|
else PyErr_SetObject(g_DatabaseErrorException, (PyObject*) error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|