Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Changes for exclusive access mode. There are still some bugs. (CVS 3712) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b6c700370be29db2b974f9abd719c3e5 |
User & Date: | danielk1977 2007-03-24 16:45:05.000 |
Context
2007-03-25
| ||
19:08 | Add the sqlite3_prepare_v2 and sqlite3_prepare16_v2 APIs to the loadable extension interface. (CVS 3713) (check-in: f02ba56d5c user: drh tags: trunk) | |
2007-03-24
| ||
16:45 | Changes for exclusive access mode. There are still some bugs. (CVS 3712) (check-in: b6c700370b user: danielk1977 tags: trunk) | |
2007-03-23
| ||
18:12 | Discard the contents of the pager-cache only when the change-counter indicates that it is stale. (CVS 3711) (check-in: 07b56965f3 user: danielk1977 tags: trunk) | |
Changes
Changes to src/attach.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** 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 contains code used to implement the ATTACH and DETACH commands. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** 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 contains code used to implement the ATTACH and DETACH commands. ** ** $Id: attach.c,v 1.55 2007/03/24 16:45:05 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Resolve an expression that was part of an ATTACH or DETACH statement. This ** is slightly different from resolving a normal SQL expression, because simple ** identifiers are treated as strings, not possible column names or aliases. |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ strcpy(zErr, "attached databases must use the same text encoding as main database"); goto attach_error; } } aNew->zName = sqliteStrDup(zName); aNew->safety_level = 3; #if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, void*, int); | > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ strcpy(zErr, "attached databases must use the same text encoding as main database"); goto attach_error; } sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode); } aNew->zName = sqliteStrDup(zName); aNew->safety_level = 3; #if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, void*, int); |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.294 2007/03/24 16:45:05 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
281 282 283 284 285 286 287 | void *pCodecArg; /* First argument to xCodec() */ int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ | < > > > | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | void *pCodecArg; /* First argument to xCodec() */ int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ u32 iChangeCount; /* Db change-counter for which cache is valid */ u8 doNotSync; /* Boolean. While true, do not spill the cache */ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ u8 changeCountDone; /* Set after incrementing the change-counter */ }; /* ** If SQLITE_TEST is defined then increment the variable given in ** the argument */ #ifdef SQLITE_TEST |
︙ | ︙ | |||
850 851 852 853 854 855 856 | return p; } /* ** Unlock the database file. */ static void pager_unlock(Pager *pPager){ | > | | | | | | > > < | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 | return p; } /* ** Unlock the database file. */ static void pager_unlock(Pager *pPager){ if( !pPager->exclusiveMode ){ if( !MEMDB ){ sqlite3OsUnlock(pPager->fd, NO_LOCK); pPager->dbSize = -1; IOTRACE(("UNLOCK %p\n", pPager)) } pPager->state = PAGER_UNLOCK; pPager->changeCountDone = 0; } } /* ** Execute a rollback if a transaction is active and unlock the ** database file. This is a no-op if the pager has already entered ** the error-state. */ static void pagerUnlockAndRollback(Pager *pPager){ if( pPager->errCode ) return; if( pPager->state>=PAGER_RESERVED ){ sqlite3PagerRollback(pPager); } pager_unlock(pPager); } /* ** Unlock the database and clear the in-memory cache. This routine ** sets the state of the pager back to what it was when it was first ** opened. Any outstanding pages are invalidated and subsequent attempts |
︙ | ︙ | |||
898 899 900 901 902 903 904 | pPager->nHash = 0; sqliteFree(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } | < < < < < < < < < < < < < < < < < < < < < < | > > > > > | | | > > > | | | > > > > > > > > | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 | pPager->nHash = 0; sqliteFree(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } /* ** When this routine is called, the pager has the journal file open and ** a RESERVED or EXCLUSIVE lock on the database. This routine releases ** the database lock and acquires a SHARED lock in its place. The journal ** file is deleted and closed. ** ** TODO: Consider keeping the journal file open for temporary databases. ** This might give a performance improvement on windows where opening ** a file is an expensive operation. */ static int pager_unwritelock(Pager *pPager){ PgHdr *pPg; int rc = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; } if( pPager->journalOpen ){ if( pPager->exclusiveMode ){ sqlite3OsTruncate(pPager->jfd, 0); sqlite3OsSeek(pPager->jfd, 0); pPager->journalOff = 0; }else{ sqlite3OsClose(&pPager->jfd); pPager->journalOpen = 0; sqlite3OsDelete(pPager->zJournal); } sqliteFree( pPager->aInJournal ); pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; pPg->alwaysRollback = 0; #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } pPager->pDirty = 0; pPager->dirtyCache = 0; pPager->nRec = 0; }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } if( !pPager->exclusiveMode ){ rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; }else{ sqlite3PagerPagecount(pPager); pPager->origDbSize = pPager->dbSize; pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( !pPager->aInJournal ){ rc = SQLITE_NOMEM; } } pPager->setMaster = 0; pPager->needSync = 0; pPager->pFirstSynced = pPager->pFirst; pPager->dbSize = -1; return rc; } |
︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 | if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/ pPager->xDestructor(pPg, pPager->pageSize); } #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif CODEC1(pPager, pData, pPg->pgno, 3); } return rc; } /* ** Parameter zMaster is the name of a master journal file. A single journal ** file that referred to the master journal file has just been rolled back. | > > > > > | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/ pPager->xDestructor(pPg, pPager->pageSize); } #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif CODEC1(pPager, pData, pPg->pgno, 3); /* If this was page 1, then restore the value of Pager.iChangeCount */ if( pgno==1 ){ pPager->iChangeCount = retrieve32bits(pPg, 24); } } return rc; } /* ** Parameter zMaster is the name of a master journal file. A single journal ** file that referred to the master journal file has just been rolled back. |
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | } if( master_open ){ sqlite3OsClose(&master); } return rc; } /* ** Make every page in the cache agree with what is on disk. In other words, ** reread the disk to reset the state of the cache. ** ** This routine is called after a rollback in which some of the dirty cache ** pages had never been written out to disk. We need to roll back the ** cache content and the easiest way to do that is to reread the old content | > | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | } if( master_open ){ sqlite3OsClose(&master); } return rc; } #if 0 /* ** Make every page in the cache agree with what is on disk. In other words, ** reread the disk to reset the state of the cache. ** ** This routine is called after a rollback in which some of the dirty cache ** pages had never been written out to disk. We need to roll back the ** cache content and the easiest way to do that is to reread the old content |
︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } pPager->pDirty = 0; return rc; } /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); | > | 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 | #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } pPager->pDirty = 0; return rc; } #endif /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); |
︙ | ︙ | |||
2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 | ThreadData *pTsd = sqlite3ThreadData(); assert( pPager ); assert( pTsd && pTsd->nAlloc ); #endif disable_simulated_io_errors(); pPager->errCode = 0; pager_reset(pPager); pagerUnlockAndRollback(pPager); enable_simulated_io_errors(); TRACE2("CLOSE %d\n", PAGERID(pPager)); IOTRACE(("CLOSE %p\n", pPager)) assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); if( pPager->journalOpen ){ | > | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | ThreadData *pTsd = sqlite3ThreadData(); assert( pPager ); assert( pTsd && pTsd->nAlloc ); #endif disable_simulated_io_errors(); pPager->errCode = 0; pPager->exclusiveMode = 0; pager_reset(pPager); pagerUnlockAndRollback(pPager); enable_simulated_io_errors(); TRACE2("CLOSE %d\n", PAGERID(pPager)); IOTRACE(("CLOSE %p\n", pPager)) assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); if( pPager->journalOpen ){ |
︙ | ︙ | |||
2730 2731 2732 2733 2734 2735 2736 | */ u32 iChangeCount = retrieve32bits(pPage1, 24); pPager->nRef++; sqlite3PagerUnref(pPage1); pPager->nRef--; if( iChangeCount!=pPager->iChangeCount ){ pager_reset(pPager); | < < | 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 | */ u32 iChangeCount = retrieve32bits(pPage1, 24); pPager->nRef++; sqlite3PagerUnref(pPage1); pPager->nRef--; if( iChangeCount!=pPager->iChangeCount ){ pager_reset(pPager); } pPager->iChangeCount = iChangeCount; } } } pPager->state = PAGER_SHARED; } |
︙ | ︙ | |||
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 | TRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); continue; } pHist = PGHDR_TO_HIST(p, pPager); if( pHist->pOrig ){ | > > | 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 | TRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ assert( p->inJournal==0 ); assert( p->inStmt==0 ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); continue; } pHist = PGHDR_TO_HIST(p, pPager); if( pHist->pOrig ){ |
︙ | ︙ | |||
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 | /* Increment the value just read and write it back to byte 24. */ change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); pPager->iChangeCount = change_counter; /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); return SQLITE_OK; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual ** journal file. zMaster may be NULL, which is interpreted as no master | > | 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 | /* Increment the value just read and write it back to byte 24. */ change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); pPager->iChangeCount = change_counter; /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); pPager->changeCountDone = 1; return SQLITE_OK; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual ** journal file. zMaster may be NULL, which is interpreted as no master |
︙ | ︙ | |||
4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 | ** Return a pointer to the Pager.nExtra bytes of "extra" space ** allocated along with the specified page. */ void *sqlite3PagerGetExtra(DbPage *pPg){ Pager *pPager = pPg->pPager; return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0); } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ | > > > > > > > > > > > > > > > > > | 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 | ** Return a pointer to the Pager.nExtra bytes of "extra" space ** allocated along with the specified page. */ void *sqlite3PagerGetExtra(DbPage *pPg){ Pager *pPager = pPg->pPager; return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0); } /* ** Get/set the locking-mode for this pager. Parameter eMode must be one ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then ** the locking-mode is set to the value specified. ** ** The returned value is either PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated) ** locking-mode. */ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ if( eMode>=0 ){ pPager->exclusiveMode = eMode; } return (int)pPager->exclusiveMode; } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** ** @(#) $Id: pager.h,v 1.55 2007/03/24 16:45:05 danielk1977 Exp $ */ #ifndef _PAGER_H_ #define _PAGER_H_ /* ** The default size of a database page. |
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: This values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ /* ** See source code comments for a detailed description of the following ** routines: */ int sqlite3PagerOpen(Pager **ppPager, const char *zFilename, int nExtra, int flags); | > > > > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: This values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ /* ** Valid values for the second argument to sqlite3PagerLockingMode(). */ #define PAGER_LOCKINGMODE_QUERY -1 #define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* ** See source code comments for a detailed description of the following ** routines: */ int sqlite3PagerOpen(Pager **ppPager, const char *zFilename, int nExtra, int flags); |
︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*); int sqlite3PagerMovepage(Pager*,DbPage*,Pgno); int sqlite3PagerReset(Pager*); int sqlite3PagerReleaseMemory(int); void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3PagerLockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3PagerRefdump(Pager*); int pager3_refinfo_enable; #endif #endif /* _PAGER_H_ */ | > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*); int sqlite3PagerMovepage(Pager*,DbPage*,Pgno); int sqlite3PagerReset(Pager*); int sqlite3PagerReleaseMemory(int); void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); int sqlite3PagerLockingMode(Pager *, int); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3PagerLockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3PagerRefdump(Pager*); int pager3_refinfo_enable; #endif #endif /* _PAGER_H_ */ |
Changes to src/pragma.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** 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 contains code used to implement the PRAGMA command. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** 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 contains code used to implement the PRAGMA command. ** ** $Id: pragma.c,v 1.130 2007/03/24 16:45:05 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> /* Ignore this whole file if pragmas are disabled */ |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /* ** Interpret the given string as a boolean value. */ static int getBoolean(const char *z){ return getSafetyLevel(z)&1; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Interpret the given string as a temp db location. Return 1 for file ** backed temporary databases, 2 for the Red-Black tree in memory database ** and 0 to use the compile-time default. */ | > > > > > > > > > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | /* ** Interpret the given string as a boolean value. */ static int getBoolean(const char *z){ return getSafetyLevel(z)&1; } /* ** Interpret the given string as a locking mode value. */ static int getLockingMode(const char *z){ if( z ){ if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE; if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL; } return PAGER_LOCKINGMODE_QUERY; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Interpret the given string as a temp db location. Return 1 for file ** backed temporary databases, 2 for the Red-Black tree in memory database ** and 0 to use the compile-time default. */ |
︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 321 322 323 324 | if( !zRight ){ int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1); } }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** PRAGMA [database.]auto_vacuum ** PRAGMA [database.]auto_vacuum=N ** ** Get or set the (boolean) value of the database 'auto-vacuum' parameter. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | if( !zRight ){ int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1); } }else /* ** PRAGMA [database.]locking_mode ** PRAGMA [database.]locking_mode = (normal|exclusive) */ if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){ const char *zRet = "normal"; int eMode = getLockingMode(zRight); if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){ /* Simple "PRAGMA locking_mode;" statement. This is a query for ** the current default locking mode (which may be different to ** the locking-mode of the main database). */ eMode = db->dfltLockMode; }else{ Pager *pPager; if( pId2->n==0 ){ /* This indicates that no database name was specified as part ** of the PRAGMA command. In this case the locking-mode must be ** set on all attached databases, as well as the main db file. ** ** Also, the sqlite3.dfltLockMode variable is set so that ** any subsequently attached databases also use the specified ** locking mode. */ int ii; assert(pDb==&db->aDb[0]); for(ii=2; ii<db->nDb; ii++){ pPager = sqlite3BtreePager(db->aDb[ii].pBt); sqlite3PagerLockingMode(pPager, eMode); } db->dfltLockMode = eMode; } pPager = sqlite3BtreePager(pDb->pBt); eMode = sqlite3PagerLockingMode(pPager, eMode); } assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE); if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ zRet = "exclusive"; } sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC); sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** PRAGMA [database.]auto_vacuum ** PRAGMA [database.]auto_vacuum=N ** ** Get or set the (boolean) value of the database 'auto-vacuum' parameter. |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.543 2007/03/24 16:45:05 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Extra interface definitions for those who need them */ |
︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 517 518 519 | Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ #endif }; /* ** A macro to discover the encoding of a database. */ #define ENC(db) ((db)->aDb[0].pSchema->enc) | > | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ #endif u8 dfltLockMode; /* Default locking-mode for attached dbs */ }; /* ** A macro to discover the encoding of a database. */ #define ENC(db) ((db)->aDb[0].pSchema->enc) |
︙ | ︙ |
Added test/exclusive.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | # 2007 March 24 # # 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. # # $Id: exclusive.test,v 1.1 2007/03/24 16:45:05 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!pager_pragmas} { finish_test return } file delete -force test2.db-journal file delete -force test2.db file delete -force test3.db-journal file delete -force test3.db file delete -force test4.db-journal file delete -force test4.db #---------------------------------------------------------------------- # Test cases exclusive-1.X test the PRAGMA logic. # do_test exclusive-1.0 { execsql { pragma locking_mode; pragma main.locking_mode; } } {normal normal} do_test exclusive-1.1 { execsql { pragma locking_mode = exclusive; } } {exclusive} do_test exclusive-1.2 { execsql { pragma locking_mode; pragma main.locking_mode; } } {exclusive exclusive} do_test exclusive-1.3 { execsql { pragma locking_mode = normal; } } {normal} do_test exclusive-1.4 { execsql { pragma locking_mode; pragma main.locking_mode; } } {normal normal} do_test exclusive-1.5 { execsql { pragma locking_mode = invalid; } } {normal} do_test exclusive-1.6 { execsql { pragma locking_mode; pragma main.locking_mode; } } {normal normal} do_test exclusive-1.7 { execsql { pragma locking_mode = exclusive; ATTACH 'test2.db' as aux; } execsql { pragma main.locking_mode; pragma aux.locking_mode; } } {exclusive exclusive} do_test exclusive-1.8 { execsql { pragma main.locking_mode = normal; } execsql { pragma main.locking_mode; pragma aux.locking_mode; } } {normal exclusive} do_test exclusive-1.9 { execsql { pragma locking_mode; } } {exclusive} do_test exclusive-1.10 { execsql { ATTACH 'test3.db' as aux2; } execsql { pragma main.locking_mode; pragma aux.locking_mode; pragma aux2.locking_mode; } } {normal exclusive exclusive} do_test exclusive-1.11 { execsql { pragma aux.locking_mode = normal; } execsql { pragma main.locking_mode; pragma aux.locking_mode; pragma aux2.locking_mode; } } {normal normal exclusive} do_test exclusive-1.12 { execsql { pragma locking_mode = normal; } execsql { pragma main.locking_mode; pragma aux.locking_mode; pragma aux2.locking_mode; } } {normal normal normal} do_test exclusive-1.13 { execsql { ATTACH 'test4.db' as aux3; } execsql { pragma main.locking_mode; pragma aux.locking_mode; pragma aux2.locking_mode; pragma aux3.locking_mode; } } {normal normal normal normal} do_test exclusive-1.99 { execsql { DETACH aux; DETACH aux2; DETACH aux3; } } {} #---------------------------------------------------------------------- # Test cases exclusive-2.X verify that connections in exclusive # locking_mode do not relinquish locks. # do_test exclusive-2.0 { execsql { CREATE TABLE abc(a, b, c); INSERT INTO abc VALUES(1, 2, 3); PRAGMA locking_mode = exclusive; } } {exclusive} do_test exclusive-2.1 { sqlite3 db2 test.db execsql { INSERT INTO abc VALUES(4, 5, 6); SELECT * FROM abc; } db2 } {1 2 3 4 5 6} do_test exclusive-2.2 { # This causes connection 'db' (in exclusive mode) to establish # a shared-lock on the db. The other connection should now be # locked out as a writer. execsql { SELECT * FROM abc; } db } {1 2 3 4 5 6} do_test exclusive-2.4 { execsql { SELECT * FROM abc; } db2 } {1 2 3 4 5 6} do_test exclusive-2.5 { catchsql { INSERT INTO abc VALUES(7, 8, 9); } db2 } {1 {database is locked}} do_test exclusive-2.6 { # Because connection 'db' only has a shared-lock, the other connection # will be able to get a RESERVED, but will fail to upgrade to EXCLUSIVE. execsql { BEGIN; INSERT INTO abc VALUES(7, 8, 9); } db2 catchsql { COMMIT } db2 } {1 {database is locked}} do_test exclusive-2.7 { catchsql { COMMIT } db2 } {1 {database is locked}} do_test exclusive-2.8 { execsql { ROLLBACK; } db2 } {} do_test exclusive-2.9 { # Write the database to establish the exclusive lock with connection 'db. execsql { INSERT INTO abc VALUES(7, 8, 9); } db catchsql { SELECT * FROM abc; } db2 } {1 {database is locked}} do_test exclusive-2.10 { # Changing the locking-mode does not release any locks. execsql { PRAGMA locking_mode = normal; } db catchsql { SELECT * FROM abc; } db2 } {1 {database is locked}} do_test exclusive-2.11 { # After changing the locking mode, accessing the db releases locks. execsql { SELECT * FROM abc; } db execsql { SELECT * FROM abc; } db2 } {1 2 3 4 5 6 7 8 9} db2 close #---------------------------------------------------------------------- # Tests exclusive-3.X - test that a connection in exclusive mode # truncates instead of deletes the journal file when committing # a transaction. # proc filestate {fname} { set exists 0 set content 0 if {[file exists $fname]} { set exists 1 set content [expr {[file size $fname] > 0}] } list $exists $content } do_test exclusive-3.0 { filestate test.db-journal } {0 0} do_test exclusive-3.1 { execsql { PRAGMA locking_mode = exclusive; BEGIN; DELETE FROM abc; } filestate test.db-journal } {1 1} do_test exclusive-3.2 { execsql { COMMIT; } filestate test.db-journal } {1 0} do_test exclusive-3.3 { execsql { INSERT INTO abc VALUES('A', 'B', 'C'); SELECT * FROM abc; } } {A B C} do_test exclusive-3.4 { execsql { BEGIN; UPDATE abc SET a = 1, b = 2, c = 3; ROLLBACK; SELECT * FROM abc; } } {1 2 3} do_test exclusive-3.5 { filestate test.db-journal } {1 0} do_test exclusive-3.6 { execsql { PRAGMA locking_mode = normal; SELECT * FROM abc; } filestate test.db-journal } {0 0} # The following procedure computes a "signature" for table "t3". If # T3 changes in any way, the signature should change. # # This is used to test ROLLBACK. We gather a signature for t3, then # make lots of changes to t3, then rollback and take another signature. # The two signatures should be the same. # proc signature {} { return [db eval {SELECT count(*), md5sum(x) FROM t3}] } if 0 { do_test exclusive-4.0 { execsql { PRAGMA default_cache_size=10; } db close sqlite3 db test.db execsql { PRAGMA locking_mode = exclusive; } execsql { BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; COMMIT; SELECT count(*) FROM t3; } } {1024} set sig [signature] do_test exclusive-4.1 { execsql { BEGIN; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; ROLLBACK; } signature } $sig } finish_test |
Changes to test/trans.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # 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 script is database locks. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # 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 script is database locks. # # $Id: trans.test,v 1.33 2007/03/24 16:45:05 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create several tables to work with. |
︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 821 822 823 824 | # do_test trans-9.1 { execsql { PRAGMA default_cache_size=10; } db close sqlite3 db test.db execsql { BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; | > | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | # do_test trans-9.1 { execsql { PRAGMA default_cache_size=10; } db close sqlite3 db test.db # execsql { PRAGMA locking_mode = exclusive; } execsql { BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; |
︙ | ︙ |