Re: DBD::Oracle, Support binding of integers so they are returned as IVs
John Scoles <[email protected]>
| Newsgroups | gmane.comp.lang.perl.modules.dbi.sybase.devel |
|---|---|
| Organization | The Pythian Group |
| Message-ID | <[email protected]> |
Just to let you guys know I am following this very closely
Right now I as still pinned down with regular work but hopefully this
week I will get some DBD::Oracle time.
So far I have to agree with Tim about the 'magic numbers'
I think as well as we do a describe before the execute we can get the
size automatically and sizer them up there a little better than I do now.
we do get the
OCI_ATTR_DATA_TYPE and OCI_ATTR_DATA_SIZE
and I handle the number stuff like this
case ORA_NUMBER: /* NUMBER */
case 21: /* BINARY FLOAT os-endian */
case 22: /* BINARY DOUBLE os-endian */
case 100: /* BINARY FLOAT oracle-endian */
case 101: /* BINARY DOUBLE oracle-endian */
fbh->disize = 130+38+3; /* worst case */
avg_width = 4; /* NUMBER approx +/- 1_000_000 */
break;
maybe we can just diddle with this code and fix it for you long ints
Like you I am just taking a quick look at it
chees
John Scoles
Martin Evans wrote:
> 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
>