Martin J. Evans wrote:
> Hi,
> 
> With reference to the rt I created "Support binding of integers so they
> are returned as IVs" at http://rt.cpan.org/Public/Bug/Display.html?id=49818
> 
> I am now at the point where being unable to bind columns to results-sets
> in DBD::Oracle with a bind type of SQL_INTEGER (or whatever) so they
> look like integers in Perl is slowing some code of ours down
> dramatically. We convert a fetchall_arrayref returned structure into
> JSON with JSON::XS and JSON::XS converts strings to "string" and numbers
> to a plain number. Our select returns a number of columns which are
> really integer columns and as the result-set is very large the extra
> space we use encoding integers as "number" is more than just annoying.
> JSON::XS appears to know a perl scalar has been used in the context of a
> number as if we add 0 to the integer columns returned in
> fetchall_arrayref it encodes them as plain numbers instead of strings
> like "number" (see the rt for the snippet from JSON::XS which does
> this). As a result, a workaround we are using now is to loop through the
> rows adding 0 to all integer columns. I believe DBI allows bind_col to
> be called without a destination scalar so you can use it to specify the
> type of the bind e.g., SQL_INTEGER but still call fetchall_arrayref.
> 
> Does anyone know if it is feasible to make this work with DBD::Oracle
> and if so do you have some pointers as to how it may be achieved. I am
> not looking for anyone else to do the work but would like to sound
> people out about the possibility before I launch into it.
> 
> Thanks
> 
> Martin
> 
> 

What follows is a very rough patch (definitely not finished) which
proves you can do what I wanted to do. However, there on no checks on
the column being bound existing and I'm not sure how to save the TYPE
attribute when bind_col is called before execute (that is when the
result-set is not described yet). Basically, I think more is required in
dbd_st_bind_col but I've not sure as yet what that is and it is possible
returning 1 is a total hack. I'd appreciate any advice to complete this.

Index: oci8.c
===================================================================
--- oci8.c      (revision 13427)
+++ oci8.c      (working copy)
@@ -3279,10 +3279,31 @@
                                                while(datalen && p[datalen - 
1]==' ')
                                                        --datalen;
                                        }
-                                       sv_setpvn(sv, p, (STRLEN)datalen);
-                                       if (CSFORM_IMPLIES_UTF8(fbh->csform) ){
-                                               SvUTF8_on(sv);
-                                       }
+
+                    if ((fbh->req_type == 3) &&
+                        ((fbh->dbtype == 2) || (fbh->dbtype == 3))){
+                        char *e;
+                        char zval[32];
+                        long val;
+
+                        memcpy(zval, p, datalen);
+                        zval[datalen] = '\0';
+                        val = strtol(zval, &e, 10);
+
+                        if ((val == LONG_MAX) || (val == LONG_MIN) ||
+                            (e && (*e != '\0'))) {
+                            oci_error(sth, imp_sth->errhp, OCI_ERROR,
+                                      "invalid number or over/under flow");
+                            return Nullav;
+                        }
+
+                        sv_setiv(sv, val);
+                    } else {
+                        sv_setpvn(sv, p, (STRLEN)datalen);
+                        if (CSFORM_IMPLIES_UTF8(fbh->csform) ){
+                            SvUTF8_on(sv);
+                        }
+                    }
                                }
                        }

Index: dbdimp.c
===================================================================
--- dbdimp.c    (revision 13427)
+++ dbdimp.c    (working copy)
@@ -869,7 +869,16 @@
        return 1;
 }

+int dbd_st_bind_col(SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV
type, SV *attribs) {
+    dTHX;

+    int field = SvIV(col);
+
+    imp_sth->fbh[field-1].req_type = type;
+
+    return 1;
+}
+
 int
 dbd_db_disconnect(SV *dbh, imp_dbh_t *imp_dbh)
 {
Index: dbdimp.h
===================================================================
--- dbdimp.h    (revision 13427)
+++ dbdimp.h    (working copy)
@@ -191,6 +191,8 @@
        int                     piece_lob;  /*use piecewise fetch for lobs*/
        /* Our storage space for the field data as it's fetched */
        sword           ftype;  /* external datatype we wish to get     */
+        IV            req_type;                /* type passed to
bind_col */
+
        fb_ary_t        *fb_ary ;       /* field buffer array                   
*/
        /* if this is an embedded object we use this */
        fbh_obj_t       *obj;
@@ -371,6 +373,7 @@
 #define dbd_st_FETCH_attrib    ora_st_FETCH_attrib
 #define dbd_describe           ora_describe
 #define dbd_bind_ph                    ora_bind_ph
+#define dbd_st_bind_col         ora_st_bind_col
 #include "ocitrace.h"

 /* end */
Index: Oracle.h
===================================================================
--- Oracle.h    (revision 13427)
+++ Oracle.h    (working copy)
@@ -67,6 +67,7 @@
 int     dbd_db_do _((SV *sv, char *statement));
 int     dbd_db_commit     _((SV *dbh, imp_dbh_t *imp_dbh));
 int     dbd_db_rollback   _((SV *dbh, imp_dbh_t *imp_dbh));
+int dbd_st_bind_col(SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV
type, SV *attribs);
 int     dbd_db_disconnect _((SV *dbh, imp_dbh_t *imp_dbh));
 void dbd_db_destroy    _((SV *dbh, imp_dbh_t *imp_dbh));
 int     dbd_db_STORE_attrib _((SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV
*valuesv));

Martin
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to