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.

Reply via email to