From 41e13e1268e1d9edeb3a0fff552ed4a2cc7b900e Mon Sep 17 00:00:00 2001
From: drh <drh@noemail.net>
Date: Thu, 7 Nov 2013 14:09:39 +0000
Subject: [PATCH] Make sure cached KeyInfo objects are only valid for a single
 database connection.  Clear all cached KeyInfo objects on any collating
 sequence change.

FossilOrigin-Name: 55eea1782aead6a6aaf93f14d85486f8fd2209ad
---
 manifest      | 18 +++++++++---------
 manifest.uuid |  2 +-
 src/build.c   | 15 ++++++++++-----
 src/main.c    | 27 +++++++++++++++++++++++++++
 src/select.c  |  3 +--
 src/vdbe.c    | 19 +++++++++++--------
 6 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/manifest b/manifest
index f47df63713..21d31fb94d 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Reference\scount\sthe\sKeyInfo\sobject.\s\sCache\sa\scopy\sof\san\sappropriate\sKeyInfo\nfor\seach\sindex\sin\sthe\sIndex\sobject,\sand\sreuse\sthat\sone\scopy\sas\smuch\sas\spossible.
-D 2013-11-06T19:59:23.699
+C Make\ssure\scached\sKeyInfo\sobjects\sare\sonly\svalid\sfor\sa\ssingle\sdatabase\nconnection.\s\sClear\sall\scached\sKeyInfo\sobjects\son\sany\scollating\ssequence\s\nchange.
+D 2013-11-07T14:09:39.090
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -168,7 +168,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
 F src/btree.c 260dedc13119e6fb7930380bd3d294b98362bf5a
 F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
-F src/build.c a74889231fc0bb9196f88e8ae29551e65461446a
+F src/build.c d4d5ceedf196a7da36d6dd15f4d073cb68c8f079
 F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
@@ -187,7 +187,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
 F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
-F src/main.c 9bcfc400b5f727dd562996d0bdf507bfbcf31583
+F src/main.c 32bf1e6e164a6fa0ddf1bf2616c6eafbefd6e9b0
 F src/malloc.c 543a8eb5508eaf4cadf55a9b503379eba2088128
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
@@ -218,7 +218,7 @@ F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
 F src/resolve.c e729889b2c7a680ba4aa7296efa72c09369956d8
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c 76477fe7f07bb04891378d9b11ff701807565923
+F src/select.c 60af46f5f6bc3803c27af3edd8881ed2d0c3f19f
 F src/shell.c 03d8d9b4052430343ff30d646334621f980f1202
 F src/sqlite.h.in a8cad179541b8d171fed425a737084702ef462ef
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
@@ -279,7 +279,7 @@ F src/update.c 516e0ea0f853bfb852e098f3b643a3f2bfd423ef
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
-F src/vdbe.c 3493de8d6214aa290d793c7a4062f32bb3d35742
+F src/vdbe.c ff0170cd3c5fea68386818cbd19a23bbfc711364
 F src/vdbe.h 8d5a7351024d80374fc0acdbbe3cfe65c51ba8b6
 F src/vdbeInt.h f2fa3ceccceeb757773921fb08af7c6e9f3caa1c
 F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
@@ -1134,7 +1134,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 474555002d45f8741faceea599c057eef4e7931e
-R 11b6d6465d5ad443e1f3ccfcc5b7af21
+P defd5205a7cc3543cdd18f906f568e943b8b3a2c
+R 0a7295680bb25731824803a052760874
 U drh
-Z ed3df5fd60cd920e736dadf48c637db6
+Z 813173a99e20e783c085a6d86fb32041
diff --git a/manifest.uuid b/manifest.uuid
index 1f612a840b..01ab178fce 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-defd5205a7cc3543cdd18f906f568e943b8b3a2c
\ No newline at end of file
+55eea1782aead6a6aaf93f14d85486f8fd2209ad
\ No newline at end of file
diff --git a/src/build.c b/src/build.c
index 11de95eaf3..27ea43e2f3 100644
--- a/src/build.c
+++ b/src/build.c
@@ -4154,13 +4154,18 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
 ** when it has finished using it.
 */
 KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
-  int i;
-  int nCol = pIdx->nColumn;
-  int nKey = pIdx->nKeyCol;
-  KeyInfo *pKey;
-
   if( pParse->nErr ) return 0;
+#ifndef SQLITE_OMIT_SHARED_CACHE
+  if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
+    sqlite3KeyInfoUnref(pIdx->pKeyInfo);
+    pIdx->pKeyInfo = 0;
+  }
+#endif
   if( pIdx->pKeyInfo==0 ){
+    int i;
+    int nCol = pIdx->nColumn;
+    int nKey = pIdx->nKeyCol;
+    KeyInfo *pKey;
     if( pIdx->uniqNotNull ){
       pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
     }else{
diff --git a/src/main.c b/src/main.c
index a8b6c84ec0..5e03662d38 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1951,6 +1951,32 @@ const char *sqlite3_errstr(int rc){
   return sqlite3ErrStr(rc);
 }
 
+/*
+** Invalidate all cached KeyInfo objects for database connection "db"
+*/
+static void invalidateCachedKeyInfo(sqlite3 *db){
+  Db *pDb;                    /* A single database */
+  int iDb;                    /* The database index number */
+  HashElem *k;                /* For looping over tables in pDb */
+  Table *pTab;                /* A table in the database */
+  Index *pIdx;                /* Each index */
+
+  for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
+    if( pDb->pBt==0 ) continue;
+    sqlite3BtreeEnter(pDb->pBt);
+    for(k=sqliteHashFirst(&pDb->pSchema->tblHash);  k; k=sqliteHashNext(k)){
+      pTab = (Table*)sqliteHashData(k);
+      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+        if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){
+          sqlite3KeyInfoUnref(pIdx->pKeyInfo);
+          pIdx->pKeyInfo = 0;
+        }
+      }
+    }
+    sqlite3BtreeLeave(pDb->pBt);
+  }
+}
+
 /*
 ** Create a new collating function for database "db".  The name is zName
 ** and the encoding is enc.
@@ -1995,6 +2021,7 @@ static int createCollation(
       return SQLITE_BUSY;
     }
     sqlite3ExpirePreparedStatements(db);
+    invalidateCachedKeyInfo(db);
 
     /* If collation sequence pColl was created directly by a call to
     ** sqlite3_create_collation, and not generated by synthCollSeq(),
diff --git a/src/select.c b/src/select.c
index 2d985d6c30..cab161fd2d 100644
--- a/src/select.c
+++ b/src/select.c
@@ -828,9 +828,8 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
 void sqlite3KeyInfoUnref(KeyInfo *p){
   if( p ){
     assert( p->nRef>0 );
-    assert( p->db==0 || p->db->pnBytesFreed==0 );
     p->nRef--;
-    if( p->nRef==0 ) sqlite3DbFree(p->db, p);
+    if( p->nRef==0 ) sqlite3_free(p);
   }
 }
 
diff --git a/src/vdbe.c b/src/vdbe.c
index 9851f4a33c..97b35196d3 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3288,7 +3288,8 @@ case OP_OpenWrite: {
   }
   if( pOp->p4type==P4_KEYINFO ){
     pKeyInfo = pOp->p4.pKeyInfo;
-    pKeyInfo->enc = ENC(p->db);
+    assert( pKeyInfo->enc==ENC(db) );
+    assert( pKeyInfo->db==db );
     nField = pKeyInfo->nField+pKeyInfo->nXField;
   }else if( pOp->p4type==P4_INT32 ){
     nField = pOp->p4.i;
@@ -3345,13 +3346,14 @@ case OP_OpenWrite: {
 case OP_OpenAutoindex: 
 case OP_OpenEphemeral: {
   VdbeCursor *pCx;
+  KeyInfo *pKeyInfo;
+
   static const int vfsFlags = 
       SQLITE_OPEN_READWRITE |
       SQLITE_OPEN_CREATE |
       SQLITE_OPEN_EXCLUSIVE |
       SQLITE_OPEN_DELETEONCLOSE |
       SQLITE_OPEN_TRANSIENT_DB;
-
   assert( pOp->p1>=0 );
   pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
   if( pCx==0 ) goto no_mem;
@@ -3367,16 +3369,16 @@ case OP_OpenEphemeral: {
     ** opening it. If a transient table is required, just use the
     ** automatically created table with root-page 1 (an BLOB_INTKEY table).
     */
-    if( pOp->p4.pKeyInfo ){
+    if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
       int pgno;
       assert( pOp->p4type==P4_KEYINFO );
       rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); 
       if( rc==SQLITE_OK ){
         assert( pgno==MASTER_ROOT+1 );
-        rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, 
-                                (KeyInfo*)pOp->p4.z, pCx->pCursor);
-        pCx->pKeyInfo = pOp->p4.pKeyInfo;
-        pCx->pKeyInfo->enc = ENC(p->db);
+        assert( pKeyInfo->db==db );
+        assert( pKeyInfo->enc==ENC(db) );
+        pCx->pKeyInfo = pKeyInfo;
+        rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor);
       }
       pCx->isTable = 0;
     }else{
@@ -3401,7 +3403,8 @@ case OP_SorterOpen: {
   pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
   if( pCx==0 ) goto no_mem;
   pCx->pKeyInfo = pOp->p4.pKeyInfo;
-  pCx->pKeyInfo->enc = ENC(p->db);
+  assert( pCx->pKeyInfo->db==db );
+  assert( pCx->pKeyInfo->enc==ENC(db) );
   pCx->isSorter = 1;
   rc = sqlite3VdbeSorterInit(db, pCx);
   break;