diff --git a/manifest b/manifest index 21c833d140..6f6ac49fc0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s2.1.7\s(CVS\s454) -D 2001-12-15T03:05:00 +C Comment\sand\sdocumentation\schanges.\s(CVS\s331) +D 2001-12-15T14:22:19 F Makefile.in 352fed589f09dd94347e0bb391d047118ebd6105 F Makefile.template 0fbf0ee1fe38183d760170a13e91fffec64e73f5 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -19,8 +19,8 @@ F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6 F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1 F publish.sh cb0f8f7bcb65b8360d0f6668a216a9ac9d5da892 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 -F src/btree.c c27474fdafb7036eef17673c7291e54c2116d6ff -F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650 +F src/btree.c c3c36b3b5f07c3efdabf76df9ea423086b1ce142 +F src/btree.h 8767bd4ecf841c4999b7aee6876906bd607546e7 F src/build.c 5127f737837a9d2a8cb4b998dbab505c08b8f06a F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2 F src/expr.c 6b25c5bb1e750af2e2217c0134a7aa1fc0b11444 @@ -31,8 +31,8 @@ F src/main.c e5fa4773e6684b81fc0bcd9d9ae4578d56660c0c F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c F src/os.c 07882cde5c61f26751b8ee76fd84726c1f7e453c F src/os.h 00a18e0ae1139a64f1d3ead465ae2b9ff43f3db2 -F src/pager.c f39d99e9339e5fff3fd9852f48d2fc8308933d3b -F src/pager.h df1fb8a759ab69112ea88b9f14601a7633d0ccc0 +F src/pager.c dde0eb5bf9af0ac0ff8a4429b2bee2aec2194ec9 +F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b @@ -108,7 +108,7 @@ F www/changes.tcl 0b921ad20b5dd262e5a9594691b9708a311e5912 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c -F www/faq.tcl 3c26fb2f2acfc9254f2685e23a34acae2490b44f +F www/faq.tcl 5c6fba68e238a52b4d9d86b0a63ed2d706fc7f1f F www/index.tcl 6d6d847dd3e39e9aa7b0c9b8f3144819ff3f9f51 F www/lang.tcl 6482d90e40fb5ee004a86cf98f3007312a75444e F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc @@ -117,7 +117,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 880ef67cb4f2797b95bf1368fc4e0d8ca0fda956 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 3a31daf6465b989a2b0790a2d1ba22ff955486a0 -R fe372d30b06d43519de0595e4ea6a38e +P 0d44465347125c8e7e962ffb67213f9953a9b7ab +R f9524b24c72db56ae24d23e4dfe8d2a7 U drh -Z 1ebde59941b4e5e9dcfe12e6c3caef81 +Z c454c32fd5ff2d794a364b8c8ca2dfec diff --git a/manifest.uuid b/manifest.uuid index 0c060d3280..6b0bcea620 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d44465347125c8e7e962ffb67213f9953a9b7ab \ No newline at end of file +e8595579a5218aa3f344f967a23ac52ea89daca1 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9695a281c1..289282b55f 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.44 2001/12/15 02:47:28 drh Exp $ +** $Id: btree.c,v 1.45 2001/12/15 14:22:19 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -251,7 +251,7 @@ struct OverflowPage { /* ** For every page in the database file, an instance of the following structure ** is stored in memory. The u.aDisk[] array contains the raw bits read from -** the disk. The rest is auxiliary information that held in memory only. The +** the disk. The rest is auxiliary information held in memory only. The ** auxiliary info is only valid for regular database pages - it is not ** used for overflow pages and pages on the freelist. ** @@ -635,7 +635,7 @@ int sqliteBtreeClose(Btree *pBt){ } /* -** Change the number of pages in the cache. +** Change the limit on the number of pages allowed the cache. */ int sqliteBtreeSetCacheSize(Btree *pBt, int mxPage){ sqlitepager_set_cachesize(pBt->pPager, mxPage); @@ -806,9 +806,13 @@ int sqliteBtreeRollback(Btree *pBt){ ** If wrFlag==0, then the cursor can only be used for reading. ** If wrFlag==1, then the cursor can be used for reading or writing. ** A read/write cursor requires exclusive access to its table. There -** cannot be two or more cursors open on the same table is any one of +** cannot be two or more cursors open on the same table if any one of ** cursors is a read/write cursor. But there can be two or more ** read-only cursors open on the same table. +** +** No checking is done to make sure that page iTable really is the +** root page of a b-tree. If it is not, then the cursor acquired +** will not work correctly. */ int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){ int rc; diff --git a/src/btree.h b/src/btree.h index b468a55367..bce1a84d97 100644 --- a/src/btree.h +++ b/src/btree.h @@ -10,9 +10,10 @@ ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file -** subsystem. +** subsystem. See comments in the source code for a detailed description +** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.17 2001/11/07 14:22:00 drh Exp $ +** @(#) $Id: btree.h,v 1.18 2001/12/15 14:22:19 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ diff --git a/src/pager.c b/src/pager.c index 1cb2bef945..09268e9ac5 100644 --- a/src/pager.c +++ b/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.33 2001/12/14 15:09:57 drh Exp $ +** @(#) $Id: pager.c,v 1.34 2001/12/15 14:22:19 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -230,17 +230,6 @@ static void pager_reset(Pager *pPager){ ** a write lock on the database. This routine releases the database ** write lock and acquires a read lock in its place. The journal file ** is deleted and closed. -** -** We have to release the write lock before acquiring the read lock, -** so there is a race condition where another process can get the lock -** while we are not holding it. But, no other process should do this -** because we are also holding a lock on the journal, and no process -** should get a write lock on the database without first getting a lock -** on the journal. So this routine should never fail. But it can fail -** if another process is not playing by the rules. If it does fail, -** all in-memory cache pages are invalidated, the PAGER_ERR_LOCK bit -** is set in pPager->errMask, and this routine returns SQLITE_PROTOCOL. -** SQLITE_OK is returned on success. */ static int pager_unwritelock(Pager *pPager){ int rc; @@ -273,8 +262,15 @@ static int pager_unwritelock(Pager *pPager){ ** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data. See ** the PageRecord structure for details. ** -** For playback, the pages have to be read from the journal in +** For playback, the pages are read from the journal in ** reverse order and put back into the original database file. +** It used to be required to replay pages in reverse order because +** there was a possibility of a page appearing in the journal more +** than once. In that case, the original value of the page was +** the first entry so it should be reset last. But now, a bitmap +** is used to record every page that is in the journal. No pages +** are ever repeated. So we could, in theory, playback the journal +** in the forward direction and it would still work. ** ** If the file opened as the journal file is not a well-formed ** journal file (as determined by looking at the magic number @@ -383,9 +379,9 @@ void sqlitepager_set_cachesize(Pager *pPager, int mxPage){ ** the first call to sqlitepager_get() and is only held open until the ** last page is released using sqlitepager_unref(). ** -** If zFilename is NULL then a random temporary file is created and used -** as the file to be cached. The file will be deleted automatically when -** it is closed. +** If zFilename is NULL then a randomly-named temporary file is created +** and used as the file to be cached. The file will be deleted +** automatically when it is closed. */ int sqlitepager_open( Pager **ppPager, /* Return the Pager structure here */ @@ -573,11 +569,12 @@ int sqlitepager_ref(void *pData){ ** ** Writing all free dirty pages to the database after the sync is a ** non-obvious optimization. fsync() is an expensive operation so we -** want to minimize the number that occur. So after an fsync() is forced -** and we are free to write dirty pages back to the database, it is best -** to go ahead and do as much of that as possible to minimize the chance -** of having to do another fsync() later on. Writing dirty free pages -** in this way make database operations go up to 10 times faster. +** want to minimize the number it is called. After an fsync() call, +** we are free to write dirty pages back to the database. It is best +** to go ahead and write as many dirty pages as possible to minimize +** the risk of having to do another fsync() later on. Writing dirty +** free pages in this way was observed to make database operations go +** up to 10 times faster. */ static int syncAllPages(Pager *pPager){ PgHdr *pPg; @@ -652,7 +649,7 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ */ rc = sqliteOsWriteLock(&pPager->fd); if( rc!=SQLITE_OK ){ - rc = sqliteOsReadLock(&pPager->fd); + rc = sqliteOsUnlock(&pPager->fd); assert( rc==SQLITE_OK ); *ppPage = 0; return SQLITE_BUSY; @@ -912,14 +909,25 @@ int sqlitepager_write(void *pData){ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; + /* Check for errors + */ if( pPager->errMask ){ return pager_errcode(pPager); } if( pPager->readOnly ){ return SQLITE_PERM; } + + /* Mark the page as dirty. If the page has already been written + ** to the journal then we can return right away. + */ pPg->dirty = 1; if( pPg->inJournal ){ return SQLITE_OK; } + + /* If we get this far, it means that the page needs to be + ** written to the journal file. First check to see if the + ** journal exists and create it if it does not. + */ assert( pPager->state!=SQLITE_UNLOCK ); if( pPager->state==SQLITE_READLOCK ){ assert( pPager->aInJournal==0 ); @@ -956,6 +964,10 @@ int sqlitepager_write(void *pData){ } assert( pPager->state==SQLITE_WRITELOCK ); assert( pPager->journalOpen ); + + /* The journal now exists and we have a write lock on the + ** main database file. Write the current page to the journal. + */ if( pPg->pgno <= pPager->origDbSize ){ rc = sqliteOsWrite(&pPager->jfd, &pPg->pgno, sizeof(Pgno)); if( rc==SQLITE_OK ){ @@ -970,6 +982,9 @@ int sqlitepager_write(void *pData){ pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); pPager->needSync = 1; } + + /* Mark the current page as being in the journal and return. + */ pPg->inJournal = 1; if( pPager->dbSizepgno ){ pPager->dbSize = pPg->pgno; diff --git a/src/pager.h b/src/pager.h index 9ed51dcda5..c0b83f0de4 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,7 +13,7 @@ ** 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.12 2001/11/10 13:51:09 drh Exp $ +** @(#) $Id: pager.h,v 1.13 2001/12/15 14:22:19 drh Exp $ */ /* @@ -43,6 +43,10 @@ typedef unsigned int Pgno; */ typedef struct Pager Pager; +/* +** See source code comments for a detailed description of the following +** routines: +*/ int sqlitepager_open(Pager **ppPager,const char *zFilename,int nPage,int nEx); void sqlitepager_set_destructor(Pager*, void(*)(void*)); void sqlitepager_set_cachesize(Pager*, int); diff --git a/www/faq.tcl b/www/faq.tcl index 20cc8ff487..641069db24 100644 --- a/www/faq.tcl +++ b/www/faq.tcl @@ -1,7 +1,7 @@ # # Run this script to generated a faq.html output file # -set rcsid {$Id: faq.tcl,v 1.3 2001/12/05 00:21:21 drh Exp $} +set rcsid {$Id: faq.tcl,v 1.4 2001/12/15 14:22:19 drh Exp $} puts { @@ -93,29 +93,21 @@ faq { } faq { - Why does the second INSERT in the following sequence of commands throw - a constraint exception? -
- CREATE TABLE t(s varchar(10) primary key);
- INSERT INTO t VALUES('0');
- INSERT INTO t VALUES('0.0');
-
+ Why doesn't SQLite allow me to use '0' and '0.0' as the primary + key on two different rows of the same table? } { -

Because column s is a primary key, all values of s must - be unique. But SQLite thinks that '0' and '0.0' are the +

Every row much have a unique primary key. + But SQLite thinks that '0' and '0.0' are the same value because they compare equal to one another numerically. - (See the previous question.) Hence the values are not unique and the - constraint fails.

+ (See the previous question.) Hence the values are not unique.

-

You can work around this issue in several ways:

+

You can work around this issue in two ways:

    -
  1. Remove the primary key clause from the CREATE TABLE so that - s can contain more than one entry with the same value. - If you need an index on the s column then create it separately. -

  2. -
  3. Prepend a space to the beginning of every s value. The initial - space will mean that the entries are not pure numerics and hence - will be compared as strings using strcmp().

  4. +
  5. Remove the primary key clause from the CREATE TABLE.

  6. +
  7. Prepend a space to the beginning of every value you use for + the primary key. The initial + space will mean that the entries are not pure numerics and hence + will be compared as strings using strcmp().

} @@ -234,7 +226,7 @@ ORDER BY name; } faq { - Is there any known size limits to SQLite databases. + Are there any known size limits to SQLite databases. } {

Internally, SQLite can handle databases up to 2^40 bytes (1 terabyte) in size. But the backend interface to POSIX and Win32 limits files to @@ -257,6 +249,32 @@ faq { number of columns, etc. Indices are similarly unconstrained.

} +faq { + How do I add or delete columns from an existing table in SQLite. +} { +

SQLite does not support the "ALTER TABLE" SQL command. If you + what to change the structure of a table, you have to recreate the + table. You can save existing data to a temporary table, drop the + old table, create the new table, then copy the data back in from + the temporary table.

+ +

For example, suppose you have a table named "t1" with columns + names "a", "b", and "c" and that you want to delete column "c" from + this table. The following steps illustrate how this could be done: +

+ +
+BEGIN TRANSACTION;
+CREATE TEMPORARY TABLE t1_backup(a,b);
+INSERT INTO t1_backup SELECT a,b FROM t1;
+DROP TABLE t1;
+CREATE TABLE t1(a,b);
+INSERT INTO t1 SELECT a,b FROM t1_backup;
+DROP TABLE t1_backup;
+COMMIT;
+
+} + # End of questions and answers. #############