Re: Problem retrieving a numeric(38,0) value as SQL_NUMERIC_STRUCT if value needs to use all 16 SQLCHAR elements of the val array - Mailing list pgsql-odbc

From Heikki Linnakangas
Subject Re: Problem retrieving a numeric(38,0) value as SQL_NUMERIC_STRUCT if value needs to use all 16 SQLCHAR elements of the val array
Date
Msg-id 5398C651.70508@vmware.com
Whole thread Raw
In response to Re: Problem retrieving a numeric(38,0) value as SQL_NUMERIC_STRUCT if value needs to use all 16 SQLCHAR elements of the val array  (Hiroshi Inoue <inoue@tpf.co.jp>)
List pgsql-odbc
Ok, committed.

On 06/11/2014 03:05 PM, Hiroshi Inoue wrote:
> Thanks for your investigation.
>
> I don't object to the change.
> Probably few people used SQL_C_NUMERIC extensively.
>
> regards,
> Hiroshi Inoue
>
> (2014/06/10 17:34), Heikki Linnakangas wrote:
>> Ugh, the decimal->binary conversion algorithm is really ugly even before
>> this patch, and the patch doesn't make it any prettier. It took me quite
>> a while to understand how it works: it repeatedly divides the base-10
>> representation by two, and outputs the reminder bit. There are much
>> better and faster ways to convert from decimal to binary, and they're
>> not really any more complicated either.
>>
>> The binary->decimal conversion in ResolveNumericParam is even more ugly.
>> To be honest, I still don't understand the algorithm behind it, but it
>> looks complicated and slow. There's a fast-path for small numbers that
>> fit in an UInt4, which doesn't make it any simpler.
>>
>> Aside from ugly and slow, the binary->decimal conversion is also buggy:
>>
>> 1.The following input creates a core dump with "Floating point exception":
>>
>> precision=3, scale=50, val=0x02 0x03
>>
>> 2. Building the final output string is broken if scale is large, e.g.
>> this produces garbage output:
>>
>> precision=25, scale=80
>>
>> ERROR: invalid input syntax for type numeric:
>> "p.000`000H0000000000000000000000aT000000000000000000000000000000000000000000000770";
>>
>>
>> 3. The param_string buffer allocated for the result of the
>> binary->decimal conversion is too small. The buffer is 128 bytes, but a
>> numeric can have a scale as large as 127. That won't fit, as the sign
>> and decimal dot use two more bytes.
>>
>> I propose the attached patch to fix all of the above, rewriting the
>> binary->decimal and decimal->binary conversions altogether. It fixes all
>> of the known issues, the ones listed above and the one Walter reported.
>> It also adds a regression test for all of them.
>>
>> Can anyone come up with some more special cases that this patched or the
>> old conversion might handle incorrectly, for adding to the regression
>> suite?
>>
>>
>> One more thing: The precision works in a funny way, if you pass a "val"
>> with more bits than fit in precision. I filled the val-bytes with 0x9F
>> 0x86 0x01, which corresponds to 99999 in decimal. I passed that as a
>> param with different precisions:
>>
>> sign 1 prec 1 scale 0 val 9F8601:
>>       159
>> sign 1 prec 2 scale 0 val 9F8601:
>>       159
>> sign 1 prec 3 scale 0 val 9F8601:
>>       34463
>> sign 1 prec 4 scale 0 val 9F8601:
>>       34463
>> sign 1 prec 5 scale 0 val 9F8601:
>>       99999
>> sign 1 prec 6 scale 0 val 9F8601:
>>       99999
>>
>> The conversion algorithm seems to assume that there are no extra bits in
>> the val-array that don't fit within the precision. Perhaps that's a
>> reasonable assumption, but I think it would be more robust to ignore any
>> extra bits if they are there, rather than sometimes take some of them
>> into account. (Or, always parse all the bits, ignoring the precision.) I
>> did that in the attached patch.
>>
>> However, according to this article I found from Microsoft:
>> https://support.microsoft.com/kb/222831
>>
>> "The precision and scale fields of the numeric structure are never used
>> for input from an application, only for output from the driver to the
>> application."
>>
>> So we probably should be ignoring them completely, and get the precision
>> and scale from elsewhere.
>>
>>
>> PS. ResolveNumericParam always returns TRUE. That's fortunate, because
>> the caller would incorrectly fall through the switch-case if it didn't..
>> When the code was added, it fell through to the "default" case, but the
>> interval-cases were later added in between, breaking it. But it's not a
>> live bug, since ResolveNumericParam always returns TRUE. Fixed that too
>> in the attached patch.
>>
>> - Heikki
>>


--
- Heikki


pgsql-odbc by date:

Previous
From: Walter Couto
Date:
Subject: Missing meta data information for bit and bit varying
Next
From: Jade Koskela
Date:
Subject: Problem in SQLFreeHandle (Statement)