Hi you remember my report
http://mail.zope.org/pipermail/zope/2005-August/160762.html of an BUG for the handling of LONGs in DCO2? The consequence of this BUG is stochastic results for LONG fields We use an Fix of this BUG: Hint: The Documentation of the OCI from Oracle say us: defnp (IN), iter (IN), bufpp (OUT), alenpp (IN/OUT), piecep (IN/OUT), indpp (IN), rcodep (IN) Caution: When working with callback parameters, it is important to keep in mind what is meant by IN and OUT for the parameter mode. Normally, in an OCI function, an IN parameter refers to data being passed to Oracle, and an OUT parameter refers to data coming back from Oracle. In the case of callbacks, this is reversed. IN means data is coming from Oracle into the callback, and OUT means data is coming out of the callback and going to Oracle. Docu from OCI for OCIDefineByPos: indp (IN/OUT), alenp (IN/OUT), rcodep (OUT): Ignored for dynamic binds. First we fix Cursor_ResultSet and Second we fix Cursor_fetch: First Fix: static PyObject *Cursor_ResultSet(Cursor *self, int count) { PyObject *list; ResultSet *rs; int status; int i; sword mode = OCI_DEFAULT; dvoid *valuep; ub4 width; LongFetch *lf; TRACE(T_ENTRY,("sAd", "Cursor_ResultSet", self, count)); if (self->definition == NULL) { TRACE(T_ERROR,("ss","Cursor_ResultSet","description is NULL")); PyErr_SetString(ProgrammingErrorObject, "cursor description is None"); return NULL; } self->batchsz = count; if ((list = Py_BuildValue("[]")) == NULL) { TRACE(T_ERROR,("ss","Cursor_ResultSet", "PyBuildValue returned NULL")); return NULL; } for (i = 1; i <= PyList_Size(self->definition); i++) { mode = OCI_DEFAULT; if ((rs = (ResultSet *) ResultSet_alloc(self, i, count)) == NULL) { Py_DECREF(list); TRACE(T_ERROR,("ss","Cursor_ResultSet", "ResultSetAlloc returned NULL")); return NULL; } valuep = rs->valuep; width = rs->width; rs->fetchResultCode = OCI_SUCCESS; if (self->flags & LONG_COLUMN && (char) i == self->longcol) { mode = OCI_DYNAMIC_FETCH; lf = (LongFetch *) rs->valuep; longFetchInit(lf); /*valuep = NULL;*/ width = 0x7FFFFFFF; /* Max unsigned long */ rs->indp = &lf->ind; //KMH, 2.8.2005 synchronisation of dynamicFetch with ResultSet rs->rcodep = &lf->rcode; //KMH, 2.8.2005 synchronisation of dynamicFetch with ResultSet } TRACE(T_CALL,("sdAddd", "OCIDefineByPos", i, valuep, width, rs->cdty, mode)); /* Now bind the result set */ /* Docu from OCI: indp (IN/OUT), alenp (IN/OUT), rcodep (OUT): Ignored for dynamic binds. */ status = OCIDefineByPos(self->stmtp, &(rs->defnp), self->errhp, i, valuep, width, rs->cdty, (dvoid *) rs->indp, rs->rlenp, rs->rcodep, mode); TRACE(T_RETURN,("sR", "OCIDefineByPos", status)); if (status != OCI_SUCCESS) { Py_DECREF(rs); Py_DECREF(list); return RaiseOCIError(self->errhp, OCI_HTYPE_ERROR); } if (self->flags & LONG_COLUMN && (char) i == self->longcol) { TRACE(T_CALL,("sA", "OCIDefineDynamic", rs->valuep)); status = OCIDefineDynamic(rs->defnp, self->errhp, (dvoid *) rs->valuep, (OCICallbackDefine) dynamicFetch); TRACE(T_RETURN,("sR", "OCIDefineDynamic", status)); if (status != OCI_SUCCESS) { Py_DECREF(rs); Py_DECREF(list); return RaiseOCIError(self->errhp, OCI_HTYPE_ERROR); } } PyList_Append(list, OBJECT(rs)); Py_DECREF(rs); /* Now that its in the list ... */ } if (self->results != NULL) { Py_DECREF(self->results); } self->results = list; self->current = 0; Py_INCREF(Py_None); TRACE(T_EXIT,("s","Cursor_ResultSet")); return Py_None; } Second Fix: static PyObject *Cursor_fetch(Cursor *self, PyObject *args) { int count = 1; ub4 rcount; int status; ub2 *rlenp; ResultSet *rs; int i; int j; int resetlong = 0; int releaseresults = 0; PyObject *answer; TRACE(T_ENTRY,("sAA", "Cursor_fetch", self, args)); /* bindObject may have bound this cursor, in which case we ** must refetch the description */ if (self->flags & CURSOR_INSPECT) Cursor_getdesc(self); if (!PyArg_ParseTuple(args, "|i", &count)) return NULL; TRACE(T_ARGS,("sd", "Cursor_fetch", count)); if (count < 1 || count > 200) { PyErr_SetString(PyExc_ValueError, "Count out of range"); return NULL; } if (self->flags & LONG_COLUMN) { count = 1; /* Should we raise an error? */ if (self->current != -1) resetlong = 1; } if (self->flags & NO_RESULT) { TRACE((T_PROGRAM|T_ERROR),("ss","Cursor_fetch", "no result set from execute")); PyErr_SetObject(ProgrammingErrorObject, Py_BuildValue("s", "No results available from last execute operation")); return NULL; } if (self->current == -1) if (Cursor_ResultSet(self, count) == NULL) return NULL; /* Set the result widths */ for (i = 0; i < PyList_Size(self->results); i++) { if ((rs = (ResultSet *) PyList_GetItem(self->results, i)) == NULL) return NULL; rlenp = rs->rlenp; for (j = 0; j < rs->size; j++) { *rlenp = (ub2) rs->width; rlenp++; } if (resetlong == 1 && (i+1) == self->longcol) { LongFetch *lf = (LongFetch *) rs->valuep; longFetchRelease(lf); longFetchInit(lf); rs->indp = &lf->ind; //KMH, 2.8.2005 synchronisation of dynamicFetch with ResultSet rs->rcodep = &lf->rcode; //KMH, 2.8.2005 synchronisation of dynamicFetch with ResultSet } } TRACE(T_CALL,("sd", "OCIStmtFetch", count)); Py_BEGIN_ALLOW_THREADS /* ** NB: A fetch of length 0 will cancel the cursor ** ** Do we *need* to cancel the cursor when the Cursor is ** deallocated or will Oracle figure it out when the statement ** handle is released? */ status = OCIStmtFetch(self->stmtp, self->errhp, count, OCI_FETCH_NEXT, OCI_DEFAULT); Py_END_ALLOW_THREADS TRACE(T_RETURN,("sR", "OCIStmtFetch", status)); /* ** Copy the fetch status into each result */ if (status == OCI_SUCCESS_WITH_INFO) { for (i = 0; i < PyList_Size(self->results); i++) { rs = (ResultSet *) PyList_GetItem(self->results, i); rs->fetchResultCode=status; } } if (status == OCI_SUCCESS) { for (i = 0; i < PyList_Size(self->results); i++) { rs = (ResultSet *) PyList_GetItem(self->results, i); rs->fetchResultCode=status; } } TRACE(T_VERBOSE,("sd", "Cursor_fetch status", status)); if (status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO) { text buff[OCI_ERROR_MAXMSG_SIZE]; sb4 errcode; OCIErrorGet(self->errhp, 1, NULL, &errcode, buff, sizeof(buff), OCI_HTYPE_ERROR); /* Oracle errors meaning "end of fetch" ** 1403 is ** 1002 is fetch out of sequence */ TRACE(T_OERROR,("sdS","OCIStmtFetch",errcode,buff)); if (errcode != 1403 && errcode != 1002) {/* Not End of data */ Py_DECREF(self->results); self->results = NULL; self->current = -1; return RaiseOCIError(self->errhp, OCI_HTYPE_ERROR); } releaseresults = 1; } TRACE(T_HCALL,("sAsAs", "OCIAttrGet", self->stmtp, "OCI_HTYPE_STMT", &rcount, "OCI_ATTR_ROW_COUNT")); status = OCIAttrGet((dvoid *) self->stmtp, OCI_HTYPE_STMT, (ub4 *) &rcount, 0, OCI_ATTR_ROW_COUNT, self->errhp); TRACE(T_HRETURN,("sRd", "OCIAttrGet", status, rcount)); if (status == OCI_SUCCESS) { if (self->batchct == -1) self->batchct = 0; self->count = rcount - self->batchct; self->batchct = rcount; } else return RaiseOCIError(self->errhp, OCI_HTYPE_ERROR); answer = self->results; if (!releaseresults) Py_INCREF(answer); else { self->results = NULL; /* Our caller gets our only copy*/ self->current = -1; } TRACE(T_EXIT,("sA", "Cursor_fetch", answer)); return answer; } Klaus Happle -----Ursprüngliche Nachricht----- Von: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Im Auftrag von Maciej Wisniowski Gesendet: Freitag, 17. November 2006 17:32 An: Zope-DB@zope.org Betreff: [Zope-DB] [ANN] Modified version of DCOracle2 is available Hi Due to discussion on Zope list and some work I did before I've published modified version of DCOracle2. What is in this version: 1. Bug fixes - StoredProcedures caused deadlocks in database - StoredProcedures caused conflict errors under heavy load removed self._errors reference and added _p_resolveConflict - other I don't remember now 2. Changes Changes are only in python files - DCOracle2 now uses connection pool Pool implementation is based on psycopg but it doesn't use volatile attributes. As a result: - Open/Close button in ZMI works as it should - DCOracle is possibly slower a bit - Ability to reconnect after the connection is broken When Oracle is restarted, connection is closed by firewall etc. Zope will show an error but only once for every broken connection. Second request will cause DCOracle2 to reconnect 3. To do: - Possibly useage of raise ConflictError may cause that there will be no errors shown during reconnect - Pool size attribute may be set via ZMI - Testing... This code is now in use at my company, but not yet in production environment. So far this works with Zope 2.8.x and Oracle9. If somebody knows better place for this code then let me know. Any ideas how should file headers (I mean licences) look? Comments are welcome Code is here: http://code.google.com/p/dcoracle2da/ Should be available via svn with: svn checkout http://dcoracle2da.googlecode.com/svn/trunk/ dcoracle2da THERE IS NO GUARANTEE THAT THIS WILL WORK FOR YOU, SO BE CAREFULL :) -- Maciej Wisniowski _______________________________________________ Zope-DB mailing list Zope-DB@zope.org http://mail.zope.org/mailman/listinfo/zope-db _______________________________________________ Zope-DB mailing list Zope-DB@zope.org http://mail.zope.org/mailman/listinfo/zope-db