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);
 

Reply via email to