On 01/27/18 20:18, Mark Rotteveel wrote:
I'm implementing the new precision 34 decimal/numeric support in
Jaybird, and I notice that the underlying Decimal128 is used as just
an integer container, instead of already applying an appropriate
exponent for the scale. This was a bit of a surprise to me.
For example, a decimal(19,2) with value 123.45 returns a Decimal128
with value 12345 (or 12345E0), where I would have expected it to
already have the scale applied, that is: 12345E-2.
Why was this implementation chosen? And doesn't this make things
harder when performing calculations (or other operations) with these
values?
May be taken standalone your suggestion is simpler but in conjunction
with existing logic for numerics based on bigint and smaller integer
values and need to cast between them use of existing impelmentation
appeared to me simpler.
And if it is used as a container for a plain big integer, why not just
use a densely packed decimal (the format used in a Decimal128 to
encode the coefficient), or 'better', a binary encoded big integer?
Both would allow for even higher precision with the same storage
requirements (or smaller storage requirements for the same precision).
And have a nihgtmare casting from this 'better' format to Decimal(34)?
Also take into an account that for existing format we already have
support in indices. Alternative formats/libraries were discussed but
decision was taken to use same library for both Decimal and DecimalFixed.
And also very interesting: inserting a pre-scaled Decimal128 value is
allowed, but results in a doubly scaled value (so in essence a
decimal(34,2) suddenly contains a value with scale 4). For example,
inserting a Decimal128 with value 123.45 (as in 12345E-2) into a
decimal(34,2) and then casting to varchar results in value 1.2345.
It's just s a bug - missing check for incorrect input parameter.
From a technical perspective, I would prefer if Firebird would use
(send and accept) the Decimal128 values that correspond with the value
(that is: correctly scaled, ie 12345E-2 in above examples), and reject
values that have the wrong scale.
Alternatively - but more complex - scale and round where appropriate
(that is sending a 100E0 value will be scaled to 10000E-2, and
123456E-3 is rounded to 12346E-2), and throw an overflow error if the
value is too big. (eg sending 1234567890123456789012345678901234E0 for
a decimal(34,1)).
However, if the current solution is kept, then Firebird must reject
any Decimal128 parameter values with an (unbiased) exponent other than
0 to prevent issues like demonstrated with inserting a pre-scaled value.
Certainly.
From the perspective of Jaybird, where otherwise I would have been
able to use the handling of Decimal128 I already had in place for
DECFLOAT (only needing to round to the target scale when sending
values), I now need to perform additional fiddling to either correctly
scale on receive, or get the unscaled value and convert that to
Decimal128 when sending values.
Exactly same logic as applied when dealing with Numeric(15,2), is not it?
In terms of memory, this will require the creation of at least one
additional intermediate object per value sent or received, or creating
ugly hacks to circumvent the need to create these intermediate objects.
I'm not familiar with details of JB implementation. In native API one
should place a value into the message and may be scale it correctly.
That's what engine itself does here and there, I see no problems with it
and no memory losses. But certainly that all highly depends upon the
rest of implementation details.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel