From 4cf3766d09c888c09651e7c5590f8b2292492263 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 5 Oct 2026 11:29:02 +0000 Subject: [PATCH] Ensure that when a value that may be stored without data loss as an integer is stored in a column with REAL affinity, the values passed to the preupdate-hook are of type SQLITE_FLOAT, not SQLITE_INTEGER. Report [bugs:/info/2026-10-04T16:18:21Z | 2026-10-04T16:18:21Z]. FossilOrigin-Name: 9f7490065e24fc69a5fc13371aeb40214d617209bb0cd9a3e23f76486d4704c0 --- manifest | 14 +++++----- manifest.uuid | 2 +- src/vdbeapi.c | 5 ++++ test/hook2.test | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index ea50f501d4..5960eddef3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sit\sis\snot\sa\sconstraint\sviolation\sif\sa\sCHECK\sconstraint\sthat\sevaluates\sto\sNULL\sfor\sone\sor\smore\sexisting\srows\sis\sadded\sto\sa\stable\susing\sALTER\sTABLE.\sReport\s[bugs:/info/2026-10-05T07:36:38Z\s|\s2026-10-05T07:36:38Z]. -D 2026-10-05T10:54:29.895 +C Ensure\sthat\swhen\sa\svalue\sthat\smay\sbe\sstored\swithout\sdata\sloss\sas\san\sinteger\sis\sstored\sin\sa\scolumn\swith\sREAL\saffinity,\sthe\svalues\spassed\sto\sthe\spreupdate-hook\sare\sof\stype\sSQLITE_FLOAT,\snot\sSQLITE_INTEGER.\sReport\s[bugs:/info/2026-10-04T16:18:21Z\s|\s2026-10-04T16:18:21Z]. +D 2026-10-05T11:29:02.005 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -870,7 +870,7 @@ F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 134147162547f7d02e96aad416c7922185a47e4568327cbf773cc7de313c4310 F src/vdbe.h b6ffb28da04363fd5d439b8204118fd3f2e751abe4f8e3edb089155fb90d4607 F src/vdbeInt.h 68e5ab63f184f2871780c83ce78b425d0360869611baea4c65575f91f76ac1d3 -F src/vdbeapi.c 5f5f86d4642ce1927b4b45a6b87a978ef6b11c8420e6ce440695177618fc25d0 +F src/vdbeapi.c 8015628172d959885d5df592b9ddc07c66a803f61f86f1197cc17929c095b2ca F src/vdbeaux.c 1d8190de670cfa4df06f5e57a2c5b54d018c1ffb13c722fb7507ec52a80cc849 F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 F src/vdbemem.c b2113c949e2ed918294e16a5ebaacdaca6be4f820f670517e3362e94c7019432 @@ -1340,7 +1340,7 @@ F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21 F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751 F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711 F test/hook.test 2d89bf9480646feb8093be3a58ea502d6521906779ed960de31dd9c4502c0541 -F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 +F test/hook2.test b7221eecc8800edd7fadbf894c66b95fe7ad9f2a333ff9fc8a72e84e72f626c0 F test/icu.test 3903d97f414741036e48d74af6be904eb69170f5bca7a0031ff3b33925c85582 F test/ieee754.test 0d3ab84ab2069c9994c833a7cd820ee6037f0cf888e206a4a7fc05f735d5790a F test/import01.sql 83afbb4d408b07563f3bcd2088e96d2a9443551c79c69621a6e6000bb8b6ee19 @@ -2278,8 +2278,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e68aa6e1293a2c7ad37d4b9fea8e649c318f9b4c64381eefebd0413363f56da4 -R b98db61d087d8224ef25f27f85824b21 +P f940c67b21b112e33bfdd54f2c3a19b06ad5bf661ddf2f85dd464fb76d115e31 +R d54dc4174e35368b365ed1dab90abee9 U dan -Z c622ecd2a9a57d09c53b9bf7d7f4c808 +Z 91bfb1a10c5ca74730896a453bd88857 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3683ae7fd3..562085e84e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f940c67b21b112e33bfdd54f2c3a19b06ad5bf661ddf2f85dd464fb76d115e31 +9f7490065e24fc69a5fc13371aeb40214d617209bb0cd9a3e23f76486d4704c0 diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 180599d22e..7d7b0239b1 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -2517,6 +2517,11 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else if( iStore>=pUnpack->nField ){ pMem = (sqlite3_value *)columnNullValue(); + }else if( (p->pTab->aCol) + && (p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL) + && (pMem->flags & (MEM_Int|MEM_IntReal)) + ){ + sqlite3VdbeMemRealify(pMem); } }else{ /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required diff --git a/test/hook2.test b/test/hook2.test index 9ae1103a7d..9a0d19dd00 100644 --- a/test/hook2.test +++ b/test/hook2.test @@ -215,4 +215,74 @@ do_preupdate_test 2.3.5 { } +#------------------------------------------------------------------------- +# Test that the values passed to the preupdate hook for columns with +# REAL affinity are always FLOAT values, even if the value is one that +# could be stored as an integer without loss of data. +# +# 3.1.* - INSERT, UPDATE and DELETE on a rowid table. +# 3.2.* - INSERT, UPDATE and DELETE on a WITHOUT ROWID table with a +# REAL PRIMARY KEY. +# +do_execsql_test 3.0 { + CREATE TABLE t4(a REAL, b REAL DEFAULT 5); + CREATE TABLE t5(a REAL PRIMARY KEY, b REAL, c) WITHOUT ROWID; +} + +do_preupdate_test 3.1.1 { + INSERT INTO t4 VALUES(7, 7.0); +} { + INSERT main t4 1 1 7.0 7.0 +} +do_preupdate_test 3.1.2 { + INSERT INTO t4(a) VALUES('-12'); +} { + INSERT main t4 2 2 -12.0 5.0 +} +do_preupdate_test 3.1.3 { + INSERT INTO t4 SELECT a+1, 'abc' FROM t4 WHERE rowid=1; +} { + INSERT main t4 3 3 8.0 abc +} +do_preupdate_test 3.1.4 { + UPDATE t4 SET b=b*2 WHERE rowid=1; +} { + UPDATE main t4 1 1 7.0 7.0 7.0 14.0 +} +do_preupdate_test 3.1.5 { + DELETE FROM t4 WHERE rowid=2; +} { + DELETE main t4 2 2 -12.0 5.0 +} +do_execsql_test 3.1.6 { + SELECT typeof(a), typeof(b) FROM t4 ORDER BY rowid; +} {real real real text} +do_preupdate_test 3.1.7 { + UPDATE t4 SET a=5 WHERE rowid=3; +} { + UPDATE main t4 3 3 8.0 abc 5.0 abc +} + +do_preupdate_test 3.2.1 { + INSERT INTO t5 VALUES(1, 2, 3); +} { + INSERT main t5 0 0 1.0 2.0 3 +} +do_preupdate_test 3.2.2 { + UPDATE t5 SET a=a+1, b=10 WHERE a=1; +} { + UPDATE main t5 0 0 1.0 2.0 3 2.0 10.0 3 +} +do_preupdate_test 3.2.3 { + REPLACE INTO t5 VALUES(2, 4, 5); +} { + DELETE main t5 0 0 2.0 10.0 3 + INSERT main t5 0 0 2.0 4.0 5 +} +do_preupdate_test 3.2.4 { + DELETE FROM t5; +} { + DELETE main t5 0 0 2.0 4.0 5 +} + finish_test