Thanks Tim for the help on this. Tim Bunce wrote: > On Mon, Oct 26, 2009 at 05:29:21PM +0000, Martin Evans wrote: >> 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 @@ >> + >> + if ((fbh->req_type == 3) && >> + ((fbh->dbtype == 2) || (fbh->dbtype == 3))){ > > Best to avoid 'magic numbers'.
As I said = very rough. I'd already changed those to SQLT_NUM and SQLT_INT as ORA types but I guessed they would need to be SQL_INTEGER, SQL_NUMERIC, SQL_DOUBLE when finished i.e. you use the DBI types not the oracle types here since the data is coming back into perl. >> + 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); >> + } >> + } Tried your suggestion of the grok_number but it does not work well for negative numbers since it returns the abs then and puts the result in a UV which may not fit signed into an IV. Anyway, you seem to have had other ideas so I'll not worry about that too much. > A simpler safer and more portable approach may be to just let the > existing code store the value in an sv and then add these lines: > > if (fbh->req_type == 3) > sv_2iv(sv); > > If the number is too large for an IV (or UV) you'll get an NV (float). > The original string of digits is preserved in all cases. That's all very > natural and predictable perlish behaviour. Ok, I get that except you keep saying "(or UV)". Are you suggesting there is some other logic to decide whether you create an IV or a UV? I tried out various values and sv_2iv(sv) and what was returned looked ok - I get a string when the number has decimal places or is too big and an IV when it is an integer and fits. > The next question is whether overflowing to an NV should be an error. > I'm thinking we could adopt these semantics for bind_col types: > > SQL_INTEGER IV or UV via sv_2iv(sv) with error on overflow this would be ideal. > SQL_DOUBLE NV via sv_2nv(sv) > SQL_NUMERIC IV else UV else NV via grok_number() with no error > > I could sketch out the logic for those cases if you'd be happy to polish > up and test. I would be happy to do that. BTW, did you look over the possible hackery I did in dbd_st_bind_col - I wasn't sure if simply storing the requested type and returning 1 was acceptable. My current dbd_st_bind_col is: 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); if (field <= DBIc_NUM_FIELDS(imp_sth)) { imp_sth->fbh[field-1].req_type = type; } return 1; } This means if someone attempts to bind a non-existent column it falls back into DBI's bind_col and signals the error but it also means dbd_st_bind_col in DBD::Oracle is only there to capture the requested bind type. Thanks Martin -- Martin J. Evans Easysoft Limited http://www.easysoft.com