]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid loading the entire record into memory for an sqlite3_preupdate_old() call that... branch-3.46
authordan <Dan Kennedy>
Mon, 4 Nov 2024 17:33:26 +0000 (17:33 +0000)
committerdan <Dan Kennedy>
Mon, 4 Nov 2024 17:33:26 +0000 (17:33 +0000)
FossilOrigin-Name: f9a90a0d2cd04e44dcc53e8bd270447f5acf9b4d679e23b67810875b6ee95ca7

ext/session/sessionblob.test [new file with mode: 0644]
manifest
manifest.uuid
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c

diff --git a/ext/session/sessionblob.test b/ext/session/sessionblob.test
new file mode 100644 (file)
index 0000000..ed7ec67
--- /dev/null
@@ -0,0 +1,55 @@
+# 2024 November 04
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname [info script]] .. .. test]
+} 
+source [file join [file dirname [info script]] session_common.tcl]
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+
+if {$::tcl_platform(pointerSize)<8} {
+  finish_test
+  return
+}
+
+set testprefix sessionblob
+
+forcedelete test.db2
+sqlite3 db2 test.db2
+
+set NBLOB 2000000
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+  INSERT INTO t1 VALUES(123, zeroblob($NBLOB));
+}
+
+do_test 1.1 {
+  sqlite3session S db main
+  S attach t1
+} {}
+
+set b2 [string repeat x 1000]
+do_test 1.2 {
+  set ::blob [db incrblob t1 b 123]
+  for {set ii 0} {$ii < $NBLOB} {incr ii [string length $b2]} {
+    seek $::blob $ii
+    puts -nonewline $::blob $b2
+  }
+  close $::blob
+} {}
+
+S delete
+
+finish_test
+
index b0a2fbf76f0b93df318afd498ea47fbf87ca333d..f6a9073209f95fde0c1d5c71b221e417ca745c65 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\sOPFS\sVFS's\sxOpen()\sto\shonor\sthe\sread-only\sflag.\sFix\sthe\sOPFS\sSAHPool\sVFS\sto\senable\sre-installation\sof\sthe\sVFS\safter\scalling\sOpfsSAHPoolUtil.removeVfs().
-D 2024-10-17T12:17:18.240
+C Avoid\sloading\sthe\sentire\srecord\sinto\smemory\sfor\san\ssqlite3_preupdate_old()\scall\sthat\sretrieves\san\sIPK\svalue.
+D 2024-11-04T17:33:26.757
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -568,6 +568,7 @@ F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8
 F ext/session/sessionalter.test 460bdac2832a550519f6bc32e5db2c0cee94f335870aaf25a3a403a81ab20e17
 F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
 F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
+F ext/session/sessionblob.test 87faf667870b72f08e91969abd9f52a383ab7b514506ee194d64a39d8faff00a
 F ext/session/sessionchange.test 77c4702050f24270b58070e2cf01c95c3d232a3ef164b70f31974b386ce69903
 F ext/session/sessionconflict.test 8b8cbd98548e2e636ddc17d0986276f60e833fb865617dd4f88ea5bbe3a16b96
 F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
@@ -826,9 +827,9 @@ F src/util.c 4d6d7ebfe6772a1b950c97bbb1d1a72ad4874617ec498ab8aa73b7f5a43e44bb
 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
 F src/vdbe.c 3b1793c5d2235ae89b01ef051a33d7d2ad3704c71799653b112686735ad401ff
 F src/vdbe.h c2d78d15112c3fc5ab87f5e8e0b75d2db1c624409de2e858c3d1aafb1650bb4f
-F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
-F src/vdbeapi.c 80235ac380e9467fec1cb0883354d841f2a771976e766995f7e0c77f845406df
-F src/vdbeaux.c 6e37cb918506c28fe7657454fcbc2e01e66bfba4164f306c2f075fd5c5fef609
+F src/vdbeInt.h dc5a717607385857dd65e8661fc967aeee77b3c0bcbfb7c7acb1ea99e9007578
+F src/vdbeapi.c 1e6880bbc1b5930752ed1b67fbfcc751d4782e59763859249db699fb3e75a986
+F src/vdbeaux.c dd58f3dd2c0fee9b1a497201269511af633b67ce9ddfc0719c9b5b2b48a15d1e
 F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
 F src/vdbemem.c 831a244831eaa45335f9ae276b50a7a82ee10d8c46c2c72492d4eb8c98d94d89
 F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
@@ -2192,10 +2193,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 242cb4bbee0707f470833d9f47efcfb5631f2302b9d48cffdbba63e64984827c
-Q +0a32624015f16fd881a4ecbb56b7833391028d327a95f4c899eee864ed7fe00d
-Q +b7f7a5deeae61920dbfec7606cf9014de711f959a285b29e12673abfd2f88646
-R 35167de4f82ff4a760245cc11df277ba
-U stephan
-Z 23bdd4bd7373bf8ed99c8093853b8c62
+P 63ee3584201fe3a126991e278bd4d7bf2d4ae5c4937d97e311686a69fd1cf69b
+Q +7f4de43733200beeb3ff0a70d51bbc68f5331895698ea95a82741cfd7bb66834
+R 1925f50d4d915494bbec6d09eb751f2d
+U dan
+Z bfb0012b12d420c95f9f9c70ce345eb0
 # Remove this line to create a well-formed Fossil manifest.
index 0551b59cb6294c74412253a10f5fbc0f86bd9a8d..7bcfcc43d229a2790f8ca19acd02383614f80f96 100644 (file)
@@ -1 +1 @@
-63ee3584201fe3a126991e278bd4d7bf2d4ae5c4937d97e311686a69fd1cf69b
+f9a90a0d2cd04e44dcc53e8bd270447f5acf9b4d679e23b67810875b6ee95ca7
index 2a23c3f2855acb271ea462b98ae01613eed1996a..23f987b6b637f5ae2b8ff1d48e31f0bcabc32ff2 100644 (file)
@@ -540,6 +540,7 @@ struct PreUpdate {
   int iBlobWrite;                 /* Value returned by preupdate_blobwrite() */
   i64 iKey1;                      /* First key value passed to hook */
   i64 iKey2;                      /* Second key value passed to hook */
+  Mem oldipk;                     /* Memory cell holding "old" IPK value */
   Mem *aNew;                      /* Array of new.* values */
   Table *pTab;                    /* Schema object being updated */
   Index *pPk;                     /* PK index if pTab is WITHOUT ROWID */
index 3182e4070ffbbfe5b6f933e45cf365ea7e7dae7d..a256e68c23536fc86d774373d8ae4911be12ce79 100644 (file)
@@ -2180,37 +2180,40 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
     goto preupdate_old_out;
   }
 
-  /* If the old.* record has not yet been loaded into memory, do so now. */
-  if( p->pUnpacked==0 ){
-    u32 nRec;
-    u8 *aRec;
-
-    assert( p->pCsr->eCurType==CURTYPE_BTREE );
-    nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
-    aRec = sqlite3DbMallocRaw(db, nRec);
-    if( !aRec ) goto preupdate_old_out;
-    rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
-    if( rc==SQLITE_OK ){
-      p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
-      if( !p->pUnpacked ) rc = SQLITE_NOMEM;
-    }
-    if( rc!=SQLITE_OK ){
-      sqlite3DbFree(db, aRec);
-      goto preupdate_old_out;
-    }
-    p->aRecord = aRec;
-  }
-
-  pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
   if( iIdx==p->pTab->iPKey ){
+    pMem = *ppValue = &p->oldipk;
     sqlite3VdbeMemSetInt64(pMem, p->iKey1);
-  }else if( iIdx>=p->pUnpacked->nField ){
-    *ppValue = (sqlite3_value *)columnNullValue();
-  }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
-    if( pMem->flags & (MEM_Int|MEM_IntReal) ){
-      testcase( pMem->flags & MEM_Int );
-      testcase( pMem->flags & MEM_IntReal );
-      sqlite3VdbeMemRealify(pMem);
+  }else{
+    /* If the old.* record has not yet been loaded into memory, do so now. */
+    if( p->pUnpacked==0 ){
+      u32 nRec;
+      u8 *aRec;
+
+      assert( p->pCsr->eCurType==CURTYPE_BTREE );
+      nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
+      aRec = sqlite3DbMallocRaw(db, nRec);
+      if( !aRec ) goto preupdate_old_out;
+      rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
+      if( rc==SQLITE_OK ){
+        p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
+        if( !p->pUnpacked ) rc = SQLITE_NOMEM;
+      }
+      if( rc!=SQLITE_OK ){
+        sqlite3DbFree(db, aRec);
+        goto preupdate_old_out;
+      }
+      p->aRecord = aRec;
+    }
+
+    pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
+    if( iIdx>=p->pUnpacked->nField ){
+      *ppValue = (sqlite3_value *)columnNullValue();
+    }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
+      if( pMem->flags & (MEM_Int|MEM_IntReal) ){
+        testcase( pMem->flags & MEM_Int );
+        testcase( pMem->flags & MEM_IntReal );
+        sqlite3VdbeMemRealify(pMem);
+      }
     }
   }
 
index 665f6cd17ab3fd3c4352151bc35c0e7ab09b071b..18b1183a41567c9bfd5175ade5c70870d6f48fa5 100644 (file)
@@ -5525,6 +5525,7 @@ void sqlite3VdbePreUpdateHook(
   sqlite3DbFree(db, preupdate.aRecord);
   vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
   vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
+  sqlite3VdbeMemRelease(&preupdate.oldipk);
   if( preupdate.aNew ){
     int i;
     for(i=0; i<pCsr->nField; i++){