[fpc-devel] Implementing TFmtBCDField - ftFmtBCD and SQLite
LacaK
lacak at zoznam.sk
Thu Mar 24 09:43:42 CET 2011
Hi,
after doing some test with new implementation of TFmtBCDField for
TSQLite3Connection connector I encounter this problem:
When you declare in SQLite some column as NUMERIC or DECIMAL then this
column will have NUMERIC affinity.
CREATE TABLE t (d DECIMAL(30,7));
If you insert in such column any numeric value (quoted or unquoted):
INSERT INTO t VALUES('123456789123456789.123456');
SQLite converts such numeric value to 8-byte floating point
representation (REAL) or 8-byte integer (INTEGER), so:
(lost of precision occurs)
SELECT * FROM t;
returns 123456789123456784
See: http://www.sqlite.org/datatype3.html#affinity
"A column with NUMERIC affinity may contain values using all five
storage classes. When text data is inserted into a NUMERIC column, the
storage class of the text is converted to INTEGER or REAL (in order of
preference) if such conversion is lossless and reversible. For
conversions between TEXT and REAL storage classes, SQLite considers the
conversion to be lossless and reversible if the first 15 significant
decimal digits of the number are preserved. If the lossless conversion
of TEXT to INTEGER or REAL is not possible then the value is stored
using the TEXT storage class. No attempt is made to convert NULL or BLOB
values."
My original understanding was, that when I store big numbers as TEXT and
lossless conversion to REAL can not be done, then value will be stored
as TEXT, but in meaning in SQLite lossless is: " if the first 15
significant decimal digits of the number are preserved" (not all digits
only first 15!!!)
I have asked about this in sqlite-users mailing list (topic "storing big
numbers into NUMERIC, DECIMAL columns") and results are:
(I attach some of comments from sqlite-users mailing list)
A.) if we want preserve precision of BCD values we must store them as
BLOBs (using sqlite3_bind_blob()) ... see (1) and (2) in attachment
(with optimalization like : if BCDPrecision(...) > 15 then use
sqlite3_bind_blob(...) else sqlite3_bind_double(...) )
Here my test shows, that if I store value like BLOB I still can do
select like:
SELECT d+100 FROM t;
SELECT sum(d) FROM t;
SELECT * FROM t WHERE d>12345678912345678;
(it seems, that SQLite converts BLOB->TEXT->REAL ...of course precision
is lost)
B.) does not support numbers (big exact numbers), which are not
supported by SQLite (SQLite supports only REAL and INTEGER). ... see (3)
So DECIMAL, NUMERIC map to ftFloat if "decimal places">4 (out of range
ftBCD) and map to ftLargeInt if "decimal places"=0
What do you think, which way to go ?
-Laco.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: LazSqlite-bignums-discussion.txt
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20110324/f2fcee57/attachment.txt>
More information about the fpc-devel
mailing list