]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix many problems in the sqlite3_schema_copy() function.
authordan <Dan Kennedy>
Tue, 7 Jan 2025 21:04:51 +0000 (21:04 +0000)
committerdan <Dan Kennedy>
Tue, 7 Jan 2025 21:04:51 +0000 (21:04 +0000)
FossilOrigin-Name: ac9ca885902a105a4afc3bf157688c30f100bdb1064380328fd7f7a7fa126ee8

13 files changed:
manifest
manifest.uuid
src/analyze.c
src/btree.c
src/build.c
src/callback.c
src/global.c
src/main.c
src/prepare.c
src/sqlite.h.in
src/sqliteInt.h
src/test1.c
test/tester.tcl

index 0c8916618bc63d714ff6b6df79b0d47ea8bde7a6..f852c967ed9441b97b38a888366ff679db5ad5af 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Implemenation\sof\sexperimental\sAPI\ssqlite3_schema_copy(),\sfor\scopying\sa\sdatabase\sschema\sbetween\sconnections.\sMore\stesting\sto\scome.
-D 2025-01-06T20:39:57.366
+C Fix\smany\sproblems\sin\sthe\ssqlite3_schema_copy()\sfunction.
+D 2025-01-07T21:04:51.236
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -707,17 +707,17 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
 F src/alter.c c48e7cbb7f87b28e9e954bfed3327d8e1b8e2a020fbb5bbeca78f6534d6c3c31
-F src/analyze.c 19a2b6ed803a3c0add5f48adbac4735a064d329aa91790b94c968fef0bf7c438
+F src/analyze.c baba2f987e2564cfcfc31cc52b90da282644e35f93a94dcef30c07536bdf82c2
 F src/attach.c 08235ab62ed5ccc93c22bf36e640d19effcd632319615851bccf724ec9341333
 F src/auth.c 4c1ea890e0069ad73bead5d17a5b12c34cfa4f1a24175c8147ea439b64be271c
 F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
 F src/bitvec.c 501daeef838fa82a9fb53540d72f29e3d9172c8867f1e19f94f681e2e20b966e
 F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
-F src/btree.c 2664c81f217a42afadc7c010bb4a175057d5e53b99e9512234eb74817f2ad59c
+F src/btree.c f840a13b2f7fe8d94925012946f0cc46251e4943852b9f00f2e11e808f716736
 F src/btree.h bdeeb35614caa33526b603138f04c8d07a3f90a1300b5ade76848b755edf2027
 F src/btreeInt.h caa893e74d2261fb0ff1681fce998533c0552858e882bd04fc6805075f5f6e75
-F src/build.c 19d6ba76fb72f81fed5323298284d56f0c32c7a59c38532e56c9811cdd9a89a5
-F src/callback.c 43c8ca52b1ecbdec43522f121126fd4e3ee10bc9ca01cdd3ae207cfa419780b6
+F src/build.c c8b1ce2275630b936f9e4f15694394fe29f542929e137771a03276dd285e628d
+F src/callback.c a8f3276f3f506e94b75b7102b8d4a76417cf9fa6ec1596faf0a6f7b8b4823e0e
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 193f6f9a75204274b7e7f45ac6d6517c12c70b55a5dfb39312dfc3a52e2a8138
 F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a
@@ -728,7 +728,7 @@ F src/expr.c f126029aed954608925395cfde214564f2f781f40ea5951ca8e987f07b73b0e4
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
 F src/func.c ce9dc15867388c76894fa67b3500f5726579b766b00ba617a2ad46c16ca76c1e
-F src/global.c 61a419dd9e993b9be0f91de4c4ccf322b053eb829868e089f0321dd669be3b90
+F src/global.c c8f0ed504e7d4eec373e57d2ddc513c0cb03887de7c05ccb1865160e1ec6d601
 F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
@@ -737,7 +737,7 @@ F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70
 F src/json.c 68a98c020c22127f2d65f08855f7fc7460ff352a6ce0b543d8931dde83319c22
 F src/legacy.c 5fff8efbb4f20396136beb913fff323686cff8f6f5d7d728189f68e98f7310bb
 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
-F src/main.c 2aa8cea363b16f4093fc317f8bab38922c8e7b8d2c78b99cb64b6ab782a7c8e8
+F src/main.c bfeeca76e234be2f81c13f0ee9b08f399dbd7f06ee077158d2968cbfcc5d8894
 F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -769,23 +769,23 @@ F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
 F src/pcache1.c 437282ad81350c98a8592425b19e1b4e132196f7a81aef49b2ca39c50937b827
 F src/pragma.c 464813bf39538eaa2c2cfe349de97888cc4d82645c0574d9c522190d46898149
 F src/pragma.h 6ebbdee90ed56a892d2c728e27fd9c1ce48c8a28841888d0c6c147946b38cb25
-F src/prepare.c 3476a2d3353d3a881822f888fcd04bfdf5bf62a2a0566ffca83dc42190fdae19
+F src/prepare.c 4a8b68907511de0e8cd9a7ead5ee27d2fcee219683bf2c1d36bb9ae198700926
 F src/printf.c 9480e90343dfde2406eeb25ff072774a77453d0f57fcd6495102f915dcc26a82
 F src/random.c 9bd018738ec450bf35d28050b4b33fa9a6eebf3aaefb1a1cff42dc14a7725673
 F src/resolve.c 2c127880c0634962837f16f2f48a295e514357af959330cc038de73015d5b5e8
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c d07d1872161db7c922194c5279d67686e8355c6d304ed0e0646fbaa59b59f561
 F src/shell.c.in 40de636c1d90fb8a9ca7f49dc8f50d930f1b60736e73aca5eb37c4c7d0e47f9d
-F src/sqlite.h.in f991accd827e7853d092366690772b2de831a8fcbe1cb127f3831e39a4302e7e
+F src/sqlite.h.in b9d8969b238d4560d0cf6458957e710a3ebbbe85c8c614bd000819b34958bc40
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 9e7a2d0941b10f059c1c62f13cea460b55bcd6b68c3a3c2fe170ce79e25a0032
+F src/sqliteInt.h 53123981e9aba70c4c58649b9b8b0f72b63025a413e69b3ca196d18ae68bd47e
 F src/sqliteLimit.h da2cffdffa7d71b035f9e59668fbaad74b5939300dbfa9915304e6d8f72b0761
 F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
 F src/tclsqlite.c c6888598f08dee3d9112a38ef42c8f5c89ca7f3190f4694744d0b84250f4bf8c
 F src/tclsqlite.h c6af51f31a2b2172d674608763a4b98fdf5cd587e4025053e546fb8077757262
-F src/test1.c 10d600bdbd99b4fa078195ca7d4746880f61553196a341ac7f1c246c1e882f24
+F src/test1.c ccbac0fdb30e4f77c515761aa776742f98258234e9d5be2d6a21bc6e1bf7ecd1
 F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
 F src/test3.c e7573aa0f78ee4e070a4bc8c3493941c1aa64d5c66d4825c74c0f055451f432b
 F src/test4.c 13e57ae7ec7a959ee180970aef09deed141252fe9bb07c61054f0dfa4f1dfd5d
@@ -1735,7 +1735,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
 F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16
 F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
-F test/tester.tcl b4b9cc1520542d34ee061f9f12df0944d6ad1c438feba9db4078f6214e0a8111
+F test/tester.tcl 3c036e092942b97274718b7265142a6c8c57d90cdc6b66280d7974a69d5d6c5d
 F test/testrunner.tcl 982939f0f1835007298b92e52694c207d16ef79143993b35e5cbc9f0c585938b x
 F test/testrunner_data.tcl dbc0bb1c5b912dfd1e32b25d544318e412edd6085bd5fc9e6619cb93a739b786
 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
@@ -2251,11 +2251,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P dc3a24a784c95398656e0d7885f7eb0ee626b86c896e759a6ac5c243fd6f0ab7
-R 319fabba106aeb0d0322166af764ce3c
-T *branch * schema-copy
-T *sym-schema-copy *
-T -sym-cf8f1552-commit-instr *
+P 65ede04d2176e7206ca6ac004df14f488c274a6b092f6a7dc897b049012898fb
+R 1e0aeb33d9fdf3db04ec8caf3017ac1d
 U dan
-Z 463cbc692201d0ebdc4f4cfb189d8b05
+Z 38efdb858d3d69b6af28ade3c3b371f8
 # Remove this line to create a well-formed Fossil manifest.
index 71e458f44a7fe63513a671d9ccef20a47337caff..3b0a011ebe3c1ef13607e15e719ec5df7968538b 100644 (file)
@@ -1 +1 @@
-65ede04d2176e7206ca6ac004df14f488c274a6b092f6a7dc897b049012898fb
+ac9ca885902a105a4afc3bf157688c30f100bdb1064380328fd7f7a7fa126ee8
index b8f1f70d8ddf7aec46d4ad67707917cfba14b0fc..e9cfd3fbaf0d254761fe95b8988afee9c9dcc6bc 100644 (file)
@@ -1861,10 +1861,15 @@ int sqlite3AnalyzeCopyStat4(
     memcpy(pTo->aAvgEq, pFrom->aAvgEq, pFrom->nSampleCol * sizeof(tRowcnt));
     memcpy(pTo->aSample[0].anEq, pFrom->aSample[0].anEq, 
         pTo->nSampleCol * 3 * sizeof(tRowcnt) * pTo->nSample
-        );
+    );
     for(ii=0; ii<pTo->nSample; ii++){
-      pTo->aSample[ii].p = pFrom->aSample[ii].p;
-      pTo->aSample[ii].n = pFrom->aSample[ii].n;
+      int nByte = pFrom->aSample[ii].n;
+      void *p = sqlite3DbMallocZero(db, nByte+8);
+      if( p ){
+        memcpy(p, pFrom->aSample[ii].p, nByte);
+      }
+      pTo->aSample[ii].p = p;
+      pTo->aSample[ii].n = nByte;
     }
   }
   return SQLITE_OK;
index cb8aa1195040c6a6912010dca9497df262829413..989f48536e77760802a8d8273f6d6f52a3c6f962 100644 (file)
@@ -11839,6 +11839,17 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
   return pBt->pSchema;
 }
 
+void sqlite3BtreeSchemaPut(Btree *p, void *pTo){
+  BtShared *pBt = p->pBt;
+  assert( sqlite3BtreeHoldsMutex(p) );
+  assert( pBt->xFreeSchema );
+  assert( pBt->pSchema );
+
+  pBt->xFreeSchema(pBt->pSchema);
+  sqlite3DbFree(0, pBt->pSchema);
+  pBt->pSchema = pTo;
+}
+
 /*
 ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
 ** btree as the argument handle holds an exclusive lock on the
index 7d4709e6b2f104f2f6bd98e47a0f597d5a66b93e..2c833f7d136ebd8e19130e93a540031e9e97460f 100644 (file)
@@ -5796,6 +5796,26 @@ void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){
   sqlite3WithDelete(db, (With*)pWith);
 }
 
+struct TwoTable {
+  Table *pNew;
+  Table *pOld;
+};
+
+static int schemaCopyExprCb(Walker *p, Expr *pExpr){
+  struct TwoTable *pT = (struct TwoTable*)p->u.pSchema;
+  if( pExpr->op==TK_COLUMN && pExpr->y.pTab==pT->pOld ){
+    pExpr->y.pTab = pT->pNew;
+  }
+  return WRC_Continue;
+}
+
+static void schemaCopyExprWalker(Walker *p, struct TwoTable *pT){
+  memset(p, 0, sizeof(*p));
+  p->xExprCallback = schemaCopyExprCb;
+  p->xSelectCallback = sqlite3SelectWalkNoop;
+  p->u.pSchema = (Schema*)pT;
+}
+
 static Index *schemaCopyIndexList(sqlite3 *db, Table *pTab, Index *pIdx){
   Schema *pSchema = pTab->pSchema;
   Index *pRet = 0;
@@ -5815,6 +5835,9 @@ static Index *schemaCopyIndexList(sqlite3 *db, Table *pTab, Index *pIdx){
 
     pNew = sqlite3AllocateIndexObject(db, p->nColumn, nName+nExtra, &zExtra);
     if( pNew ){
+      struct TwoTable twotable;
+      Walker sExprWalker;
+
       pNew->zName = zExtra;
       memcpy(pNew->zName, p->zName, nName);
       zExtra += nName;
@@ -5836,14 +5859,26 @@ static Index *schemaCopyIndexList(sqlite3 *db, Table *pTab, Index *pIdx){
         }
         pNew->azColl[ii] = zColl;
       }
+
       pNew->pPartIdxWhere = sqlite3ExprDup(db, p->pPartIdxWhere, 0);
+      twotable.pNew = pTab;
+      twotable.pOld = p->pTable;
+      schemaCopyExprWalker(&sExprWalker, &twotable);
+      sqlite3WalkExpr(&sExprWalker, pNew->pPartIdxWhere);
+
       pNew->aColExpr = sqlite3ExprListDup(db, p->aColExpr, 0);
+      sqlite3WalkExprList(&sExprWalker, pNew->aColExpr);
+
       pNew->tnum = p->tnum;
       pNew->szIdxRow = p->szIdxRow;
-      memcpy(&pNew->onError,&p->onError,sizeof(Index)-offsetof(Index, onError));
+      memcpy(&pNew->nKeyCol,&p->nKeyCol,sizeof(Index)-offsetof(Index, nKeyCol));
       pNew->isResized = 0;
 #ifdef SQLITE_ENABLE_STAT4 
       assert( pNew->aiRowEst==0 && p->aiRowEst==0 );
+      pNew->aAvgEq = 0;
+      pNew->aSample = 0;
+      pNew->nSample = 0;
+      pNew->nSampleAlloc = 0;
       sqlite3AnalyzeCopyStat4(db, pNew, p);
 #endif
 
@@ -6008,9 +6043,14 @@ static void schemaCopyTable(sqlite3 *db, Schema *pTo, Table *pTab){
 
   pNew = (Table*)sqlite3DbMallocRawNN(db, sizeof(Table));
   if( pNew ){
+    Walker sExprWalker;
+    struct TwoTable twotable;
     memcpy(pNew, pTab, sizeof(Table));
     pNew->zName = sqlite3DbStrDup(db, pNew->zName);
-    pNew->aCol = sqlite3DbMallocRawNN(db, pNew->nCol*sizeof(Column));
+    assert( pNew->nCol>0 || pNew->eTabType!=TABTYP_NORM );
+    if( pNew->nCol>0 ){
+      pNew->aCol = sqlite3DbMallocRawNN(db, pNew->nCol*sizeof(Column));
+    }
     pNew->nTabRef = 1;
     if( pNew->aCol ){
       int ii;
@@ -6036,6 +6076,11 @@ static void schemaCopyTable(sqlite3 *db, Schema *pTo, Table *pTab){
     pNew->zColAff = 0;
     pNew->pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
 
+    twotable.pNew = pNew;
+    twotable.pOld = pTab;
+    schemaCopyExprWalker(&sExprWalker, &twotable);
+    sqlite3WalkExprList(&sExprWalker, pNew->pCheck);
+
     if( IsView(pNew) ){
       Walker sWalker;
       memset(&sWalker, 0, sizeof(sWalker));
@@ -6056,6 +6101,7 @@ static void schemaCopyTable(sqlite3 *db, Schema *pTo, Table *pTab){
       }
     }else{
       pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pNew->u.tab.pDfltList, 0);
+      sqlite3WalkExprList(&sExprWalker, pNew->u.tab.pDfltList);
       pNew->u.tab.pFKey = schemaCopyFKeyList(db, pNew, pNew->u.tab.pFKey);
     }
 
@@ -6067,7 +6113,7 @@ static void schemaCopyTable(sqlite3 *db, Schema *pTo, Table *pTab){
       db->mallocFailed = 1;
     }
 #ifndef SQLITE_OMIT_AUTOINCREMENT
-    if( strcmp(pNew->zName, "sqlite_sequence")==0 ){
+    if( pTab->pSchema->pSeqTab==pTab ){
       pTo->pSeqTab = pNew;
     }
 #endif
@@ -6077,6 +6123,35 @@ static void schemaCopyTable(sqlite3 *db, Schema *pTo, Table *pTab){
   }
 }
 
+void sqlite3SchemaCopy(sqlite3 *db, Schema *pTo, Schema *pFrom){
+  HashElem *k = 0;
+
+  DisableLookaside;
+  pTo->schema_cookie = pFrom->schema_cookie;
+  pTo->iGeneration = pFrom->iGeneration;
+  pTo->file_format = pFrom->file_format;
+  pTo->enc = pFrom->enc;
+  pTo->cache_size = pFrom->cache_size;
+  pTo->schemaFlags = pFrom->schemaFlags;
+
+#ifdef SQLITE_ENABLE_STAT4
+  if( pFrom->pStat4Space ){
+    pTo->pStat4Space = sqlite3_malloc(pFrom->nStat4Space);
+    if( pTo->pStat4Space==0 ){
+      sqlite3OomFault(db);
+    }
+    pTo->nStat4Space = 0;
+  }
+#endif
+
+  for(k=sqliteHashFirst(&pFrom->tblHash); k; k=sqliteHashNext(k)){
+    Table *pTab = (Table*)sqliteHashData(k);
+    schemaCopyTable(db, pTo, pTab);
+  }
+
+  EnableLookaside;
+}
+
 int sqlite3_schema_copy(
     sqlite3 *db, const char *zTo, 
     sqlite3 *dbFrom, const char *zFrom
@@ -6085,12 +6160,10 @@ int sqlite3_schema_copy(
   int iFrom = 0;
   Schema *pTo = 0;
   Schema *pFrom = 0;
-  HashElem *k = 0;
   int rc = SQLITE_OK;
 
   sqlite3_mutex_enter(db->mutex);
   sqlite3BtreeEnterAll(db);
-  DisableLookaside;
 
   if( zTo ) iTo = sqlite3FindDbName(db, zTo);
   if( zFrom ) iFrom = sqlite3FindDbName(dbFrom, zFrom);
@@ -6109,31 +6182,9 @@ int sqlite3_schema_copy(
   pFrom = dbFrom->aDb[iFrom].pSchema;
   assert( pTo && pFrom );
 
-  pTo->schema_cookie = pFrom->schema_cookie;
-  pTo->iGeneration = pFrom->iGeneration;
-  pTo->file_format = pFrom->file_format;
-  pTo->enc = pFrom->enc;
-  pTo->cache_size = pFrom->cache_size;
-  pTo->schemaFlags = pFrom->schemaFlags;
-
-#ifdef SQLITE_ENABLE_STAT4
-  if( pFrom->pStat4Space ){
-    pTo->pStat4Space = sqlite3_malloc(pFrom->nStat4Space);
-    if( pTo->pStat4Space==0 ){
-      rc = SQLITE_NOMEM_BKPT;
-      goto schema_copy_done;
-    }
-    pTo->nStat4Space = 0;
-  }
-#endif
-
-  for(k=sqliteHashFirst(&pFrom->tblHash); k; k=sqliteHashNext(k)){
-    Table *pTab = (Table*)sqliteHashData(k);
-    schemaCopyTable(db, pTo, pTab);
-  }
+  sqlite3SchemaCopy(db, pTo, pFrom);
 
  schema_copy_done:
-  EnableLookaside;
   sqlite3BtreeLeaveAll(db);
   rc = sqlite3ApiExit(db, rc);
   sqlite3_mutex_leave(db->mutex);
index f78abe049b370a3e70e560f2ad4abc985c86d835..57b3bcc977e8dabf0bb7bd6d7d6c5f0bd503172e 100644 (file)
@@ -542,3 +542,16 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
   }
   return p;
 }
+
+int sqlite3SchemaTestCopy(sqlite3 *db, int iDb){
+  Btree *pBt = db->aDb[iDb].pBt;
+  Schema *pFrom = db->aDb[iDb].pSchema;
+  Schema *pTo = sqlite3BtreeSchema(pBt, 0, 0);
+
+  assert( pTo && pFrom );
+  sqlite3SchemaCopy(db, pTo, pFrom);
+  db->aDb[iDb].pSchema = pTo;
+
+  return (db->mallocFailed ? SQLITE_NOMEM : SQLITE_OK);
+}
+
index 121b3f6d6bb59b93635f0a363f049c93d78ce0cb..1ad10cf2e1318d79384c1785096b89a42bfca345 100644 (file)
@@ -297,6 +297,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    0x7ffffffe,                /* iOnceResetThreshold */
    SQLITE_DEFAULT_SORTERREF_SIZE,   /* szSorterRef */
    0,                         /* iPrngSeed */
+   0,                         /* bTestSchemaCopy */
 #ifdef SQLITE_DEBUG
    {0,0,0,0,0,0},             /* aTune */
 #endif
index a5bdad98d6686e2e6e08afa0d0ec379e6206ecf0..f5e0d17c5fa160d8e7f84405ed479c604a9d9cbd 100644 (file)
@@ -4637,6 +4637,18 @@ int sqlite3_test_control(int op, ...){
       break;
     }
 
+    /* sqlite3_test_control(SQLITE_TESTCTRL_SCHEMACOPY, int X);
+    **
+    **   X==0    Disable test sqlite3_schema_copy()
+    **   X==1    Enable test sqlite3_schema_copy()
+    */
+    case SQLITE_TESTCTRL_SCHEMACOPY: {
+      int b = va_arg(ap, int);
+      if( b>=0 ) sqlite3Config.bTestSchemaCopy = b>0;
+      rc = sqlite3Config.bTestSchemaCopy!=0;
+      break;
+    }
+
 #if !defined(SQLITE_OMIT_WSD)
     /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
     **
index 9246095cb5f11542a66e0b99160f78189cbe77ce..fd5440e7f0bf5fbdfc3e8e268e62224f0ea520df 100644 (file)
@@ -476,7 +476,20 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
   assert( db->nDb>0 );
   /* Do the main schema first */
   if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
+    Schema *pNew = 0;
+    if( sqlite3Config.bTestSchemaCopy ){
+      pNew = sqlite3DbMallocZero(db, sizeof(Schema));
+      if( !pNew ) return SQLITE_NOMEM;
+      pNew->cache_size = db->aDb[0].pSchema->cache_size;
+      db->aDb[0].pSchema = pNew;
+    }
     rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
+    if( sqlite3Config.bTestSchemaCopy ){
+      int rc2 = sqlite3SchemaTestCopy(db, 0);
+      if( rc==SQLITE_OK ) rc = rc2;
+      sqlite3SchemaClear(pNew);
+      sqlite3DbFree(db, pNew);
+    }
     if( rc ) return rc;
   }
   /* All other schemas after the main schema. The "temp" schema must be last */
index c3b77319b330cef9980b13138cf360392ae08b07..3d204fd9250f28654d74efbfdfc0c6fcd9bbc19e 100644 (file)
@@ -8365,7 +8365,8 @@ int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_TUNE                    32
 #define SQLITE_TESTCTRL_LOGEST                  33
 #define SQLITE_TESTCTRL_USELONGDOUBLE           34
-#define SQLITE_TESTCTRL_LAST                    34  /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_SCHEMACOPY              35
+#define SQLITE_TESTCTRL_LAST                    35  /* Largest TESTCTRL */
 
 /*
 ** CAPI3REF: SQL Keyword Checking
index e3fc83b9427fac6cad9e4f26928b4c4c55438a8b..e1050c85bdd60d35eb39f7bcbcea7398d54292d5 100644 (file)
@@ -4417,6 +4417,7 @@ struct Sqlite3Config {
   int iOnceResetThreshold;          /* When to reset OP_Once counters */
   u32 szSorterRef;                  /* Min size in bytes to use sorter-refs */
   unsigned int iPrngSeed;           /* Alternative fixed seed for the PRNG */
+  int bTestSchemaCopy;              /* True to test schema copies internally */
   /* vvvv--- must be last ---vvv */
 #ifdef SQLITE_DEBUG
   sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */
@@ -5608,6 +5609,9 @@ int sqlite3AnalyzeCopyStat4(sqlite3*, Index*, Index *pFrom);
 #endif
 
 TriggerStep *sqlite3SchemaCopyTriggerStepList(sqlite3 *, TriggerStep*);
+int sqlite3SchemaTestCopy(sqlite3 *db, int);
+void sqlite3SchemaCopy(sqlite3 *db, Schema*, Schema*);
+void sqlite3BtreeSchemaPut(Btree *pBt, void*);
 
 /*
 ** The interface to the LEMON-generated parser
index 5d7d4747385389306b2576c8742fe0f22ccc5daa..796fcafb5c653b942d55710d2c4ac5fd6bb46a65 100644 (file)
@@ -7947,6 +7947,7 @@ static int SQLITE_TCLAPI test_test_control(
     { "SQLITE_TESTCTRL_IMPOSTER",           SQLITE_TESTCTRL_IMPOSTER        },
     { "SQLITE_TESTCTRL_INTERNAL_FUNCTIONS", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS},
     { "SQLITE_TESTCTRL_FK_NO_ACTION",       SQLITE_TESTCTRL_FK_NO_ACTION},
+    { "SQLITE_TESTCTRL_SCHEMACOPY",         SQLITE_TESTCTRL_SCHEMACOPY},
     { 0, 0 }
   };
   int iVerb;
@@ -8028,6 +8029,18 @@ static int SQLITE_TCLAPI test_test_control(
       sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
       break;
     }
+
+    case SQLITE_TESTCTRL_SCHEMACOPY: {
+      int val = 0;
+      sqlite3 *db = 0;
+      if( objc!=3 ){
+        Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
+        return TCL_ERROR;
+      }
+      if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
+      sqlite3_test_control(SQLITE_TESTCTRL_SCHEMACOPY, val);
+      break;
+    }
   }
 
   Tcl_ResetResult(interp);
index adad184e568a7f873ab98a8f141976a593bc2e1a..50710769791de1dda60b8c2d021a1ec958b67f77 100644 (file)
@@ -101,6 +101,7 @@ if {[info exists ::tester_tcl_has_run]} return
 set tcl_precision 15
 sqlite3_test_control_pending_byte 0x0010000
 
+#sqlite3_test_control SQLITE_TESTCTRL_SCHEMACOPY 1
 
 # If the pager codec is available, create a wrapper for the [sqlite3]
 # command that appends "-key {xyzzy}" to the command line. i.e. this: