]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid loading the entire record into memory for an sqlite3_preupdate_old() call that...
authordan <Dan Kennedy>
Mon, 4 Nov 2024 16:59:02 +0000 (16:59 +0000)
committerdan <Dan Kennedy>
Mon, 4 Nov 2024 16:59:02 +0000 (16:59 +0000)
FossilOrigin-Name: 7f4de43733200beeb3ff0a70d51bbc68f5331895698ea95a82741cfd7bb66834

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 e80bdc173273896ed12c6800b2de8fe5b11fc09c..76c621993722164471e14b0c2034c72ebb954c9e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\stwo\smismatched\suses\sof\smalloc()\sand\ssqlite3_free()\sin\ssqlite3_stdio.c,\sas\sreported\sin\s[forum:7dd7c70038\s|\sforum\spost\s7dd7c70038].
-D 2024-11-04T13:57:20.510
+C Avoid\sloading\sthe\sentire\srecord\sinto\smemory\sfor\san\ssqlite3_preupdate_old()\scall\sthat\sretrieves\san\sIPK\svalue.
+D 2024-11-04T16:59:02.337
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md c5b4009dca54d127d2d6033c22fd9cc34f53bedb6ef12c7cbaa468381c74ab28
@@ -595,6 +595,7 @@ F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8
 F ext/session/sessionalter.test e852acb3d2357aac7d0b920a2109da758c4331bfdf85b41d39aa3a8c18914f65
 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 e89f7aedcdd89e5ebac3a455224eb553a171e9586fc3e1e6a7b3388d2648ba8d
@@ -847,9 +848,9 @@ F src/util.c ceebf912f673247e305f16f97f0bb7285fca1d37413b79680714a553a9021d33
 F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
 F src/vdbe.c 8a6eb02823b424b273614bae41579392a5c495424592b60423dd2c443a583df0
 F src/vdbe.h c2549a215898a390de6669cfa32adba56f0d7e17ba5a7f7b14506d6fd5f0c36a
-F src/vdbeInt.h af7d7e8291edd0b19f2cd698e60e4d4031078f9a2f2328ac8f0b7efb134f8a1d
-F src/vdbeapi.c 53c7e26a2c0821a892b20eee2cde4656e31998212f3d515576c780dfaa45fd17
-F src/vdbeaux.c f06f011e4fac948941ea821ac365a9f1c163ef473e63756d6e499a37c6bda9ef
+F src/vdbeInt.h 2da01c73e8e3736a9015d5b04aa04d209bc9023d279d237d4d409205e921ea1e
+F src/vdbeapi.c 6353de05e8e78e497ccb33381ba5662ccc11c0339e5b1455faff01b6dacc3075
+F src/vdbeaux.c f0706ad786b8a6c5bc7ea622f3916c2ba2b883abc872d0b4911c4f021945c0e5
 F src/vdbeblob.c 255be187436da38b01f276c02e6a08103489bbe2a7c6c21537b7aecbe0e1f797
 F src/vdbemem.c df568ef0187e4be2788c35174f6d9b8566ab9475f9aff2d73907ed05aa5684b2
 F src/vdbesort.c d0a3c7056c081703c8b6d91ad60f17da5e062a5c64bf568ed0fa1b5f4cae311f
@@ -2198,8 +2199,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P a60e5d76d06ae0568fbc6e068a7012c77778607cd60da92a1b84ff8f33049a93
-R 1e21ba8321e5a6b22692a09525e9bc1b
-U stephan
-Z 743a8b18a247cccbb6a7ea690e8b0e07
+P af0a345b3b287f82b54249cfa574ef3ce52305a6452058aac98cd473c361919e
+R 84f5bc88e95886a46e23b56039713592
+U dan
+Z ba372c464e587d954c923d1075bdeb25
 # Remove this line to create a well-formed Fossil manifest.
index 6b47a0a44222624745cb54d29a26d1abb733ab15..8ed87eec774175e459a8ba84fddc87424501ff89 100644 (file)
@@ -1 +1 @@
-af0a345b3b287f82b54249cfa574ef3ce52305a6452058aac98cd473c361919e
+7f4de43733200beeb3ff0a70d51bbc68f5331895698ea95a82741cfd7bb66834
index b26860f3a661832622d46a643e76d1b62e3a108f..467f488905a0b182f35318aa86749db0a10bc8f3 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 b6ad5f3d95f012bbd48fb3e5754dfbb5472e5320..014ad95393c20edbb9093d6000f092fb6e88f6ab 100644 (file)
@@ -2197,60 +2197,64 @@ 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 ){
+    *ppValue = pMem = &p->oldipk;
     sqlite3VdbeMemSetInt64(pMem, p->iKey1);
-  }else if( iIdx>=p->pUnpacked->nField ){
-    /* This occurs when the table has been extended using ALTER TABLE
-    ** ADD COLUMN. The value to return is the default value of the column. */
-    Column *pCol = &p->pTab->aCol[iIdx];
-    if( pCol->iDflt>0 ){
-      if( p->apDflt==0 ){
-        int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
-        p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
-        if( p->apDflt==0 ) goto preupdate_old_out;
+  }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( p->apDflt[iIdx]==0 ){
-        sqlite3_value *pVal = 0;
-        Expr *pDflt;
-        assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
-        pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
-        rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
-        if( rc==SQLITE_OK && pVal==0 ){
-          rc = SQLITE_CORRUPT_BKPT;
-        }
-        p->apDflt[iIdx] = pVal;
+      if( rc!=SQLITE_OK ){
+        sqlite3DbFree(db, aRec);
+        goto preupdate_old_out;
       }
-      *ppValue = p->apDflt[iIdx];
-    }else{
-      *ppValue = (sqlite3_value *)columnNullValue();
+      p->aRecord = aRec;
     }
-  }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);
+
+    pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
+    if( iIdx>=p->pUnpacked->nField ){
+      /* This occurs when the table has been extended using ALTER TABLE
+      ** ADD COLUMN. The value to return is the default value of the column. */
+      Column *pCol = &p->pTab->aCol[iIdx];
+      if( pCol->iDflt>0 ){
+        if( p->apDflt==0 ){
+          int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
+          p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
+          if( p->apDflt==0 ) goto preupdate_old_out;
+        }
+        if( p->apDflt[iIdx]==0 ){
+          sqlite3_value *pVal = 0;
+          Expr *pDflt;
+          assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
+          pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
+          rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
+          if( rc==SQLITE_OK && pVal==0 ){
+            rc = SQLITE_CORRUPT_BKPT;
+          }
+          p->apDflt[iIdx] = pVal;
+        }
+        *ppValue = p->apDflt[iIdx];
+      }else{
+        *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 8120536b9817c4742b81f2d9fa25b93d8bc12c39..4414f7a2ec076a37f23c70e5f344b2c17c5788de 100644 (file)
@@ -5529,6 +5529,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++){