-C New\stest\scases\sfor\sfloating-point\sconversions.
-D 2026-02-21T13:57:40.503
+C New\ssqlite3_db_config(SQLITE_DBCONFIG_FP_DIGITS)\sthat\slet's\sthe\sapplication\nspecify\sthe\snumber\sof\ssignificant\sdigits\sthat\sdouble→text\sconversions\nwill\sattempt\sto\spreserve.
+D 2026-02-21T19:26:58.856
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/json.c 8b6341a419150b28530cc21e3951b2238c35cdc312f11b2ca29017fe4b1dedc0
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
-F src/main.c e95aa130478fc98a49181ddf094baab45f319286411129253618efe0008f0dc4
+F src/main.c 211f7721b191523b815dee6c6a1e9a5f3ebc052a0ddaaed24a75cf20bf9d4b06
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c
-F src/shell.c.in 15285c21cc3f1da9289b0b6c5fd0b2ca8ab2e664b4b300c404afe7634ce9876f
-F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61
+F src/shell.c.in 3e87584890a4e9797865e4771689d8d1aca3b0f824f973192784716ecfa320a2
+F src/sqlite.h.in b8a0b4dd92b1e52caa9676e39971bdaaf44eef30c4b148c9c2fa99e88ed6cf3a
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
-F src/sqliteInt.h 347722b895995dc3015147150c1f9fed5224748c26b36d69ef405656d1603100
+F src/sqliteInt.h ffa3071dc3b9172acfe1a4edd8bc699928b0d5e02f0b8b9067676aa8e5f8f787
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 85b5a20df96016e5d1d8fdc68c8a4c279c5b93e2049b77cd806c2cc50b9d8c56
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
-F src/test1.c 302cc00a5f0bbfa36d73b299d600c073b02ffa7f2b59fd2c81091983ccd574a8
+F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a
F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
-F src/vdbemem.c 61b014628c6db12dd10b094b84f3e83ea0f85a1c485891bf0b5f370f3625d4ca
+F src/vdbemem.c 565c214150dbab0678bfb04db5488f1788df87aad4ec3ec71cc61e0eb3f18f38
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d
-F test/fpconv1.test d9e1e1bdeaf22b2e800aa6847466468a930f6aea6b59eea348711f9445a043b1
+F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08
-R e68f89bae9b5fbd05cf0e0e735a13171
+P 3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f
+R 4d154d27dd2b7e6c72267982eae3c18d
U drh
-Z 5a9c96d60317e775f664966a4b06b2ad
+Z 47c16a6580f94070b6e59ea57711afd7
# Remove this line to create a well-formed Fossil manifest.
-3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f
+3f16985dcc47a366b54164c5024f920a79dddd76faeac5e36b4770732ed72c0a
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
+ case SQLITE_DBCONFIG_FP_DIGITS: {
+ int nIn = va_arg(ap, int);
+ int *pOut = va_arg(ap, int*);
+ if( nIn>3 && nIn<24 ) db->nFpDigit = (u8)nIn;
+ if( pOut ) *pOut = db->nFpDigit;
+ rc = SQLITE_OK;
+ break;
+ }
default: {
static const struct {
int op; /* The opcode */
db->aDb = db->aDbStatic;
db->lookaside.bDisable = 1;
db->lookaside.sz = 0;
+ db->nFpDigit = 17;
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
{ "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+ { "fp_digits", SQLITE_DBCONFIG_FP_DIGITS },
{ "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
{ "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
for(ii=0; ii<ArraySize(aDbConfig); ii++){
if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
if( nArg>=3 ){
- sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
+ if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){
+ sqlite3_db_config(p->db, aDbConfig[ii].op, atoi(azArg[2]), 0);
+ }else{
+ sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
+ }
}
sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
- cli_printf(p->out, "%19s %s\n",
- aDbConfig[ii].zName, v ? "on" : "off");
+ if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){
+ cli_printf(p->out, "%19s %d\n", aDbConfig[ii].zName, v);
+ }else{
+ cli_printf(p->out, "%19s %s\n",
+ aDbConfig[ii].zName, v ? "on" : "off");
+ }
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
** comments are allowed in SQL text after processing the first argument.
** </dd>
**
+** [[SQLITE_DBCONFIG_FP_DIGITS]]
+** <dt>SQLITE_DBCONFIG_FP_DIGITS</dt>
+** <dd>The SQLITE_DBCONFIG_FP_DIGITS option is a small integer is the number
+** of significant digits that SQLite attempts to preserve when converting
+** floating point numbers (IEEE 754 "doubles") into text. The default value
+** (as of SQLite version 3.52.0) is 17.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is a small integer, between 3 and 20, or
+** zero. The FP_DIGITS setting is changed to the small integer, or left
+** altered if the first argument is out of range. The second argument is a
+** pointer to an integer. If the pointer is not NULL, then the value of
+** the FP_DIGITS setting, after possibly being modified by the first
+** arguments, is written into the integer to which the second argument points.
+** </dd>
+**
** </dl>
**
** [[DBCONFIG arguments]] <h3>Arguments To SQLITE_DBCONFIG Options</h3>
#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
u8 noSharedCache; /* True if no shared-cache backends */
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
u8 eOpenState; /* Current condition of the connection */
+ u8 nFpDigit; /* Significant digits to keep on double->text */
int nextPagesize; /* Pagesize after VACUUM if >0 */
i64 nChange; /* Value returned by sqlite3_changes() */
i64 nTotalChange; /* Value returned by sqlite3_total_changes() */
{ "ATTACH_CREATE", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
{ "ATTACH_WRITE", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
{ "COMMENTS", SQLITE_DBCONFIG_ENABLE_COMMENTS },
+ { "FP_DIGITS", SQLITE_DBCONFIG_FP_DIGITS },
};
int i;
int v = 0;
StrAccum acc;
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
assert( sz>22 );
- if( p->flags & MEM_Int ){
-#if GCC_VERSION>=7000000
+ if( p->flags & (MEM_Int|MEM_IntReal) ){
+#if 0
/* Work-around for GCC bug
- ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
+ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270.
+ ** Bug fixed circa 2020, so this work-around removed in 2026. */
i64 x;
assert( (p->flags&MEM_Int)*2==sizeof(x) );
memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
#else
p->n = sqlite3Int64ToText(p->u.i, zBuf);
#endif
+ if( p->flags & MEM_IntReal ){
+ memcpy(zBuf+p->n,".0", 3);
+ p->n += 2;
+ }
}else{
sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
- sqlite3_str_appendf(&acc, "%!.17g",
- (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
+ sqlite3_str_appendf(&acc, "%!.*g",
+ (p->db ? p->db->nFpDigit : 17), p->u.r);
assert( acc.zText==zBuf && acc.mxAlloc<=0 );
zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
p->n = acc.nChar;
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+
+# Unusual rendering cases:
+#
+do_execsql_test fpconv1-1.0 {
+ SELECT 1.23 - 2.34;
+} {-1.1099999999999999}
+# ^--- Not -1.11 as you would expect. -1.11 has a different bit pattern
+
+do_execsql_test fpconv1-1.1 {
+ SELECT 1.23 * 2.34;
+} {2.8781999999999996}
+# ^--- Not 2.8782 as you would expect. 2.8782 has a different bit pattern
+
+# Change significant digits to 15 and get a different result.
+sqlite3_db_config db FP_DIGITS 15
+do_execsql_test fpconv1-1.2 {
+ SELECT 1.23 - 2.34;
+} {-1.11}
+do_execsql_test fpconv1-1.3 {
+ SELECT 1.23 * 2.34;
+} {2.8782}
+sqlite3_db_config db FP_DIGITS 17
+
+
if {[catch {load_static_extension db decimal} error]} {
puts "Skipping decimal tests, hit load error: $error"
finish_test; return
}
sqlite3_create_function db
-do_execsql_test fpconv1-1.0 {
+do_execsql_test fpconv1-2.0 {
WITH RECURSIVE
/* Number of random floating-point values to try.
** On a circa 2021 Ryzen 5950X running Mint Linux, and
load_static_extension db ieee754
-do_execsql_test fpconv1-2.0 {
+do_execsql_test fpconv1-3.0 {
WITH RECURSIVE
c(x,s) AS MATERIALIZED (VALUES(1,random()&0xffefffffffffffff)
UNION ALL
} {}
# ^---- Values that fail to round-trip will be reported
-# Unusual rendering cases:
-#
-do_execsql_test fpconv1-3.0 {
- SELECT 1.23 - 2.34;
-} {-1.1099999999999999}
-# ^--- Not -1.11 as you would expect. -1.11 has a different bit pattern
-
-do_execsql_test fpconv1-3.1 {
- SELECT 1.23 * 2.34;
-} {2.8781999999999996}
-# ^--- Not 2.8782 as you would expect. 2.8782 has a different bit pattern
-
finish_test