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.