Split the implementation of COPY, PRAGMA, and ATTACH into separate

source code files. (CVS 902)

FossilOrigin-Name: 73359037ea639abb066c74db9c19e84bf1104006
This commit is contained in:
drh 2003-04-06 21:08:24 +00:00
parent e1051c653e
commit c11d4f9360
9 changed files with 793 additions and 680 deletions

View File

@ -62,18 +62,22 @@ ENCODING = @ENCODING@
# Object files for the SQLite library.
#
LIBOBJ = auth.lo btree.lo build.lo delete.lo expr.lo func.lo hash.lo insert.lo \
main.lo opcodes.lo os.lo pager.lo parse.lo printf.lo random.lo \
select.lo table.lo tokenize.lo update.lo util.lo vacuum.lo vdbe.lo \
LIBOBJ = attach.lo auth.lo btree.lo build.lo copy.lo \
delete.lo expr.lo func.lo hash.lo insert.lo \
main.lo opcodes.lo os.lo pager.lo parse.lo pragma.lo \
printf.lo random.lo select.lo table.lo tokenize.lo \
update.lo util.lo vacuum.lo vdbe.lo \
where.lo trigger.lo
# All of the source code files.
#
SRC = \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
$(TOP)/src/copy.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
@ -85,6 +89,7 @@ SRC = \
$(TOP)/src/pager.c \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
$(TOP)/src/select.c \
@ -241,6 +246,9 @@ vdbe.lo: $(TOP)/src/vdbe.c $(HDR)
where.lo: $(TOP)/src/where.c $(HDR)
$(LIBTOOL) $(TCC) -c $(TOP)/src/where.c
copy.lo: $(TOP)/src/copy.c $(HDR)
$(LIBTOOL) $(TCC) -c $(TOP)/src/copy.c
delete.lo: $(TOP)/src/delete.c $(HDR)
$(LIBTOOL) $(TCC) -c $(TOP)/src/delete.c
@ -277,9 +285,15 @@ vacuum.lo: $(TOP)/src/vacuum.c $(HDR)
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LIBTOOL) $(TCC) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
pragma.lo: $(TOP)/src/pragma.c $(HDR)
$(LIBTOOL) $(TCC) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
printf.lo: $(TOP)/src/printf.c $(HDR)
$(LIBTOOL) $(TCC) $(TCL_FLAGS) -c $(TOP)/src/printf.c
attach.lo: $(TOP)/src/attach.c $(HDR)
$(LIBTOOL) $(TCC) $(TCL_FLAGS) -c $(TOP)/src/attach.c
auth.lo: $(TOP)/src/auth.c $(HDR)
$(LIBTOOL) $(TCC) $(TCL_FLAGS) -c $(TOP)/src/auth.c

17
main.mk
View File

@ -54,18 +54,21 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
# Object files for the SQLite library.
#
LIBOBJ = auth.o btree.o build.o delete.o expr.o func.o hash.o insert.o \
main.o opcodes.o os.o pager.o parse.o printf.o random.o \
LIBOBJ = attach.o auth.o btree.o build.o copy.o delete.o \
expr.o func.o hash.o insert.o \
main.o opcodes.o os.o pager.o parse.o pragma.o printf.o random.o \
select.o table.o tokenize.o trigger.o update.o util.o \
vacuum.o vdbe.o where.o tclsqlite.o
# All of the source code files.
#
SRC = \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
$(TOP)/src/copy.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
@ -77,6 +80,7 @@ SRC = \
$(TOP)/src/pager.c \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
$(TOP)/src/select.c \
@ -236,6 +240,9 @@ vdbe.o: $(TOP)/src/vdbe.c $(HDR)
where.o: $(TOP)/src/where.c $(HDR)
$(TCCX) -c $(TOP)/src/where.c
copy.o: $(TOP)/src/copy.c $(HDR)
$(TCCX) -c $(TOP)/src/copy.c
delete.o: $(TOP)/src/delete.c $(HDR)
$(TCCX) -c $(TOP)/src/delete.c
@ -266,9 +273,15 @@ update.o: $(TOP)/src/update.c $(HDR)
tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
pragma.o: $(TOP)/src/pragma.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
printf.o: $(TOP)/src/printf.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/printf.c
attach.o: $(TOP)/src/attach.c $(HDR)
$(TCCX) -c $(TOP)/src/attach.c
auth.o: $(TOP)/src/auth.c $(HDR)
$(TCCX) -c $(TOP)/src/auth.c

View File

@ -1,6 +1,6 @@
C Move\sthe\simplementation\sof\sVACUUM\sinto\sa\sseparate\ssource\sfile.\s(CVS\s901)
D 2003-04-06T20:52:32
F Makefile.in 5b084c4a4abf08fa5cdebe78ccebf6310198139c
C Split\sthe\simplementation\sof\sCOPY,\sPRAGMA,\sand\sATTACH\sinto\sseparate\nsource\scode\sfiles.\s(CVS\s902)
D 2003-04-06T21:08:24
F Makefile.in 935bf18ecefa32f780acdc1660852403468f0058
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F VERSION e5b03976c56deafa24511d6ef17d64a28679e9bd
@ -14,15 +14,17 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F libtool bbbea7d79c23323e4100103836028e4fad0d9242
F ltmain.sh abfb9387049fff6996afc6e325736597795baf11
F main.mk 931fdcd4fc6ac4d4e6eb5ce975ad2fb4995ccbcc
F main.mk 08739679174d858a0f6ced3117ce8dcfdafa540a
F publish.sh 86b5e8535830a2588f62ce1d5d1ef00e1dede23a
F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c 1e429791ee28427403938388ede9fea2caef17b2
F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
F src/btree.c 3b0e0f09886bc83fa183df367d6a1b7077da9c46
F src/btree.h 5cb871546bd6fa58396a6f033e2b29b388241e1b
F src/build.c da21ffe7daeea576ebfbeb2f96ac0f99fa6b9a09
F src/build.c f0c774c4c4ec7d79d1021de7d941863faeb77fd6
F src/copy.c ddd204d5dddac09d71a07f4ceded4c9926d5512b
F src/delete.c 58d698779a6b7f819718ecd45b310a9de8537088
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
F src/expr.c b8daee83f837b24a22d889200bdd74973ca2d8db
@ -37,6 +39,7 @@ F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0
F src/pager.c df4c81350cbd80c1ab48341ae0768ba78d99ad49
F src/pager.h e3702f7d384921f6cd5ce0b3ed589185433e9f6c
F src/parse.y 3be47fa18323aa2e3364fc42bf7a6ba5b3cc0a81
F src/pragma.c 927fc036580eea38ae05c5f0da75fd4ee340f6f0
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 14e2e2a512f4edfc75fb310ebcb502ff3ee87402
@ -54,6 +57,7 @@ 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 540c480912e11e23f5c08a31b8b3594df016f4d1
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
F src/where.c e5733f7d5e9cc4ed3590dc3401f779e7b7bb8127
@ -157,7 +161,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 185d8dc8d0c26cef36aeba6992823e5124af4056
R 7a927220f0e77fb63a637996080a8eec
P b123c165fd3d0a5a86ee8a7baa669105dafb481a
R 351f9d3f3ae1d413356658b3a79e309f
U drh
Z 2542fde3715240ecd80028ec8868e426
Z 8dcf477abd69457b6da834133632d978

View File

@ -1 +1 @@
b123c165fd3d0a5a86ee8a7baa669105dafb481a
73359037ea639abb066c74db9c19e84bf1104006

129
src/attach.c Normal file
View File

@ -0,0 +1,129 @@
/*
** 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.1 2003/04/06 21:08:24 drh Exp $
*/
#include "sqliteInt.h"
/*
** This routine is called by the parser to process an ATTACH statement:
**
** ATTACH DATABASE filename AS dbname
**
** The pFilename and pDbname arguments are the tokens that define the
** filename and dbname in the ATTACH statement.
*/
void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
Db *aNew;
int rc, i;
char *zFile, *zName;
sqlite *db;
if( pParse->explain ) return;
db = pParse->db;
if( db->file_format<4 ){
sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
"older format master database", 0);
pParse->rc = SQLITE_ERROR;
return;
}
if( db->nDb>=MAX_ATTACHED+2 ){
sqliteErrorMsg(pParse, "too many attached databases - max %d",
MAX_ATTACHED);
pParse->rc = SQLITE_ERROR;
return;
}
if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
aNew = &db->aDb[db->nDb++];
memset(aNew, 0, sizeof(*aNew));
sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
zName = 0;
sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
if( zName==0 ) return;
sqliteDequote(zName);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
sqliteErrorMsg(pParse, "database %z is already in use", zName);
db->nDb--;
pParse->rc = SQLITE_ERROR;
return;
}
}
aNew->zName = zName;
zFile = 0;
sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
if( zFile==0 ) return;
sqliteDequote(zFile);
rc = sqliteBtreeOpen(zFile, 0, MAX_PAGES, &aNew->pBt);
if( rc ){
sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
}
sqliteFree(zFile);
db->flags &= ~SQLITE_Initialized;
if( pParse->nErr ) return;
rc = sqliteInit(pParse->db, &pParse->zErrMsg);
if( rc ){
sqliteResetInternalSchema(db, 0);
pParse->nErr++;
pParse->rc = SQLITE_ERROR;
}
}
/*
** This routine is called by the parser to process a DETACH statement:
**
** DETACH DATABASE dbname
**
** The pDbname argument is the name of the database in the DETACH statement.
*/
void sqliteDetach(Parse *pParse, Token *pDbname){
int i;
sqlite *db;
if( pParse->explain ) return;
db = pParse->db;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue;
if( strlen(db->aDb[i].zName)!=pDbname->n ) continue;
if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
}
if( i>=db->nDb ){
sqliteErrorMsg(pParse, "no such database: %T", pDbname);
return;
}
if( i<2 ){
sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
return;
}
sqliteBtreeClose(db->aDb[i].pBt);
db->aDb[i].pBt = 0;
sqliteResetInternalSchema(db, i);
db->nDb--;
if( i<db->nDb ){
db->aDb[i] = db->aDb[db->nDb];
memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
sqliteResetInternalSchema(db, i);
}
}

View File

@ -18,13 +18,12 @@
** CREATE INDEX
** DROP INDEX
** creating ID lists
** COPY
** BEGIN TRANSACTION
** COMMIT
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.142 2003/04/06 20:52:32 drh Exp $
** $Id: build.c,v 1.143 2003/04/06 21:08:24 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -1980,106 +1979,6 @@ void sqliteSrcListDelete(SrcList *pList){
sqliteFree(pList);
}
/*
** The COPY command is for compatibility with PostgreSQL and specificially
** for the ability to read the output of pg_dump. The format is as
** follows:
**
** COPY table FROM file [USING DELIMITERS string]
**
** "table" is an existing table name. We will read lines of code from
** file to fill this table with data. File might be "stdin". The optional
** delimiter string identifies the field separators. The default is a tab.
*/
void sqliteCopy(
Parse *pParse, /* The parser context */
SrcList *pTableName, /* The name of the table into which we will insert */
Token *pFilename, /* The file from which to obtain information */
Token *pDelimiter, /* Use this as the field delimiter */
int onError /* What to do if a constraint fails */
){
Table *pTab;
int i;
Vdbe *v;
int addr, end;
Index *pIdx;
char *zFile = 0;
sqlite *db = pParse->db;
if( sqlite_malloc_failed ) goto copy_cleanup;
assert( pTableName->nSrc==1 );
pTab = sqliteSrcListLookup(pParse, pTableName);
if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto copy_cleanup;
zFile = sqliteStrNDup(pFilename->z, pFilename->n);
sqliteDequote(zFile);
if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, zFile)
|| sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile) ){
goto copy_cleanup;
}
v = sqliteGetVdbe(pParse);
if( v ){
sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1);
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
assert( pIdx->iDb==1 || pIdx->iDb==pTab->iDb );
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
}
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
if( pDelimiter ){
sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
sqliteVdbeDequoteP3(v, addr);
}else{
sqliteVdbeChangeP3(v, addr, "\t", 1);
}
if( pTab->iPKey>=0 ){
sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
}
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
/* The integer primary key column is filled with NULL since its
** value is always pulled from the record number */
sqliteVdbeAddOp(v, OP_String, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
}
}
sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, 0, 0, onError, addr);
sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0);
if( (db->flags & SQLITE_CountRows)!=0 ){
sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
sqliteEndWriteOperation(pParse);
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}
}
copy_cleanup:
sqliteSrcListDelete(pTableName);
sqliteFree(zFile);
return;
}
/*
** Begin a transaction
*/
@ -2205,567 +2104,3 @@ void sqliteEndWriteOperation(Parse *pParse){
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
}
}
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(char *z){
static char *azTrue[] = { "yes", "on", "true" };
int i;
if( z[0]==0 ) return 0;
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
return atoi(z);
}
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
}
return 0;
}
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.
**
** Note that the values returned are one less that the values that
** should be passed into sqliteBtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static int getSafetyLevel(char *z){
static const struct {
const char *zWord;
int val;
} aKey[] = {
{ "no", 0 },
{ "off", 0 },
{ "false", 0 },
{ "yes", 1 },
{ "on", 1 },
{ "true", 1 },
{ "full", 2 },
};
int i;
if( z[0]==0 ) return 1;
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
return atoi(z);
}
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
}
return 1;
}
/*
** Process a pragma statement.
**
** Pragmas are of this form:
**
** PRAGMA id = value
**
** The identifier might also be a string. The value is a string, and
** identifier, or a number. If minusFlag is true, then the value is
** a number that was preceded by a minus sign.
*/
void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
char *zLeft = 0;
char *zRight = 0;
sqlite *db = pParse->db;
Vdbe *v = sqliteGetVdbe(pParse);
if( v==0 ) return;
zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
sqliteDequote(zLeft);
if( minusFlag ){
zRight = 0;
sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
}else{
zRight = sqliteStrNDup(pRight->z, pRight->n);
sqliteDequote(zRight);
}
if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight) ){
sqliteFree(zLeft);
sqliteFree(zRight);
return;
}
/*
** PRAGMA default_cache_size
** PRAGMA default_cache_size=N
**
** The first form reports the current persistent setting for the
** page cache size. The value returned is the maximum number of
** pages in the page cache. The second form sets both the current
** page cache size value and the persistent page cache size value
** stored in the database file.
**
** The default cache size is stored in meta-value 2 of page 1 of the
** database file. The cache size is actually the absolute value of
** this memory location. The sign of meta-value 2 determines the
** synchronous setting. A negative value means synchronous is off
** and a positive value means synchronous is on.
*/
if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
static VdbeOp getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0},
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, MAX_PAGES,0, 0},
{ OP_ColumnName, 0, 0, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
}else{
int addr;
int size = atoi(zRight);
if( size<0 ) size = -size;
sqliteBeginWriteOperation(pParse, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, size, 0);
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
sqliteEndWriteOperation(pParse);
db->cache_size = db->cache_size<0 ? -size : size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
}
}else
/*
** PRAGMA cache_size
** PRAGMA cache_size=N
**
** The first form reports the current local setting for the
** page cache size. The local setting can be different from
** the persistent cache size value that is stored in the database
** file itself. The value returned is the maximum number of
** pages in the page cache. The second form sets the local
** page cache size value. It does not change the persistent
** cache size stored on the disk so the cache size will revert
** to its default value when the database is closed and reopened.
** N should be a positive integer.
*/
if( sqliteStrICmp(zLeft,"cache_size")==0 ){
static VdbeOp getCacheSize[] = {
{ OP_ColumnName, 0, 0, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
int size = db->cache_size;;
if( size<0 ) size = -size;
sqliteVdbeAddOp(v, OP_Integer, size, 0);
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
if( db->cache_size<0 ) size = -size;
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
}
}else
/*
** PRAGMA default_synchronous
** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
**
** The first form returns the persistent value of the "synchronous" setting
** that is stored in the database. This is the synchronous setting that
** is used whenever the database is opened unless overridden by a separate
** "synchronous" pragma. The second form changes the persistent and the
** local synchronous setting to the value given.
**
** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
** to make sure data is committed to disk. Write operations are very fast,
** but a power failure can leave the database in an inconsistent state.
** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
** make sure data is being written to disk. The risk of corruption due to
** a power loss in this mode is negligible but non-zero. If synchronous
** is FULL, extra fsync()s occur to reduce the risk of corruption to near
** zero, but with a write performance penalty. The default mode is NORMAL.
*/
if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
{ OP_ReadCookie, 0, 3, 0},
{ OP_Dup, 0, 0, 0},
{ OP_If, 0, 0, 0}, /* 3 */
{ OP_ReadCookie, 0, 2, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Lt, 0, 5, 0},
{ OP_AddImm, 1, 0, 0},
{ OP_Callback, 1, 0, 0},
{ OP_Halt, 0, 0, 0},
{ OP_AddImm, -1, 0, 0}, /* 10 */
{ OP_Callback, 1, 0, 0}
};
if( pRight->z==pLeft->z ){
int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
sqliteVdbeChangeP2(v, addr+3, addr+10);
}else{
int addr;
int size = db->cache_size;
if( size<0 ) size = -size;
sqliteBeginWriteOperation(pParse, 0, 0);
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
db->safety_level = getSafetyLevel(zRight)+1;
if( db->safety_level==1 ){
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
size = -size;
}
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
sqliteEndWriteOperation(pParse);
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
}
}else
/*
** PRAGMA synchronous
** PRAGMA synchronous=OFF|ON|NORMAL|FULL
**
** Return or set the local value of the synchronous 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.
*/
if( sqliteStrICmp(zLeft,"synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
}else{
int size = db->cache_size;
if( size<0 ) size = -size;
db->safety_level = getSafetyLevel(zRight)+1;
if( db->safety_level==1 ) size = -size;
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
}
}else
if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
if( getBoolean(zRight) ){
always_code_trigger_setup = 1;
}else{
always_code_trigger_setup = 0;
}
}else
if( sqliteStrICmp(zLeft, "vdbe_trace")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_VdbeTrace;
}else{
db->flags &= ~SQLITE_VdbeTrace;
}
}else
if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_FullColNames;
}else{
db->flags &= ~SQLITE_FullColNames;
}
}else
if( sqliteStrICmp(zLeft, "show_datatypes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_ReportTypes;
}else{
db->flags &= ~SQLITE_ReportTypes;
}
}else
if( sqliteStrICmp(zLeft, "result_set_details")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_ResultDetails;
}else{
db->flags &= ~SQLITE_ResultDetails;
}
}else
if( sqliteStrICmp(zLeft, "count_changes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_CountRows;
}else{
db->flags &= ~SQLITE_CountRows;
}
}else
if( sqliteStrICmp(zLeft, "empty_result_callbacks")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_NullCallback;
}else{
db->flags &= ~SQLITE_NullCallback;
}
}else
if( sqliteStrICmp(zLeft, "table_info")==0 ){
Table *pTab;
pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){
static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "cid"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "type"},
{ OP_ColumnName, 3, 0, "notnull"},
{ OP_ColumnName, 4, 0, "dflt_value"},
};
int i;
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
sqliteViewGetColumnNames(pParse, pTab);
for(i=0; i<pTab->nCol; i++){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 5, 0);
}
}
}else
if( sqliteStrICmp(zLeft, "index_info")==0 ){
Index *pIdx;
Table *pTab;
pIdx = sqliteFindIndex(db, zRight, 0);
if( pIdx ){
static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "seqno"},
{ OP_ColumnName, 1, 0, "cid"},
{ OP_ColumnName, 2, 0, "name"},
};
int i;
pTab = pIdx->pTable;
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pTab->nCol>cnum );
sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
}
}
}else
if( sqliteStrICmp(zLeft, "index_list")==0 ){
Index *pIdx;
Table *pTab;
pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){
v = sqliteGetVdbe(pParse);
pIdx = pTab->pIndex;
}
if( pTab && pIdx ){
int i = 0;
static VdbeOp indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "unique"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
while(pIdx){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++i;
pIdx = pIdx->pNext;
}
}
}else
if( sqliteStrICmp(zLeft, "database_list")==0 ){
int i;
static VdbeOp indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, db->aDb[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#ifndef NDEBUG
if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
extern void sqliteParserTrace(FILE*, char *);
if( getBoolean(zRight) ){
sqliteParserTrace(stdout, "parser: ");
}else{
sqliteParserTrace(0, 0);
}
}else
#endif
if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
static VdbeOp checkDb[] = {
{ OP_SetInsert, 0, 0, "2"},
{ OP_Integer, 0, 0, 0},
{ OP_OpenRead, 0, 2, 0},
{ OP_Rewind, 0, 7, 0},
{ OP_Column, 0, 3, 0}, /* 4 */
{ OP_SetInsert, 0, 0, 0},
{ OP_Next, 0, 4, 0},
{ OP_IntegrityCk, 0, 0, 0}, /* 7 */
{ OP_ColumnName, 0, 0, "integrity_check"},
{ OP_Callback, 1, 0, 0},
{ OP_SetInsert, 1, 0, "2"},
{ OP_Integer, 1, 0, 0},
{ OP_OpenRead, 1, 2, 0},
{ OP_Rewind, 1, 17, 0},
{ OP_Column, 1, 3, 0}, /* 14 */
{ OP_SetInsert, 1, 0, 0},
{ OP_Next, 1, 14, 0},
{ OP_IntegrityCk, 1, 1, 0}, /* 17 */
{ OP_Callback, 1, 0, 0},
};
sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
}else
{}
sqliteFree(zLeft);
sqliteFree(zRight);
}
/*
** This routine is called by the parser to process an ATTACH statement:
**
** ATTACH DATABASE filename AS dbname
**
** The pFilename and pDbname arguments are the tokens that define the
** filename and dbname in the ATTACH statement.
*/
void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
Db *aNew;
int rc, i;
char *zFile, *zName;
sqlite *db;
if( pParse->explain ) return;
db = pParse->db;
if( db->file_format<4 ){
sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
"older format master database", 0);
pParse->rc = SQLITE_ERROR;
return;
}
if( db->nDb>=MAX_ATTACHED+2 ){
sqliteErrorMsg(pParse, "too many attached databases - max %d",
MAX_ATTACHED);
pParse->rc = SQLITE_ERROR;
return;
}
if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
aNew = &db->aDb[db->nDb++];
memset(aNew, 0, sizeof(*aNew));
sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
zName = 0;
sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
if( zName==0 ) return;
sqliteDequote(zName);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
sqliteErrorMsg(pParse, "database %z is already in use", zName);
db->nDb--;
pParse->rc = SQLITE_ERROR;
return;
}
}
aNew->zName = zName;
zFile = 0;
sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
if( zFile==0 ) return;
sqliteDequote(zFile);
rc = sqliteBtreeOpen(zFile, 0, MAX_PAGES, &aNew->pBt);
if( rc ){
sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
}
sqliteFree(zFile);
db->flags &= ~SQLITE_Initialized;
if( pParse->nErr ) return;
rc = sqliteInit(pParse->db, &pParse->zErrMsg);
if( rc ){
sqliteResetInternalSchema(db, 0);
pParse->nErr++;
pParse->rc = SQLITE_ERROR;
}
}
/*
** This routine is called by the parser to process a DETACH statement:
**
** DETACH DATABASE dbname
**
** The pDbname argument is the name of the database in the DETACH statement.
*/
void sqliteDetach(Parse *pParse, Token *pDbname){
int i;
sqlite *db;
if( pParse->explain ) return;
db = pParse->db;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue;
if( strlen(db->aDb[i].zName)!=pDbname->n ) continue;
if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
}
if( i>=db->nDb ){
sqliteErrorMsg(pParse, "no such database: %T", pDbname);
return;
}
if( i<2 ){
sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
return;
}
sqliteBtreeClose(db->aDb[i].pBt);
db->aDb[i].pBt = 0;
sqliteResetInternalSchema(db, i);
db->nDb--;
if( i<db->nDb ){
db->aDb[i] = db->aDb[db->nDb];
memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
sqliteResetInternalSchema(db, i);
}
}

116
src/copy.c Normal file
View File

@ -0,0 +1,116 @@
/*
** 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 COPY command.
**
** $Id: copy.c,v 1.1 2003/04/06 21:08:24 drh Exp $
*/
#include "sqliteInt.h"
/*
** The COPY command is for compatibility with PostgreSQL and specificially
** for the ability to read the output of pg_dump. The format is as
** follows:
**
** COPY table FROM file [USING DELIMITERS string]
**
** "table" is an existing table name. We will read lines of code from
** file to fill this table with data. File might be "stdin". The optional
** delimiter string identifies the field separators. The default is a tab.
*/
void sqliteCopy(
Parse *pParse, /* The parser context */
SrcList *pTableName, /* The name of the table into which we will insert */
Token *pFilename, /* The file from which to obtain information */
Token *pDelimiter, /* Use this as the field delimiter */
int onError /* What to do if a constraint fails */
){
Table *pTab;
int i;
Vdbe *v;
int addr, end;
Index *pIdx;
char *zFile = 0;
sqlite *db = pParse->db;
if( sqlite_malloc_failed ) goto copy_cleanup;
assert( pTableName->nSrc==1 );
pTab = sqliteSrcListLookup(pParse, pTableName);
if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto copy_cleanup;
zFile = sqliteStrNDup(pFilename->z, pFilename->n);
sqliteDequote(zFile);
if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, zFile)
|| sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile) ){
goto copy_cleanup;
}
v = sqliteGetVdbe(pParse);
if( v ){
sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1);
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
assert( pIdx->iDb==1 || pIdx->iDb==pTab->iDb );
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
}
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
if( pDelimiter ){
sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
sqliteVdbeDequoteP3(v, addr);
}else{
sqliteVdbeChangeP3(v, addr, "\t", 1);
}
if( pTab->iPKey>=0 ){
sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
}
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
/* The integer primary key column is filled with NULL since its
** value is always pulled from the record number */
sqliteVdbeAddOp(v, OP_String, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
}
}
sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, 0, 0, onError, addr);
sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0);
if( (db->flags & SQLITE_CountRows)!=0 ){
sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
sqliteEndWriteOperation(pParse);
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}
}
copy_cleanup:
sqliteSrcListDelete(pTableName);
sqliteFree(zFile);
return;
}

466
src/pragma.c Normal file
View File

@ -0,0 +1,466 @@
/*
** 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.1 2003/04/06 21:08:24 drh Exp $
*/
#include "sqliteInt.h"
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(char *z){
static char *azTrue[] = { "yes", "on", "true" };
int i;
if( z[0]==0 ) return 0;
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
return atoi(z);
}
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
}
return 0;
}
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.
**
** Note that the values returned are one less that the values that
** should be passed into sqliteBtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static int getSafetyLevel(char *z){
static const struct {
const char *zWord;
int val;
} aKey[] = {
{ "no", 0 },
{ "off", 0 },
{ "false", 0 },
{ "yes", 1 },
{ "on", 1 },
{ "true", 1 },
{ "full", 2 },
};
int i;
if( z[0]==0 ) return 1;
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
return atoi(z);
}
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
}
return 1;
}
/*
** Process a pragma statement.
**
** Pragmas are of this form:
**
** PRAGMA id = value
**
** The identifier might also be a string. The value is a string, and
** identifier, or a number. If minusFlag is true, then the value is
** a number that was preceded by a minus sign.
*/
void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
char *zLeft = 0;
char *zRight = 0;
sqlite *db = pParse->db;
Vdbe *v = sqliteGetVdbe(pParse);
if( v==0 ) return;
zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
sqliteDequote(zLeft);
if( minusFlag ){
zRight = 0;
sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
}else{
zRight = sqliteStrNDup(pRight->z, pRight->n);
sqliteDequote(zRight);
}
if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight) ){
sqliteFree(zLeft);
sqliteFree(zRight);
return;
}
/*
** PRAGMA default_cache_size
** PRAGMA default_cache_size=N
**
** The first form reports the current persistent setting for the
** page cache size. The value returned is the maximum number of
** pages in the page cache. The second form sets both the current
** page cache size value and the persistent page cache size value
** stored in the database file.
**
** The default cache size is stored in meta-value 2 of page 1 of the
** database file. The cache size is actually the absolute value of
** this memory location. The sign of meta-value 2 determines the
** synchronous setting. A negative value means synchronous is off
** and a positive value means synchronous is on.
*/
if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
static VdbeOp getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0},
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, MAX_PAGES,0, 0},
{ OP_ColumnName, 0, 0, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
}else{
int addr;
int size = atoi(zRight);
if( size<0 ) size = -size;
sqliteBeginWriteOperation(pParse, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, size, 0);
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
sqliteEndWriteOperation(pParse);
db->cache_size = db->cache_size<0 ? -size : size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
}
}else
/*
** PRAGMA cache_size
** PRAGMA cache_size=N
**
** The first form reports the current local setting for the
** page cache size. The local setting can be different from
** the persistent cache size value that is stored in the database
** file itself. The value returned is the maximum number of
** pages in the page cache. The second form sets the local
** page cache size value. It does not change the persistent
** cache size stored on the disk so the cache size will revert
** to its default value when the database is closed and reopened.
** N should be a positive integer.
*/
if( sqliteStrICmp(zLeft,"cache_size")==0 ){
static VdbeOp getCacheSize[] = {
{ OP_ColumnName, 0, 0, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
int size = db->cache_size;;
if( size<0 ) size = -size;
sqliteVdbeAddOp(v, OP_Integer, size, 0);
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
if( db->cache_size<0 ) size = -size;
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
}
}else
/*
** PRAGMA default_synchronous
** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
**
** The first form returns the persistent value of the "synchronous" setting
** that is stored in the database. This is the synchronous setting that
** is used whenever the database is opened unless overridden by a separate
** "synchronous" pragma. The second form changes the persistent and the
** local synchronous setting to the value given.
**
** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
** to make sure data is committed to disk. Write operations are very fast,
** but a power failure can leave the database in an inconsistent state.
** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
** make sure data is being written to disk. The risk of corruption due to
** a power loss in this mode is negligible but non-zero. If synchronous
** is FULL, extra fsync()s occur to reduce the risk of corruption to near
** zero, but with a write performance penalty. The default mode is NORMAL.
*/
if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
{ OP_ReadCookie, 0, 3, 0},
{ OP_Dup, 0, 0, 0},
{ OP_If, 0, 0, 0}, /* 3 */
{ OP_ReadCookie, 0, 2, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Lt, 0, 5, 0},
{ OP_AddImm, 1, 0, 0},
{ OP_Callback, 1, 0, 0},
{ OP_Halt, 0, 0, 0},
{ OP_AddImm, -1, 0, 0}, /* 10 */
{ OP_Callback, 1, 0, 0}
};
if( pRight->z==pLeft->z ){
int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
sqliteVdbeChangeP2(v, addr+3, addr+10);
}else{
int addr;
int size = db->cache_size;
if( size<0 ) size = -size;
sqliteBeginWriteOperation(pParse, 0, 0);
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
db->safety_level = getSafetyLevel(zRight)+1;
if( db->safety_level==1 ){
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
size = -size;
}
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
sqliteEndWriteOperation(pParse);
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
}
}else
/*
** PRAGMA synchronous
** PRAGMA synchronous=OFF|ON|NORMAL|FULL
**
** Return or set the local value of the synchronous 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.
*/
if( sqliteStrICmp(zLeft,"synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
}else{
int size = db->cache_size;
if( size<0 ) size = -size;
db->safety_level = getSafetyLevel(zRight)+1;
if( db->safety_level==1 ) size = -size;
db->cache_size = size;
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
}
}else
if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
if( getBoolean(zRight) ){
always_code_trigger_setup = 1;
}else{
always_code_trigger_setup = 0;
}
}else
if( sqliteStrICmp(zLeft, "vdbe_trace")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_VdbeTrace;
}else{
db->flags &= ~SQLITE_VdbeTrace;
}
}else
if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_FullColNames;
}else{
db->flags &= ~SQLITE_FullColNames;
}
}else
if( sqliteStrICmp(zLeft, "show_datatypes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_ReportTypes;
}else{
db->flags &= ~SQLITE_ReportTypes;
}
}else
if( sqliteStrICmp(zLeft, "result_set_details")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_ResultDetails;
}else{
db->flags &= ~SQLITE_ResultDetails;
}
}else
if( sqliteStrICmp(zLeft, "count_changes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_CountRows;
}else{
db->flags &= ~SQLITE_CountRows;
}
}else
if( sqliteStrICmp(zLeft, "empty_result_callbacks")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_NullCallback;
}else{
db->flags &= ~SQLITE_NullCallback;
}
}else
if( sqliteStrICmp(zLeft, "table_info")==0 ){
Table *pTab;
pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){
static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "cid"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "type"},
{ OP_ColumnName, 3, 0, "notnull"},
{ OP_ColumnName, 4, 0, "dflt_value"},
};
int i;
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
sqliteViewGetColumnNames(pParse, pTab);
for(i=0; i<pTab->nCol; i++){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 5, 0);
}
}
}else
if( sqliteStrICmp(zLeft, "index_info")==0 ){
Index *pIdx;
Table *pTab;
pIdx = sqliteFindIndex(db, zRight, 0);
if( pIdx ){
static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "seqno"},
{ OP_ColumnName, 1, 0, "cid"},
{ OP_ColumnName, 2, 0, "name"},
};
int i;
pTab = pIdx->pTable;
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pTab->nCol>cnum );
sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
}
}
}else
if( sqliteStrICmp(zLeft, "index_list")==0 ){
Index *pIdx;
Table *pTab;
pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){
v = sqliteGetVdbe(pParse);
pIdx = pTab->pIndex;
}
if( pTab && pIdx ){
int i = 0;
static VdbeOp indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "unique"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
while(pIdx){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++i;
pIdx = pIdx->pNext;
}
}
}else
if( sqliteStrICmp(zLeft, "database_list")==0 ){
int i;
static VdbeOp indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, db->aDb[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#ifndef NDEBUG
if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
extern void sqliteParserTrace(FILE*, char *);
if( getBoolean(zRight) ){
sqliteParserTrace(stdout, "parser: ");
}else{
sqliteParserTrace(0, 0);
}
}else
#endif
if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
static VdbeOp checkDb[] = {
{ OP_SetInsert, 0, 0, "2"},
{ OP_Integer, 0, 0, 0},
{ OP_OpenRead, 0, 2, 0},
{ OP_Rewind, 0, 7, 0},
{ OP_Column, 0, 3, 0}, /* 4 */
{ OP_SetInsert, 0, 0, 0},
{ OP_Next, 0, 4, 0},
{ OP_IntegrityCk, 0, 0, 0}, /* 7 */
{ OP_ColumnName, 0, 0, "integrity_check"},
{ OP_Callback, 1, 0, 0},
{ OP_SetInsert, 1, 0, "2"},
{ OP_Integer, 1, 0, 0},
{ OP_OpenRead, 1, 2, 0},
{ OP_Rewind, 1, 17, 0},
{ OP_Column, 1, 3, 0}, /* 14 */
{ OP_SetInsert, 1, 0, 0},
{ OP_Next, 1, 14, 0},
{ OP_IntegrityCk, 1, 1, 0}, /* 17 */
{ OP_Callback, 1, 0, 0},
};
sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
}else
{}
sqliteFree(zLeft);
sqliteFree(zRight);
}

36
src/vacuum.c Normal file
View File

@ -0,0 +1,36 @@
/*
** 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 VACUUM command.
**
** 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 $
*/
#include "sqliteInt.h"
/*
** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
** in PostgreSQL.
**
** In version 1.0.x of SQLite, the VACUUM command would call
** gdbm_reorganize() on all the database tables. But beginning
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
*/
void sqliteVacuum(Parse *pParse, Token *pTableName){
#ifndef SQLITE_OMIT_VACUUM
/* Do nothing */
#endif
}