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->dbSize 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.
- CREATE TABLE t(s varchar(10) primary key);
+ Why doesn't SQLite allow me to use '0' and '0.0' as the primary
+ key on two different rows of the same table?
} {
-
- INSERT INTO t VALUES('0');
- INSERT INTO t VALUES('0.0');
-
You can work around this issue in several ways:
+You can work around this issue in two ways:
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. -
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().
Remove the primary key clause from the CREATE TABLE.
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().
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: +
+ ++} + # End of questions and answers. #############+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; +