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.) > > 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. > 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! > > 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 :) > 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.