mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Fix vacuum so that it works with blobs. (CVS 1490)
FossilOrigin-Name: 4feb4b9a71ce7a92924d2358a7ccecb4cca19223
This commit is contained in:
28
manifest
28
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Avoid\sarithmetic\son\svoid\spointers.\s(CVS\s1489)
|
C Fix\svacuum\sso\sthat\sit\sworks\swith\sblobs.\s(CVS\s1490)
|
||||||
D 2004-05-29T02:44:02
|
D 2004-05-29T10:23:19
|
||||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@@ -24,9 +24,9 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
|
|||||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||||
F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
|
F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
|
||||||
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
||||||
F src/btree.c 6db76fbf63efd6008c5e6cb038ea40f94abffcf7
|
F src/btree.c 7832e4247f0d14dfe25dcf85647ddde71b614170
|
||||||
F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545
|
F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545
|
||||||
F src/build.c ed09cd54a48ef2ef700c7e3a63b5e35224bde9cc
|
F src/build.c f97826762d40dbde5f25ebaa009976078ba8b7ff
|
||||||
F src/date.c 0eb922af5c5f5e2455f8dc2f98023ed3e04a857e
|
F src/date.c 0eb922af5c5f5e2455f8dc2f98023ed3e04a857e
|
||||||
F src/delete.c 72f8febf6170cda830f509c8f9dffbed3df3596c
|
F src/delete.c 72f8febf6170cda830f509c8f9dffbed3df3596c
|
||||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||||
@@ -36,7 +36,7 @@ F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
|||||||
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
||||||
F src/insert.c dd117e8b3f50e943e6cf5fbcf4bbdc0b907b0b4c
|
F src/insert.c dd117e8b3f50e943e6cf5fbcf4bbdc0b907b0b4c
|
||||||
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
|
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
|
||||||
F src/main.c a6f3739a30d378128d424bb9add01103845ba6a5
|
F src/main.c 79f8142ee2dbf0e3b1f60251515fcf4a1339e784
|
||||||
F src/md5.c d2c738fedfb27f73cefcf2b0ac1f9f21894b073e
|
F src/md5.c d2c738fedfb27f73cefcf2b0ac1f9f21894b073e
|
||||||
F src/os.h ab42f4a7c4c716f26b988e759b6e12085a3bfc67
|
F src/os.h ab42f4a7c4c716f26b988e759b6e12085a3bfc67
|
||||||
F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f
|
F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f
|
||||||
@@ -48,7 +48,7 @@ F src/os_win.c 92b51a38437b98d8aa3ac05b57c71e1d1092e5be
|
|||||||
F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d
|
F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d
|
||||||
F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
|
F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
|
||||||
F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
|
F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
|
||||||
F src/parse.y fbb2378795cad3f6141836fb2035b97bd5ddad4e
|
F src/parse.y facaa7d07885fb9d53ec8fd676705715d3942b0f
|
||||||
F src/pragma.c 0c17b613d719c62a0dbad659b7d8a6e7ce7e9733
|
F src/pragma.c 0c17b613d719c62a0dbad659b7d8a6e7ce7e9733
|
||||||
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
|
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
|
||||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||||
@@ -64,11 +64,11 @@ F src/test3.c 5e4a6d596f982f6f47a5f9f75ede9b4a3b739968
|
|||||||
F src/test4.c 34848a9fd31aa65857b20a8bfc03aff77d8c3426
|
F src/test4.c 34848a9fd31aa65857b20a8bfc03aff77d8c3426
|
||||||
F src/test5.c 9a1f15133f6955f067c5246e564723b5f23ff221
|
F src/test5.c 9a1f15133f6955f067c5246e564723b5f23ff221
|
||||||
F src/tokenize.c 50a87c7414de54a008427c9fed22e4e86efb6844
|
F src/tokenize.c 50a87c7414de54a008427c9fed22e4e86efb6844
|
||||||
F src/trigger.c 9040e5dd7e5586e863c20acdca6808e8f7bb9727
|
F src/trigger.c 6a0751fd7d3d723f414ac1f877f16b1c0ba4722b
|
||||||
F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
|
F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
|
||||||
F src/utf.c f8604999a54483533ac20a63879074f01b0df384
|
F src/utf.c f8604999a54483533ac20a63879074f01b0df384
|
||||||
F src/util.c 4df9d9b0d930d81ec581bcb68748e7c48bdc8c7d
|
F src/util.c 4df9d9b0d930d81ec581bcb68748e7c48bdc8c7d
|
||||||
F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
|
F src/vacuum.c 53539c1d1f25b329c5f3c880f7b4427bef73183d
|
||||||
F src/vdbe.c ea010d63dfdf84b7d23781144fe2cd11add2c1bd
|
F src/vdbe.c ea010d63dfdf84b7d23781144fe2cd11add2c1bd
|
||||||
F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
|
F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
|
||||||
F src/vdbeInt.h c2bcd6e5a6e6a3753e4c5a368629c3a625719bfc
|
F src/vdbeInt.h c2bcd6e5a6e6a3753e4c5a368629c3a625719bfc
|
||||||
@@ -77,9 +77,9 @@ F src/vdbeaux.c bbcf1bb953526130495b01b23751cf756cfed2fb
|
|||||||
F src/vdbemem.c c97c145ff6d9fc5b4236704c04a65849117e6214
|
F src/vdbemem.c c97c145ff6d9fc5b4236704c04a65849117e6214
|
||||||
F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
|
F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
F test/attach.test e872e1cf3e97949727d1a2c9582efeaf04b192a3
|
F test/attach.test 0dd7cf9bf9bc915bce2da4fb616c4ea9c3da64af
|
||||||
F test/attach2.test 5472d442bb2ef1ee587e0ae7472bb68b52509a38
|
F test/attach2.test 5472d442bb2ef1ee587e0ae7472bb68b52509a38
|
||||||
F test/attach3.test 65c52f1e5f435518db06a877eed6afe2cac652c9
|
F test/attach3.test d384ac2e59f305743f73aec4b3d97b36fa5c6975
|
||||||
F test/auth.test 95809b8f6a9bec18b94d28cafd03fe27d2f8a9e9
|
F test/auth.test 95809b8f6a9bec18b94d28cafd03fe27d2f8a9e9
|
||||||
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
@@ -159,7 +159,7 @@ F test/types.test 6c49e574970866558365a025b44c9fd8a162ef0d
|
|||||||
F test/types2.test 5d725fcb68dbd032c6d4950d568d75fa33872687
|
F test/types2.test 5d725fcb68dbd032c6d4950d568d75fa33872687
|
||||||
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
||||||
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
||||||
F test/vacuum.test c083e578c4f159b1ce7b5a4594149fd19b3f4f5f
|
F test/vacuum.test d1f1e033307740bf2bc7c51b43d2ccffbfe3548c
|
||||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||||
F test/version.test 2ba212ba06380e65e476bdf2fcd390e8b05af5a0
|
F test/version.test 2ba212ba06380e65e476bdf2fcd390e8b05af5a0
|
||||||
F test/view.test 1ee12c6f8f4791a2c0655120d5562a49400cfe53
|
F test/view.test 1ee12c6f8f4791a2c0655120d5562a49400cfe53
|
||||||
@@ -204,7 +204,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
|||||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||||
P 4060a37d0baaa60c50f2dde4a1ab344133fcabbb
|
P 3d68703e2e4e793012cb3c13a6744e915475e006
|
||||||
R d21f0b4291c09165c09eb3b6a7a0c291
|
R f8accc05ba8c9231b807adb94db50997
|
||||||
U danielk1977
|
U danielk1977
|
||||||
Z 0bb4938ee61dc0247765dcbff1fe235c
|
Z ed82235366e6cbf4a32cc9a53171200e
|
||||||
|
@@ -1 +1 @@
|
|||||||
3d68703e2e4e793012cb3c13a6744e915475e006
|
4feb4b9a71ce7a92924d2358a7ccecb4cca19223
|
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.147 2004/05/26 00:01:54 drh Exp $
|
** $Id: btree.c,v 1.148 2004/05/29 10:23:19 danielk1977 Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -4150,7 +4150,7 @@ const char *sqlite3BtreeGetFilename(Btree *pBt){
|
|||||||
** must be active for both files.
|
** must be active for both files.
|
||||||
**
|
**
|
||||||
** The size of file pBtFrom may be reduced by this operation.
|
** The size of file pBtFrom may be reduced by this operation.
|
||||||
** If anything goes wrong, the transaction on pBtFrom is rolled back.
|
** If anything goes wrong, the transaction on pBtTo is rolled back.
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
15
src/build.c
15
src/build.c
@@ -23,7 +23,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.198 2004/05/29 02:37:19 danielk1977 Exp $
|
** $Id: build.c,v 1.199 2004/05/29 10:23:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -566,14 +566,11 @@ void sqlite3StartTable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the new table name does not collide with an existing
|
/* Make sure the new table name does not collide with an existing
|
||||||
** index or table name. Issue an error message if it does.
|
** index or table name in the same database. Issue an error message if
|
||||||
**
|
** it does.
|
||||||
** If we are re-reading the sqlite_master table because of a schema
|
|
||||||
** change and a new permanent table is found whose name collides with
|
|
||||||
** an existing temporary table, that is not an error.
|
|
||||||
*/
|
*/
|
||||||
pTable = sqlite3FindTable(db, zName, 0);
|
pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
|
||||||
if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
|
if( pTable ){
|
||||||
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
||||||
sqliteFree(zName);
|
sqliteFree(zName);
|
||||||
return;
|
return;
|
||||||
@@ -1691,7 +1688,7 @@ void sqlite3CreateIndex(
|
|||||||
Table *pTSameName; /* A table with same name as the index */
|
Table *pTSameName; /* A table with same name as the index */
|
||||||
zName = sqliteStrNDup(pName->z, pName->n);
|
zName = sqliteStrNDup(pName->z, pName->n);
|
||||||
if( zName==0 ) goto exit_create_index;
|
if( zName==0 ) goto exit_create_index;
|
||||||
if( (pISameName = sqlite3FindIndex(db, zName, 0))!=0 ){
|
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
|
||||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
|
63
src/main.c
63
src/main.c
@@ -14,7 +14,7 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** accessed by users of the library.
|
||||||
**
|
**
|
||||||
** $Id: main.c,v 1.195 2004/05/27 23:56:16 danielk1977 Exp $
|
** $Id: main.c,v 1.196 2004/05/29 10:23:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -247,16 +247,28 @@ static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||||||
memset(meta, 0, sizeof(meta));
|
memset(meta, 0, sizeof(meta));
|
||||||
}
|
}
|
||||||
db->aDb[iDb].schema_cookie = meta[0];
|
db->aDb[iDb].schema_cookie = meta[0];
|
||||||
if( iDb==0 ){
|
|
||||||
db->next_cookie = meta[0];
|
/* If opening a non-empty database, check the text encoding. For the
|
||||||
db->file_format = meta[1];
|
** main database, set sqlite3.enc to the encoding of the main database.
|
||||||
if( meta[4] ){
|
** For an attached db, it is an error if the encoding is not the same
|
||||||
/* If meta[4] is still zero, then we are opening a previously empty
|
** as sqlite3.enc.
|
||||||
** file. Leave db->enc to the default value set by the sqlite3_open()
|
*/
|
||||||
** call in this case.
|
if( meta[4] ){ /* text encoding */
|
||||||
*/
|
if( iDb==0 ){
|
||||||
|
/* If opening the main database, set db->enc. */
|
||||||
db->enc = (u8)meta[4];
|
db->enc = (u8)meta[4];
|
||||||
|
}else{
|
||||||
|
/* If opening an attached database, the encoding much match db->enc */
|
||||||
|
if( meta[4]!=db->enc ){
|
||||||
|
sqlite3BtreeCloseCursor(curMain);
|
||||||
|
sqlite3SetString(pzErrMsg, "attached databases must use the same"
|
||||||
|
" text encoding as main database", (char*)0);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iDb==0 ){
|
||||||
size = meta[2];
|
size = meta[2];
|
||||||
if( size==0 ){ size = MAX_PAGES; }
|
if( size==0 ){ size = MAX_PAGES; }
|
||||||
db->cache_size = size;
|
db->cache_size = size;
|
||||||
@@ -266,40 +278,35 @@ static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||||||
}
|
}
|
||||||
if( db->safety_level==0 ) db->safety_level = 2;
|
if( db->safety_level==0 ) db->safety_level = 2;
|
||||||
|
|
||||||
/*
|
/* FIX ME: Every struct Db will need a next_cookie */
|
||||||
** file_format==1 Version 3.0.0.
|
db->next_cookie = meta[0];
|
||||||
*/
|
db->file_format = meta[1];
|
||||||
if( db->file_format==0 ){
|
if( db->file_format==0 ){
|
||||||
/* This happens if the database was initially empty */
|
/* This happens if the database was initially empty */
|
||||||
db->file_format = 1;
|
db->file_format = 1;
|
||||||
}else if( db->file_format>1 ){
|
|
||||||
sqlite3BtreeCloseCursor(curMain);
|
|
||||||
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
|
||||||
return SQLITE_ERROR;
|
|
||||||
}
|
}
|
||||||
}else if( db->file_format!=meta[1] ){
|
|
||||||
if( meta[1]==0 ){
|
|
||||||
sqlite3SetString(pzErrMsg, "cannot attach empty database: ",
|
|
||||||
db->aDb[iDb].zName, (char*)0);
|
|
||||||
}else{
|
|
||||||
sqlite3SetString(pzErrMsg, "incompatible file format in auxiliary "
|
|
||||||
"database: ", db->aDb[iDb].zName, (char*)0);
|
|
||||||
}
|
|
||||||
sqlite3BtreeClose(db->aDb[iDb].pBt);
|
|
||||||
db->aDb[iDb].pBt = 0;
|
|
||||||
return SQLITE_FORMAT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** file_format==1 Version 3.0.0.
|
||||||
|
*/
|
||||||
|
if( meta[1]>1 ){
|
||||||
|
sqlite3BtreeCloseCursor(curMain);
|
||||||
|
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size);
|
sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size);
|
||||||
sqlite3BtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[3]==0 ? 2 : meta[3]);
|
sqlite3BtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[3]==0 ? 2 : meta[3]);
|
||||||
|
|
||||||
/* Read the schema information out of the schema tables
|
/* Read the schema information out of the schema tables
|
||||||
*/
|
*/
|
||||||
assert( db->init.busy );
|
assert( db->init.busy );
|
||||||
sqlite3SafetyOff(db);
|
|
||||||
if( rc==SQLITE_EMPTY ){
|
if( rc==SQLITE_EMPTY ){
|
||||||
/* For an empty database, there is nothing to read */
|
/* For an empty database, there is nothing to read */
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}else{
|
}else{
|
||||||
|
sqlite3SafetyOff(db);
|
||||||
if( iDb==0 ){
|
if( iDb==0 ){
|
||||||
/* This SQL statement tries to read the temp.* schema from the
|
/* This SQL statement tries to read the temp.* schema from the
|
||||||
** sqlite_temp_master table. It might return SQLITE_EMPTY.
|
** sqlite_temp_master table. It might return SQLITE_EMPTY.
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.123 2004/05/29 02:37:19 danielk1977 Exp $
|
** @(#) $Id: parse.y,v 1.124 2004/05/29 10:23:20 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@@ -782,17 +782,18 @@ plus_opt ::= .
|
|||||||
|
|
||||||
//////////////////////////// The CREATE TRIGGER command /////////////////////
|
//////////////////////////// The CREATE TRIGGER command /////////////////////
|
||||||
|
|
||||||
cmd ::= CREATE(A) trigger_decl BEGIN trigger_cmd_list(S) END(Z). {
|
cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
|
||||||
Token all;
|
Token all;
|
||||||
all.z = A.z;
|
all.z = A.z;
|
||||||
all.n = (Z.z - A.z) + Z.n;
|
all.n = (Z.z - A.z) + Z.n;
|
||||||
sqlite3FinishTrigger(pParse, S, &all);
|
sqlite3FinishTrigger(pParse, S, &all);
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger_decl ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C) trigger_event(D)
|
trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C) trigger_event(D)
|
||||||
ON nm(E) dbnm(DB) foreach_clause(F) when_clause(G). {
|
ON nm(E) dbnm(DB) foreach_clause(F) when_clause(G). {
|
||||||
SrcList *pTab = sqlite3SrcListAppend(0, &E, &DB);
|
SrcList *pTab = sqlite3SrcListAppend(0, &E, &DB);
|
||||||
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, pTab, F, G, T);
|
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, pTab, F, G, T);
|
||||||
|
A = (Z.n==0?B:Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
%type trigger_time {int}
|
%type trigger_time {int}
|
||||||
|
@@ -213,7 +213,9 @@ void sqlite3FinishTrigger(
|
|||||||
{ OP_String, 0, 0, 0 }, /* 2: trigger name */
|
{ OP_String, 0, 0, 0 }, /* 2: trigger name */
|
||||||
{ OP_String, 0, 0, 0 }, /* 3: table name */
|
{ OP_String, 0, 0, 0 }, /* 3: table name */
|
||||||
{ OP_Integer, 0, 0, 0 },
|
{ OP_Integer, 0, 0, 0 },
|
||||||
{ OP_String, 0, 0, 0 }, /* 5: SQL */
|
{ OP_String, 0, 0, "CREATE TRIGGER "},
|
||||||
|
{ OP_String, 0, 0, 0 }, /* 6: SQL */
|
||||||
|
{ OP_Concat, 2, 0, 0 },
|
||||||
{ OP_MakeRecord, 5, 0, "tttit" },
|
{ OP_MakeRecord, 5, 0, "tttit" },
|
||||||
{ OP_PutIntKey, 0, 0, 0 },
|
{ OP_PutIntKey, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
@@ -228,7 +230,7 @@ void sqlite3FinishTrigger(
|
|||||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||||
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
|
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
|
||||||
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
|
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
|
||||||
sqlite3VdbeChangeP3(v, addr+5, pAll->z, pAll->n);
|
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
|
||||||
if( nt->iDb==0 ){
|
if( nt->iDb==0 ){
|
||||||
sqlite3ChangeCookie(db, v, 0);
|
sqlite3ChangeCookie(db, v, 0);
|
||||||
}
|
}
|
||||||
|
386
src/vacuum.c
386
src/vacuum.c
@@ -14,173 +14,12 @@
|
|||||||
** Most of the code in this file may be omitted by defining the
|
** Most of the code in this file may be omitted by defining the
|
||||||
** SQLITE_OMIT_VACUUM macro.
|
** SQLITE_OMIT_VACUUM macro.
|
||||||
**
|
**
|
||||||
** $Id: vacuum.c,v 1.16 2004/05/22 09:21:21 danielk1977 Exp $
|
** $Id: vacuum.c,v 1.17 2004/05/29 10:23:20 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
/*
|
|
||||||
** 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[] */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** A structure that holds the vacuum context
|
|
||||||
*/
|
|
||||||
typedef struct vacuumStruct vacuumStruct;
|
|
||||||
struct vacuumStruct {
|
|
||||||
sqlite *dbOld; /* Original database */
|
|
||||||
sqlite *dbNew; /* New database */
|
|
||||||
char **pzErrMsg; /* Write errors here */
|
|
||||||
int rc; /* Set to non-zero on an error */
|
|
||||||
const char *zTable; /* Name of a table being copied */
|
|
||||||
const char *zPragma; /* Pragma to execute with results */
|
|
||||||
dynStr s1, s2; /* Two dynamic strings */
|
|
||||||
};
|
|
||||||
|
|
||||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
#if !defined(SQLITE_OMIT_VACUUM) || 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( j<i ){
|
|
||||||
appendText(p, &zText[j], i-j);
|
|
||||||
}
|
|
||||||
appendText(p, "'", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Execute statements of SQL. If an error occurs, write the error
|
|
||||||
** message into *pzErrMsg and return non-zero.
|
|
||||||
*/
|
|
||||||
static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){
|
|
||||||
char *zErrMsg = 0;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* printf("***** executing *****\n%s\n", zSql); */
|
|
||||||
rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
|
|
||||||
if( zErrMsg ){
|
|
||||||
sqlite3SetString(pzErrMsg, zErrMsg, (char*)0);
|
|
||||||
sqlite3_freemem(zErrMsg);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This is the second stage callback. Each invocation contains all the
|
|
||||||
** data for a single row of a single table in the original database. This
|
|
||||||
** routine must write that information into the new database.
|
|
||||||
*/
|
|
||||||
static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
|
|
||||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
|
||||||
const char *zSep = "(";
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if( argv==0 ) return 0;
|
|
||||||
p->s2.nUsed = 0;
|
|
||||||
appendText(&p->s2, "INSERT INTO ", -1);
|
|
||||||
appendQuoted(&p->s2, p->zTable);
|
|
||||||
appendText(&p->s2, " VALUES", -1);
|
|
||||||
for(i=0; i<argc; i++){
|
|
||||||
appendText(&p->s2, zSep, 1);
|
|
||||||
zSep = ",";
|
|
||||||
if( argv[i]==0 ){
|
|
||||||
appendText(&p->s2, "NULL", 4);
|
|
||||||
}else{
|
|
||||||
appendQuoted(&p->s2, argv[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appendText(&p->s2,")", 1);
|
|
||||||
p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
|
|
||||||
return p->rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This is the first stage callback. Each invocation contains three
|
|
||||||
** arguments where are taken from the SQLITE_MASTER table of the original
|
|
||||||
** database: (1) the entry type, (2) the entry name, and (3) the SQL for
|
|
||||||
** the entry. In all cases, execute the SQL of the third argument.
|
|
||||||
** For tables, run a query to select all entries in that table and
|
|
||||||
** transfer them to the second-stage callback.
|
|
||||||
*/
|
|
||||||
static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
|
|
||||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
|
||||||
int rc = 0;
|
|
||||||
assert( argc==3 );
|
|
||||||
if( argv==0 ) return 0;
|
|
||||||
assert( argv[0]!=0 );
|
|
||||||
assert( argv[1]!=0 );
|
|
||||||
assert( argv[2]!=0 );
|
|
||||||
rc = execsql(p->pzErrMsg, p->dbNew, argv[2]);
|
|
||||||
if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){
|
|
||||||
char *zErrMsg = 0;
|
|
||||||
p->s1.nUsed = 0;
|
|
||||||
appendText(&p->s1, "SELECT * FROM ", -1);
|
|
||||||
appendQuoted(&p->s1, argv[1]);
|
|
||||||
p->zTable = argv[1];
|
|
||||||
rc = sqlite3_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg);
|
|
||||||
if( zErrMsg ){
|
|
||||||
sqlite3SetString(p->pzErrMsg, zErrMsg, (char*)0);
|
|
||||||
sqlite3_freemem(zErrMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_ABORT ) p->rc = rc;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This callback is used to transfer PRAGMA settings from one database
|
|
||||||
** to the other. The value in argv[0] should be passed to a pragma
|
|
||||||
** identified by ((vacuumStruct*)pArg)->zPragma.
|
|
||||||
*/
|
|
||||||
static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
|
|
||||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
|
||||||
char zBuf[200];
|
|
||||||
assert( argc==1 );
|
|
||||||
if( argv==0 ) return 0;
|
|
||||||
assert( argv[0]!=0 );
|
|
||||||
assert( strlen(p->zPragma)<100 );
|
|
||||||
assert( strlen(argv[0])<30 );
|
|
||||||
sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]);
|
|
||||||
p->rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
|
|
||||||
return p->rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate a random name of 20 character in length.
|
** Generate a random name of 20 character in length.
|
||||||
*/
|
*/
|
||||||
@@ -194,6 +33,41 @@ static void randomName(unsigned char *zBuf){
|
|||||||
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
|
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Execute zSql on database db. Return an error code.
|
||||||
|
*/
|
||||||
|
static int execSql(sqlite3 *db, const char *zSql){
|
||||||
|
sqlite3_stmt *pStmt;
|
||||||
|
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||||
|
return sqlite3_errcode(db);
|
||||||
|
}
|
||||||
|
while( SQLITE_ROW==sqlite3_step(pStmt) );
|
||||||
|
return sqlite3_finalize(pStmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Execute zSql on database db. The statement returns exactly
|
||||||
|
** one column. Execute this as SQL on the same database.
|
||||||
|
*/
|
||||||
|
static int execExecSql(sqlite3 *db, const char *zSql){
|
||||||
|
sqlite3_stmt *pStmt;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
|
||||||
|
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||||
|
rc = execSql(db, sqlite3_column_text(pStmt, 0));
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_finalize(pStmt);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -216,108 +90,150 @@ void sqlite3Vacuum(Parse *pParse, Token *pTableName){
|
|||||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||||
*/
|
*/
|
||||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
|
int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
|
||||||
|
int rc = SQLITE_OK; /* Return code from service routines */
|
||||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
||||||
const char *zFilename; /* full pathname of the database file */
|
const char *zFilename; /* full pathname of the database file */
|
||||||
int nFilename; /* number of characters in zFilename[] */
|
int nFilename; /* number of characters in zFilename[] */
|
||||||
char *zTemp = 0; /* a temporary file in same directory as zFilename */
|
char *zTemp = 0; /* a temporary file in same directory as zFilename */
|
||||||
sqlite *dbNew = 0; /* The new vacuumed database */
|
|
||||||
int rc = SQLITE_OK; /* Return code from service routines */
|
|
||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
char *zErrMsg; /* Error message */
|
|
||||||
vacuumStruct sVac; /* Information passed to callbacks */
|
|
||||||
|
|
||||||
/* These are all of the pragmas that need to be transferred over
|
char *zSql = 0;
|
||||||
** to the new database */
|
sqlite3_stmt *pStmt = 0;
|
||||||
static const char *zPragma[] = {
|
|
||||||
"default_synchronous",
|
|
||||||
"default_cache_size",
|
|
||||||
/* "default_temp_store", */
|
|
||||||
};
|
|
||||||
|
|
||||||
if( db->flags & SQLITE_InTrans ){
|
if( db->flags & SQLITE_InTrans ){
|
||||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||||
(char*)0);
|
(char*)0);
|
||||||
return SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
|
goto end_of_vacuum;
|
||||||
}
|
}
|
||||||
memset(&sVac, 0, sizeof(sVac));
|
|
||||||
|
|
||||||
/* Get the full pathname of the database file and create two
|
/* Get the full pathname of the database file and create a
|
||||||
** temporary filenames in the same directory as the original file.
|
** temporary filename in the same directory as the original file.
|
||||||
*/
|
*/
|
||||||
zFilename = sqlite3BtreeGetFilename(db->aDb[0].pBt);
|
zFilename = sqlite3BtreeGetFilename(db->aDb[0].pBt);
|
||||||
if( zFilename==0 ){
|
if( zFilename==0 ){
|
||||||
/* This only happens with the in-memory database. VACUUM is a no-op
|
/* The in-memory database. Do nothing. */
|
||||||
** there, so just return */
|
goto end_of_vacuum;
|
||||||
return SQLITE_OK;
|
|
||||||
}
|
}
|
||||||
nFilename = strlen(zFilename);
|
nFilename = strlen(zFilename);
|
||||||
zTemp = sqliteMalloc( nFilename+100 );
|
zTemp = sqliteMalloc( nFilename+100 );
|
||||||
if( zTemp==0 ) return SQLITE_NOMEM;
|
if( zTemp==0 ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
goto end_of_vacuum;
|
||||||
|
}
|
||||||
strcpy(zTemp, zFilename);
|
strcpy(zTemp, zFilename);
|
||||||
for(i=0; i<10; i++){
|
for(i=0; i<10; i++){
|
||||||
zTemp[nFilename] = '-';
|
zTemp[nFilename] = '-';
|
||||||
randomName((unsigned char*)&zTemp[nFilename+1]);
|
randomName((unsigned char*)&zTemp[nFilename+1]);
|
||||||
if( !sqlite3OsFileExists(zTemp) ) break;
|
if( !sqlite3OsFileExists(zTemp) ) break;
|
||||||
}
|
}
|
||||||
if( i>=10 ){
|
|
||||||
sqlite3SetString(pzErrMsg, "unable to create a temporary database file "
|
|
||||||
"in the same directory as the original database", (char*)0);
|
|
||||||
goto end_of_vacuum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Attach the temporary database as 'vacuum' */
|
||||||
if( SQLITE_OK!=sqlite3_open(zTemp, &dbNew, 0) ){
|
zSql = sqlite3MPrintf("ATTACH '%s' AS vacuum_db;", zTemp);
|
||||||
sqlite3SetString(pzErrMsg, "unable to open a temporary database at ",
|
if( !zSql ){
|
||||||
zTemp, " - ", sqlite3_errmsg(dbNew), (char*)0);
|
rc = SQLITE_NOMEM;
|
||||||
goto end_of_vacuum;
|
goto end_of_vacuum;
|
||||||
}
|
}
|
||||||
if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
|
rc = execSql(db, zSql);
|
||||||
if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
|
sqliteFree(zSql);
|
||||||
goto end_of_vacuum;
|
zSql = 0;
|
||||||
}
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
|
||||||
sVac.dbOld = db;
|
/* Begin a transaction */
|
||||||
sVac.dbNew = dbNew;
|
rc = execSql(db, "BEGIN;");
|
||||||
sVac.pzErrMsg = pzErrMsg;
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){
|
|
||||||
char zBuf[200];
|
/* Query the schema of the main database. Create a mirror schema
|
||||||
assert( strlen(zPragma[i])<100 );
|
** in the temporary database.
|
||||||
sprintf(zBuf, "PRAGMA %s;", zPragma[i]);
|
*/
|
||||||
sVac.zPragma = zPragma[i];
|
rc = execExecSql(db,
|
||||||
rc = sqlite3_exec(db, zBuf, vacuumCallback3, &sVac, &zErrMsg);
|
"SELECT 'CREATE ' || type || ' vacuum_db.' || "
|
||||||
}
|
"substr(sql, length(type)+9, 1000000) "
|
||||||
if( rc==SQLITE_OK ){
|
"FROM sqlite_master "
|
||||||
rc = sqlite3_exec(db,
|
"WHERE type != 'trigger' AND sql IS NOT NULL "
|
||||||
"SELECT type, name, sql FROM sqlite_master "
|
"ORDER BY (type != 'table');"
|
||||||
"WHERE sql NOT NULL AND type!='view' "
|
);
|
||||||
"UNION ALL "
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
"SELECT type, name, sql FROM sqlite_master "
|
|
||||||
"WHERE sql NOT NULL AND type=='view'",
|
/* Loop through the tables in the main database. For each, do
|
||||||
vacuumCallback1, &sVac, &zErrMsg);
|
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
|
||||||
}
|
** the contents to the temporary database.
|
||||||
if( rc==SQLITE_OK ){
|
*/
|
||||||
rc = sqlite3BtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt);
|
rc = execExecSql(db,
|
||||||
sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
"SELECT 'INSERT INTO vacuum_db.' || name "
|
||||||
sqlite3ResetInternalSchema(db, 0);
|
"|| ' SELECT * FROM ' || name || ';'"
|
||||||
|
"FROM sqlite_master "
|
||||||
|
"WHERE type = 'table';"
|
||||||
|
);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
|
||||||
|
/* Copy the triggers from the main database to the temporary database.
|
||||||
|
** This was deferred before in case the triggers interfered with copying
|
||||||
|
** the data. It's possible the indices should be deferred until this
|
||||||
|
** point also.
|
||||||
|
*/
|
||||||
|
rc = execExecSql(db,
|
||||||
|
"SELECT 'CREATE ' || type || ' vacuum_db.' || "
|
||||||
|
"substr(sql, length(type)+9, 1000000) "
|
||||||
|
"FROM sqlite_master "
|
||||||
|
"WHERE type = 'trigger' AND sql IS NOT NULL;"
|
||||||
|
);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
|
||||||
|
|
||||||
|
/* At this point, unless the main db was completely empty, there is now a
|
||||||
|
** transaction open on the vacuum database, but not on the main database.
|
||||||
|
** Open a btree level transaction on the main database. This allows a
|
||||||
|
** call to sqlite3BtreeCopyFile(). The main database btree level
|
||||||
|
** transaction is then committed, so the SQL level never knows it was
|
||||||
|
** opened for writing. This way, the SQL transaction used to create the
|
||||||
|
** temporary database never needs to be committed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIX ME: The above will be the case shortly. But for now, a transaction
|
||||||
|
** will have been started on the main database file by the 'BEGIN'.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( db->aDb[db->nDb-1].inTrans ){
|
||||||
|
Btree *pTemp = db->aDb[db->nDb-1].pBt;
|
||||||
|
Btree *pMain = db->aDb[0].pBt;
|
||||||
|
u32 meta;
|
||||||
|
|
||||||
|
/* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
|
||||||
|
** values 2 and 3, the default values of a couple of pragmas.
|
||||||
|
*/
|
||||||
|
rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
|
||||||
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||||
|
|
||||||
|
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||||
|
|
||||||
|
/* FIX ME: Remove the main btree from the transaction so that it is not
|
||||||
|
** rolled back. This won't be required once the new 'auto-commit'
|
||||||
|
** model is in place.
|
||||||
|
*/
|
||||||
|
rc = sqlite3BtreeCommit(pMain);
|
||||||
|
db->aDb[0].inTrans = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_of_vacuum:
|
end_of_vacuum:
|
||||||
if( rc && zErrMsg!=0 ){
|
execSql(db, "DETACH vacuum_db;");
|
||||||
sqlite3SetString(pzErrMsg, "unable to vacuum database - ",
|
execSql(db, "ROLLBACK;");
|
||||||
zErrMsg, (char*)0);
|
if( zTemp ){
|
||||||
|
sqlite3OsDelete(zTemp);
|
||||||
|
sqliteFree(zTemp);
|
||||||
}
|
}
|
||||||
sqlite3_exec(db, "ROLLBACK", 0, 0, 0);
|
if( zSql ) sqliteFree( zSql );
|
||||||
if( dbNew ) sqlite3_close(dbNew);
|
if( pStmt ) sqlite3_finalize( pStmt );
|
||||||
sqlite3OsDelete(zTemp);
|
|
||||||
sqliteFree(zTemp);
|
|
||||||
sqliteFree(sVac.s1.z);
|
|
||||||
sqliteFree(sVac.s2.z);
|
|
||||||
if( dbNew ) sqlite3_close(dbNew);
|
|
||||||
if( zErrMsg ) sqlite3_freemem(zErrMsg);
|
|
||||||
if( rc==SQLITE_ABORT ) sVac.rc = SQLITE_ERROR;
|
|
||||||
return sVac.rc;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
# focus of this script is testing the ATTACH and DETACH commands
|
# focus of this script is testing the ATTACH and DETACH commands
|
||||||
# and related functionality.
|
# and related functionality.
|
||||||
#
|
#
|
||||||
# $Id: attach.test,v 1.17 2004/05/29 02:37:20 danielk1977 Exp $
|
# $Id: attach.test,v 1.18 2004/05/29 10:23:20 danielk1977 Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@@ -72,17 +72,17 @@ do_test attach-1.8 {
|
|||||||
catchsql {
|
catchsql {
|
||||||
ATTACH DATABASE 'test3.db' AS three;
|
ATTACH DATABASE 'test3.db' AS three;
|
||||||
}
|
}
|
||||||
} {1 {cannot attach empty database: three}}
|
} {0 {}}
|
||||||
do_test attach-1.9 {
|
do_test attach-1.9 {
|
||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM three.sqlite_master;
|
SELECT * FROM three.sqlite_master;
|
||||||
}
|
}
|
||||||
} {1 {no such table: three.sqlite_master}}
|
} {0 {}}
|
||||||
do_test attach-1.10 {
|
do_test attach-1.10 {
|
||||||
catchsql {
|
catchsql {
|
||||||
DETACH DATABASE three;
|
DETACH DATABASE three;
|
||||||
}
|
}
|
||||||
} {1 {no such database: three}}
|
} {0 {}}
|
||||||
do_test attach-1.11 {
|
do_test attach-1.11 {
|
||||||
execsql {
|
execsql {
|
||||||
ATTACH 'test.db' AS db2;
|
ATTACH 'test.db' AS db2;
|
||||||
@@ -563,7 +563,7 @@ do_test attach-6.1 {
|
|||||||
catchsql {
|
catchsql {
|
||||||
ATTACH DATABASE 'no-such-file' AS nosuch;
|
ATTACH DATABASE 'no-such-file' AS nosuch;
|
||||||
}
|
}
|
||||||
} {1 {cannot attach empty database: nosuch}}
|
} {0 {}}
|
||||||
file delete -force no-such-file
|
file delete -force no-such-file
|
||||||
if {$tcl_platform(platform)=="unix"} {
|
if {$tcl_platform(platform)=="unix"} {
|
||||||
do_test attach-6.2 {
|
do_test attach-6.2 {
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
# focus of this script is testing the ATTACH and DETACH commands
|
# focus of this script is testing the ATTACH and DETACH commands
|
||||||
# and schema changes to attached databases.
|
# and schema changes to attached databases.
|
||||||
#
|
#
|
||||||
# $Id: attach3.test,v 1.4 2004/05/29 02:37:20 danielk1977 Exp $
|
# $Id: attach3.test,v 1.5 2004/05/29 10:23:20 danielk1977 Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ do_test attach3-5.3 {
|
|||||||
execsql {
|
execsql {
|
||||||
SELECT * FROM aux.sqlite_master WHERE name = 'tr1';
|
SELECT * FROM aux.sqlite_master WHERE name = 'tr1';
|
||||||
}
|
}
|
||||||
} {trigger tr1 t3 0 {CREATE TRIGGER aux.tr1 AFTER INSERT ON t3 BEGIN
|
} {trigger tr1 t3 0 {CREATE TRIGGER tr1 AFTER INSERT ON t3 BEGIN
|
||||||
INSERT INTO t3 VALUES(new.e*2, new.f*2);
|
INSERT INTO t3 VALUES(new.e*2, new.f*2);
|
||||||
END}}
|
END}}
|
||||||
|
|
||||||
|
@@ -11,14 +11,16 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the VACUUM statement.
|
# focus of this file is testing the VACUUM statement.
|
||||||
#
|
#
|
||||||
# $Id: vacuum.test,v 1.18 2004/05/26 10:11:07 danielk1977 Exp $
|
# $Id: vacuum.test,v 1.19 2004/05/29 10:23:20 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
proc cksum {{db db}} {
|
proc cksum {{db db}} {
|
||||||
set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
|
set sql "SELECT name, type, sql FROM sqlite_master ORDER BY name, type"
|
||||||
foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
|
set txt [$db eval $sql]\n
|
||||||
|
set sql "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
||||||
|
foreach tbl [$db eval $sql] {
|
||||||
append txt [$db eval "SELECT * FROM $tbl"]\n
|
append txt [$db eval "SELECT * FROM $tbl"]\n
|
||||||
}
|
}
|
||||||
foreach prag {default_synchronous default_cache_size} {
|
foreach prag {default_synchronous default_cache_size} {
|
||||||
|
Reference in New Issue
Block a user