From: dan Date: Tue, 7 Jan 2025 21:04:51 +0000 (+0000) Subject: Fix many problems in the sqlite3_schema_copy() function. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=193a686d6886df98c06acb5b788f54f46bd4a95a;p=thirdparty%2Fsqlite.git Fix many problems in the sqlite3_schema_copy() function. FossilOrigin-Name: ac9ca885902a105a4afc3bf157688c30f100bdb1064380328fd7f7a7fa126ee8 --- diff --git a/manifest b/manifest index 0c8916618b..f852c967ed 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index 71e458f44a..3b0a011ebe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -65ede04d2176e7206ca6ac004df14f488c274a6b092f6a7dc897b049012898fb +ac9ca885902a105a4afc3bf157688c30f100bdb1064380328fd7f7a7fa126ee8 diff --git a/src/analyze.c b/src/analyze.c index b8f1f70d8d..e9cfd3fbaf 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -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; iinSample; 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; diff --git a/src/btree.c b/src/btree.c index cb8aa11950..989f48536e 100644 --- a/src/btree.c +++ b/src/btree.c @@ -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 diff --git a/src/build.c b/src/build.c index 7d4709e6b2..2c833f7d13 100644 --- a/src/build.c +++ b/src/build.c @@ -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); diff --git a/src/callback.c b/src/callback.c index f78abe049b..57b3bcc977 100644 --- a/src/callback.c +++ b/src/callback.c @@ -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); +} + diff --git a/src/global.c b/src/global.c index 121b3f6d6b..1ad10cf2e1 100644 --- a/src/global.c +++ b/src/global.c @@ -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 diff --git a/src/main.c b/src/main.c index a5bdad98d6..f5e0d17c5f 100644 --- a/src/main.c +++ b/src/main.c @@ -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); ** diff --git a/src/prepare.c b/src/prepare.c index 9246095cb5..fd5440e7f0 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -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 */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c3b77319b3..3d204fd925 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e3fc83b942..e1050c85bd 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 diff --git a/src/test1.c b/src/test1.c index 5d7d474738..796fcafb5c 100644 --- a/src/test1.c +++ b/src/test1.c @@ -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); diff --git a/test/tester.tcl b/test/tester.tcl index adad184e56..5071076979 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -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: