mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Add part of the btree layer of the shared-cache feature. (CVS 2848)
FossilOrigin-Name: 2afcad990190af97d1ad0010f211a5ca8f0fd745
This commit is contained in:
45
manifest
45
manifest
@ -1,5 +1,5 @@
|
||||
C Add\ssupport\sfor\sCREATE\sTABLE\sIF\sNOT\sEXISTS.\s(CVS\s2847)
|
||||
D 2005-12-29T23:33:54
|
||||
C Add\spart\sof\sthe\sbtree\slayer\sof\sthe\sshared-cache\sfeature.\s(CVS\s2848)
|
||||
D 2005-12-30T16:28:02
|
||||
F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
|
||||
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -34,8 +34,8 @@ F src/alter.c 5905a3372379daa4f860199452b4de5a836e53f3
|
||||
F src/analyze.c ea42005eed52c382fcc7ef66969e7f1858597633
|
||||
F src/attach.c 07822dbd2dcf6de548aba6cb24142aec800fa3b6
|
||||
F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
|
||||
F src/btree.c 2b2651e0f6f9f8c5976b662fbfab7fc8f54f02c9
|
||||
F src/btree.h 8ff86378bb5af0cde282614c16bf0c0190b6d216
|
||||
F src/btree.c ccb912b1f27b6de4ed9f8ab5289a5491c9be5bc8
|
||||
F src/btree.h d6481f9253f0b5fa40b35da4b93a54d0f9c5f9f2
|
||||
F src/build.c bb4c9df2583246728167659d401fd75aa3d9997f
|
||||
F src/callback.c 62066afd516f220575e81b1a1239ab92a2eae252
|
||||
F src/complete.c df1681cef40dec33a286006981845f87b194e7a4
|
||||
@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c a5629e462560d6aa9be7e0dafb6ed1518bb623bb
|
||||
F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
|
||||
F src/main.c ec04b37605752a4294ae98f2b7d78ba62950ba2f
|
||||
F src/main.c c93f80d1fcaf3ed508d62a163819b10a730c2fb7
|
||||
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
|
||||
F src/os.c 7b4a002d9c9421580276db55d2329636a604e8ef
|
||||
F src/os.h e941992043b127fdb1bd114f0b4319ae1c4562a7
|
||||
@ -59,7 +59,7 @@ F src/os_unix.c 6394d2fa3a8bfbceb227579b44b4b343b5b54a8f
|
||||
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
|
||||
F src/os_win.c 9feb97f49b93d451f8ef7c5dd388e05a44647dc6
|
||||
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c 5227ea29acbea4b6a9c6f1dfd3e8493de5fc2a93
|
||||
F src/pager.c 681b4e39d581ead8fd54283176138bec924a4bae
|
||||
F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f
|
||||
F src/parse.y fea607bdc0f4440e001ca277a49f507b5a3fb1e5
|
||||
F src/pragma.c 8883b4d34796efa315bdd0ec1b03f580ef1575b9
|
||||
@ -68,13 +68,13 @@ F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
|
||||
F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
|
||||
F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57
|
||||
F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
|
||||
F src/sqlite.h.in 015e02efa9e8bafa31b6c270116369ddff4e9803
|
||||
F src/sqliteInt.h 3541350fd0617225a61c6ff4af5e6e9d33bc3794
|
||||
F src/sqlite.h.in ba3a29daa6a16e054191ccb384a981964e882a1d
|
||||
F src/sqliteInt.h bb648c5274d67060cb13f0cd0da141aff1205358
|
||||
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
|
||||
F src/tclsqlite.c ce481c0a21a20641cdfe87c9cbbb328cfb3a58b9
|
||||
F src/test1.c 4691cc7235683324791a0be560308ca338de36de
|
||||
F src/tclsqlite.c 230a367c50d84f15e92545f3d468acf192726696
|
||||
F src/test1.c 7374e6576e15a85f11d6032ea8a69d99643695b3
|
||||
F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
|
||||
F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97
|
||||
F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054
|
||||
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
|
||||
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
|
||||
F src/test6.c cb811391ec0b7c75f29e545d4820a9cf19f3637e
|
||||
@ -88,7 +88,7 @@ F src/vdbe.c 8b0d676bcd8d8b12606f684ea2d7934147b40101
|
||||
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
|
||||
F src/vdbeInt.h 9b78ba00cc006bff17e04a54ba3ded9fc7810a10
|
||||
F src/vdbeapi.c b270b680cbc5d20b5a1abfdb08339667985df94e
|
||||
F src/vdbeaux.c 9dc10a70f0f697b9ede43237522e93ef863763e1
|
||||
F src/vdbeaux.c e7c116d4b14868d5fe570e361c6872839b6ab07a
|
||||
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
|
||||
F src/vdbemem.c deba8d6e3727643924b210a8c531a496c2b8d386
|
||||
F src/where.c 0296a20c2e2a39c0cb785efe471fd1958a5259f3
|
||||
@ -96,11 +96,11 @@ F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
|
||||
F test/all.test 55706917a12cd616440d50c35323747b4a9f03c3
|
||||
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
|
||||
F test/alter2.test 60ba0a7057dc71ad630a1cc7c487104346849d50
|
||||
F test/alter3.test d4eecd8dbd008d0e66f1c201fa6dc2edca853c38
|
||||
F test/alter3.test 6e144ea3dcc395afcc28e794bb532be83dc8fdcb
|
||||
F test/altermalloc.test 6e1f404ec021eb2ba6582e3c77b0a35cf206b7af
|
||||
F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0
|
||||
F test/attach.test dae07fa1554b618b9cc4c7bc349b3bc1a532180e
|
||||
F test/attach2.test 4c31484096fd24b7b98487f9c6d04d9f3f156c6c
|
||||
F test/attach2.test 609604393708c3d3227f7c316d15b25d015aa4dd
|
||||
F test/attach3.test 63013383adc4380af69779f34f4af19bd49f7cbe
|
||||
F test/attachmalloc.test cdb26c42850f04698377ccec05f5fa89d987837c
|
||||
F test/auth.test 973ae7274eae32c4453fbbcbd0ec2b80c5b1eeb3
|
||||
@ -184,7 +184,7 @@ F test/malloc.test a5ed721cf7d1b12602ede4f98c11b65ab1582cc0
|
||||
F test/malloc2.test e6e321db96d6c94cb18bf82ad7215070c41e624e
|
||||
F test/malloc3.test 9797d39eca7087a1022bcc0eb0b22215475c9698
|
||||
F test/malloc4.test 2e29d155eb4b4808019ef47eeedfcbe9e09e0f05
|
||||
F test/malloc5.test 8dd58affc441a726d16448a7188ab175bc9e7280
|
||||
F test/malloc5.test cd31d7be49690abc6845baa1f83bfd7b789ee187
|
||||
F test/manydb.test d81debbf5871242e3b5df1d3bb5e14c50431b6f8
|
||||
F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea
|
||||
F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac
|
||||
@ -204,7 +204,7 @@ F test/pagesize.test cbc6a312b6f6c0f02619b189985df2a14164b690
|
||||
F test/pragma.test 95ea907adf68459e1be6f310c9ae94d1d59c465b
|
||||
F test/printf.test 9e10c74e16bf889f8495ddb3d6f5f891e75ff1b7
|
||||
F test/progress.test 16496001da445e6534afb94562c286708316d82f x
|
||||
F test/quick.test 4be1733beae790f4a61fb7c7827b396c95375d7e
|
||||
F test/quick.test 24ef81e4e9c1784e7f081e7ce4576c15659b97a7
|
||||
F test/quote.test 5891f2338980916cf7415484b4ce785294044adb
|
||||
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
||||
F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
|
||||
@ -218,6 +218,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
|
||||
F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b
|
||||
F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4
|
||||
F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
|
||||
F test/shared.test 1f68f8aecf5064d1da2fb2f316bbb6e70054f08e
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
F test/subquery.test e6de53332c0301b3cfa34edc3f3cd5fa1e859efd
|
||||
F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
|
||||
@ -226,7 +227,7 @@ F test/table.test 149b76a28bbe2a1cd799232e4ae5133881e1902a
|
||||
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
|
||||
F test/tclsqlite.test 19578d32a7692311918caf0ae3521d19525bcb62
|
||||
F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
|
||||
F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875
|
||||
F test/tester.tcl fae9e5b9ca4cfda10a6a52e95f7ebf731e52f3e5
|
||||
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
|
||||
@ -242,7 +243,7 @@ F test/tkt1536.test 83ff7a7b6e248016f8d682d4f7a4ae114070d466
|
||||
F test/tkt1537.test 8e6c8399b5be8abeaac18ca17133990806b175fa
|
||||
F test/tkt1567.test 18023cc3626a365f0118e17b66decedec93b1a6f
|
||||
F test/trace.test 9fd28695c463b90c2d32c387a432e01eb26e8ccf
|
||||
F test/trans.test 10506dc30305cfb8c4098359f7f6f64786f69c5e
|
||||
F test/trans.test abd2f74c5685b156d79438e6e812db5bf984eea4
|
||||
F test/trigger1.test 152aed5a1fa90709fe171f2ca501a6b7f7901479
|
||||
F test/trigger2.test dea71f4b05e22896e72527278bc8ef71b7475bf2
|
||||
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
|
||||
@ -331,7 +332,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||
P a88580bce045ee1c11cc6fd986ee7bab043ded4f
|
||||
R 2caf522c84042dde1b412f517fefbe54
|
||||
U drh
|
||||
Z a798ff6c2214d388933326d22672d220
|
||||
P 0bd9e35fd22946640f4fb1c1874922ae096916f7
|
||||
R 4baca77991845360aad68bb03e406c8e
|
||||
U danielk1977
|
||||
Z 2dfbc30edccb7b747e04832859ba5105
|
||||
|
@ -1 +1 @@
|
||||
0bd9e35fd22946640f4fb1c1874922ae096916f7
|
||||
2afcad990190af97d1ad0010f211a5ca8f0fd745
|
679
src/btree.c
679
src/btree.c
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.65 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
** @(#) $Id: btree.h,v 1.66 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@ -36,10 +36,12 @@
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
typedef struct BtShared BtShared;
|
||||
|
||||
|
||||
int sqlite3BtreeOpen(
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
sqlite3 *db, /* Associated database connection */
|
||||
Btree **, /* Return open Btree* here */
|
||||
int flags /* Flags */
|
||||
);
|
||||
|
13
src/main.c
13
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.312 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.313 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -26,15 +26,6 @@
|
||||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** Linked list of all open database handles. This is used by the
|
||||
** sqlite3_global_recover() function. Entries are added to the list
|
||||
** by openDatabase() and removed by sqlite3_close().
|
||||
*/
|
||||
static sqlite3 *pDbList = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The version of the library
|
||||
*/
|
||||
@ -648,7 +639,7 @@ int sqlite3BtreeFactory(
|
||||
#endif /* SQLITE_OMIT_MEMORYDB */
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
|
||||
rc = sqlite3BtreeOpen(zFilename, db, ppBtree, btree_flags);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
|
||||
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
|
||||
|
194
src/pager.c
194
src/pager.c
@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.228 2005/12/20 09:19:37 danielk1977 Exp $
|
||||
** @(#) $Id: pager.c,v 1.229 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
@ -301,12 +301,36 @@ struct Pager {
|
||||
|
||||
/*
|
||||
** These are bits that can be set in Pager.errMask.
|
||||
**
|
||||
** TODO: Maybe we just want a variable - Pager.errCode. Can we really
|
||||
** have two simultaneous error conditions?
|
||||
**
|
||||
** Recovering from an SQLITE_FULL, SQLITE_LOCK, SQLITE_CORRUPT or
|
||||
** SQLITE_IOERR error is not a simple matter, particularly if the pager
|
||||
** cache is shared between multiple connections.
|
||||
**
|
||||
** SQLITE_FULL (PAGER_ERR_FULL):
|
||||
** Cleared when the transaction is rolled back.
|
||||
**
|
||||
** SQLITE_CORRUPT (PAGER_ERR_CORRUPT):
|
||||
** Cannot be cleared. The upper layer must close the current pager
|
||||
** and open a new one on the same file to continue.
|
||||
**
|
||||
** SQLITE_PROTOCOL (PAGER_ERR_LOCK):
|
||||
** This error only occurs if an internal error occurs or another process
|
||||
** is not following the sqlite locking protocol (i.e. someone is
|
||||
** manipulating the database file using something other than sqlite).
|
||||
** This is handled in the same way as database corruption - the error
|
||||
** cannot be cleared except by closing the current pager and opening
|
||||
** a brand new one on the same file.
|
||||
**
|
||||
** SQLITE_IOERR (PAGER_ERR_DISK):
|
||||
** Cleared when the transaction is rolled back.
|
||||
*/
|
||||
#define PAGER_ERR_FULL 0x01 /* a write() failed */
|
||||
#define PAGER_ERR_MEM 0x02 /* malloc() failed */
|
||||
#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */
|
||||
#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */
|
||||
#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */
|
||||
#define PAGER_ERR_LOCK 0x02 /* error in the locking protocol */
|
||||
#define PAGER_ERR_CORRUPT 0x04 /* database or journal corruption */
|
||||
#define PAGER_ERR_DISK 0x08 /* general disk I/O error - bad hard drive? */
|
||||
|
||||
/*
|
||||
** Journal files begin with the following magic string. The data
|
||||
@ -465,11 +489,32 @@ static int pager_errcode(Pager *pPager){
|
||||
if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL;
|
||||
if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR;
|
||||
if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL;
|
||||
if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM;
|
||||
if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function should be called when an error occurs within the pager
|
||||
** code to set the appropriate bits in Pager.errMask.
|
||||
*/
|
||||
static int pager_error(Pager *pPager, int rc){
|
||||
switch( rc ){
|
||||
case SQLITE_PROTOCOL:
|
||||
pPager->errMask |= PAGER_ERR_LOCK;
|
||||
break;
|
||||
case SQLITE_IOERR:
|
||||
pPager->errMask |= PAGER_ERR_DISK;
|
||||
break;
|
||||
case SQLITE_FULL:
|
||||
pPager->errMask |= PAGER_ERR_FULL;
|
||||
break;
|
||||
case SQLITE_CORRUPT:
|
||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
/*
|
||||
** Return a 32-bit hash of the page data for pPage.
|
||||
@ -739,6 +784,9 @@ static int readJournalHdr(
|
||||
**
|
||||
** The master journal page checksum is the sum of the bytes in the master
|
||||
** journal name.
|
||||
**
|
||||
** If zMaster is a NULL pointer (occurs for a single database transaction),
|
||||
** this call is a no-op.
|
||||
*/
|
||||
static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
int rc;
|
||||
@ -861,29 +909,6 @@ static void pager_reset(Pager *pPager){
|
||||
assert( pPager->journalOpen==0 );
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to reset the pager after a malloc() failure. This
|
||||
** doesn't work with in-memory databases. If a malloc() fails when an
|
||||
** in-memory database is in use it is not possible to recover.
|
||||
**
|
||||
** If a transaction or statement transaction is active, it is rolled back.
|
||||
**
|
||||
** It is an error to call this function if any pages are in use.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
int sqlite3pager_reset(Pager *pPager){
|
||||
if( pPager ){
|
||||
if( pPager->nRef || MEMDB ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pPager->errMask &= ~(PAGER_ERR_MEM);
|
||||
pager_reset(pPager);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** When this routine is called, the pager has the journal file open and
|
||||
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
|
||||
@ -1586,7 +1611,7 @@ int sqlite3pager_open(
|
||||
int nExtra, /* Extra bytes append to each in-memory page */
|
||||
int flags /* flags controlling this file */
|
||||
){
|
||||
Pager *pPager;
|
||||
Pager *pPager = 0;
|
||||
char *zFullPathname = 0;
|
||||
int nameLen;
|
||||
OsFile *fd;
|
||||
@ -1600,17 +1625,24 @@ int sqlite3pager_open(
|
||||
char zTemp[SQLITE_TEMPNAME_SIZE];
|
||||
SqliteTsd *pTsd = sqlite3Tsd();
|
||||
|
||||
/* If malloc() has already failed return SQLITE_NOMEM. Before even
|
||||
** testing for this, set *ppPager to NULL so the caller knows the pager
|
||||
** structure was never allocated.
|
||||
*/
|
||||
*ppPager = 0;
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
if( sqlite3Tsd()->mallocFailed ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
|
||||
/* Open the pager file and set zFullPathname to point at malloc()ed
|
||||
** memory containing the complete filename (i.e. including the directory).
|
||||
*/
|
||||
if( zFilename && zFilename[0] ){
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
if( strcmp(zFilename,":memory:")==0 ){
|
||||
memDb = 1;
|
||||
zFullPathname = sqliteStrDup("");
|
||||
rc = SQLITE_OK;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
@ -1627,28 +1659,35 @@ int sqlite3pager_open(
|
||||
tempFile = 1;
|
||||
}
|
||||
}
|
||||
if( !zFullPathname ){
|
||||
sqlite3OsClose(&fd);
|
||||
return SQLITE_NOMEM;
|
||||
|
||||
/* Allocate the Pager structure. As part of the same allocation, allocate
|
||||
** space for the full paths of the file, directory and journal
|
||||
** (Pager.zFilename, Pager.zDirectory and Pager.zJournal).
|
||||
*/
|
||||
if( zFullPathname ){
|
||||
nameLen = strlen(zFullPathname);
|
||||
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
||||
/* If an error occured in either of the blocks above, free the memory
|
||||
** pointed to by zFullPathname, free the Pager structure and close the
|
||||
** file. Since the pager is not allocated there is no need to set
|
||||
** any Pager.errMask variables.
|
||||
*/
|
||||
if( !pPager || !zFullPathname || rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&fd);
|
||||
sqliteFree(zFullPathname);
|
||||
return rc;
|
||||
}
|
||||
nameLen = strlen(zFullPathname);
|
||||
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
|
||||
if( pPager==0 ){
|
||||
sqlite3OsClose(&fd);
|
||||
sqliteFree(zFullPathname);
|
||||
return SQLITE_NOMEM;
|
||||
sqliteFree(pPager);
|
||||
return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc);
|
||||
}
|
||||
|
||||
TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
|
||||
pPager->zFilename = (char*)&pPager[1];
|
||||
pPager->zDirectory = &pPager->zFilename[nameLen+1];
|
||||
pPager->zJournal = &pPager->zDirectory[nameLen+1];
|
||||
strcpy(pPager->zFilename, zFullPathname);
|
||||
strcpy(pPager->zDirectory, zFullPathname);
|
||||
|
||||
for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
|
||||
if( i>0 ) pPager->zDirectory[i-1] = 0;
|
||||
strcpy(pPager->zJournal, zFullPathname);
|
||||
@ -1762,7 +1801,13 @@ void enable_simulated_io_errors(void){
|
||||
|
||||
/*
|
||||
** Read the first N bytes from the beginning of the file into memory
|
||||
** that pDest points to. No error checking is done.
|
||||
** that pDest points to.
|
||||
**
|
||||
** No error checking is done. The rational for this is that this function
|
||||
** may be called even if the file does not exist or contain a header. In
|
||||
** these cases sqlite3OsRead() will return an error, to which the correct
|
||||
** response is to zero the memory at pDest and continue. A real IO error
|
||||
** will presumably recur and be picked up later (Todo: Think about this).
|
||||
*/
|
||||
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
|
||||
memset(pDest, 0, N);
|
||||
@ -1973,6 +2018,11 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
|
||||
** and their memory is freed. Any attempt to use a page associated
|
||||
** with this page cache after this function returns will likely
|
||||
** result in a coredump.
|
||||
**
|
||||
** This function always succeeds. If a transaction is active an attempt
|
||||
** is made to roll it back. If an error occurs during the rollback
|
||||
** a hot journal may be left in the filesystem but no error is returned
|
||||
** to the caller.
|
||||
*/
|
||||
int sqlite3pager_close(Pager *pPager){
|
||||
PgHdr *pPg, *pNext;
|
||||
@ -2037,6 +2087,9 @@ int sqlite3pager_close(Pager *pPager){
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT
|
||||
/* Remove the pager from the linked list of pagers starting at
|
||||
** SqliteTsd.pPager.
|
||||
*/
|
||||
if( pPager==pTsd->pPager ){
|
||||
pTsd->pPager = pPager->pNext;
|
||||
}else{
|
||||
@ -2310,7 +2363,10 @@ static int hasHotJournal(Pager *pPager){
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to find a page in the cache that can be recycled.
|
||||
** Try to find a page in the cache that can be recycled.
|
||||
**
|
||||
** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It
|
||||
** does not set the pPager->errMask variable.
|
||||
*/
|
||||
static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
|
||||
PgHdr *pPg;
|
||||
@ -2329,8 +2385,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
|
||||
if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){
|
||||
int rc = syncJournal(pPager);
|
||||
if( rc!=0 ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
return SQLITE_IOERR;
|
||||
return rc;
|
||||
}
|
||||
if( pPager->fullSync ){
|
||||
/* If in full-sync mode, write a new journal header into the
|
||||
@ -2343,8 +2398,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
|
||||
assert( pPager->journalOff > 0 );
|
||||
rc = writeJournalHdr(pPager);
|
||||
if( rc!=0 ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
return SQLITE_IOERR;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
pPg = pPager->pFirst;
|
||||
@ -2363,8 +2417,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
|
||||
pPg->pDirty = 0;
|
||||
rc = pager_write_pagelist( pPg );
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
return SQLITE_IOERR;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( pPg->dirty==0 );
|
||||
@ -2425,9 +2478,9 @@ int sqlite3pager_release_memory(int nReq){
|
||||
** loop).
|
||||
*/
|
||||
while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) {
|
||||
/* We've found a page to free. At this point the page has been
|
||||
/* We've found a page to free. At this point the page has been
|
||||
** removed from the page hash-table, free-list and synced-list
|
||||
** (pFirstSynced). It is still in the all pages (pAll) list.
|
||||
** (pFirstSynced). It is still in the all pages (pAll) list.
|
||||
** Remove it from this list before freeing.
|
||||
**
|
||||
** Todo: Check the Pager.pStmt list to make sure this is Ok. It
|
||||
@ -2435,6 +2488,7 @@ int sqlite3pager_release_memory(int nReq){
|
||||
*/
|
||||
PgHdr *pTmp;
|
||||
assert( pPg );
|
||||
page_remove_from_stmt_list(pPg);
|
||||
if( pPg==p->pAll ){
|
||||
p->pAll = pPg->pNextAll;
|
||||
}else{
|
||||
@ -2446,23 +2500,22 @@ int sqlite3pager_release_memory(int nReq){
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* Assert that fsync() was enabled and the error was an io-error
|
||||
** or a full database. Nothing else should be able to wrong in
|
||||
** pager_recycle.
|
||||
/* An error occured whilst writing to the database file or
|
||||
** journal in pager_recycle(). The error is not returned to the
|
||||
** caller of this function. Instead, set the Pager.errMask variable.
|
||||
** The error will be returned to the user (or users, in the case
|
||||
** of a shared pager cache) of the pager for which the error occured.
|
||||
*/
|
||||
assert( i && (rc==SQLITE_IOERR || rc==SQLITE_FULL) );
|
||||
|
||||
/* TODO: Figure out what to do about this. The IO-error
|
||||
** belongs to the connection that is executing a transaction.
|
||||
*/
|
||||
assert(0);
|
||||
assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
|
||||
assert( p->state>=PAGER_RESERVED );
|
||||
pager_error(p, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nReleased;
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_OMIT_MEMORY_MANAGEMENT */
|
||||
|
||||
/*
|
||||
** Acquire a page.
|
||||
@ -2513,7 +2566,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
if( !pPager->noReadlock ){
|
||||
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2538,7 +2591,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsUnlock(pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
return rc;
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
pPager->state = PAGER_EXCLUSIVE;
|
||||
|
||||
@ -2567,7 +2620,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
*/
|
||||
rc = pager_playback(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
}
|
||||
pPg = 0;
|
||||
@ -2588,7 +2641,6 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
+ sizeof(u32) + pPager->nExtra
|
||||
+ MEMDB*sizeof(PgHistory) );
|
||||
if( pPg==0 ){
|
||||
// pPager->errMask |= PAGER_ERR_MEM;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(pPg, 0, sizeof(*pPg));
|
||||
@ -2606,7 +2658,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}else{
|
||||
rc = pager_recycle(pPager, 1, &pPg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
assert(pPg) ;
|
||||
}
|
||||
@ -2662,7 +2714,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
if( sqlite3OsFileSize(pPager->fd,&fileSize)!=SQLITE_OK
|
||||
|| fileSize>=pgno*pPager->pageSize ){
|
||||
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
|
||||
return rc;
|
||||
return pager_error(pPager, rc);
|
||||
}else{
|
||||
clear_simulated_io_error();
|
||||
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.151 2005/12/20 09:19:37 danielk1977 Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.152 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
@ -1338,6 +1338,14 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
|
||||
int sqlite3_release_memory(int);
|
||||
|
||||
/*
|
||||
** This function is only available if the library is compiled without
|
||||
** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or
|
||||
** disable (if the argument is true or false, respectively) the
|
||||
** "shared pager" feature.
|
||||
*/
|
||||
int sqlite3_enable_shared_cache(int);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.445 2005/12/29 23:33:54 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.446 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@ -289,6 +289,11 @@ struct SqliteTsd {
|
||||
Pager *pPager; /* Linked list of all pagers in this thread */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
u8 useSharedData; /* True if shared pagers and schemas are enabled */
|
||||
BtShared *pBtree;
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
i64 nMaxAlloc; /* High water mark of SqliteTsd.nAlloc */
|
||||
int mallocAllowed; /* assert() in sqlite3Malloc() if not set */
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.141 2005/12/19 14:18:11 danielk1977 Exp $
|
||||
** $Id: tclsqlite.c,v 1.142 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@ -1754,11 +1754,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** $db soft_heap_limit N
|
||||
**
|
||||
** Set the soft-heap-limit for this thread. Note that the limit is
|
||||
** per-thread, not per-database. An empty string is returned.
|
||||
** per-thread, not per-database. The previous limit is returned.
|
||||
*/
|
||||
case DB_SOFT_HEAP_LIMIT: {
|
||||
#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT
|
||||
int n;
|
||||
int ret;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "BYTES");
|
||||
return TCL_ERROR;
|
||||
@ -1766,8 +1767,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &n) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
ret = sqlite3Tsd()->nSoftHeapLimit;
|
||||
sqlite3_soft_heap_limit(n);
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
43
src/test1.c
43
src/test1.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.177 2005/12/20 09:19:37 danielk1977 Exp $
|
||||
** $Id: test1.c,v 1.178 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -890,6 +890,38 @@ static int sqlite_malloc_outstanding(
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_enable_shared_cache BOOLEAN
|
||||
**
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
static int test_enable_shared_cache(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int rc;
|
||||
int enable;
|
||||
SqliteTsd *pTsd = sqlite3Tsd();
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(pTsd->useSharedData));
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_enable_shared_cache(enable);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Usage: sqlite_abort
|
||||
**
|
||||
@ -3074,6 +3106,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_SUBQUERY
|
||||
Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@ -3250,6 +3288,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#endif
|
||||
{ "sqlite3_test_errstr", test_errstr, 0 },
|
||||
{ "tcl_variable_type", tcl_variable_type, 0 },
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
{ "sqlite3_enable_shared_cache", test_enable_shared_cache, 0},
|
||||
#endif
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test3.c,v 1.63 2005/12/09 20:21:59 drh Exp $
|
||||
** $Id: test3.c,v 1.64 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -69,7 +69,7 @@ static int btree_open(
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
|
||||
rc = sqlite3BtreeOpen(argv[1], &pBt, flags);
|
||||
rc = sqlite3BtreeOpen(argv[1], 0, &pBt, flags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -926,7 +926,6 @@ static int vdbeCommit(sqlite3 *db){
|
||||
|
||||
/* If there are any write-transactions at all, invoke the commit hook */
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
int rc;
|
||||
sqlite3SafetyOff(db);
|
||||
rc = db->xCommitCallback(db->pCommitArg);
|
||||
sqlite3SafetyOn(db);
|
||||
|
@ -13,7 +13,7 @@
|
||||
# file format change that may be used in the future to implement
|
||||
# "ALTER TABLE ... ADD COLUMN".
|
||||
#
|
||||
# $Id: alter3.test,v 1.6 2005/03/29 03:11:00 danielk1977 Exp $
|
||||
# $Id: alter3.test,v 1.7 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -360,6 +360,7 @@ do_test alter3-8.1 {
|
||||
CREATE TABLE t4(c1);
|
||||
}
|
||||
} {}
|
||||
set ::sql ""
|
||||
do_test alter3-8.2 {
|
||||
set cols c1
|
||||
for {set i 2} {$i < 100} {incr i} {
|
||||
|
@ -12,13 +12,12 @@
|
||||
# focus of this script is testing the ATTACH and DETACH commands
|
||||
# and related functionality.
|
||||
#
|
||||
# $Id: attach2.test,v 1.33 2005/12/06 17:19:12 danielk1977 Exp $
|
||||
# $Id: attach2.test,v 1.34 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
# Ticket #354
|
||||
#
|
||||
# Databases test.db and test2.db contain identical schemas. Make
|
||||
@ -157,7 +156,7 @@ proc lock_status {testnum db expected_result} {
|
||||
# If the database was compiled with OMIT_TEMPDB set, then
|
||||
# the lock_status list will not contain an entry for the temp
|
||||
# db. But the test code doesn't know this, so it's easiest
|
||||
# to filter it out here.
|
||||
# to filter it out of the $expected_result list here.
|
||||
ifcapable !tempdb {
|
||||
set expected_result [concat \
|
||||
[lrange $expected_result 0 1] \
|
||||
|
@ -9,7 +9,10 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# $Id: malloc5.test,v 1.2 2005/12/20 09:19:38 danielk1977 Exp $
|
||||
# This file contains test cases focused on the two memory-management APIs,
|
||||
# sqlite3_soft_heap_limit() and sqlite3_release_memory().
|
||||
#
|
||||
# $Id: malloc5.test,v 1.3 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# NOTES ON EXPECTED BEHAVIOUR
|
||||
@ -19,6 +22,13 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Only run these tests if memory debugging is turned on.
|
||||
if {[info command sqlite_malloc_stat]==""} {
|
||||
puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_test malloc5-1.1 {
|
||||
# Simplest possible test. Call [db release_memory] when there is exactly
|
||||
# one unused page in a single pager cache. This test case set's the
|
||||
@ -159,6 +169,11 @@ sqlite_malloc_outstanding -clearmaxbytes
|
||||
# and tests to see that this limit is not exceeded at any point during
|
||||
# transaction execution.
|
||||
#
|
||||
# Before executing malloc5-4.* we save the value of the current soft heap
|
||||
# limit in variable ::soft_limit. The original value is restored after
|
||||
# running the tests.
|
||||
#
|
||||
set ::soft_limit [db soft_heap_limit -1]
|
||||
do_test malloc5-4.1 {
|
||||
execsql {BEGIN;}
|
||||
execsql {DELETE FROM abc;}
|
||||
@ -188,8 +203,8 @@ do_test malloc5-4.3 {
|
||||
}
|
||||
} [list 20000 [expr int(20000.0 * 4999.5)] [expr int(20000.0 * 4999.5)]]
|
||||
|
||||
# Unset the soft-heap-limit value.
|
||||
db soft_heap_limit -1
|
||||
# Restore the soft heap limit.
|
||||
db soft_heap_limit $::soft_limit
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -6,7 +6,25 @@
|
||||
#***********************************************************************
|
||||
# This file runs all tests.
|
||||
#
|
||||
# $Id: quick.test,v 1.38 2005/12/15 10:11:32 danielk1977 Exp $
|
||||
# $Id: quick.test,v 1.39 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
|
||||
proc lshift {lvar} {
|
||||
upvar $lvar l
|
||||
set ret [lindex $l 0]
|
||||
set l [lrange $l 1 end]
|
||||
return $ret
|
||||
}
|
||||
while {[set arg [lshift argv]] != ""} {
|
||||
switch -- $arg {
|
||||
-sharedpagercache {
|
||||
sqlite3_enable_shared_cache 1
|
||||
}
|
||||
default {
|
||||
set argv [linsert $argv 0 $arg]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
205
test/shared.test
Normal file
205
test/shared.test
Normal file
@ -0,0 +1,205 @@
|
||||
# 2005 December 30
|
||||
#
|
||||
# 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 SELECT statement.
|
||||
#
|
||||
# $Id: shared.test,v 1.1 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
db close
|
||||
|
||||
ifcapable !shared_cache {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Test organization:
|
||||
#
|
||||
# shared-1.*: Simple test to verify basic sanity of table level locking when
|
||||
# two connections share a pager cache.
|
||||
# shared-2.*: Test that a read transaction can co-exist with a
|
||||
# write-transaction, including a simple test to ensure the
|
||||
# external locking protocol is still working.
|
||||
#
|
||||
|
||||
do_test shared-1.1 {
|
||||
# Open a second database on the file test.db. It should use the same pager
|
||||
# cache and schema as the original connection. Verify that only 1 file is
|
||||
# opened.
|
||||
sqlite3 db2 test.db
|
||||
sqlite3 db test.db
|
||||
set ::sqlite_open_file_count
|
||||
} {1}
|
||||
do_test shared-1.2 {
|
||||
# Add a table and a single row of data via the first connection.
|
||||
# Ensure that the second connection can see them.
|
||||
execsql {
|
||||
CREATE TABLE abc(a, b, c);
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
} db
|
||||
execsql {
|
||||
SELECT * FROM abc;
|
||||
} db2
|
||||
} {1 2 3}
|
||||
do_test shared-1.3 {
|
||||
# Have the first connection begin a transaction and obtain a read-lock
|
||||
# on table abc. This should not prevent the second connection from
|
||||
# querying abc.
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
}
|
||||
execsql {
|
||||
SELECT * FROM abc;
|
||||
} db2
|
||||
} {1 2 3}
|
||||
do_test shared-1.4 {
|
||||
# Try to insert a row into abc via connection 2. This should fail because
|
||||
# of the read-lock connection 1 is holding on table abc (obtained in the
|
||||
# previous test case).
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES(4, 5, 6);
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
do_test shared-1.5 {
|
||||
# Using connection 2 (the one without the open transaction), create a
|
||||
# new table and add a row to it. This is permitted as the transaction
|
||||
# started by connection 1 is currently a read transaction.
|
||||
execsql {
|
||||
CREATE TABLE def(d, e, f);
|
||||
INSERT INTO def VALUES('I', 'II', 'III');
|
||||
} db2
|
||||
} {}
|
||||
do_test shared-1.6 {
|
||||
# Upgrade connection 1's transaction to a write transaction. Insert
|
||||
# a row into table def - the table just created by connection 2.
|
||||
#
|
||||
# Connection 1 is able to see table def, even though it was created
|
||||
# "after" the connection 1 transaction was started. This is because no
|
||||
# lock was established on the sqlite_master table.
|
||||
|
||||
# Todo: Remove this. Because the implementation does not include
|
||||
# shared-schemas yet, we need to run some query (that will fail at
|
||||
# OP_VerifyCookie) so that connection 1 picks up the schema change
|
||||
# made via connection 2. Otherwise the sqlite3_prepare("INSERT INTO def...")
|
||||
# below will fail.
|
||||
execsql {
|
||||
SELECT * FROM sqlite_master;
|
||||
}
|
||||
|
||||
execsql {
|
||||
INSERT INTO def VALUES('IV', 'V', 'VI');
|
||||
}
|
||||
} {}
|
||||
do_test shared-1.7 {
|
||||
# Read from the sqlite_master table with connection 1 (inside the
|
||||
# transaction). Then test that we can no longer create a table
|
||||
# with connection 2. This is because of the read-lock on sqlite_master.
|
||||
execsql {
|
||||
SELECT * FROM sqlite_master;
|
||||
}
|
||||
catchsql {
|
||||
CREATE TABLE ghi(g, h, i);
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
do_test shared-1.8 {
|
||||
# Check that connection 2 can read the sqlite_master table. Then
|
||||
# create a table using connection 1 (this should write-lock the
|
||||
# sqlite_master table). Then try to read sqlite_master again using
|
||||
# connection 2 and verify that the write-lock prevents this.
|
||||
execsql {
|
||||
SELECT * FROM sqlite_master;
|
||||
} db2
|
||||
execsql {
|
||||
CREATE TABLE ghi(g, h, i);
|
||||
}
|
||||
catchsql {
|
||||
SELECT * FROM sqlite_master;
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
do_test shared-1.9 {
|
||||
# Commit the connection 1 transaction.
|
||||
execsql {
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test shared-2.1 {
|
||||
# Open connection db3 to the database. Use a different path to the same
|
||||
# file so that db3 does *not* share the same pager cache as db and db2
|
||||
# (there should be two open file handles).
|
||||
sqlite3 db3 ./test.db
|
||||
set ::sqlite_open_file_count
|
||||
} {2}
|
||||
do_test shared-2.2 {
|
||||
# Start read transactions on db and db2 (the shared pager cache). Ensure
|
||||
# db3 cannot write to the database.
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
}
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
} db2
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
} db2
|
||||
} {1 {database is locked}}
|
||||
do_test shared-2.3 {
|
||||
# Turn db's transaction into a write-transaction. db3 should still be
|
||||
# able to read from table def (but will not see the new row). Connection
|
||||
# db2 should not be able to read def (because of the write-lock).
|
||||
|
||||
# Todo: The failed "INSERT INTO abc ..." statement in the above test
|
||||
# has started a write-transaction on db2 (should this be so?). This
|
||||
# would prevent connection db from starting a write-transaction. So roll the
|
||||
# db2 transaction back and replace it with a new read transaction.
|
||||
execsql {
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
} db2
|
||||
|
||||
execsql {
|
||||
INSERT INTO def VALUES('VII', 'VIII', 'IX');
|
||||
}
|
||||
concat [
|
||||
catchsql { SELECT * FROM def; } db3
|
||||
] [
|
||||
catchsql { SELECT * FROM def; } db2
|
||||
]
|
||||
} {0 {I II III IV V VI} 1 {database is locked}}
|
||||
do_test shared-2.4 {
|
||||
# Commit the open transaction on db. db2 still holds a read-transaction.
|
||||
# This should prevent db3 from writing to the database, but not from
|
||||
# reading.
|
||||
execsql {
|
||||
COMMIT;
|
||||
}
|
||||
concat [
|
||||
catchsql { SELECT * FROM def; } db3
|
||||
] [
|
||||
catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3
|
||||
]
|
||||
} {0 {I II III IV V VI VII VIII IX} 1 {database is locked}}
|
||||
|
||||
|
||||
catch {db close}
|
||||
catch {db2 close}
|
||||
catch {db3 close}
|
||||
|
||||
finish_test
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements some common TCL routines used for regression
|
||||
# testing the SQLite library
|
||||
#
|
||||
# $Id: tester.tcl,v 1.54 2005/12/09 14:39:05 danielk1977 Exp $
|
||||
# $Id: tester.tcl,v 1.55 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
|
||||
# Make sure tclsqlite3 was compiled correctly. Abort now with an
|
||||
# error message if not.
|
||||
@ -440,6 +440,7 @@ proc copy_file {from to} {
|
||||
#
|
||||
proc check_for_leaks {} {
|
||||
set ret [list]
|
||||
set cnt 0
|
||||
foreach alloc [sqlite_malloc_outstanding] {
|
||||
foreach {nBytes file iLine userstring backtrace} $alloc {}
|
||||
set stack [list]
|
||||
@ -447,18 +448,21 @@ proc check_for_leaks {} {
|
||||
|
||||
# The first command in this block will probably fail on windows. This
|
||||
# means there will be no stack dump available.
|
||||
catch {
|
||||
set stuff [eval "exec addr2line -e ./testfixture -f $backtrace"]
|
||||
foreach {func line} $stuff {
|
||||
if {$func != "??" || $line != "??:0"} {
|
||||
regexp {.*/(.*)} $line dummy line
|
||||
lappend stack "${func}() $line"
|
||||
} else {
|
||||
if {[lindex $stack end] != "..."} {
|
||||
lappend stack "..."
|
||||
if {$cnt < 25} {
|
||||
catch {
|
||||
set stuff [eval "exec addr2line -e ./testfixture -f $backtrace"]
|
||||
foreach {func line} $stuff {
|
||||
if {$func != "??" || $line != "??:0"} {
|
||||
regexp {.*/(.*)} $line dummy line
|
||||
lappend stack "${func}() $line"
|
||||
} else {
|
||||
if {[lindex $stack end] != "..."} {
|
||||
lappend stack "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
incr cnt
|
||||
}
|
||||
|
||||
if {!$skip} {
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is database locks.
|
||||
#
|
||||
# $Id: trans.test,v 1.26 2005/03/29 03:11:00 danielk1977 Exp $
|
||||
# $Id: trans.test,v 1.27 2005/12/30 16:28:02 danielk1977 Exp $
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -97,6 +97,7 @@ do_test trans-3.2 {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} altdb
|
||||
} {0 {1 5 10}}
|
||||
|
||||
do_test trans-3.3 {
|
||||
catchsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
@ -135,6 +136,7 @@ do_test trans-3.9 {
|
||||
do_test trans-3.10 {
|
||||
execsql {END TRANSACTION}
|
||||
} {}
|
||||
|
||||
do_test trans-3.11 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
|
Reference in New Issue
Block a user