]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Simplify the sessions preupdate-hook logic for transforming NULL to X'' for
authordan <dan@noemail.net>
Thu, 18 Jan 2018 15:06:23 +0000 (15:06 +0000)
committerdan <dan@noemail.net>
Thu, 18 Jan 2018 15:06:23 +0000 (15:06 +0000)
column sqlite_stat1.idx.

FossilOrigin-Name: 089d7cecaaa47db58320b216a111a5e56123d022008be6c81bc0746148bbdb58

ext/session/sqlite3session.c
manifest
manifest.uuid

index cbe75d5667cf032dcfcfebe2eabe870dbecc758a..fa7dd677a11a49ea591b5d4722d6049cef219a71 100644 (file)
@@ -46,6 +46,7 @@ struct sqlite3_session {
   int rc;                         /* Non-zero if an error has occurred */
   void *pFilterCtx;               /* First argument to pass to xTableFilter */
   int (*xTableFilter)(void *pCtx, const char *zTab);
+  sqlite3_value *pZeroBlob;       /* Value containing X'' */
   sqlite3_session *pNext;         /* Next session object on same db. */
   SessionTable *pTable;           /* List of attached tables */
   SessionHook hook;               /* APIs to grab new and old data with */
@@ -473,35 +474,32 @@ static int sessionPreupdateHash(
       if( rc!=SQLITE_OK ) return rc;
 
       eType = sqlite3_value_type(pVal);
-      if( pTab->bStat1 && eType==SQLITE_NULL ){
-        h = sessionHashAppendType(h, SQLITE_BLOB);
-      }else{
-        h = sessionHashAppendType(h, eType);
-        if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-          i64 iVal;
-          if( eType==SQLITE_INTEGER ){
-            iVal = sqlite3_value_int64(pVal);
-          }else{
-            double rVal = sqlite3_value_double(pVal);
-            assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
-            memcpy(&iVal, &rVal, 8);
-          }
-          h = sessionHashAppendI64(h, iVal);
-        }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
-          const u8 *z;
-          int n;
-          if( eType==SQLITE_TEXT ){
-            z = (const u8 *)sqlite3_value_text(pVal);
-          }else{
-            z = (const u8 *)sqlite3_value_blob(pVal);
-          }
-          n = sqlite3_value_bytes(pVal);
-          if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
-          h = sessionHashAppendBlob(h, n, z);
+      h = sessionHashAppendType(h, eType);
+      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        i64 iVal;
+        if( eType==SQLITE_INTEGER ){
+          iVal = sqlite3_value_int64(pVal);
+        }else{
+          double rVal = sqlite3_value_double(pVal);
+          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+          memcpy(&iVal, &rVal, 8);
+        }
+        h = sessionHashAppendI64(h, iVal);
+      }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+        const u8 *z;
+        int n;
+        if( eType==SQLITE_TEXT ){
+          z = (const u8 *)sqlite3_value_text(pVal);
         }else{
-          assert( eType==SQLITE_NULL );
-          *pbNullPK = 1;
+          z = (const u8 *)sqlite3_value_blob(pVal);
         }
+        n = sqlite3_value_bytes(pVal);
+        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+        h = sessionHashAppendBlob(h, n, z);
+      }else{
+        assert( eType==SQLITE_NULL );
+        assert( pTab->bStat1==0 || i!=1 );
+        *pbNullPK = 1;
       }
     }
   }
@@ -555,7 +553,7 @@ static unsigned int sessionChangeHash(
          || eType==SQLITE_TEXT || eType==SQLITE_BLOB 
          || eType==SQLITE_NULL || eType==0 
     );
-    assert( !isPK || (eType!=0 && (pTab->bStat1 || eType!=SQLITE_NULL)) );
+    assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
 
     if( isPK ){
       a++;
@@ -563,7 +561,7 @@ static unsigned int sessionChangeHash(
       if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
         h = sessionHashAppendI64(h, sessionGetI64(a));
         a += 8;
-      }else if( eType!=SQLITE_NULL ){
+      }else{
         int n; 
         a += sessionVarintGet(a, &n);
         h = sessionHashAppendBlob(h, n, a);
@@ -799,7 +797,6 @@ static int sessionPreupdateEqual(
       sqlite3_value *pVal;        /* Value returned by preupdate_new/old */
       int rc;                     /* Error code from preupdate_new/old */
       int eType = *a++;           /* Type of value from change record */
-      int eValType;
 
       /* The following calls to preupdate_new() and preupdate_old() can not
       ** fail. This is because they cache their return values, and by the
@@ -814,14 +811,7 @@ static int sessionPreupdateEqual(
         rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
       }
       assert( rc==SQLITE_OK );
-      eValType = sqlite3_value_type(pVal);
-      if( eType==SQLITE_BLOB && eValType==SQLITE_NULL && pTab->bStat1 ){
-        int n;
-        a += sessionVarintGet(a, &n);
-        if( n!=0 ) return 0;
-        continue;
-      }
-      if( eValType!=eType ) return 0;
+      if( sqlite3_value_type(pVal)!=eType ) return 0;
 
       /* A SessionChange object never has a NULL value in a PK column */
       assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
@@ -1068,6 +1058,47 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
   return (pSession->rc || pTab->abPK==0);
 }
 
+/*
+** Versions of the four methods in object SessionHook for use with the
+** sqlite_stat1 table. The purpose of this is to substitute a zero-length
+** blob each time a NULL value is read from the "idx" column of the
+** sqlite_stat1 table.
+*/
+typedef struct SessionStat1Ctx SessionStat1Ctx;
+struct SessionStat1Ctx {
+  SessionHook hook;
+  sqlite3_session *pSession;
+};
+static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  sqlite3_value *pVal = 0;
+  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
+  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+    pVal = p->pSession->pZeroBlob;
+  }
+  *ppVal = pVal;
+  return rc;
+}
+static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  sqlite3_value *pVal = 0;
+  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
+  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+    pVal = p->pSession->pZeroBlob;
+  }
+  *ppVal = pVal;
+  return rc;
+}
+static int sessionStat1Count(void *pCtx){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  return p->hook.xCount(p->hook.pCtx);
+}
+static int sessionStat1Depth(void *pCtx){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  return p->hook.xDepth(p->hook.pCtx);
+}
+
+
 /*
 ** This function is only called from with a pre-update-hook reporting a 
 ** change on table pTab (attached to session pSession). The type of change
@@ -1084,6 +1115,7 @@ static void sessionPreupdateOneChange(
   int iHash; 
   int bNull = 0; 
   int rc = SQLITE_OK;
+  SessionStat1Ctx stat1;
 
   if( pSession->rc ) return;
 
@@ -1103,13 +1135,32 @@ static void sessionPreupdateOneChange(
     return;
   }
 
+  if( pTab->bStat1 ){
+    stat1.hook = pSession->hook;
+    stat1.pSession = pSession;
+    pSession->hook.pCtx = (void*)&stat1;
+    pSession->hook.xNew = sessionStat1New;
+    pSession->hook.xOld = sessionStat1Old;
+    pSession->hook.xCount = sessionStat1Count;
+    pSession->hook.xDepth = sessionStat1Depth;
+    if( pSession->pZeroBlob==0 ){
+      sqlite3_value *p = sqlite3ValueNew(0);
+      if( p==0 ){
+        rc = SQLITE_NOMEM;
+        goto error_out;
+      }
+      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
+      pSession->pZeroBlob = p;
+    }
+  }
+
   /* Calculate the hash-key for this change. If the primary key of the row
   ** includes a NULL value, exit early. Such changes are ignored by the
   ** session module. */
   rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
   if( rc!=SQLITE_OK ) goto error_out;
 
-  if( bNull==0 || pTab->bStat1 ){
+  if( bNull==0 ){
     /* Search the hash table for an existing record for this row. */
     SessionChange *pC;
     for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
@@ -1144,7 +1195,6 @@ static void sessionPreupdateOneChange(
         rc = sessionSerializeValue(0, p, &nByte);
         if( rc!=SQLITE_OK ) goto error_out;
       }
-      if( pTab->bStat1 ) nByte += 30;
   
       /* Allocate the change object */
       pChange = (SessionChange *)sqlite3_malloc(nByte);
@@ -1168,12 +1218,7 @@ static void sessionPreupdateOneChange(
         }else if( pTab->abPK[i] ){
           pSession->hook.xNew(pSession->hook.pCtx, i, &p);
         }
-        if( p && pTab->bStat1 && sqlite3_value_type(p)==SQLITE_NULL ){
-          pChange->aRecord[nByte++] = SQLITE_BLOB;
-          nByte += sessionVarintPut(&pChange->aRecord[nByte], 0);
-        }else{
-          sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
-        }
+        sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
       }
 
       /* Add the change to the hash-table */
@@ -1198,6 +1243,9 @@ static void sessionPreupdateOneChange(
 
   /* If an error has occurred, mark the session object as failed. */
  error_out:
+  if( pTab->bStat1 ){
+    pSession->hook = stat1.hook;
+  }
   if( rc!=SQLITE_OK ){
     pSession->rc = rc;
   }
@@ -1659,6 +1707,7 @@ void sqlite3session_delete(sqlite3_session *pSession){
     }
   }
   sqlite3_mutex_leave(sqlite3_db_mutex(db));
+  sqlite3ValueFree(pSession->pZeroBlob);
 
   /* Delete all attached table objects. And the contents of their 
   ** associated hash-tables. */
@@ -2188,7 +2237,7 @@ static int sessionSelectBind(
     switch( eType ){
       case 0:
       case SQLITE_NULL:
-        /* assert( abPK[i]==0 ); */
+        assert( abPK[i]==0 );
         break;
 
       case SQLITE_INTEGER: {
index ce17059a628c52edd499f0ae18dbe722f87e9f81..8c535b94095b66766526b55fd0787b5770c2c56e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sproblem\sin\sthe\ssessions\smodule\swith\slogging\ssqlite_stat1\srows\sfor\swhich\n(idx\sIS\sNULL)\sis\strue.
-D 2018-01-17T20:57:20.602
+C Simplify\sthe\ssessions\spreupdate-hook\slogic\sfor\stransforming\sNULL\sto\sX''\sfor\ncolumn\ssqlite_stat1.idx.
+D 2018-01-18T15:06:23.750
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 38f84f301cbef443b2d269f67a74b8cc536469831f70df7c3e912acc04932cc2
@@ -400,7 +400,7 @@ F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
 F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
 F ext/session/sessionstat1.test 16268a9bf62ab19c9bc9e41404bf7a13b5fd37c9cb6cf278a472f0c6c50d7ac1
 F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
-F ext/session/sqlite3session.c 870d142ec13c0e053139e7f3427aa550e59faf1775ae2bca051766089d9faf7b
+F ext/session/sqlite3session.c 55f20fa4a9b6acc338e11867439633c7faa3d18809cdd826fde6abf9a75dd7a0
 F ext/session/sqlite3session.h cb4d860101ba6d3ac810f18684539b766d24d668fa2436cdde90d711af9464fb
 F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
@@ -1700,10 +1700,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 09aed13678374bf22087cd808808b711dc703b7c18bc8aaf704850611e17f5cd
-R 99a2e08bb84b46a9c74125d0aa1dbedc
-T *branch * sessions-stat1
-T *sym-sessions-stat1 *
-T -sym-trunk *
+P 25bf734be1b3883fccf12ac4d93d50289aa307fb60a52e0e32df12f7ee4edc7a
+R f7c998dd2622eae2189b630c53aa0780
 U dan
-Z 913b883400e9793131764656e068c1a3
+Z 3f8bd6ff445f731b364c070e53a9b8ca
index a3bd20f4c8b03541159c6341b51392b31d9a6168..0823a466b216ce6e4c0c9414ff7883444f700c3b 100644 (file)
@@ -1 +1 @@
-25bf734be1b3883fccf12ac4d93d50289aa307fb60a52e0e32df12f7ee4edc7a
\ No newline at end of file
+089d7cecaaa47db58320b216a111a5e56123d022008be6c81bc0746148bbdb58
\ No newline at end of file