On 14/01/10 12:19, Charles Jardine wrote:
My environment is Linux x86-64, Perl 5.10.1 (64 bit), DBI 1.609, Oracle 10.2.0.4.2 (64 bit). Database charset UTF8, national charset AL16UTF16 Three things:
[ snip ]
2. Back in early October, I reported a problem with the support for objects. Specifically, fetching a column value which was a nested table of objects was failing if $dbh->{ora_objects} was true. I have found the cause of the problem and have developed a patch. Unfortunately, while investigating this I have found another serious problem with the object support. Fetching a column value which is an object, one of whose properties is an object, segfaults, regardless of the value of $dbh->{ora_objects}. The cause of this looks like a simple type error. I hope to be able to post a patch which fixes both these problems within the next few days.
I have attached a patch which fixes the first problem. I will post another message about the second problem, which I no longer see as easy to fix. I should explain what the patch does, and why. There are two calls of OCITypeByRef in oci8.c. The second one, which is in get_object, is the one which was problematic. The purpose of the call is to obtain the true type of a fetched object. This is to deal with the possibility that the fetched object's type is a subtype of the type obtained at describe time. In the example case I posted back in October this call fails badly; see <http://www.mail-archive.com/dbi-us...@perl.org/msg32378.html>. With 1.23 the failure was a segfault, with 1.24-RC3 the message is "OCI-21500: internal error code, arguments: [kocgpn129]". I now know that it is significant that the type of my example object was a FINAL type. FINAL types can have no subtypes. If I change my example by adding "NOT FINAL" to the to the CREATE TYPE statement for the object, the problem goes away - the OCITypeByRef call succeeds. If the type found at describe time is FINAL, all the fetched instances must be of the described type, since subtypes are not possible. So, in this case, it is a correct optimisation to skip the block of code containing the call of OCITypeByRef. The patch implements this optimisation, and so circumvents the problem. The patch also adds a call of OCIObjectFree, to match the call of OCIObjectNew in the same code sequence. I think this removes a small per-row store drain. -- Charles Jardine - Computing Service, University of Cambridge c...@cam.ac.uk Tel: +44 1223 334506, Fax: +44 1223 334679
Only in DBD-Oracle-1.24-RC3.object_patches: Makefile.old diff -ur DBD-Oracle-1.24-RC3/dbdimp.h DBD-Oracle-1.24-RC3.object_patches/dbdimp.h --- DBD-Oracle-1.24-RC3/dbdimp.h 2010-01-08 19:39:46.000000000 +0000 +++ DBD-Oracle-1.24-RC3.object_patches/dbdimp.h 2010-01-15 13:00:44.567065736 +0000 @@ -141,7 +141,7 @@ }; -typedef struct fbh_obj_st fbh_obj_t; /*Ebbedded Object Descriptor */ +typedef struct fbh_obj_st fbh_obj_t; /*Embedded Object Descriptor */ struct fbh_obj_st { /* embedded object or table will work recursively*/ text *type_name; /*object's name (TDO)*/ @@ -152,6 +152,7 @@ OCITypeCode typecode; /*object's OOCI_ATTR_TYPECODE */ OCITypeCode col_typecode; /*if collection this is its OCI_ATTR_COLLECTION_TYPECODE */ OCITypeCode element_typecode; /*if collection this is its element's OCI_ATTR_TYPECODE*/ + ub1 is_final_type; /*object's OCI_ATTR_IS_FINAL_TYPE*/ OCIRef *obj_ref; /*if an embeded object this is ref handle to its TDO*/ OCIInd *obj_ind; /*Null indictator for object */ OCIComplexObject *obj_value; /*the actual value from the DB*/ diff -ur DBD-Oracle-1.24-RC3/oci8.c DBD-Oracle-1.24-RC3.object_patches/oci8.c --- DBD-Oracle-1.24-RC3/oci8.c 2010-01-08 19:39:46.000000000 +0000 +++ DBD-Oracle-1.24-RC3.object_patches/oci8.c 2010-01-15 13:04:43.444036727 +0000 @@ -2205,9 +2205,9 @@ case OCI_TYPECODE_OPAQUE: /*doesn't do anything though*/ if (ora_objects){ - OCIRef *type_ref=0; sword status; - if (!instance_tdo) { + if (!instance_tdo && !obj->is_final_type) { + OCIRef *type_ref=0; status = OCIObjectNew(fbh->imp_sth->envhp, fbh->imp_sth->errhp, fbh->imp_sth->svchp, OCI_TYPECODE_REF, (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, TRUE, @@ -2229,6 +2229,15 @@ oci_error(sth, fbh->imp_sth->errhp, status, "OCITypeByRef"); return 0; } + + status = OCIObjectFree(fbh->imp_sth->envhp, fbh->imp_sth->errhp, type_ref, (ub2)0); + + if (status != OCI_SUCCESS) { + oci_error(sth, fbh->imp_sth->errhp, status, "OCIObjectFree"); + return 0; + } + + } @@ -2933,6 +2942,13 @@ return 0; } + OCIAttrGet_parmdp(imp_sth, obj->parmdp, (dvoid *)&obj->is_final_type,(ub4 *) 0, OCI_ATTR_IS_FINAL_TYPE, status); + + if (status != OCI_SUCCESS) { + oci_error(sth,imp_sth->errhp, status, "OCIAttrGet"); + return 0; + } + OCIAttrGet_parmdp(imp_sth, obj->parmdp, (dvoid *)&obj->field_count,(ub4 *) 0, OCI_ATTR_NUM_TYPE_ATTRS, status); if (status != OCI_SUCCESS) { @@ -3051,6 +3067,7 @@ PerlIO_printf(DBILOGFP, " obj_ref = %p\n",obj->obj_ref); PerlIO_printf(DBILOGFP, " obj_value = %p\n",obj->obj_value); PerlIO_printf(DBILOGFP, " obj_type = %p\n",obj->obj_type); + PerlIO_printf(DBILOGFP, " is_final_type = %u\n",obj->is_final_type); PerlIO_printf(DBILOGFP, " field_count = %d\n",obj->field_count); PerlIO_printf(DBILOGFP, " fields = %p\n",obj->fields);