diff --git a/manifest b/manifest index aaad18cb5b..336c603f40 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\smissing\s"extern\sC"\sterminator\sto\sthe\send\sof\ssqlite3session.h. -D 2011-04-06T23:40:28.737 +C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch. +D 2011-04-09T18:07:51.034 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -124,19 +124,19 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c 280f5c04b11b492703a342222b3de0a999445280 -F src/analyze.c a1ad9f4d8aac055c4a4bbd99073e2e78fe66129c -F src/attach.c 7cae2cf0c14762ce14c074a860ec52890a973a56 +F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a +F src/attach.c 7f97ca76ef2453440170929531a9c778267c0830 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c b7529a6691f0fd534ae8ff622203c46a7f1b626b +F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 4fcad108b612a4d33dac568b11d26e4d38ccbe35 +F src/btree.c 6a9164af8a2ef4612ee30b253635a9bd8e5e1b1b F src/btree.h 11753dd46597a20702bca8746cb4caa4486a82b5 F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3 -F src/build.c b7c993274ee2a029937b0bc4815bdef80b330017 +F src/build.c f09c46c66a1e7668c6ee25c9a2518aaa6842044c F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac -F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01 +F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4 F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b F src/delete.c ad9fa1cbf91a83ec6990d0aecb7e21cd5ff07e71 F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be @@ -147,12 +147,12 @@ F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c ef33ce1522a77f6d8077f0bdb6ab22d306900950 +F src/insert.c 8796ca3f9209b699cb8120fc44290fc97ac26abe F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85 -F src/main.c 37608a8346394e52690368742d734f7b01330aaa +F src/main.c 8b97db74cb876bf34ca4fb3720b18e4ffdcf9fd5 F src/malloc.c 788f2ed928786dfe305b6783d551d6b1a9080976 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 @@ -180,16 +180,16 @@ F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e F src/pragma.c 49c90ab27a4339d4b5bc0b03c08cbcf20ed8d454 -F src/prepare.c 206e1f06479fb5f756592bded468bd3ece3f41d4 +F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4 F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c 649a6f10f7eb7b52a5a28847773cb9968a828ae8 -F src/shell.c a73b30067ec15f116d5d0c28880179898fbe3d0b -F src/sqlite.h.in 235300cdca517ce148385d3ab816e7e8cf9e1ff3 +F src/shell.c 9c8389796764f65d4506bcd614ac8061f4160d5c +F src/sqlite.h.in 9cff46ef60540f044c1b665db606aa63ba67048f F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 0873a71099f763cdf24cfabf04a237ad100e20d0 +F src/sqliteInt.h 9a29e5bb82f3abef6b4af91e18d637050fa3c883 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -207,7 +207,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 -F src/test_config.c 3050df9faf023fb52937f7e9998004c2415d4122 +F src/test_config.c 25a4128c2dc9e1dbebafcb7e8c61d45f09f7fbc3 F src/test_demovfs.c 31050680fa6925b4f677cfd4fa965b5f19195e50 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 @@ -239,7 +239,7 @@ F src/test_vfstrace.c 2265c9895f350c8d3c39b079998fbe7481505cc1 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 -F src/trigger.c d5bc8b9ffa2b54569ce635084765c6e41aa9d174 +F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8 F src/update.c 3f3f3bb734a0da1dffd0ed33e504642b35ed3605 F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/util.c cd997077bad039efc0597eb027c929658f93c018 @@ -256,7 +256,7 @@ F src/vtab.c b0abc931f95af94c9ffdf9f747eb191cda953123 F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 71e6808f74b9df913b5cdf242419b0edaf768310 +F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125 @@ -269,9 +269,9 @@ F test/analyze.test c8cb89e8736336f1f0646c8123e6028a14c7b55e F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3 F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045 -F test/analyze5.test adc89b92fc9fee5ca1cb0bc8512f3206ad0fe5aa +F test/analyze5.test 1de8d66b11aae5a1453aa042d62e834a476bac9c F test/analyze6.test c125622a813325bba1b4999040ddc213773c2290 -F test/analyze7.test 9cbca440bebc5142a875ad23947797ff52f7b37c +F test/analyze7.test 5508e7828164ea0b518ed219bed7320a481863d4 F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3 F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6 F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e @@ -280,7 +280,7 @@ F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf F test/attach.test 2bb09073d7d5499127db00f50780766dcea913e1 F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437 F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc -F test/attach4.test d58859e62e0a70f17481eed01bf94995f72fea7f +F test/attach4.test 31f9eb0ca7bdbc393cc4657b877903a226a83d4b F test/attachmalloc.test 1d5b821a676f7bf0b00d87cc106b78966789ba57 F test/auth.test b047105c32da7db70b842fd24056723125ecc2ff F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882 @@ -290,7 +290,7 @@ F test/autoindex1.test 860fc83f4fefb0c68ad062afc3ff43faa1534fc4 F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 -F test/backcompat.test 541314d69ec9db3e03630b7616696ddc5048efb1 +F test/backcompat.test 0f23ff8d516acdf42f3d866a66d85306de2d02bc F test/backup.test 004d3b78bffd990741ab50133ed4347c25c172b1 F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49 F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38 @@ -397,6 +397,7 @@ F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062 F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 +F test/exists.test 81363f6982ea49dfd820a50845466390e60a4a0c F test/expr.test 19e8ac40313e2282a47b586d11c4892040990d3a F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6 F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e @@ -503,7 +504,7 @@ F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7 F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0 F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462 -F test/incrvacuum2.test 9e22a794899c91b7d8c8e12eaacac8df249faafe +F test/incrvacuum2.test ae04573b73ad52179f56e194fff0fbe43b509d23 F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291 F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 @@ -602,7 +603,6 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 -F test/omitunique.test bbb2ec4345d9125d9ee21cd9488d97a163020d5f F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec F test/oserror.test 498d8337e9d15543eb7b004fef8594bf204ff43c F test/pager1.test d8672fd0af5f4f9b99b06283d00f01547809bebe @@ -702,9 +702,9 @@ F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f F test/thread005.test bf5c374ca65dd89fd56c8fe511ccfb46875bda5e -F test/thread1.test 862dd006d189e8b0946935db17399dcac2f8ef91 -F test/thread2.test e08034b83fe9693ade77049732518e5b3d2d700d -F test/thread_common.tcl 2aa6f2fdcd4d6e461169c3e5ca098eebf643b863 +F test/thread1.test df115faa10a4ba1d456e9d4d9ec165016903eae4 +F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 +F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef @@ -871,7 +871,7 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d -F test/wal.test bac92a13276ce9b65d3d5c9ff3411d24c795826c +F test/wal.test 5617ad308bfdb8a8885220d8a261a6096a8d7e57 F test/wal2.test e561a8c6fdd1c2cd1876f3e39757934e7b7361f8 F test/wal3.test 5c396cc22497244d627306f4c1d360167353f8dd F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 @@ -937,7 +937,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 7b7c8d366c51e89aefc6efc9dcffe3f62c7e1d25 -R 35a03a7ffb44f2b52e4ebaca11ffd944 +P 29090b695a95feaba1b74f9894997083a060263a 1c2f0f8477bcf251fe874a2cfae4d7a403cb88ff +R a40e5f171b5b8b5d469c7b8e3eba3790 U drh -Z efe884ab8aaf8c7e1eec316d7a2437f1 +Z 7e220d1108384435c7d9af48b2056273 diff --git a/manifest.uuid b/manifest.uuid index cf1a04a1ea..1c2583a835 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29090b695a95feaba1b74f9894997083a060263a \ No newline at end of file +83705e90a54bad462a5b7fbca70cc129998f871c \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index fd040a7ec2..17c1de83a9 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -548,6 +548,10 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ if( pIndex==0 ) break; pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; + if( memcmp(z, "unordered", 10)==0 ){ + pIndex->bUnordered = 1; + break; + } } return 0; } diff --git a/src/attach.c b/src/attach.c index fe88aa73cd..bda1c87445 100644 --- a/src/attach.c +++ b/src/attach.c @@ -176,7 +176,9 @@ static void attachFunc( case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){ + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + } break; } } diff --git a/src/backup.c b/src/backup.c index c062744c5c..4d7ae31834 100644 --- a/src/backup.c +++ b/src/backup.c @@ -219,6 +219,10 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; +#ifdef SQLITE_HAS_CODEC + int nSrcReserve = sqlite3BtreeGetReserve(p->pSrc); + int nDestReserve = sqlite3BtreeGetReserve(p->pDest); +#endif int rc = SQLITE_OK; i64 iOff; @@ -237,11 +241,22 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ #ifdef SQLITE_HAS_CODEC /* Backup is not possible if the page size of the destination is changing - ** a a codec is in use. + ** and a codec is in use. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ rc = SQLITE_READONLY; } + + /* Backup is not possible if the number of bytes of reserve space differ + ** between source and destination. If there is a difference, try to + ** fix the destination to agree with the source. If that is not possible, + ** then the backup cannot proceed. + */ + if( nSrcReserve!=nDestReserve ){ + u32 newPgsz = nSrcPgsz; + rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); + if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; + } #endif /* This loop runs once for each destination page spanned by the source @@ -607,7 +622,11 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ ** has been modified by a transaction on the source pager. Copy ** the new data into the backup. */ - int rc = backupOnePage(p, iPage, aData); + int rc; + assert( p->pDestDb ); + sqlite3_mutex_enter(p->pDestDb->mutex); + rc = backupOnePage(p, iPage, aData); + sqlite3_mutex_leave(p->pDestDb->mutex); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); if( rc!=SQLITE_OK ){ p->rc = rc; diff --git a/src/btree.c b/src/btree.c index bfdc3d98a8..103a1f3230 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4819,7 +4819,7 @@ static int allocateBtreePage( goto end_allocate_page; } - k = get4byte(&pTrunk->aData[4]); + k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */ if( k==0 && !searchList ){ /* The trunk has no leaves and the list is not being searched. ** So extract the trunk page itself and use it as the newly @@ -4904,10 +4904,6 @@ static int allocateBtreePage( u32 closest; Pgno iPage; unsigned char *aData = pTrunk->aData; - rc = sqlite3PagerWrite(pTrunk->pDbPage); - if( rc ){ - goto end_allocate_page; - } if( nearby>0 ){ u32 i; int dist; @@ -4937,11 +4933,12 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ) goto end_allocate_page; if( closestpDbPage) ); noContent = !btreeGetHasContent(pBt, *pPgno); rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); if( rc==SQLITE_OK ){ @@ -5010,6 +5007,7 @@ end_allocate_page: }else{ *ppPage = 0; } + assert( rc!=SQLITE_OK || sqlite3PagerIswriteable((*ppPage)->pDbPage) ); return rc; } diff --git a/src/build.c b/src/build.c index 8ab07c857c..83a1db8400 100644 --- a/src/build.c +++ b/src/build.c @@ -813,6 +813,9 @@ void sqlite3StartTable( if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); } goto begin_table_error; } @@ -2000,6 +2003,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ if( noErr ) db->suppressErr--; if( pTab==0 ){ + if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -2518,6 +2522,9 @@ Index *sqlite3CreateIndex( if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); } goto exit_create_index; } @@ -2911,6 +2918,8 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + }else{ + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); } pParse->checkSchema = 1; goto exit_drop_index; @@ -3500,6 +3509,21 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ } } +/* +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each +** attached database. Otherwise, invoke it for the database named zDb only. +*/ +void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ + sqlite3 *db = pParse->db; + int i; + for(i=0; inDb; i++){ + Db *pDb = &db->aDb[i]; + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ + sqlite3CodeVerifySchema(pParse, i); + } + } +} + /* ** Generate VDBE code that prepares for doing an operation that ** might change the database. diff --git a/src/ctime.c b/src/ctime.c index a04c567b40..a128f61a69 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -302,9 +302,6 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif -#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT - "OMIT_UNIQUE_ENFORCEMENT", -#endif #ifdef SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif diff --git a/src/insert.c b/src/insert.c index c76e8249b6..621479ce64 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1322,9 +1322,8 @@ void sqlite3GenerateConstraintChecks( */ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ int regIdx; -#ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT int regR; -#endif + if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ @@ -1342,11 +1341,6 @@ void sqlite3GenerateConstraintChecks( sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); -#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); - continue; /* Treat pIdx as if it is not a UNIQUE index */ -#else - /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ){ @@ -1420,7 +1414,6 @@ void sqlite3GenerateConstraintChecks( } sqlite3VdbeJumpHere(v, j3); sqlite3ReleaseTempReg(pParse, regR); -#endif } if( pbMayReplace ){ diff --git a/src/main.c b/src/main.c index ffd4858785..cb2e98947a 100644 --- a/src/main.c +++ b/src/main.c @@ -515,7 +515,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){ va_start(ap, op); switch( op ){ case SQLITE_DBCONFIG_LOOKASIDE: { - void *pBuf = va_arg(ap, void*); /* IMP: R-21112-12275 */ + void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ rc = setupLookaside(db, pBuf, sz, cnt); diff --git a/src/prepare.c b/src/prepare.c index b5edaf5032..fc45b8e6aa 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -34,7 +34,7 @@ static void corruptSchema( "%s - %s", *pData->pzErrMsg, zExtra); } } - pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT; + pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT; } /* diff --git a/src/shell.c b/src/shell.c index 78788a5bb9..4f34ccceb6 100644 --- a/src/shell.c +++ b/src/shell.c @@ -2199,7 +2199,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ /* convert testctrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ - n = strlen(azArg[1]); + n = strlen30(azArg[1]); for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){ if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ if( testctrl<0 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 3daf72cd36..a1743ba2dc 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -727,7 +727,7 @@ struct sqlite3_io_methods { ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this -** opcode as doing so may disrupt the operation of the specilized VFSes +** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1309,7 +1309,7 @@ struct sqlite3_mem_methods { **
SQLITE_CONFIG_SCRATCH
**
^This option specifies a static memory buffer that SQLite can use for ** scratch memory. There are three arguments: A pointer an 8-byte -** aligned memory buffer from which the scrach allocations will be +** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), ** and the maximum number of scratch allocations (N). The sz ** argument must be a multiple of 16. @@ -1461,7 +1461,7 @@ struct sqlite3_mem_methods { **
^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a -** pointer to an memory buffer to use for lookaside memory. +** pointer to a memory buffer to use for lookaside memory. ** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb ** may be NULL in which case SQLite will allocate the ** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the @@ -1493,7 +1493,7 @@ struct sqlite3_mem_methods { **
^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable triggers, -** positive to enable trigers or negative to leave the setting unchanged. +** positive to enable triggers or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in @@ -2105,7 +2105,7 @@ void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** -** ^This routine registers a authorizer callback with a particular +** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], @@ -2751,7 +2751,7 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); ** whether or not it requires a protected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not -** a mutex is held. A internal mutex is held for a protected +** a mutex is held. An internal mutex is held for a protected ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) @@ -3437,7 +3437,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** these routines are the text encoding expected for -** the the second parameter (the name of the function being created) +** the second parameter (the name of the function being created) ** and the presence or absence of a destructor callback for ** the application data pointer. ** @@ -3482,7 +3482,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** callback only; NULL pointers must be passed as the xStep and xFinal ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing -** SQL function or aggregate, pass NULL poiners for all three function +** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, @@ -3916,7 +3916,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n); ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin ** on an even byte address. ** -** ^The fourth argument, pArg, is a application data pointer that is passed +** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** ** ^The fifth argument, xCallback, is a pointer to the collating function. @@ -3932,7 +3932,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n); ** by the eTextRep argument. The collating function must return an ** integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, -** respectively. A collating function must alway return the same answer +** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered ** to the same collation name (using different eTextRep values) then all ** must give an equivalent answer when invoked with equivalent strings. @@ -4344,7 +4344,7 @@ int sqlite3_release_memory(int); **
  • Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. -**
  • An alternative page cache implementation is specifed using +**
  • An alternative page cache implementation is specified using ** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...). **
  • The page cache allocates from its own memory pool supplied ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than @@ -4565,7 +4565,7 @@ typedef struct sqlite3_module sqlite3_module; ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** -** This structure, sometimes called a a "virtual table module", +** This structure, sometimes called a "virtual table module", ** defines the implementation of a [virtual tables]. ** This structure consists mostly of methods for the module. ** @@ -4877,7 +4877,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** This is true if any column of the row is changed, even a column ** other than the one the BLOB handle is open on.)^ ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for -** a expired BLOB handle fail with an return code of [SQLITE_ABORT]. +** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. ** ^(Changes written into a BLOB prior to the BLOB expiring are not ** rolled back by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion.)^ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 33e4aba842..1314048cdf 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1484,6 +1484,7 @@ struct Index { int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ + u8 bUnordered; /* Use this index for == or IN queries only */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ @@ -2776,6 +2777,7 @@ void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); +void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); void sqlite3RollbackTransaction(Parse*); diff --git a/src/test_config.c b/src/test_config.c index 2bf7af5729..0bd1848cef 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -97,6 +97,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "mutex", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_MUTEX_NOOP + Tcl_SetVar2(interp, "sqlite_options", "mutex_noop", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "mutex_noop", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_ALTERTABLE Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY); #else @@ -487,12 +493,6 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double", Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY); #endif -#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT - Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "0", TCL_GLOBAL_ONLY); -#else - Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "1", TCL_GLOBAL_ONLY); -#endif - #ifdef SQLITE_OMIT_UTF16 Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/trigger.c b/src/trigger.c index 8a050eac50..0f3f5bad39 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -171,6 +171,9 @@ void sqlite3BeginTrigger( zName, sqlite3Strlen30(zName)) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); } goto trigger_cleanup; } @@ -499,6 +502,8 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ if( !pTrigger ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); + }else{ + sqlite3CodeVerifyNamedSchema(pParse, zDb); } pParse->checkSchema = 1; goto drop_trigger_cleanup; diff --git a/src/where.c b/src/where.c index ca1fcf6d36..cf30d94d67 100644 --- a/src/where.c +++ b/src/where.c @@ -1342,7 +1342,10 @@ static void exprAnalyze( ** of the loop. Without the TERM_VNULL flag, the not-null check at ** the start of the loop will prevent any results from being returned. */ - if( pExpr->op==TK_NOTNULL && pExpr->pLeft->iColumn>=0 ){ + if( pExpr->op==TK_NOTNULL + && pExpr->pLeft->op==TK_COLUMN + && pExpr->pLeft->iColumn>=0 + ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; int idxNew; @@ -2532,7 +2535,7 @@ range_est_fallback: ** for a UTF conversion required for comparison. The error is stored ** in the pParse structure. */ -int whereEqualScanEst( +static int whereEqualScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ @@ -2589,7 +2592,7 @@ whereEqualScanEst_cancel: ** for a UTF conversion required for comparison. The error is stored ** in the pParse structure. */ -int whereInScanEst( +static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ @@ -2860,7 +2863,7 @@ static void bestBtreeIndex( } /* Determine the value of estBound. */ - if( nEqnColumn ){ + if( nEqnColumn && pProbe->bUnordered==0 ){ int j = pProbe->aiColumn[nEq]; if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); @@ -2892,6 +2895,7 @@ static void bestBtreeIndex( ** will scan rows in a different order, set the bSort variable. */ if( pOrderBy ){ if( (wsFlags & WHERE_COLUMN_IN)==0 + && pProbe->bUnordered==0 && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev) ){ diff --git a/test/analyze5.test b/test/analyze5.test index 224433b7df..a0469da125 100644 --- a/test/analyze5.test +++ b/test/analyze5.test @@ -209,6 +209,8 @@ foreach {testid where index rows} { 502 {x IS NULL} {} 100 503 {x=1} t1x 50 504 {x IS NOT NULL} t1x 25 + 505 {+x IS NOT NULL} {} 500 + 506 {upper(x) IS NOT NULL} {} 500 } { # Verify that the expected index is used with the expected row count diff --git a/test/analyze7.test b/test/analyze7.test index a796ab78af..4892a2233a 100644 --- a/test/analyze7.test +++ b/test/analyze7.test @@ -87,7 +87,7 @@ ifcapable stat2 { # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~102 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~51 rows)}} } else { # If ENABLE_STAT2 is not defined, the expected row count for (c=2) is the # same as that for (c=?). diff --git a/test/attach4.test b/test/attach4.test index fe7392610f..f597f5d035 100644 --- a/test/attach4.test +++ b/test/attach4.test @@ -74,7 +74,11 @@ do_test 1.4 { set L [list] set S "" foreach {name f} $files { - lappend L wal + if {[permutation] == "journaltest"} { + lappend L delete + } else { + lappend L wal + } append S " PRAGMA $name.journal_mode = WAL; UPDATE $name.tbl SET x = '$name'; diff --git a/test/backcompat.test b/test/backcompat.test index 3b11607274..fa643f9b76 100644 --- a/test/backcompat.test +++ b/test/backcompat.test @@ -369,4 +369,77 @@ do_allbackcompat_test { } } +#------------------------------------------------------------------------- +# Test that Rtree tables may be read/written by different versions of +# SQLite. +# +set contents { + CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2); +} +foreach {id x1 x2 y1 y2} { + 1 -47.64 43.87 33.86 34.42 2 -21.51 17.32 2.05 31.04 + 3 -43.67 -38.33 -19.79 3.43 4 32.41 35.16 9.12 19.82 + 5 33.28 34.87 14.78 28.26 6 49.31 116.59 -9.87 75.09 + 7 -14.93 34.51 -17.64 64.09 8 -43.05 23.43 -1.19 69.44 + 9 44.79 133.56 28.09 80.30 10 -2.66 81.47 -41.38 -10.46 + 11 -42.89 -3.54 15.76 71.63 12 -3.50 84.96 -11.64 64.95 + 13 -45.69 26.25 11.14 55.06 14 -44.09 11.23 17.52 44.45 + 15 36.23 133.49 -19.38 53.67 16 -17.89 81.54 14.64 50.61 + 17 -41.97 -24.04 -39.43 28.95 18 -5.85 7.76 -6.38 47.02 + 19 18.82 27.10 42.82 100.09 20 39.17 113.45 26.14 73.47 + 21 22.31 103.17 49.92 106.05 22 -43.06 40.38 -1.75 76.08 + 23 2.43 57.27 -14.19 -3.83 24 -47.57 -4.35 8.93 100.06 + 25 -37.47 49.14 -29.11 8.81 26 -7.86 75.72 49.34 107.42 + 27 1.53 45.49 20.36 49.74 28 -48.48 32.54 28.81 54.45 + 29 2.67 39.77 -4.05 13.67 30 4.11 62.88 -47.44 -5.72 + 31 -21.47 51.75 37.25 116.09 32 45.59 111.37 -6.43 43.64 + 33 35.23 48.29 23.54 113.33 34 16.61 68.35 -14.69 65.97 + 35 13.98 16.60 48.66 102.87 36 19.74 23.84 31.15 77.27 + 37 -27.61 24.43 7.96 94.91 38 -34.77 12.05 -22.60 -6.29 + 39 -25.83 8.71 -13.48 -12.53 40 -17.11 -1.01 18.06 67.89 + 41 14.13 71.72 -3.78 39.25 42 23.75 76.00 -16.30 8.23 + 43 -39.15 28.63 38.12 125.88 44 48.62 86.09 36.49 102.95 + 45 -31.39 -21.98 2.52 89.78 46 5.65 56.04 15.94 89.10 + 47 18.28 95.81 46.46 143.08 48 30.93 102.82 -20.08 37.36 + 49 -20.78 -3.48 -5.58 35.46 50 49.85 90.58 -24.48 46.29 +} { +if {$x1 >= $x2 || $y1 >= $y2} { error "$x1 $x2 $y1 $y2" } + append contents "INSERT INTO t1 VALUES($id, $x1, $x2, $y1, $y2);" +} +set queries { + 1 "SELECT id FROM t1 WHERE x1>10 AND x2<44" + 2 "SELECT id FROM t1 WHERE y1<100" + 3 "SELECT id FROM t1 WHERE y1<100 AND x1>0" + 4 "SELECT id FROM t1 WHERE y1>10 AND x1>0 AND x2<50 AND y2<550" +} +do_allbackcompat_test { + if {[code1 {set ::sqlite_options(fts3)}] + && [code2 {set ::sqlite_options(fts3)}] + } { + + do_test backcompat-4.1 { sql1 $contents } {} + + foreach {n q} $::queries { + do_test backcompat-4.2.$n [list sql1 $q] [sql2 $q] + } + + do_test backcompat-4.3 { sql1 { + INSERT INTO t1 SELECT id+100, x1+10.0, x2+10.0, y1-10.0, y2-10.0 FROM t1; + } } {} + + foreach {n q} $::queries { + do_test backcompat-4.4.$n [list sql1 $q] [sql2 $q] + } + + do_test backcompat-4.5 { sql2 { + INSERT INTO t1 SELECT id+200, x1+20.0, x2+20.0, y1-20.0, y2-20.0 FROM t1; + } } {} + + foreach {n q} $::queries { + do_test backcompat-4.6.$n [list sql1 $q] [sql2 $q] + } + + } +} + finish_test diff --git a/test/exists.test b/test/exists.test new file mode 100644 index 0000000000..db87afc788 --- /dev/null +++ b/test/exists.test @@ -0,0 +1,192 @@ +# 2011 April 9 +# +# 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the various schema modification statements +# that feature "IF EXISTS" or "IF NOT EXISTS" clauses. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl + +set testprefix exists + +# This block of tests is targeted at CREATE XXX IF NOT EXISTS statements. +# +do_multiclient_test tn { + + # TABLE objects. + # + do_test 1.$tn.1.1 { + sql2 { CREATE TABLE t1(x) } + sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) } + sql2 { DROP TABLE t1 } + sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) } + sql2 { SELECT name FROM sqlite_master WHERE type = 'table' } + } {t1} + + do_test 1.$tn.1.2 { + sql2 { CREATE TABLE t2(x) } + sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 } + sql2 { DROP TABLE t2 } + sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'table' } + } {t1 t2} + + + # INDEX objects. + # + do_test 1.$tn.2 { + sql2 { CREATE INDEX i1 ON t1(a) } + sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) } + sql2 { DROP INDEX i1 } + sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) } + sql2 { SELECT name FROM sqlite_master WHERE type = 'index' } + } {i1} + + # VIEW objects. + # + do_test 1.$tn.3 { + sql2 { CREATE VIEW v1 AS SELECT * FROM t1 } + sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 } + sql2 { DROP VIEW v1 } + sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'view' } + } {v1} + + # TRIGGER objects. + # + do_test $tn.4 { + sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END } +sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END } + sql2 { DROP TRIGGER tr1 } +sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END } + sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' } + } {tr1} +} + +# This block of tests is targeted at DROP XXX IF EXISTS statements. +# +do_multiclient_test tn { + + # TABLE objects. + # + do_test 2.$tn.1 { + sql1 { DROP TABLE IF EXISTS t1 } + sql2 { CREATE TABLE t1(x) } + sql1 { DROP TABLE IF EXISTS t1 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'table' } + } {} + + # INDEX objects. + # + do_test 2.$tn.2 { + sql1 { CREATE TABLE t2(x) } + sql1 { DROP INDEX IF EXISTS i2 } + sql2 { CREATE INDEX i2 ON t2(x) } + sql1 { DROP INDEX IF EXISTS i2 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'index' } + } {} + + # VIEW objects. + # + do_test 2.$tn.3 { + sql1 { DROP VIEW IF EXISTS v1 } + sql2 { CREATE VIEW v1 AS SELECT * FROM t2 } + sql1 { DROP VIEW IF EXISTS v1 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'view' } + } {} + + # TRIGGER objects. + # + do_test 2.$tn.4 { + sql1 { DROP TRIGGER IF EXISTS tr1 } + sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END } + sql1 { DROP TRIGGER IF EXISTS tr1 } + sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' } + } {} +} + +# This block of tests is targeted at DROP XXX IF EXISTS statements with +# attached databases. +# +do_multiclient_test tn { + + forcedelete test.db2 + do_test 3.$tn.0 { + sql1 { ATTACH 'test.db2' AS aux } + sql2 { ATTACH 'test.db2' AS aux } + } {} + + # TABLE objects. + # + do_test 3.$tn.1.1 { + sql1 { DROP TABLE IF EXISTS aux.t1 } + sql2 { CREATE TABLE aux.t1(x) } + sql1 { DROP TABLE IF EXISTS aux.t1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' } + } {} + do_test 3.$tn.1.2 { + sql1 { DROP TABLE IF EXISTS t1 } + sql2 { CREATE TABLE aux.t1(x) } + sql1 { DROP TABLE IF EXISTS t1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' } + } {} + + # INDEX objects. + # + do_test 3.$tn.2.1 { + sql1 { CREATE TABLE aux.t2(x) } + sql1 { DROP INDEX IF EXISTS aux.i2 } + sql2 { CREATE INDEX aux.i2 ON t2(x) } + sql1 { DROP INDEX IF EXISTS aux.i2 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' } + } {} + do_test 3.$tn.2.2 { + sql1 { DROP INDEX IF EXISTS i2 } + sql2 { CREATE INDEX aux.i2 ON t2(x) } + sql1 { DROP INDEX IF EXISTS i2 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' } + } {} + + # VIEW objects. + # + do_test 3.$tn.3.1 { + sql1 { DROP VIEW IF EXISTS aux.v1 } + sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 } + sql1 { DROP VIEW IF EXISTS aux.v1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' } + } {} + do_test 3.$tn.3.2 { + sql1 { DROP VIEW IF EXISTS v1 } + sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 } + sql1 { DROP VIEW IF EXISTS v1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' } + } {} + + # TRIGGER objects. + # + do_test 3.$tn.4.1 { + sql1 { DROP TRIGGER IF EXISTS aux.tr1 } + sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END } + sql1 { DROP TRIGGER IF EXISTS aux.tr1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' } + } {} + do_test 3.$tn.4.2 { + sql1 { DROP TRIGGER IF EXISTS tr1 } + sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END } + sql1 { DROP TRIGGER IF EXISTS tr1 } + sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' } + } {} +} + + +finish_test diff --git a/test/incrvacuum2.test b/test/incrvacuum2.test index d8a391b713..902517c949 100644 --- a/test/incrvacuum2.test +++ b/test/incrvacuum2.test @@ -23,6 +23,7 @@ ifcapable {!autovacuum || !pragma} { return } +set testprefix incrvacuum2 # Create a database in incremental vacuum mode that has many # pages on the freelist. @@ -131,6 +132,80 @@ do_test incrvacuum2-3.2 { } } {} -integrity_check incremental2-3.3 +integrity_check incrvacuum2-3.3 + +ifcapable wal { + # At one point, when a specific page was being extracted from the b-tree + # free-list (e.g. during an incremental-vacuum), all trunk pages that + # occurred before the specific page in the free-list trunk were being + # written to the journal or wal file. This is not necessary. Only the + # extracted page and the page that contains the pointer to it need to + # be journalled. + # + # This problem was fixed by [d03d63d77e] (just before 3.7.6 release). + # + # This test case builds a database containing many free pages. Then runs + # "PRAGMA incremental_vacuum(1)" until the db contains zero free pages. + # Each "PRAGMA incremental_vacuum(1)" should modify at most 4 pages. The + # worst case is when a trunk page is removed from the end of the db file. + # In this case pages written are: + # + # 1. The previous trunk page (that contains a pointer to the recycled + # trunk page), and + # 2. The leaf page transformed into a trunk page to replace the recycled + # page, and + # 3. The trunk page that contained a pointer to the leaf page used + # in (2), and + # 4. Page 1. Page 1 is always updated, even in WAL mode, since it contains + # the "number of free-list pages" field. + # + db close + forcedelete test.db + sqlite3 db test.db + + do_execsql_test 4.1 { + PRAGMA page_size = 512; + PRAGMA auto_vacuum = 2; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(400)); + INSERT INTO t1 SELECT * FROM t1; -- 2 + INSERT INTO t1 SELECT * FROM t1; -- 4 + INSERT INTO t1 SELECT * FROM t1; -- 8 + INSERT INTO t1 SELECT * FROM t1; -- 16 + INSERT INTO t1 SELECT * FROM t1; -- 32 + INSERT INTO t1 SELECT * FROM t1; -- 128 + INSERT INTO t1 SELECT * FROM t1; -- 256 + INSERT INTO t1 SELECT * FROM t1; -- 512 + INSERT INTO t1 SELECT * FROM t1; -- 1024 + INSERT INTO t1 SELECT * FROM t1; -- 2048 + INSERT INTO t1 SELECT * FROM t1; -- 4096 + INSERT INTO t1 SELECT * FROM t1; -- 8192 + DELETE FROM t1 WHERE oid>512; + DELETE FROM t1; + } + + do_test 4.2 { + execsql { + PRAGMA journal_mode = WAL; + PRAGMA incremental_vacuum(1); + PRAGMA wal_checkpoint; + } + file size test.db-wal + } {1640} + + do_test 4.3 { + db close + sqlite3 db test.db + set maxsz 0 + while {[file size test.db] > [expr 512*3]} { + execsql { PRAGMA journal_mode = WAL } + execsql { PRAGMA wal_checkpoint } + execsql { PRAGMA incremental_vacuum(1) } + set newsz [file size test.db-wal] + if {$newsz>$maxsz} {set maxsz $newsz} + } + set maxsz + } {2176} +} finish_test diff --git a/test/omitunique.test b/test/omitunique.test deleted file mode 100644 index 83a2a95bdc..0000000000 --- a/test/omitunique.test +++ /dev/null @@ -1,170 +0,0 @@ -# 2011 March 10 -# -# 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. -# -#*********************************************************************** -# This file implements regression tests for SQLite library. The -# focus of this file is testing the SQLITE_OMIT_UNIQUE_ENFORCEMENT -# compiler option. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl - -set uniq_enforced 1 -ifcapable !unique_enforcement { - set uniq_enforced 0 -} - -# table with UNIQUE keyword on column -do_test omitunique-1.1 { - catchsql { CREATE TABLE t1(a TEXT UNIQUE); } -} {0 {}} - -# table with UNIQUE clause on column -do_test omitunique-1.2 { - catchsql { CREATE TABLE t2(a TEXT, UNIQUE(a)); } -} {0 {}} - -# table with UNIQUE index on column -do_test omitunique-1.3 { - catchsql { - CREATE TABLE t3(a TEXT); - CREATE UNIQUE INDEX t3a ON t3(a); - } -} {0 {}} - -# table with regular index on column -do_test omitunique-1.4 { - catchsql { - CREATE TABLE t4(a TEXT); - CREATE INDEX t4a ON t4(a); - } -} {0 {}} - -# table with no index on column -do_test omitunique-1.5 { - catchsql { CREATE TABLE t5(a TEXT); } -} {0 {}} - -# run our tests using several table/index forms -foreach {j tbl uniq cnt qp_est stat_enforce stat_omit } { -1 {t1} 1 1 1 {2 1} {9 9} -2 {t2} 1 1 1 {2 1} {9 9} -3 {t3} 1 1 1 {2 1} {9 9} -4 {t4} 0 9 10 {9 9} {9 9} -5 {t5} 0 9 100000 9 9 -} { - - do_test omitunique-2.0.$j.1 { - catchsql [ subst {INSERT INTO $tbl (a) VALUES('abc'); }] - } {0 {}} - do_test omitunique-2.0.$j.2 { - catchsql [ subst {INSERT INTO $tbl (a) VALUES('123'); }] - } {0 {}} - - # check various INSERT commands - foreach {i cmd err} { - 1 {INSERT} 1 - 2 {INSERT OR IGNORE} 0 - 3 {INSERT OR REPLACE} 0 - 4 {REPLACE} 0 - 5 {INSERT OR FAIL} 1 - 6 {INSERT OR ABORT} 1 - 7 {INSERT OR ROLLBACK} 1 - } { - - ifcapable explain { - set x [execsql [ subst { EXPLAIN $cmd INTO $tbl (a) VALUES('abc'); }]] - ifcapable unique_enforcement { - do_test omitunique-2.1.$j.$i.1 { - regexp { IsUnique } $x - } $uniq - } - ifcapable !unique_enforcement { - do_test omitunique-2.1.$j.$i.1 { - regexp { IsUnique } $x - } {0} - } - } - - if { $uniq_enforced==0 || $uniq==0 || $err==0 } { - set msg {0 {}} - } { - set msg {1 {column a is not unique}} - } - do_test omitunique-2.1.$j.$i.3 { - catchsql [ subst {$cmd INTO $tbl (a) VALUES('abc'); }] - } $msg - - } - # end foreach cmd - - # check UPDATE command - ifcapable explain { - set x [execsql [ subst { EXPLAIN UPDATE $tbl SET a='abc'; }]] - ifcapable unique_enforcement { - do_test omitunique-2.2.$j.1 { - regexp { IsUnique } $x - } $uniq - } - ifcapable !unique_enforcement { - do_test omitunique-2.2.$j.1 { - regexp { IsUnique } $x - } {0} - } - } - if { $uniq_enforced==0 || $uniq==0 } { - set msg {0 {}} - } { - set msg {1 {column a is not unique}} - } - do_test omitunique-2.2.$j.3 { - catchsql [ subst { UPDATE $tbl SET a='abc'; }] - } $msg - - # check record counts - do_test omitunique-2.3.$j { - execsql [ subst { SELECT count(*) FROM $tbl WHERE a='abc'; }] - } $cnt - - # make sure the query planner row estimate not affected because of omit enforcement - ifcapable explain { - do_test omitunique-2.4.$j { - set x [ execsql [ subst { EXPLAIN QUERY PLAN SELECT count(*) FROM $tbl WHERE a='abc'; }]] - set y [ subst {~$qp_est row} ] - regexp $y $x - } {1} - } - - # make sure we omit extra OP_Next opcodes when the UNIQUE constraints - # mean there will only be a single pass through the code - ifcapable explain { - set x [execsql [ subst { EXPLAIN SELECT * FROM $tbl WHERE a='abc'; }]] - do_test omitunique-2.5.$j { - if { [ regexp { Next } $x ] } { expr { 0 } } { expr { 1 } } - } $uniq - } - - # make sure analyze index stats correct - ifcapable analyze { - if { $uniq_enforced==0 } { - set msg [ list $stat_omit ] - } { - set msg [ list $stat_enforce ] - } - do_test omitunique-2.6.$j { - execsql [ subst { ANALYZE $tbl; } ] - execsql [ subst { SELECT stat FROM sqlite_stat1 WHERE tbl='$tbl'; } ] - } $msg - } - -} -# end foreach tbl - -finish_test diff --git a/test/thread1.test b/test/thread1.test index 70bcc22c22..0618f2c66f 100644 --- a/test/thread1.test +++ b/test/thread1.test @@ -19,10 +19,7 @@ source $testdir/tester.tcl # Skip this whole file if the thread testing code is not enabled # -ifcapable !mutex { - finish_test - return -} +if {[run_thread_tests]==0} { finish_test ; return } if {[llength [info command thread_step]]==0 || [sqlite3 -has-codec]} { finish_test return diff --git a/test/thread2.test b/test/thread2.test index 253b3d61ca..dad2bf2c5f 100644 --- a/test/thread2.test +++ b/test/thread2.test @@ -17,11 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !mutex { - finish_test - return -} - +if {[run_thread_tests]==0} { finish_test ; return } # Skip this whole file if the thread testing code is not enabled # diff --git a/test/thread_common.tcl b/test/thread_common.tcl index 9b7a95dd9a..6b17082ad4 100644 --- a/test/thread_common.tcl +++ b/test/thread_common.tcl @@ -89,6 +89,9 @@ proc run_thread_tests {{print_warning 0}} { ifcapable !mutex { set zProblem "SQLite build is not threadsafe" } + ifcapable mutex_noop { + set zProblem "SQLite build uses SQLITE_MUTEX_NOOP" + } if {[info commands sqlthread] eq ""} { set zProblem "SQLite build is not threadsafe" } diff --git a/test/wal.test b/test/wal.test index bc5df883ee..1aa70e0525 100644 --- a/test/wal.test +++ b/test/wal.test @@ -1544,6 +1544,7 @@ ifcapable autovacuum { } [expr 84 * 1024] do_test 24.4 { execsql { + PRAGMA cache_size = 200; PRAGMA incremental_vacuum; PRAGMA wal_checkpoint; }