diff --git a/Makefile.in b/Makefile.in index ea77dbeb21..a89204140b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,15 +58,16 @@ LIBREADLINE = @TARGET_READLINE_LIBS@ ENCODING = @ENCODING@ # Flags controlling use of the in memory btree implementation -# INCOREDB says whether to build btree_rb.c -# TEMPDBINCORE controls the default placement of temporary databases. -# ALLOWATTACHMEM controls whether ATTACH DATABASE ':memory:' is supported +# +# SQLITE_OMIT_INMEMORYDB is defined in order to omit the in-memory +# red/black tree driver in the file btree_rb.c +# +# TEMP_STORE is 0 to force temporary tables to be in a file, 1 to +# default to file, 2 to default ot memory, and 3 to force temporary +# tables to always be in memory. +# INCOREDB = @INCOREDB@ -TEMPDBINCORE = @TEMPDBINCORE@ -ALLOWATTACHMEM = @ALLOWATTACHMEM@ - -INCOREFLAGS = -DINCOREDB=${INCOREDB} -DTEMPDBINCORE=${TEMPDBINCORE} -INCOREFLAGS += -DALLOWATTACHMEM=${ALLOWATTACHMEM} +INCOREFLAGS = -DSQLITE_OMIT_INMEMORYDB=1 -DTEMP_STORE=${INCOREDB} # You should not have to change anything below this line ############################################################################### diff --git a/manifest b/manifest index 4f77037db4..6d758ea353 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Support\sin-memory\sdatabases\sfor\stemp\stables\s(CVS\s903) -D 2003-04-13T18:26:49 -F Makefile.in 503590f4bdb4733d4c1f114939d68ff8a74523c6 +C Change\ssome\svariable\snames\sand\scomments\sin\sthe\snew\sin-memory\sdatabase\sfile\nimplementation.\s\sPartial\s(non-working)\simplementation\sof\sthe\sVACUUM\scommand.\s(CVS\s904) +D 2003-04-15T01:19:48 +F Makefile.in df3a4db41a7450468b5fe934d9dd8f723b631249 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F VERSION e5b03976c56deafa24511d6ef17d64a28679e9bd @@ -23,7 +23,7 @@ F src/attach.c 8c98e2c0ca434b94deca1b8694c72bd0303a9a87 F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729 F src/btree.c 9949031b6087e9d1b43b359b84c68a491086984f F src/btree.h 5cb871546bd6fa58396a6f033e2b29b388241e1b -F src/build.c 77b910f739174b0655f052ce8c1a7a0f01d3bfca +F src/build.c daed1dacdb70e5d4def9df2e34a1cabeeb8467c9 F src/copy.c ddd204d5dddac09d71a07f4ceded4c9926d5512b F src/delete.c 58d698779a6b7f819718ecd45b310a9de8537088 F src/encode.c faf03741efe921755ec371cf4a6984536de00042 @@ -32,21 +32,21 @@ F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605 F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c e2f5e7feecb507d904a7da48874595f440b715aa -F src/main.c 8500dcd5dab93b201842b6688e0329c2b25c0d79 +F src/main.c daf5b7c256340fb9aa77df7254865218a47d5a63 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c c33ebb320921b8df6d09ea19fe846348df86a0c9 F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0 F src/pager.c df4c81350cbd80c1ab48341ae0768ba78d99ad49 F src/pager.h e3702f7d384921f6cd5ce0b3ed589185433e9f6c F src/parse.y 3be47fa18323aa2e3364fc42bf7a6ba5b3cc0a81 -F src/pragma.c 476b13896571bc8d1049d6dbe9c9a84e6d4e33c8 +F src/pragma.c aef327bd597e15f0d31f45b042bd2797cca65039 F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/select.c 14e2e2a512f4edfc75fb310ebcb502ff3ee87402 F src/shell.c 97f397c0c108176ccbc52ea5b8ec688f995eba7a F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in f49c2cdec7d24cb03e496a1ca519e16306495ee1 -F src/sqliteInt.h 3dcd08da7d9a9f85dcd67a064f1e9baa17238d3a +F src/sqliteInt.h 048303eafaf5811a0977528756386873931cd914 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/tclsqlite.c 7a072c3c8ba9796edc25e5ffa62b68558134e192 F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8 @@ -57,8 +57,8 @@ F src/tokenize.c 675b4718d17c69fe7609dc8e85e426ef002be811 F src/trigger.c bd5a5b234b47f28f9f21a46243dcaf1c5b2383a3 F src/update.c b368369f1fbe6d7f56a53e5ffad3b75dae9e3e1a F src/util.c 8953c612a036e30f24c1c1f5a1498176173daa37 -F src/vacuum.c 6b9ebf0ef5761b06ce86672574c71b1e9098ef9c -F src/vdbe.c 45d2987a5f8337d9aa0da92830fd654fb5fcd478 +F src/vacuum.c ac65e9578506a0cdf70ece2668e5b22f4895477c +F src/vdbe.c cf9ef07b1fce5a340d8926a493f9313208f1773f F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21 F src/where.c e5733f7d5e9cc4ed3590dc3401f779e7b7bb8127 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -161,7 +161,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 73359037ea639abb066c74db9c19e84bf1104006 -R 4a0923ca1b7d3d92da7657c4b796ad95 -U paul -Z 85c89f43ad9bfc64133f7dac4ee2ff75 +P 96336bffde6c441af197a521ee9e56fdfd7efff8 +R 502f917ded2eef9644690cdab0eeb915 +U drh +Z 288074bf98169396dec5124561acfdbb diff --git a/manifest.uuid b/manifest.uuid index 44bbc6d75e..4daf83b66c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -96336bffde6c441af197a521ee9e56fdfd7efff8 \ No newline at end of file +e76787f877c456abdc8bc88bfefc50eaeed68744 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 9f41cbbd90..6db409278d 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.144 2003/04/13 18:26:51 paul Exp $ +** $Id: build.c,v 1.145 2003/04/15 01:19:48 drh Exp $ */ #include "sqliteInt.h" #include @@ -436,7 +436,7 @@ void sqliteStartTable( ** holding temporary tables is open. */ if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){ - int rc = sqliteBtreeFactory(db, ":temp:", 0, MAX_PAGES, &db->aDb[1].pBt); + int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt); if( rc!=SQLITE_OK ){ sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database " "file for storing temporary tables", 0); diff --git a/src/main.c b/src/main.c index 211eb7012f..9eb5fb3654 100644 --- a/src/main.c +++ b/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.122 2003/04/13 18:26:51 paul Exp $ +** $Id: main.c,v 1.123 2003/04/15 01:19:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1057,10 +1057,31 @@ void *sqlite_commit_hook( } /* -** This routine is called when sqlite wants to open a btree. zFilename is -** either the name of a btree file or the magic name ":memory:" which opens an -** in-memory btree or ":temp:" which opens a temporary btree. This may either -** be in memory or backed by a temporary file depending on run-time settings. +** This routine is called to create a connection to a database BTree +** driver. If zFilename is the name of a file, then that file is +** opened and used. If zFilename is the magic name ":memory:" then +** the database is stored in memory (and is thus forgotten as soon as +** the connection is closed.) If zFilename is NULL then the database +** is for temporary use only and is deleted as soon as the connection +** is closed. +** +** +** +** A temporary database can be either a disk file (that is automatically +** deleted when the file is closed) or a set of red-black trees held in memory, +** depending on the values of the TEMP_STORE compile-time macro and the +** db->temp_store variable, according to the following chart: +** +** TEMP_STORE db->temp_store Location of temporary database +** ---------- -------------- ------------------------------ +** 0 any file +** 1 1 file +** 1 2 memory +** 1 0 file +** 2 1 file +** 2 2 memory +** 2 0 memory +** 3 any memory */ int sqliteBtreeFactory( const sqlite *db, /* Main database when opening aux otherwise 0 */ @@ -1069,22 +1090,16 @@ int sqliteBtreeFactory( int nCache, /* How many pages in the page cache */ Btree **ppBtree){ /* Pointer to new Btree object written here */ - assert( zFilename != 0 ); assert( ppBtree != 0); - if (strcmp(zFilename, ":memory:") == 0) { - if (ALLOWATTACHMEM) { - return sqliteRBtreeOpen(0, 0, 0, ppBtree); - } else { - return SQLITE_CANTOPEN; - } - } else if (strcmp(zFilename, ":temp:") == 0) { - if (TEMPDBINCORE == 0) { +#ifndef SQLITE_OMIT_INMEMORYDB + if( zFilename==0 ){ + if (TEMP_STORE == 0) { /* Always use file based temporary DB */ return sqliteBtreeOpen(0, omitJournal, nCache, ppBtree); - } else if (TEMPDBINCORE == 1 || TEMPDBINCORE == 2) { + } else if (TEMP_STORE == 1 || TEMP_STORE == 2) { /* Switch depending on compile-time and/or runtime settings. */ - int location = db->tmpdb_loc == 0 ? TEMPDBINCORE : db->tmpdb_loc; + int location = db->temp_store==0 ? TEMP_STORE : db->temp_store; if (location == 1) { return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree); @@ -1095,7 +1110,11 @@ int sqliteBtreeFactory( /* Always use in-core DB */ return sqliteRBtreeOpen(0, 0, 0, ppBtree); } - } else { + }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ + return sqliteRBtreeOpen(0, 0, 0, ppBtree); + }else +#endif + { return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree); } } diff --git a/src/pragma.c b/src/pragma.c index f3f7b62dad..1466cc1b64 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,9 +11,10 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.2 2003/04/13 18:26:51 paul Exp $ +** $Id: pragma.c,v 1.3 2003/04/15 01:19:49 drh Exp $ */ #include "sqliteInt.h" +#include /* ** Interpret the given string as a boolean value. @@ -69,14 +70,14 @@ static int getSafetyLevel(char *z){ ** backed temporary databases, 2 for the Red-Black tree in memory database ** and 0 to use the compile-time default. */ -static int getTmpdbLocation(char *z){ - if (sqliteStrICmp(z, "file") == 0) { - return 1; - } else if (sqliteStrICmp(z, "memory") == 0) { - return 2; - } else { - return 0; - } +static int getTempStore(char *z){ + if (sqliteStrICmp(z, "file") == 0) { + return 1; + }else if(sqliteStrICmp(z, "memory") == 0) { + return 2; + }else{ + return 0; + } } /* @@ -439,56 +440,59 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ } }else /* - ** PRAGMA tmpdb_location - ** PRAGMA tmpdb_location= DEFAULT|MEMORY|FILE + ** PRAGMA temp_store + ** PRAGMA temp_store = "default"|"memory"|"file" ** - ** Return or set the local value of the tmpdb_location flag. Changing + ** Return or set the local value of the temp_store flag. Changing ** the local value does not make changes to the disk file and the default ** value will be restored the next time the database is opened. ** ** Note that it is possible for the library compile-time options to ** override this setting */ - if( sqliteStrICmp(zLeft, "tmpdb_location")==0 ){ + if( sqliteStrICmp(zLeft, "temp_store")==0 ){ static VdbeOp getTmpDbLoc[] = { - { OP_ColumnName, 0, 0, "tmpdb_location"}, + { OP_ColumnName, 0, 0, "temp_store"}, { OP_Callback, 1, 0, 0}, }; if( pRight->z==pLeft->z ){ - sqliteVdbeAddOp(v, OP_Integer, db->tmpdb_loc, 0); + sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0); sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); }else{ if (&db->aDb[1].pBt != 0) { - sqliteErrorMsg(pParse, "The temporary database already exists, its location cannot now be changed"); + sqliteErrorMsg(pParse, "The temporary database already exists - " + "its location cannot now be changed"); } else { - db->tmpdb_loc = getTmpdbLocation(zRight); + db->temp_store = getTempStore(zRight); } } }else + /* - ** PRAGMA default_tmpdb_location - ** PRAGMA default_tmpdb_location= DEFAULT|MEMORY|FILE + ** PRAGMA default_temp_store + ** PRAGMA default_temp_store = "default"|"memory"|"file" ** - ** Return or set the value of the persistent tmpdb_location flag (as + ** Return or set the value of the persistent temp_store flag (as ** well as the value currently in force). ** ** Note that it is possible for the library compile-time options to ** override this setting */ - if( sqliteStrICmp(zLeft, "default_tmpdb_location")==0 ){ + if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){ static VdbeOp getTmpDbLoc[] = { - { OP_ColumnName, 0, 0, "tmpdb_location"}, + { OP_ColumnName, 0, 0, "temp_store"}, { OP_ReadCookie, 0, 5, 0}, { OP_Callback, 1, 0, 0}}; if( pRight->z==pLeft->z ){ sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); }else{ if (&db->aDb[1].pBt != 0) { - sqliteErrorMsg(pParse, "The temporary database already exists, its location cannot now be changed"); + sqliteErrorMsg(pParse, "The temporary database already exists - " + "its location cannot now be changed"); } else { sqliteBeginWriteOperation(pParse, 0, 0); - db->tmpdb_loc = getTmpdbLocation(zRight); - sqliteVdbeAddOp(v, OP_Integer, db->tmpdb_loc, 0); + db->temp_store = getTempStore(zRight); + sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 5); sqliteEndWriteOperation(pParse); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 838da3a3bf..fe3743a015 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.171 2003/04/13 18:26:52 paul Exp $ +** @(#) $Id: sqliteInt.h,v 1.172 2003/04/15 01:19:49 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -65,6 +65,30 @@ */ #define MAX_ATTACHED 10 +/* +** The next macro is used to determine where TEMP tables and indices +** are stored. Possible values: +** +** 0 Always use a temporary files +** 1 Use a file unless overridden by "PRAGMA temp_store" +** 2 Use memory unless overridden by "PRAGMA temp_store" +** 3 Always use memory +*/ +#ifndef TEMP_STORE +# define TEMP_STORE 1 +#endif + +/* +** When building SQLite for embedded systems where memory is scarce, +** you can define one or more of the following macros to omit extra +** features of the library and thus keep the size of the library to +** a minimum. +*/ +/* #define SQLITE_OMIT_AUTHORIZATION 1 */ +#define SQLITE_OMIT_INMEMORYDB 1 +/* #define SQLITE_OMIT_TRACE 1 */ +/* #define SQLITE_OMIT_VACUUM 1 */ + /* ** Integers of known sizes. These typedefs might change for architectures ** where the sizes very. Preprocessor macros are available so that the @@ -230,6 +254,11 @@ struct Db { ** file_format==3 Version 2.6.0. Fix empty-string index bug. ** file_format==4 Version 2.7.0. Add support for separate numeric and ** text datatypes. +** +** The sqlite.temp_store determines where temporary database files +** are stored. If 1, then a file is created to hold those tables. If +** 2, then they are held in memory. 0 means use the default value in +** the TEMP_STORE macro. */ struct sqlite { int nDb; /* Number of backends currently in use */ @@ -241,7 +270,7 @@ struct sqlite { u8 want_to_close; /* Close after all VDBEs are deallocated */ int next_cookie; /* Next value of aDb[0].schema_cookie */ int cache_size; /* Number of pages to use in the cache */ - int tmpdb_loc; /* Temp DB loc */ + int temp_store; /* 1=file, 2=memory, 0=compile-time default */ int nTable; /* Number of tables in the database */ void *pBusyArg; /* 1st Argument to the busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ diff --git a/src/vacuum.c b/src/vacuum.c index cb8b404e83..dc8cd1edf3 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,10 +14,104 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.1 2003/04/06 21:08:24 drh Exp $ +** $Id: vacuum.c,v 1.2 2003/04/15 01:19:49 drh Exp $ */ #include "sqliteInt.h" +#define SQLITE_OMIT_VACUUM 1 + +/* +** A structure for holding a dynamic string - a string that can grow +** without bound. +*/ +typedef struct dynStr dynStr; +struct dynStr { + char *z; /* Text of the string in space obtained from sqliteMalloc() */ + int nAlloc; /* Amount of space allocated to z[] */ + int nUsed; /* Next unused slot in z[] */ +}; + +#ifndef SQLITE_OMIT_VACUUM +/* +** Append text to a dynamic string +*/ +static void appendText(dynStr *p, const char *zText, int nText){ + if( nText<0 ) nText = strlen(zText); + if( p->z==0 || p->nUsed + nText + 1 >= p->nAlloc ){ + char *zNew; + p->nAlloc = p->nUsed + nText + 1000; + zNew = sqliteRealloc(p->z, p->nAlloc); + if( zNew==0 ){ + sqliteFree(p->z); + memset(p, 0, sizeof(*p)); + return; + } + p->z = zNew; + } + memcpy(&p->z[p->nUsed], zText, nText+1); + p->nUsed += nText; +} + +/* +** Append text to a dynamic string, having first put the text in quotes. +*/ +static void appendQuoted(dynStr *p, const char *zText){ + int i, j; + appendText(p, "'", 1); + for(i=j=0; zText[i]; i++){ + if( zText[i]='\'' ){ + appendText(p, &zText[j], i-j+1); + j = i + 1; + appendText(p, "'", 1); + } + } + if( jexplain ){ + return; + } + db = pParse->db; + if( db->flags & SQLITE_InTrans ){ + sqliteErrorMsg(pParse, "cannot VACUUM from within a transaction"); + return; + } + memset(&sStr, 0, sizeof(sStr)); + + /* Get the full pathname of the database file and create two + ** temporary filenames in the same directory as the original file. + */ + zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt); + if( zFilename==0 ){ + /* This only happens with the in-memory database. VACUUM is a no-op + ** there, so just return */ + return; + } + nFilename = strlen(zFilename); + zTemp = sqliteMalloc( 2*(nFilename+40) ); + if( zTemp==0 ) return; + zTemp2 = &zTemp[nFilename+40]; + strcpy(zTemp, zFilename); + strcpy(zTemp2, zFilename); + for(i=0; i<10; i++){ + zTemp[nFilename] = '-'; + randomName(&zTemp[nFilename+1]); + randomName(&zTemp2[nFilename+1]); + if( !sqliteOsFileExists(zTemp) && !sqliteOsFileExists(zTemp2) ) break; + } + if( i>=10 ){ + sqliteErrorMsg(pParse, "unable to create a temporary database files " + "in the same directory as the original database"); + goto end_of_vacuum; + } + + + dbNew = sqlite_open(zTemp, 0, &zErrMsg); + if( dbNew==0 ){ + sqliteErrorMsg(pParse, "unable to open a temporary database at %s - %s", + zTemp, zErrMsg); + goto end_of_vacuum; + } + appendText(&sStr, "ATTACH DATABASE ", -1); + appendQuoted(&sStr, zFilename); + appendText(&sStr, " AS orig;\nBEGIN;\n", -1); + if( execsql(pParse, dbNew, sStr.z) ) goto end_of_vacuum; + sStr.nUsed = 0; + rc = sqlite_exec(dbNew, "SELECT type, name, sql FROM sqlite_master " + "WHERE sql NOT NULL", vacuumCallback, &sStr, &zErrMsg); + if( rc ){ + sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg); + goto end_of_vacuum; + } + appendText(&sStr, "COMMIT;\n", -1); + if( execsql(pParse, dbNew, sStr.z) ) goto end_of_vacuum; + + + +end_of_vacuum: + sqliteFree(zTemp); + sqliteFree(zSql); + sqliteFree(sStr.z); + if( zErrMsg ) sqlite_freemem(zErrMsg); + if( dbNew ) sqlite_close(dbNew); #endif } diff --git a/src/vdbe.c b/src/vdbe.c index 7579255ea7..c160dacd5f 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -36,7 +36,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.212 2003/04/13 18:26:52 paul Exp $ +** $Id: vdbe.c,v 1.213 2003/04/15 01:19:49 drh Exp $ */ #include "sqliteInt.h" #include @@ -3503,7 +3503,7 @@ case OP_OpenTemp: { cleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); pCx->nullRow = 1; - rc = sqliteBtreeFactory(db, ":temp:", 1, TEMP_PAGES, &pCx->pBt); + rc = sqliteBtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt);