//----------------------------------------------------------------------------- // Cursor.c // Definition of the Python type OracleCursor. //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // structure for the Python type "Cursor" //----------------------------------------------------------------------------- typedef struct { PyObject_HEAD OCIStmt *handle; udt_Connection *connection; udt_Environment *environment; PyObject *statement; PyObject *statementTag; PyObject *bindVariables; PyObject *fetchVariables; PyObject *rowFactory; PyObject *inputTypeHandler; PyObject *outputTypeHandler; int arraySize; int bindArraySize; int fetchArraySize; int numbersAsStrings; int setInputSizes; int outputSize; int outputSizeColumn; int rowCount; int actualRows; int rowNum; int statementType; int isDML; int isOpen; int isOwned; } udt_Cursor; //----------------------------------------------------------------------------- // dependent function defintions //----------------------------------------------------------------------------- static void Cursor_Free(udt_Cursor*); //----------------------------------------------------------------------------- // functions for the Python type "Cursor" //----------------------------------------------------------------------------- static PyObject *Cursor_GetIter(udt_Cursor*); static PyObject *Cursor_GetNext(udt_Cursor*); static PyObject *Cursor_Close(udt_Cursor*, PyObject*); static PyObject *Cursor_CallFunc(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_CallProc(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_Execute(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_ExecuteMany(udt_Cursor*, PyObject*); static PyObject *Cursor_ExecuteManyPrepared(udt_Cursor*, PyObject*); static PyObject *Cursor_FetchOne(udt_Cursor*, PyObject*); static PyObject *Cursor_FetchMany(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_FetchAll(udt_Cursor*, PyObject*); static PyObject *Cursor_FetchRaw(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_Parse(udt_Cursor*, PyObject*); static PyObject *Cursor_Prepare(udt_Cursor*, PyObject*); static PyObject *Cursor_SetInputSizes(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_SetOutputSize(udt_Cursor*, PyObject*); static PyObject *Cursor_Var(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_ArrayVar(udt_Cursor*, PyObject*); static PyObject *Cursor_BindNames(udt_Cursor*, PyObject*); static PyObject *Cursor_GetDescription(udt_Cursor*, void*); static PyObject *Cursor_New(PyTypeObject*, PyObject*, PyObject*); static int Cursor_Init(udt_Cursor*, PyObject*, PyObject*); static PyObject *Cursor_Repr(udt_Cursor*); //----------------------------------------------------------------------------- // declaration of methods for Python type "Cursor" //----------------------------------------------------------------------------- static PyMethodDef g_CursorMethods[] = { { "execute", (PyCFunction) Cursor_Execute, METH_VARARGS | METH_KEYWORDS }, { "fetchall", (PyCFunction) Cursor_FetchAll, METH_NOARGS }, { "fetchone", (PyCFunction) Cursor_FetchOne, METH_NOARGS }, { "fetchmany", (PyCFunction) Cursor_FetchMany, METH_VARARGS | METH_KEYWORDS }, { "fetchraw", (PyCFunction) Cursor_FetchRaw, METH_VARARGS | METH_KEYWORDS }, { "prepare", (PyCFunction) Cursor_Prepare, METH_VARARGS }, { "parse", (PyCFunction) Cursor_Parse, METH_VARARGS }, { "setinputsizes", (PyCFunction) Cursor_SetInputSizes, METH_VARARGS | METH_KEYWORDS }, { "executemany", (PyCFunction) Cursor_ExecuteMany, METH_VARARGS }, { "callproc", (PyCFunction) Cursor_CallProc, METH_VARARGS | METH_KEYWORDS }, { "callfunc", (PyCFunction) Cursor_CallFunc, METH_VARARGS | METH_KEYWORDS }, { "executemanyprepared", (PyCFunction) Cursor_ExecuteManyPrepared, METH_VARARGS }, { "setoutputsize", (PyCFunction) Cursor_SetOutputSize, METH_VARARGS }, { "var", (PyCFunction) Cursor_Var, METH_VARARGS | METH_KEYWORDS }, { "arrayvar", (PyCFunction) Cursor_ArrayVar, METH_VARARGS }, { "bindnames", (PyCFunction) Cursor_BindNames, METH_NOARGS }, { "close", (PyCFunction) Cursor_Close, METH_NOARGS }, { NULL, NULL } }; //----------------------------------------------------------------------------- // declaration of members for Python type "Cursor" //----------------------------------------------------------------------------- static PyMemberDef g_CursorMembers[] = { { "arraysize", T_INT, offsetof(udt_Cursor, arraySize), 0 }, { "bindarraysize", T_INT, offsetof(udt_Cursor, bindArraySize), 0 }, { "rowcount", T_INT, offsetof(udt_Cursor, rowCount), READONLY }, { "statement", T_OBJECT, offsetof(udt_Cursor, statement), READONLY }, { "connection", T_OBJECT_EX, offsetof(udt_Cursor, connection), READONLY }, { "numbersAsStrings", T_INT, offsetof(udt_Cursor, numbersAsStrings), 0 }, { "rowfactory", T_OBJECT, offsetof(udt_Cursor, rowFactory), 0 }, { "inputtypehandler", T_OBJECT, offsetof(udt_Cursor, inputTypeHandler), 0 }, { "outputtypehandler", T_OBJECT, offsetof(udt_Cursor, outputTypeHandler), 0 }, { NULL } }; //----------------------------------------------------------------------------- // declaration of calculated members for Python type "Connection" //----------------------------------------------------------------------------- static PyGetSetDef g_CursorCalcMembers[] = { { "description", (getter) Cursor_GetDescription, 0, 0, 0 }, { NULL } }; //----------------------------------------------------------------------------- // declaration of Python type "Cursor" //----------------------------------------------------------------------------- static PyTypeObject g_CursorType = { PyVarObject_HEAD_INIT(NULL, 0) "OracleCursor", // tp_name sizeof(udt_Cursor), // tp_basicsize 0, // tp_itemsize (destructor) Cursor_Free, // tp_dealloc 0, // tp_print 0, // tp_getattr 0, // tp_setattr 0, // tp_compare (reprfunc) Cursor_Repr, // 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 | Py_TPFLAGS_BASETYPE, // tp_flags 0, // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare 0, // tp_weaklistoffset (getiterfunc) Cursor_GetIter, // tp_iter (iternextfunc) Cursor_GetNext, // tp_iternext g_CursorMethods, // tp_methods g_CursorMembers, // tp_members g_CursorCalcMembers, // tp_getset 0, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc) Cursor_Init, // tp_init 0, // tp_alloc Cursor_New, // tp_new 0, // tp_free 0, // tp_is_gc 0 // tp_bases }; //----------------------------------------------------------------------------- // Cursor_AllocateHandle() // Allocate a new handle. //----------------------------------------------------------------------------- static int Cursor_AllocateHandle( udt_Cursor *self) // cursor object { sword status; self->isOwned = 1; status = OCIHandleAlloc(self->environment->handle, (dvoid**) &self->handle, OCI_HTYPE_STMT, 0, 0); if (Environment_CheckForError(self->environment, status, "Cursor_New()") < 0) return -1; return 0; } //----------------------------------------------------------------------------- // Cursor_FreeHandle() // Free the handle which may be reallocated if necessary. //----------------------------------------------------------------------------- static int Cursor_FreeHandle( udt_Cursor *self, // cursor object int raiseException) // raise an exception, if necesary? { udt_StringBuffer buffer; sword status; if (self->handle) { if (self->isOwned) { OCIHandleFree(self->handle, OCI_HTYPE_STMT); } else if (self->connection->handle != 0) { if (!StringBuffer_Fill(&buffer, self->statementTag) < 0) return (raiseException) ? -1 : 0; status = OCIStmtRelease(self->handle, self->environment->errorHandle, (text*) buffer.ptr, buffer.size, OCI_DEFAULT); StringBuffer_Clear(&buffer); if (raiseException && Environment_CheckForError( self->environment, status, "Cursor_FreeHandle()") < 0) return -1; } } return 0; } #include "Variable.c" //----------------------------------------------------------------------------- // Cursor_IsOpen() // Determines if the cursor object is open and if so, if the connection is // also open. //----------------------------------------------------------------------------- static int Cursor_IsOpen( udt_Cursor *self) // cursor to check { if (!self->isOpen) { PyErr_SetString(g_InterfaceErrorException, "not open"); return -1; } return Connection_IsConnected(self->connection); } //----------------------------------------------------------------------------- // Cursor_New() // Create a new cursor object. //----------------------------------------------------------------------------- static PyObject *Cursor_New( PyTypeObject *type, // type object PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { return type->tp_alloc(type, 0); } //----------------------------------------------------------------------------- // Cursor_Init() // Create a new cursor object. //----------------------------------------------------------------------------- static int Cursor_Init( udt_Cursor *self, // cursor object PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { udt_Connection *connection; // parse arguments if (!PyArg_ParseTuple(args, "O!", &g_ConnectionType, &connection)) return -1; // initialize members Py_INCREF(connection); self->connection = connection; self->environment = connection->environment; self->arraySize = 50; self->fetchArraySize = 50; self->bindArraySize = 1; self->statementType = -1; self->outputSize = -1; self->outputSizeColumn = -1; self->isOpen = 1; return 0; } //----------------------------------------------------------------------------- // Cursor_Repr() // Return a string representation of the cursor. //----------------------------------------------------------------------------- static PyObject *Cursor_Repr( udt_Cursor *cursor) // cursor to return the string for { PyObject *connectionRepr, *module, *name, *result, *format, *formatArgs; format = cxString_FromAscii("<%s.%s on %s>"); if (!format) return NULL; connectionRepr = PyObject_Repr((PyObject*) cursor->connection); if (!connectionRepr) { Py_DECREF(format); return NULL; } if (GetModuleAndName(Py_TYPE(cursor), &module, &name) < 0) { Py_DECREF(format); Py_DECREF(connectionRepr); return NULL; } formatArgs = PyTuple_Pack(3, module, name, connectionRepr); Py_DECREF(module); Py_DECREF(name); Py_DECREF(connectionRepr); if (!formatArgs) { Py_DECREF(format); return NULL; } result = cxString_Format(format, formatArgs); Py_DECREF(format); Py_DECREF(formatArgs); return result; } //----------------------------------------------------------------------------- // Cursor_Free() // Deallocate the cursor. //----------------------------------------------------------------------------- static void Cursor_Free( udt_Cursor *self) // cursor object { Cursor_FreeHandle(self, 0); Py_XDECREF(self->statement); Py_XDECREF(self->statementTag); Py_XDECREF(self->bindVariables); Py_XDECREF(self->fetchVariables); Py_XDECREF(self->connection); Py_XDECREF(self->rowFactory); Py_XDECREF(self->inputTypeHandler); Py_XDECREF(self->outputTypeHandler); Py_TYPE(self)->tp_free((PyObject*) self); } //----------------------------------------------------------------------------- // Cursor_GetBindNames() // Return a list of bind variable names. At this point the cursor must have // already been prepared. //----------------------------------------------------------------------------- static int Cursor_GetBindNames( udt_Cursor *self, // cursor to get information from int numElements, // number of elements (IN/OUT) PyObject **names) // list of names (OUT) { ub1 *bindNameLengths, *indicatorNameLengths, *duplicate; char *buffer, **bindNames, **indicatorNames; OCIBind **bindHandles; int elementSize, i; sb4 foundElements; PyObject *temp; sword status; // ensure that a statement has already been prepared if (!self->statement) { PyErr_SetString(g_ProgrammingErrorException, "statement must be prepared first"); return -1; } // avoid bus errors on 64-bit platforms numElements = numElements + (sizeof(void*) - numElements % sizeof(void*)); // initialize the buffers elementSize = sizeof(char*) + sizeof(ub1) + sizeof(char*) + sizeof(ub1) + sizeof(ub1) + sizeof(OCIBind*); buffer = (char*) PyMem_Malloc(numElements * elementSize); if (!buffer) { PyErr_NoMemory(); return -1; } bindNames = (char**) buffer; bindNameLengths = (ub1*) (((char*) bindNames) + sizeof(char*) * numElements); indicatorNames = (char**) (((char*) bindNameLengths) + sizeof(ub1) * numElements); indicatorNameLengths = (ub1*) (((char*) indicatorNames) + sizeof(char*) * numElements); duplicate = (ub1*) (((char*) indicatorNameLengths) + sizeof(ub1) * numElements); bindHandles = (OCIBind**) (((char*) duplicate) + sizeof(ub1) * numElements); // get the bind information status = OCIStmtGetBindInfo(self->handle, self->environment->errorHandle, numElements, 1, &foundElements, (text**) bindNames, bindNameLengths, (text**) indicatorNames, indicatorNameLengths, duplicate, bindHandles); if (status != OCI_NO_DATA && Environment_CheckForError(self->environment, status, "Cursor_GetBindNames()") < 0) return -1; if (foundElements < 0) { *names = NULL; PyMem_Free(buffer); return abs(foundElements); } // create the list which is to be returned *names = PyList_New(0); if (!*names) { PyMem_Free(buffer); return -1; } // process the bind information returned for (i = 0; i < foundElements; i++) { if (!duplicate[i]) { temp = cxString_FromEncodedString(bindNames[i], bindNameLengths[i]); if (!temp) { Py_DECREF(*names); PyMem_Free(buffer); return -1; } if (PyList_Append(*names, temp) < 0) { Py_DECREF(*names); Py_DECREF(temp); PyMem_Free(buffer); return -1; } Py_DECREF(temp); } } PyMem_Free(buffer); return 0; } //----------------------------------------------------------------------------- // Cursor_PerformDefine() // Perform the defines for the cursor. At this point it is assumed that the // statement being executed is in fact a query. //----------------------------------------------------------------------------- static int Cursor_PerformDefine( udt_Cursor *self) // cursor to perform define on { int numParams, pos; udt_Variable *var; sword status; // determine number of items in select-list status = OCIAttrGet(self->handle, OCI_HTYPE_STMT, (dvoid*) &numParams, 0, OCI_ATTR_PARAM_COUNT, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_PerformDefine()") < 0) return -1; // create a list corresponding to the number of items self->fetchVariables = PyList_New(numParams); if (!self->fetchVariables) return -1; // define a variable for each select-item self->fetchArraySize = self->arraySize; for (pos = 1; pos <= numParams; pos++) { var = Variable_Define(self, self->fetchArraySize, pos); if (!var) return -1; PyList_SET_ITEM(self->fetchVariables, pos - 1, (PyObject *) var); } return 0; } //----------------------------------------------------------------------------- // Cursor_SetRowCount() // Set the rowcount variable. //----------------------------------------------------------------------------- static int Cursor_SetRowCount( udt_Cursor *self) // cursor to set the rowcount on { ub4 rowCount; sword status; if (self->statementType == OCI_STMT_SELECT) { self->rowCount = 0; self->actualRows = -1; self->rowNum = 0; } else if (self->statementType == OCI_STMT_INSERT || self->statementType == OCI_STMT_UPDATE || self->statementType == OCI_STMT_DELETE) { status = OCIAttrGet(self->handle, OCI_HTYPE_STMT, &rowCount, 0, OCI_ATTR_ROW_COUNT, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_SetRowCount()") < 0) return -1; self->rowCount = rowCount; } else { self->rowCount = -1; } return 0; } //----------------------------------------------------------------------------- // Cursor_InternalExecute() // Perform the work of executing a cursor and set the rowcount appropriately // regardless of whether an error takes place. //----------------------------------------------------------------------------- static int Cursor_InternalExecute( udt_Cursor *self, // cursor to perform the execute on ub4 numIters) // number of iterations to execute { sword status; ub4 mode; if (self->connection->autocommit) mode = OCI_COMMIT_ON_SUCCESS; else mode = OCI_DEFAULT; Py_BEGIN_ALLOW_THREADS status = OCIStmtExecute(self->connection->handle, self->handle, self->environment->errorHandle, numIters, 0, 0, 0, mode); Py_END_ALLOW_THREADS if (Environment_CheckForError(self->environment, status, "Cursor_InternalExecute()") < 0) { if (Cursor_SetRowCount(self) < 0) PyErr_Clear(); return -1; } return Cursor_SetRowCount(self); } //----------------------------------------------------------------------------- // Cursor_GetStatementType() // Determine if the cursor is executing a select statement. //----------------------------------------------------------------------------- static int Cursor_GetStatementType( udt_Cursor *self) // cursor to perform binds on { ub2 statementType; sword status; status = OCIAttrGet(self->handle, OCI_HTYPE_STMT, (dvoid*) &statementType, 0, OCI_ATTR_STMT_TYPE, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_GetStatementType()") < 0) return -1; self->statementType = statementType; if (self->fetchVariables) { Py_DECREF(self->fetchVariables); self->fetchVariables = NULL; } return 0; } //----------------------------------------------------------------------------- // Cursor_FixupBoundCursor() // Fixup a cursor so that fetching and returning cursor descriptions are // successful after binding a cursor to another cursor. //----------------------------------------------------------------------------- static int Cursor_FixupBoundCursor( udt_Cursor *self) // cursor that may have been bound { if (self->handle && self->statementType < 0) { if (Cursor_GetStatementType(self) < 0) return -1; if (self->statementType == OCI_STMT_SELECT && Cursor_PerformDefine(self) < 0) return -1; if (Cursor_SetRowCount(self) < 0) return -1; } return 0; } //----------------------------------------------------------------------------- // Cursor_ItemDescriptionHelper() // Helper for Cursor_ItemDescription() used so that it is not necessary to // constantly free the descriptor when an error takes place. //----------------------------------------------------------------------------- static PyObject *Cursor_ItemDescriptionHelper( udt_Cursor *self, // cursor object unsigned pos, // position in description OCIParam *param) // parameter to use for description { udt_VariableType *varType; int displaySize, index; PyObject *tuple, *type; ub2 internalSize; ub4 nameLength; sb2 precision; sword status; char *name; ub1 nullOk; sb1 scale; // acquire usable type of item varType = Variable_TypeByOracleDescriptor(param, self->environment); if (!varType) return NULL; // acquire internal size of item status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &internalSize, 0, OCI_ATTR_DATA_SIZE, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): internal size") < 0) return NULL; // aquire name of item status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &nameLength, OCI_ATTR_NAME, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): name") < 0) return NULL; // lookup precision and scale scale = 0; precision = 0; if (varType->pythonType == &g_NumberVarType) { status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0, OCI_ATTR_SCALE, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): scale") < 0) return NULL; status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0, OCI_ATTR_PRECISION, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): precision") < 0) return NULL; } // lookup whether null is permitted for the attribute status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &nullOk, 0, OCI_ATTR_IS_NULL, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): nullable") < 0) return NULL; // set display size based on data type type = (PyObject*) varType->pythonType; if (type == (PyObject*) &g_StringVarType) displaySize = internalSize; #ifndef WITH_UNICODE else if (type == (PyObject*) &g_UnicodeVarType) displaySize = internalSize / 2; #endif else if (type == (PyObject*) &g_BinaryVarType) displaySize = internalSize; else if (type == (PyObject*) &g_FixedCharVarType) displaySize = internalSize; #ifndef WITH_UNICODE else if (type == (PyObject*) &g_FixedUnicodeVarType) displaySize = internalSize / 2; #endif else if (type == (PyObject*) &g_NumberVarType) { if (precision) { displaySize = precision + 1; if (scale > 0) displaySize += scale + 1; } else displaySize = 127; } else if (type == (PyObject*) &g_DateTimeVarType) { displaySize = 23; } else { displaySize = -1; } // create the tuple and populate it tuple = PyTuple_New(7); if (!tuple) return NULL; // set each of the items in the tuple PyTuple_SET_ITEM(tuple, 0, cxString_FromEncodedString(name, nameLength)); Py_INCREF(type); PyTuple_SET_ITEM(tuple, 1, type); PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(displaySize)); PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(internalSize)); PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(precision)); PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong(scale)); PyTuple_SET_ITEM(tuple, 6, PyInt_FromLong(nullOk != 0)); // make sure the tuple is ok for (index = 0; index < 7; index++) { if (!PyTuple_GET_ITEM(tuple, index)) { Py_DECREF(tuple); return NULL; } } return tuple; } //----------------------------------------------------------------------------- // Cursor_ItemDescription() // Return a tuple describing the item at the given position. //----------------------------------------------------------------------------- static PyObject *Cursor_ItemDescription( udt_Cursor *self, // cursor object unsigned pos) // position { PyObject *tuple; OCIParam *param; sword status; // acquire parameter descriptor status = OCIParamGet(self->handle, OCI_HTYPE_STMT, self->environment->errorHandle, (void**) ¶m, pos); if (Environment_CheckForError(self->environment, status, "Cursor_ItemDescription(): parameter") < 0) return NULL; // use helper routine to get tuple tuple = Cursor_ItemDescriptionHelper(self, pos, param); OCIDescriptorFree(param, OCI_DTYPE_PARAM); return tuple; } //----------------------------------------------------------------------------- // Cursor_GetDescription() // Return a list of 7-tuples consisting of the description of the define // variables. //----------------------------------------------------------------------------- static PyObject *Cursor_GetDescription( udt_Cursor *self, // cursor object void *arg) // optional argument (ignored) { PyObject *results, *tuple; int numItems, index; sword status; // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // fixup bound cursor, if necessary if (Cursor_FixupBoundCursor(self) < 0) return NULL; // if not a query, return None if (self->statementType != OCI_STMT_SELECT) { Py_INCREF(Py_None); return Py_None; } // determine number of items in select-list status = OCIAttrGet(self->handle, OCI_HTYPE_STMT, (dvoid*) &numItems, 0, OCI_ATTR_PARAM_COUNT, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_GetDescription()") < 0) return NULL; // create a list of the required length results = PyList_New(numItems); if (!results) return NULL; // create tuples corresponding to the select-items for (index = 0; index < numItems; index++) { tuple = Cursor_ItemDescription(self, index + 1); if (!tuple) { Py_DECREF(results); return NULL; } PyList_SET_ITEM(results, index, tuple); } return results; } //----------------------------------------------------------------------------- // Cursor_Close() // Close the cursor. //----------------------------------------------------------------------------- static PyObject *Cursor_Close( udt_Cursor *self, // cursor to close PyObject *args) // arguments { // make sure we are actually open if (Cursor_IsOpen(self) < 0) return NULL; // close the cursor if (Cursor_FreeHandle(self, 1) < 0) return NULL; self->handle = NULL; self->isOpen = 0; Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_SetBindVariableHelper() // Helper for setting a bind variable. //----------------------------------------------------------------------------- static int Cursor_SetBindVariableHelper( udt_Cursor *self, // cursor to perform bind on unsigned numElements, // number of elements to create unsigned arrayPos, // array position to set PyObject *value, // value to bind udt_Variable *origVar, // original variable bound udt_Variable **newVar, // new variable to be bound int deferTypeAssignment) // defer type assignment if null? { int isValueVar; // initialization *newVar = NULL; isValueVar = Variable_Check(value); // handle case where variable is already bound if (origVar) { // if the value is a variable object, rebind it if necessary if (isValueVar) { if ( (PyObject*) origVar != value) { Py_INCREF(value); *newVar = (udt_Variable*) value; } // if the number of elements has changed, create a new variable // this is only necessary for executemany() since execute() always // passes a value of 1 for the number of elements } else if (numElements > origVar->allocatedElements) { *newVar = Variable_New(self, numElements, origVar->type, origVar->maxLength); if (!*newVar) return -1; if (Variable_SetValue(*newVar, arrayPos, value) < 0) return -1; // otherwise, attempt to set the value } else if (Variable_SetValue(origVar, arrayPos, value) < 0) { // executemany() should simply fail after the first element if (arrayPos > 0) return -1; // anything other than index error or type error should fail if (!PyErr_ExceptionMatches(PyExc_IndexError) && !PyErr_ExceptionMatches(PyExc_TypeError)) return -1; // clear the exception and try to create a new variable PyErr_Clear(); origVar = NULL; } } // if no original variable used, create a new one if (!origVar) { // if the value is a variable object, bind it directly if (isValueVar) { Py_INCREF(value); *newVar = (udt_Variable*) value; (*newVar)->boundPos = 0; Py_XDECREF((*newVar)->boundName); (*newVar)->boundName = NULL; // otherwise, create a new variable, unless the value is None and // we wish to defer type assignment } else if (value != Py_None || !deferTypeAssignment) { *newVar = Variable_NewByValue(self, value, numElements); if (!*newVar) return -1; if (Variable_SetValue(*newVar, arrayPos, value) < 0) return -1; } } return 0; } //----------------------------------------------------------------------------- // Cursor_SetBindVariables() // Create or set bind variables. //----------------------------------------------------------------------------- static int Cursor_SetBindVariables( udt_Cursor *self, // cursor to perform binds on PyObject *parameters, // parameters to bind unsigned numElements, // number of elements to create unsigned arrayPos, // array position to set int deferTypeAssignment) // defer type assignment if null? { int i, origBoundByPos, origNumParams, boundByPos, numParams; PyObject *key, *value, *origVar; udt_Variable *newVar; Py_ssize_t pos; // make sure positional and named binds are not being intermixed numParams = 0; boundByPos = PySequence_Check(parameters); if (boundByPos) { numParams = PySequence_Size(parameters); if (numParams < 0) return -1; } if (self->bindVariables) { origBoundByPos = PyList_Check(self->bindVariables); if (boundByPos != origBoundByPos) { PyErr_SetString(g_ProgrammingErrorException, "positional and named binds cannot be intermixed"); return -1; } origNumParams = PyList_GET_SIZE(self->bindVariables); // otherwise, create the list or dictionary if needed } else { if (boundByPos) self->bindVariables = PyList_New(numParams); else self->bindVariables = PyDict_New(); if (!self->bindVariables) return -1; origNumParams = 0; } // handle positional binds if (boundByPos) { for (i = 0; i < numParams; i++) { value = PySequence_GetItem(parameters, i); if (!value) return -1; Py_DECREF(value); if (i < origNumParams) { origVar = PyList_GET_ITEM(self->bindVariables, i); if (origVar == Py_None) origVar = NULL; } else origVar = NULL; if (Cursor_SetBindVariableHelper(self, numElements, arrayPos, value, (udt_Variable*) origVar, &newVar, deferTypeAssignment) < 0) return -1; if (newVar) { if (i < PyList_GET_SIZE(self->bindVariables)) { if (PyList_SetItem(self->bindVariables, i, (PyObject*) newVar) < 0) { Py_DECREF(newVar); return -1; } } else { if (PyList_Append(self->bindVariables, (PyObject*) newVar) < 0) { Py_DECREF(newVar); return -1; } Py_DECREF(newVar); } } } // handle named binds } else { pos = 0; while (PyDict_Next(parameters, &pos, &key, &value)) { origVar = PyDict_GetItem(self->bindVariables, key); if (Cursor_SetBindVariableHelper(self, numElements, arrayPos, value, (udt_Variable*) origVar, &newVar, deferTypeAssignment) < 0) return -1; if (newVar) { if (PyDict_SetItem(self->bindVariables, key, (PyObject*) newVar) < 0) { Py_DECREF(newVar); return -1; } Py_DECREF(newVar); } } } return 0; } //----------------------------------------------------------------------------- // Cursor_PerformBind() // Perform the binds on the cursor. //----------------------------------------------------------------------------- static int Cursor_PerformBind( udt_Cursor *self) // cursor to perform binds on { PyObject *key, *var; Py_ssize_t pos; ub2 i; // set values and perform binds for all bind variables if (self->bindVariables) { if (PyDict_Check(self->bindVariables)) { pos = 0; while (PyDict_Next(self->bindVariables, &pos, &key, &var)) { if (Variable_Bind((udt_Variable*) var, self, key, 0) < 0) return -1; } } else { for (i = 0; i < (ub2) PyList_GET_SIZE(self->bindVariables); i++) { var = PyList_GET_ITEM(self->bindVariables, i); if (var != Py_None) { if (Variable_Bind((udt_Variable*) var, self, NULL, i + 1) < 0) return -1; } } } } // ensure that input sizes are reset self->setInputSizes = 0; return 0; } //----------------------------------------------------------------------------- // Cursor_CreateRow() // Create an object for the row. The object created is a tuple unless a row // factory function has been defined in which case it is the result of the // row factory function called with the argument tuple that would otherwise be // returned. //----------------------------------------------------------------------------- static PyObject *Cursor_CreateRow( udt_Cursor *self) // cursor object { PyObject *tuple, *item, *result; int numItems, pos; udt_Variable *var; // create a new tuple numItems = PyList_GET_SIZE(self->fetchVariables); tuple = PyTuple_New(numItems); if (!tuple) return NULL; // acquire the value for each item for (pos = 0; pos < numItems; pos++) { var = (udt_Variable*) PyList_GET_ITEM(self->fetchVariables, pos); item = Variable_GetValue(var, self->rowNum); if (!item) { Py_DECREF(tuple); return NULL; } PyTuple_SET_ITEM(tuple, pos, item); } // increment row counters self->rowNum++; self->rowCount++; // if a row factory is defined, call it if (self->rowFactory && self->rowFactory != Py_None) { result = PyObject_CallObject(self->rowFactory, tuple); Py_DECREF(tuple); return result; } return tuple; } //----------------------------------------------------------------------------- // Cursor_InternalPrepare() // Internal method for preparing a statement for execution. //----------------------------------------------------------------------------- static int Cursor_InternalPrepare( udt_Cursor *self, // cursor to perform prepare on PyObject *statement, // statement to prepare PyObject *statementTag) // tag of statement to prepare { udt_StringBuffer statementBuffer, tagBuffer; sword status; // make sure we don't get a situation where nothing is to be executed if (statement == Py_None && !self->statement) { PyErr_SetString(g_ProgrammingErrorException, "no statement specified and no prior statement prepared"); return -1; } // nothing to do if the statement is identical to the one already stored // but go ahead and prepare anyway for create, alter and drop statments if (statement == Py_None || statement == self->statement) { if (self->statementType != OCI_STMT_CREATE && self->statementType != OCI_STMT_DROP && self->statementType != OCI_STMT_ALTER) return 0; statement = self->statement; } // keep track of the statement Py_XDECREF(self->statement); Py_INCREF(statement); self->statement = statement; // release existing statement, if necessary Py_XDECREF(self->statementTag); Py_XINCREF(statementTag); self->statementTag = statementTag; if (Cursor_FreeHandle(self, 1) < 0) return -1; // prepare statement Py_BEGIN_ALLOW_THREADS self->isOwned = 0; if (StringBuffer_Fill(&statementBuffer, statement) < 0) return -1; if (StringBuffer_Fill(&tagBuffer, statementTag) < 0) { StringBuffer_Clear(&statementBuffer); return -1; } status = OCIStmtPrepare2(self->connection->handle, &self->handle, self->environment->errorHandle, (text*) statementBuffer.ptr, statementBuffer.size, (text*) tagBuffer.ptr, tagBuffer.size, OCI_NTV_SYNTAX, OCI_DEFAULT); Py_END_ALLOW_THREADS StringBuffer_Clear(&statementBuffer); StringBuffer_Clear(&tagBuffer); if (Environment_CheckForError(self->environment, status, "Cursor_InternalPrepare(): prepare") < 0) { // this is needed to avoid "invalid handle" errors since Oracle doesn't // seem to leave the pointer alone when an error is raised but the // resulting handle is still invalid self->handle = NULL; return -1; } // clear bind variables, if applicable if (!self->setInputSizes) { Py_XDECREF(self->bindVariables); self->bindVariables = NULL; } // clear row factory, if spplicable Py_XDECREF(self->rowFactory); self->rowFactory = NULL; // determine if statement is a query if (Cursor_GetStatementType(self) < 0) return -1; return 0; } //----------------------------------------------------------------------------- // Cursor_Parse() // Parse the statement without executing it. This also retrieves information // about the select list for select statements. //----------------------------------------------------------------------------- static PyObject *Cursor_Parse( udt_Cursor *self, // cursor to perform parse on PyObject *args) // arguments { PyObject *statement; sword status; // statement text is expected if (!PyArg_ParseTuple(args, "S", &statement)) return NULL; // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // prepare the statement if (Cursor_InternalPrepare(self, statement, NULL) < 0) return NULL; // parse the statement Py_BEGIN_ALLOW_THREADS status = OCIStmtExecute(self->connection->handle, self->handle, self->environment->errorHandle, 0, 0, 0, 0, OCI_DESCRIBE_ONLY); Py_END_ALLOW_THREADS if (Environment_CheckForError(self->environment, status, "Cursor_Parse()") < 0) return NULL; Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_Prepare() // Prepare the statement for execution. //----------------------------------------------------------------------------- static PyObject *Cursor_Prepare( udt_Cursor *self, // cursor to perform prepare on PyObject *args) // arguments { PyObject *statement, *statementTag; // statement text and optional tag is expected statementTag = NULL; if (!PyArg_ParseTuple(args, "O!|O!", cxString_Type, &statement, cxString_Type, &statementTag)) return NULL; // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // prepare the statement if (Cursor_InternalPrepare(self, statement, statementTag) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_Call() // Call a stored procedure or function. //----------------------------------------------------------------------------- static int Cursor_Call( udt_Cursor *self, // cursor to call procedure/function udt_Variable *returnValue, // return value variable (optional) PyObject *name, // name of procedure/function to call PyObject *listOfArguments) // arguments to procedure/function { PyObject *bindVariables, *results, *arguments, *statementObj; int numArguments, statementSize, i, offset; PyObject *format, *formatArgs; char *statement, *ptr; // determine the number of arguments passed if (listOfArguments) { if (!PySequence_Check(listOfArguments)) { PyErr_SetString(PyExc_TypeError, "arguments must be a sequence"); return -1; } numArguments = PySequence_Size(listOfArguments); if (numArguments < 0) return -1; } else { numArguments = 0; listOfArguments = PyList_New(0); if (!listOfArguments) return -1; } // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return -1; // determine the statement size add the return value, if applicable offset = 0; statementSize = numArguments * 9 + 17; if (returnValue) { offset = 1; statementSize += 10; bindVariables = PySequence_List(listOfArguments); if (!bindVariables) return -1; if (PyList_Insert(bindVariables, 0, (PyObject*) returnValue) < 0) { Py_DECREF(bindVariables); return -1; } } else { Py_INCREF(listOfArguments); bindVariables = listOfArguments; } // allocate a string for the statement statement = (char*) PyMem_Malloc(statementSize); if (!statement) { Py_DECREF(bindVariables); PyErr_NoMemory(); return -1; } // build up the statement arguments = PySequence_Fast(listOfArguments, "expecting sequence of arguments"); if (!arguments) { Py_DECREF(bindVariables); PyMem_Free(statement); return -1; } strcpy(statement, "begin "); if (returnValue) strcat(statement, ":1 := "); strcat(statement, "%s"); ptr = statement + strlen(statement); *ptr++ = '('; for (i = 0; i < numArguments; i++) { if (i > 0) *ptr++ = ','; ptr += sprintf(ptr, ":%d", i + offset + 1); if (PyBool_Check(PySequence_Fast_GET_ITEM(arguments, i))) ptr += sprintf(ptr, " = 1"); } strcpy(ptr, "); end;"); Py_DECREF(arguments); // create the statement object format = PyBytes_FromString(statement); PyMem_Free(statement); if (!format) { Py_DECREF(bindVariables); return -1; } formatArgs = PyTuple_New(1); if (!formatArgs) { Py_DECREF(bindVariables); Py_DECREF(format); return -1; } Py_INCREF(name); PyTuple_SET_ITEM(formatArgs, 0, name); statementObj = cxString_Format(format, formatArgs); Py_DECREF(format); Py_DECREF(formatArgs); if (!statementObj) { Py_DECREF(bindVariables); return -1; } // execute the statement on the cursor results = PyObject_CallMethod( (PyObject*) self, "execute", "OO", statementObj, bindVariables); Py_DECREF(statementObj); Py_DECREF(bindVariables); if (!results) return -1; Py_DECREF(results); return 0; } //----------------------------------------------------------------------------- // Cursor_CallFunc() // Call a stored function and return the return value of the function. //----------------------------------------------------------------------------- static PyObject *Cursor_CallFunc( udt_Cursor *self, // cursor to execute PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { static char *keywordList[] = { "name", "returnType", "parameters", NULL }; PyObject *listOfArguments, *returnType, *results, *name; udt_Variable *var; // expect stored function name, return type and optionally a list of // arguments listOfArguments = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O!O|O", keywordList, cxString_Type, &name, &returnType, &listOfArguments)) return NULL; // create the return variable var = Variable_NewByType(self, returnType, 1); if (!var) return NULL; // call the function if (Cursor_Call(self, var, name, listOfArguments) < 0) return NULL; // determine the results results = Variable_GetValue(var, 0); Py_DECREF(var); return results; } //----------------------------------------------------------------------------- // Cursor_CallProc() // Call a stored procedure and return the (possibly modified) arguments. //----------------------------------------------------------------------------- static PyObject *Cursor_CallProc( udt_Cursor *self, // cursor to execute PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { static char *keywordList[] = { "name", "parameters", NULL }; PyObject *listOfArguments, *results, *var, *temp, *name; int numArgs, i; // expect stored procedure name and optionally a list of arguments listOfArguments = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O!|O", keywordList, cxString_Type, &name, &listOfArguments)) return NULL; // call the stored procedure if (Cursor_Call(self, NULL, name, listOfArguments) < 0) return NULL; // create the return value numArgs = PyList_GET_SIZE(self->bindVariables); results = PyList_New(numArgs); if (!results) return NULL; for (i = 0; i < numArgs; i++) { var = PyList_GET_ITEM(self->bindVariables, i); temp = Variable_GetValue((udt_Variable*) var, 0); if (!temp) { Py_DECREF(results); return NULL; } PyList_SET_ITEM(results, i, temp); } return results; } //----------------------------------------------------------------------------- // Cursor_Execute() // Execute the statement. //----------------------------------------------------------------------------- static PyObject *Cursor_Execute( udt_Cursor *self, // cursor to execute PyObject *args, // arguments PyObject *keywordArgs) // keywords { PyObject *statement, *executeArgs; int isQuery; executeArgs = NULL; if (!PyArg_ParseTuple(args, "O|O", &statement, &executeArgs)) return NULL; if (statement != Py_None && !cxString_Check(statement)) { PyErr_SetString(PyExc_TypeError, "expecting None or a string"); return NULL; } if (executeArgs && keywordArgs) { if (PyDict_Size(keywordArgs) == 0) keywordArgs = NULL; else { PyErr_SetString(g_InterfaceErrorException, "expecting argument or keyword arguments, not both"); return NULL; } } if (keywordArgs) executeArgs = keywordArgs; if (executeArgs) { if (!PyDict_Check(executeArgs) && !PySequence_Check(executeArgs)) { PyErr_SetString(PyExc_TypeError, "expecting a dictionary, sequence or keyword args"); return NULL; } } // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // prepare the statement, if applicable if (Cursor_InternalPrepare(self, statement, NULL) < 0) return NULL; // perform binds if (executeArgs && Cursor_SetBindVariables(self, executeArgs, 1, 0, 0) < 0) return NULL; if (Cursor_PerformBind(self) < 0) return NULL; // execute the statement isQuery = (self->statementType == OCI_STMT_SELECT); if (Cursor_InternalExecute(self, isQuery ? 0 : 1) < 0) return NULL; // perform defines, if necessary if (isQuery && !self->fetchVariables && Cursor_PerformDefine(self) < 0) return NULL; // reset the values of setoutputsize() self->outputSize = -1; self->outputSizeColumn = -1; // for queries, return the defined variables for possible use if (isQuery) { Py_INCREF(self->fetchVariables); return self->fetchVariables; } // for all other statements, simply return None Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_ExecuteMany() // Execute the statement many times. The number of times is equivalent to the // number of elements in the array of dictionaries. //----------------------------------------------------------------------------- static PyObject *Cursor_ExecuteMany( udt_Cursor *self, // cursor to execute PyObject *args) // arguments { PyObject *arguments, *listOfArguments, *statement; int i, numRows; // expect statement text (optional) plus list of mappings if (!PyArg_ParseTuple(args, "OO!", &statement, &PyList_Type, &listOfArguments)) return NULL; if (statement != Py_None && !cxString_Check(statement)) { PyErr_SetString(PyExc_TypeError, "expecting None or string"); return NULL; } // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // prepare the statement if (Cursor_InternalPrepare(self, statement, NULL) < 0) return NULL; // queries are not supported as the result is undefined if (self->statementType == OCI_STMT_SELECT) { PyErr_SetString(g_NotSupportedErrorException, "queries not supported: results undefined"); return NULL; } // perform binds numRows = PyList_GET_SIZE(listOfArguments); for (i = 0; i < numRows; i++) { arguments = PyList_GET_ITEM(listOfArguments, i); if (!PyDict_Check(arguments) && !PySequence_Check(arguments)) { PyErr_SetString(g_InterfaceErrorException, "expecting a list of dictionaries or sequences"); return NULL; } if (Cursor_SetBindVariables(self, arguments, numRows, i, (i < numRows - 1)) < 0) return NULL; } if (Cursor_PerformBind(self) < 0) return NULL; // execute the statement, but only if the number of rows is greater than // zero since Oracle raises an error otherwise if (numRows > 0) { if (Cursor_InternalExecute(self, numRows) < 0) return NULL; } Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_ExecuteManyPrepared() // Execute the prepared statement the number of times requested. At this // point, the statement must have been already prepared and the bind variables // must have their values set. //----------------------------------------------------------------------------- static PyObject *Cursor_ExecuteManyPrepared( udt_Cursor *self, // cursor to execute PyObject *args) // arguments { int numIters; // expect number of times to execute the statement if (!PyArg_ParseTuple(args, "i", &numIters)) return NULL; if (numIters > self->bindArraySize) { PyErr_SetString(g_InterfaceErrorException, "iterations exceed bind array size"); return NULL; } // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // queries are not supported as the result is undefined if (self->statementType == OCI_STMT_SELECT) { PyErr_SetString(g_NotSupportedErrorException, "queries not supported: results undefined"); return NULL; } // perform binds if (Cursor_PerformBind(self) < 0) return NULL; // execute the statement if (Cursor_InternalExecute(self, numIters) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_VerifyFetch() // Verify that fetching may happen from this cursor. //----------------------------------------------------------------------------- static int Cursor_VerifyFetch( udt_Cursor *self) // cursor to fetch from { // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return -1; // fixup bound cursor, if necessary if (Cursor_FixupBoundCursor(self) < 0) return -1; // make sure the cursor is for a query if (self->statementType != OCI_STMT_SELECT) { PyErr_SetString(g_InterfaceErrorException, "not a query"); return -1; } return 0; } //----------------------------------------------------------------------------- // Cursor_InternalFetch() // Performs the actual fetch from Oracle. //----------------------------------------------------------------------------- static int Cursor_InternalFetch( udt_Cursor *self, // cursor to fetch from int numRows) // number of rows to fetch { udt_Variable *var; sword status; ub4 rowCount; int i; if (!self->fetchVariables) { PyErr_SetString(g_InterfaceErrorException, "query not executed"); return -1; } Py_BEGIN_ALLOW_THREADS status = OCIStmtFetch(self->handle, self->environment->errorHandle, numRows, OCI_FETCH_NEXT, OCI_DEFAULT); Py_END_ALLOW_THREADS if (status != OCI_NO_DATA) { if (Environment_CheckForError(self->environment, status, "Cursor_InternalFetch(): fetch") < 0) return -1; } for (i = 0; i < PyList_GET_SIZE(self->fetchVariables); i++) { var = (udt_Variable*) PyList_GET_ITEM(self->fetchVariables, i); var->internalFetchNum++; } status = OCIAttrGet(self->handle, OCI_HTYPE_STMT, &rowCount, 0, OCI_ATTR_ROW_COUNT, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Cursor_InternalFetch(): row count") < 0) return -1; self->actualRows = rowCount - self->rowCount; self->rowNum = 0; return 0; } //----------------------------------------------------------------------------- // Cursor_MoreRows() // Returns an integer indicating if more rows can be retrieved from the // cursor. //----------------------------------------------------------------------------- static int Cursor_MoreRows( udt_Cursor *self) // cursor to fetch from { if (self->rowNum >= self->actualRows) { if (self->actualRows < 0 || self->actualRows == self->fetchArraySize) { if (Cursor_InternalFetch(self, self->fetchArraySize) < 0) return -1; } if (self->rowNum >= self->actualRows) return 0; } return 1; } //----------------------------------------------------------------------------- // Cursor_MultiFetch() // Return a list consisting of the remaining rows up to the given row limit // (if specified). //----------------------------------------------------------------------------- static PyObject *Cursor_MultiFetch( udt_Cursor *self, // cursor to fetch from int rowLimit) // row limit { PyObject *results, *row; int rowNum, status; // create an empty list results = PyList_New(0); if (!results) return NULL; // fetch as many rows as possible for (rowNum = 0; rowLimit == 0 || rowNum < rowLimit; rowNum++) { status = Cursor_MoreRows(self); if (status < 0) { Py_DECREF(results); return NULL; } else if (status == 0) { break; } else { row = Cursor_CreateRow(self); if (!row) { Py_DECREF(results); return NULL; } if (PyList_Append(results, row) < 0) { Py_DECREF(row); Py_DECREF(results); return NULL; } Py_DECREF(row); } } return results; } //----------------------------------------------------------------------------- // Cursor_FetchOne() // Fetch a single row from the cursor. //----------------------------------------------------------------------------- static PyObject *Cursor_FetchOne( udt_Cursor *self, // cursor to fetch from PyObject *args) // arguments { int status; // verify fetch can be performed if (Cursor_VerifyFetch(self) < 0) return NULL; // setup return value status = Cursor_MoreRows(self); if (status < 0) return NULL; else if (status > 0) return Cursor_CreateRow(self); Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_FetchMany() // Fetch multiple rows from the cursor based on the arraysize. //----------------------------------------------------------------------------- static PyObject *Cursor_FetchMany( udt_Cursor *self, // cursor to fetch from PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { static char *keywordList[] = { "numRows", NULL }; int rowLimit; // parse arguments -- optional rowlimit expected rowLimit = self->arraySize; if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList, &rowLimit)) return NULL; // verify fetch can be performed if (Cursor_VerifyFetch(self) < 0) return NULL; return Cursor_MultiFetch(self, rowLimit); } //----------------------------------------------------------------------------- // Cursor_FetchAll() // Fetch all remaining rows from the cursor. //----------------------------------------------------------------------------- static PyObject *Cursor_FetchAll( udt_Cursor *self, // cursor to fetch from PyObject *args) // arguments { if (Cursor_VerifyFetch(self) < 0) return NULL; return Cursor_MultiFetch(self, 0); } //----------------------------------------------------------------------------- // Cursor_FetchRaw() // Perform raw fetch on the cursor; return the actual number of rows fetched. //----------------------------------------------------------------------------- static PyObject *Cursor_FetchRaw( udt_Cursor *self, // cursor to fetch from PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { static char *keywordList[] = { "numRows", NULL }; int numRowsToFetch, numRowsFetched; // expect an optional number of rows to retrieve numRowsToFetch = self->fetchArraySize; if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList, &numRowsToFetch)) return NULL; if (numRowsToFetch > self->fetchArraySize) { PyErr_SetString(g_InterfaceErrorException, "rows to fetch exceeds array size"); return NULL; } // do not attempt to perform fetch if no more rows to fetch if (self->actualRows > 0 && self->actualRows < self->fetchArraySize) return PyInt_FromLong(0); // perform internal fetch if (Cursor_InternalFetch(self, numRowsToFetch) < 0) return NULL; self->rowCount += self->actualRows; numRowsFetched = self->actualRows; if (self->actualRows == numRowsToFetch) self->actualRows = -1; return PyInt_FromLong(numRowsFetched); } //----------------------------------------------------------------------------- // Cursor_SetInputSizes() // Set the sizes of the bind variables. //----------------------------------------------------------------------------- static PyObject *Cursor_SetInputSizes( udt_Cursor *self, // cursor to fetch from PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { int numPositionalArgs; PyObject *key, *value; udt_Variable *var; Py_ssize_t i; // only expect keyword arguments or positional arguments, not both numPositionalArgs = PyTuple_Size(args); if (keywordArgs && numPositionalArgs > 0) { PyErr_SetString(g_InterfaceErrorException, "expecting arguments or keyword arguments, not both"); return NULL; } // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // eliminate existing bind variables Py_XDECREF(self->bindVariables); if (keywordArgs) self->bindVariables = PyDict_New(); else self->bindVariables = PyList_New(numPositionalArgs); if (!self->bindVariables) return NULL; self->setInputSizes = 1; // process each input if (keywordArgs) { i = 0; while (PyDict_Next(keywordArgs, &i, &key, &value)) { var = Variable_NewByType(self, value, self->bindArraySize); if (!var) return NULL; if (PyDict_SetItem(self->bindVariables, key, (PyObject*) var) < 0) { Py_DECREF(var); return NULL; } Py_DECREF(var); } } else { for (i = 0; i < numPositionalArgs; i++) { value = PyTuple_GET_ITEM(args, i); if (value == Py_None) { Py_INCREF(Py_None); PyList_SET_ITEM(self->bindVariables, i, Py_None); } else { var = Variable_NewByType(self, value, self->bindArraySize); if (!var) return NULL; PyList_SET_ITEM(self->bindVariables, i, (PyObject*) var); } } } Py_INCREF(self->bindVariables); return self->bindVariables; } //----------------------------------------------------------------------------- // Cursor_SetOutputSize() // Set the size of all of the long columns or just one of them. //----------------------------------------------------------------------------- static PyObject *Cursor_SetOutputSize( udt_Cursor *self, // cursor to fetch from PyObject *args) // arguments { self->outputSizeColumn = -1; if (!PyArg_ParseTuple(args, "i|i", &self->outputSize, &self->outputSizeColumn)) return NULL; Py_INCREF(Py_None); return Py_None; } //----------------------------------------------------------------------------- // Cursor_Var() // Create a bind variable and return it. //----------------------------------------------------------------------------- static PyObject *Cursor_Var( udt_Cursor *self, // cursor to fetch from PyObject *args, // arguments PyObject *keywordArgs) // keyword arguments { static char *keywordList[] = { "type", "size", "arraysize", "inconverter", "outconverter", NULL }; PyObject *inConverter, *outConverter; udt_VariableType *varType; int size, arraySize; udt_Variable *var; PyObject *type; // parse arguments size = 0; arraySize = self->bindArraySize; inConverter = outConverter = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O|iiOO", keywordList, &type, &size, &arraySize, &inConverter, &outConverter)) return NULL; // determine the type of variable varType = Variable_TypeByPythonType(self, type); if (!varType) return NULL; if (varType->isVariableLength && size == 0) size = varType->elementLength; // create the variable var = Variable_New(self, arraySize, varType, size); if (!var) return NULL; Py_XINCREF(inConverter); var->inConverter = inConverter; Py_XINCREF(outConverter); var->outConverter = outConverter; return (PyObject*) var; } //----------------------------------------------------------------------------- // Cursor_ArrayVar() // Create an array bind variable and return it. //----------------------------------------------------------------------------- static PyObject *Cursor_ArrayVar( udt_Cursor *self, // cursor to fetch from PyObject *args) // arguments { udt_VariableType *varType; int length, numElements; PyObject *type, *value; udt_Variable *var; // parse arguments length = 0; if (!PyArg_ParseTuple(args, "OO|i", &type, &value, &length)) return NULL; // determine the type of variable varType = Variable_TypeByPythonType(self, type); if (!varType) return NULL; if (varType->isVariableLength && length == 0) length = varType->elementLength; // determine the number of elements to create if (PyList_Check(value)) numElements = PyList_GET_SIZE(value); else if (PyInt_Check(value)) numElements = PyInt_AS_LONG(value); else { PyErr_SetString(PyExc_TypeError, "expecting integer or list of values"); return NULL; } // create the variable var = Variable_New(self, numElements, varType, length); if (!var) return NULL; if (Variable_MakeArray(var) < 0) { Py_DECREF(var); return NULL; } // set the value, if applicable if (PyList_Check(value)) { if (Variable_SetArrayValue(var, value) < 0) return NULL; } return (PyObject*) var; } //----------------------------------------------------------------------------- // Cursor_BindNames() // Return a list of bind variable names. //----------------------------------------------------------------------------- static PyObject *Cursor_BindNames( udt_Cursor *self, // cursor to fetch from PyObject *args) // arguments { PyObject *names; int result; // make sure the cursor is open if (Cursor_IsOpen(self) < 0) return NULL; // return result result = Cursor_GetBindNames(self, 8, &names); if (result < 0) return NULL; if (!names && Cursor_GetBindNames(self, result, &names) < 0) return NULL; return names; } //----------------------------------------------------------------------------- // Cursor_GetIter() // Return a reference to the cursor which supports the iterator protocol. //----------------------------------------------------------------------------- static PyObject *Cursor_GetIter( udt_Cursor *self) // cursor { if (Cursor_VerifyFetch(self) < 0) return NULL; Py_INCREF(self); return (PyObject*) self; } //----------------------------------------------------------------------------- // Cursor_GetNext() // Return a reference to the cursor which supports the iterator protocol. //----------------------------------------------------------------------------- static PyObject *Cursor_GetNext( udt_Cursor *self) // cursor { int status; if (Cursor_VerifyFetch(self) < 0) return NULL; status = Cursor_MoreRows(self); if (status < 0) return NULL; else if (status > 0) return Cursor_CreateRow(self); // no more rows, return NULL without setting an exception return NULL; }