AW: [Zope-DB] [ANN] Modified version of DCOracle2 is available
Happle Dr., Klaus Martin
Klaus.Happle at haufe.de
Thu Nov 23 12:59:03 EST 2006
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: zope-db-bounces at zope.org [mailto:zope-db-bounces at zope.org] Im Auftrag von Maciej Wisniowski
Gesendet: Freitag, 17. November 2006 17:32
An: Zope-DB at 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 at zope.org
http://mail.zope.org/mailman/listinfo/zope-db
More information about the Zope-DB
mailing list