Tim Bunce wrote: > On Tue, Oct 27, 2009 at 02:54:43PM +0000, Martin Evans wrote: >>>> + >>>> + 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. > > (See how grok_number is used in perl's toke.c for an example.)
will do. >>> 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? > > sv_2iv does that for you if the number is too big for an IN but will > fit in a UV. argh - didn't see that - will try again with my test code and verify that. >> 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. > > Take a look at the source code for sv_2iv (actually Perl_sv_2iv in sv.c) > It's scary! then perhaps I won't bother looking at it ;-) >>> 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. > > Ok. >> 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; >> } > > Don't forget to catch field <= 0 :) yes, fair enough - changed. >> 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. > > Yeap, that's as intended. > > Tim. > > ok, sounds like we have some progress and at least I'm nearly on the right wavelength. Thanks again. This really is useful to the project I am working on and given the feedback I've had it sounds like a) it would be useful for a DBD to implement it so other DBDs could have a reference for its use b) useful for anyone wanting to override the returned type c) provides further checks on the returned column which could fall out of range of the data the perl app expects. Martin