Update bundled SQLite to 3.5.6

This commit is contained in:
Scott MacVicar 2008-03-07 10:47:32 +00:00
parent 184173fccc
commit 5a86313123
106 changed files with 32603 additions and 22274 deletions

View file

@ -14,18 +14,12 @@
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
# include "pager.h"
# include "btree.h"
#endif
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
@ -73,6 +67,23 @@ static int getLockingMode(const char *z){
return PAGER_LOCKINGMODE_QUERY;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Interpret the given string as an auto-vacuum mode value.
**
** The following strings, "none", "full" and "incremental" are
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
*/
static int getAutoVacuum(const char *z){
int i;
if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
i = atoi(z);
return ((i>=0&&i<=2)?i:0);
}
#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
@ -136,12 +147,13 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
int mem = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, value, mem);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P4_STATIC);
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
}
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
@ -155,15 +167,17 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
const char *zName; /* Name of the pragma */
int mask; /* Mask for the db->flags value */
} aPragma[] = {
{ "vdbe_trace", SQLITE_VdbeTrace },
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
{ "vdbe_trace", SQLITE_VdbeTrace },
#endif
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
@ -191,8 +205,15 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
}else{
db->flags &= ~p->mask;
}
/* Many of the flag-pragmas modify the code generated by the SQL
** compiler (eg. count_changes). So add an opcode to expire all
** compiled SQL statements after modifying a pragma value.
*/
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
}
}
return 1;
}
}
@ -229,8 +250,9 @@ void sqlite3Pragma(
int iDb; /* Database index for <database> */
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);
if( v==0 ) return;
pParse->nMem = 2;
/* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
@ -245,12 +267,12 @@ void sqlite3Pragma(
return;
}
zLeft = sqlite3NameFromToken(pId);
zLeft = sqlite3NameFromToken(db, pId);
if( !zLeft ) return;
if( minusFlag ){
zRight = sqlite3MPrintf("-%T", pValue);
zRight = sqlite3MPrintf(db, "-%T", pValue);
}else{
zRight = sqlite3NameFromToken(pValue);
zRight = sqlite3NameFromToken(db, pValue);
}
zDb = ((iDb>0)?pDb->zName:0);
@ -277,32 +299,34 @@ void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0}, /* 0 */
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, 0, 0, 0}, /* 5 */
{ OP_Callback, 1, 0, 0},
{ OP_ReadCookie, 0, 1, 2}, /* 0 */
{ OP_IfPos, 1, 6, 0},
{ OP_Integer, 0, 2, 0},
{ OP_Subtract, 1, 2, 1},
{ OP_IfPos, 1, 6, 0},
{ OP_Integer, 0, 1, 0}, /* 5 */
{ OP_ResultRow, 1, 1, 0},
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P4_STATIC);
pParse->nMem += 2;
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
sqlite3VdbeChangeP1(v, addr+5, SQLITE_DEFAULT_CACHE_SIZE);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp(v, OP_Integer, size, 0);
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, 2);
addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 2, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
@ -323,10 +347,36 @@ void sqlite3Pragma(
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
returnSingleInt(pParse, "page_size", size);
}else{
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
/* Malloc may fail when setting the page-size, as there is an internal
** buffer that the pager module resizes using sqlite3_realloc().
*/
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1) ){
db->mallocFailed = 1;
}
}
}else
/*
** PRAGMA [database.]max_page_count
** PRAGMA [database.]max_page_count=N
**
** The first form reports the current setting for the
** maximum number of pages in the database file. The
** second form attempts to change this setting. Both
** forms return the current setting.
*/
if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
Btree *pBt = pDb->pBt;
int newMax = 0;
if( zRight ){
newMax = atoi(zRight);
}
if( pBt ){
newMax = sqlite3BtreeMaxPageCount(pBt, newMax);
}
returnSingleInt(pParse, "max_page_count", newMax);
}else
/*
** PRAGMA [database.]locking_mode
** PRAGMA [database.]locking_mode = (normal|exclusive)
@ -369,9 +419,9 @@ void sqlite3Pragma(
zRet = "exclusive";
}
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC);
sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P4_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
@ -384,16 +434,75 @@ void sqlite3Pragma(
#ifndef SQLITE_OMIT_AUTOVACUUM
if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){
Btree *pBt = pDb->pBt;
if( sqlite3ReadSchema(pParse) ){
goto pragma_out;
}
if( !zRight ){
int auto_vacuum =
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
}else{
sqlite3BtreeSetAutoVacuum(pBt, getBoolean(zRight));
int eAuto = getAutoVacuum(zRight);
db->nextAutovac = eAuto;
if( eAuto>=0 ){
/* Call SetAutoVacuum() to set initialize the internal auto and
** incr-vacuum flags. This is required in case this connection
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
*/
int rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
/* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
*/
static const VdbeOpList setMeta6[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, 3}, /* 1 */
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
{ OP_Integer, 0, 1, 0}, /* 4 */
{ OP_SetCookie, 0, 6, 1}, /* 5 */
};
int iAddr;
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
sqlite3VdbeChangeP1(v, iAddr, iDb);
sqlite3VdbeChangeP1(v, iAddr+1, iDb);
sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
sqlite3VdbeChangeP1(v, iAddr+5, iDb);
sqlite3VdbeUsesBtree(v, iDb);
}
}
}
}else
#endif
/*
** PRAGMA [database.]incremental_vacuum(N)
**
** Do N steps of incremental vacuuming on a database.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
if( sqlite3StrICmp(zLeft,"incremental_vacuum")==0 ){
int iLimit, addr;
if( sqlite3ReadSchema(pParse) ){
goto pragma_out;
}
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
iLimit = 0x7fffffff;
}
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb);
sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr);
sqlite3VdbeJumpHere(v, addr);
}else
#endif
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [database.]cache_size
@ -455,12 +564,14 @@ void sqlite3Pragma(
if( sqlite3_temp_directory ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
"temp_store_directory", P3_STATIC);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
"temp_store_directory", P4_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}else{
if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
if( zRight[0]
&& !sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE)
){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
@ -470,7 +581,7 @@ void sqlite3Pragma(
){
invalidateTempStorage(pParse);
}
sqliteFree(sqlite3_temp_directory);
sqlite3_free(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = zRight;
zRight = 0;
@ -530,29 +641,35 @@ void sqlite3Pragma(
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i;
int nHidden = 0;
Column *pCol;
sqlite3VdbeSetNumCols(v, 6);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC);
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
pParse->nMem = 6;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P4_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P4_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P4_STATIC);
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P4_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const Token *pDflt;
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, (char*)pDflt->z, pDflt->n);
}else{
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
if( IsHiddenColumn(pCol) ){
nHidden++;
continue;
}
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 4);
if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
}else
@ -566,16 +683,17 @@ void sqlite3Pragma(
int i;
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
pParse->nMem = 3;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P4_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P4_STATIC);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
assert( pTab->nCol>cnum );
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
}else
@ -591,14 +709,15 @@ void sqlite3Pragma(
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
pParse->nMem = 3;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P4_STATIC);
while(pIdx){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
++i;
pIdx = pIdx->pNext;
}
@ -610,17 +729,18 @@ void sqlite3Pragma(
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC);
pParse->nMem = 3;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P4_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}else
@ -628,13 +748,14 @@ void sqlite3Pragma(
int i = 0;
HashElem *p;
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
pParse->nMem = 2;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pColl->zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}else
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
@ -651,22 +772,23 @@ void sqlite3Pragma(
if( pFK ){
int i = 0;
sqlite3VdbeSetNumCols(v, 5);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC);
pParse->nMem = 5;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P4_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P4_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
char *zCol = pFK->aCol[j].zCol;
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, j, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0);
sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
++i;
pFK = pFK->pNextFrom;
@ -678,7 +800,6 @@ void sqlite3Pragma(
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
extern void sqlite3ParserTrace(FILE*, char *);
if( zRight ){
if( getBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
@ -703,7 +824,13 @@ void sqlite3Pragma(
#endif
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
/* Pragma "quick_check" is an experimental reduced version of
** integrity_check designed to detect most database corruption
** without most of the overhead of a full integrity-check.
*/
if( sqlite3StrICmp(zLeft, "integrity_check")==0
|| sqlite3StrICmp(zLeft, "quick_check")==0
){
int i, j, addr, mxErr;
/* Code that appears at the end of the integrity check. If no error
@ -711,17 +838,19 @@ void sqlite3Pragma(
** error message
*/
static const VdbeOpList endCode[] = {
{ OP_MemLoad, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 0, 0}, /* 2 */
{ OP_String8, 0, 0, "ok"},
{ OP_Callback, 1, 0, 0},
{ OP_AddImm, 1, 0, 0}, /* 0 */
{ OP_IfNeg, 1, 0, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0},
};
int isQuick = (zLeft[0]=='q');
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pParse->nMem = 6;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P4_STATIC);
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
@ -731,7 +860,7 @@ void sqlite3Pragma(
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
}
sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0);
sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
@ -742,100 +871,115 @@ void sqlite3Pragma(
if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i);
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree
**
** Begin by filling registers 2, 3, ... with the root pages numbers
** for all tables and indices in the database.
*/
pTbls = &db->aDb[i].pSchema->tblHash;
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
cnt++;
}
}
if( cnt==0 ) continue;
sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
/* Make sure sufficient number of registers have been allocated */
if( pParse->nMem < cnt+3 ){
pParse->nMem = cnt+3;
}
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
sqlite3VdbeChangeP5(v, i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 2);
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
if( pTab->pIndex==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */
loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
{ OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "},
{ OP_String8, 0, 0, 0}, /* 4 */
{ OP_Concat, 2, 0, 0},
{ OP_Callback, 1, 0, 0},
{ OP_AddImm, 1, -1, 0},
{ OP_String8, 0, 3, 0}, /* 1 */
{ OP_Rowid, 1, 4, 0},
{ OP_String8, 0, 5, 0}, /* 3 */
{ OP_String8, 0, 6, 0}, /* 4 */
{ OP_Concat, 4, 3, 3},
{ OP_Concat, 5, 3, 3},
{ OP_Concat, 6, 3, 3},
{ OP_ResultRow, 3, 1, 0},
};
sqlite3GenerateIndexKey(v, pIdx, 1);
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
sqlite3GenerateIndexKey(pParse, pIdx, 1, 3);
jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_STATIC);
sqlite3VdbeJumpHere(v, jmp2);
}
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop+1);
sqlite3VdbeJumpHere(v, loopTop);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static const VdbeOpList cntIdx[] = {
{ OP_MemInt, 0, 2, 0},
{ OP_Integer, 0, 3, 0},
{ OP_Rewind, 0, 0, 0}, /* 1 */
{ OP_MemIncr, 1, 2, 0},
{ OP_AddImm, 3, 1, 0},
{ OP_Next, 0, 0, 0}, /* 3 */
{ OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */
{ OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0},
{ OP_Eq, 2, 0, 3}, /* 4 */
{ OP_AddImm, 1, -1, 0},
{ OP_String8, 0, 2, 0}, /* 6 */
{ OP_String8, 0, 3, 0}, /* 7 */
{ OP_Concat, 3, 2, 2},
{ OP_ResultRow, 2, 1, 0},
};
if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4);
sqlite3VdbeChangeP1(v, addr+3, j+2);
sqlite3VdbeChangeP2(v, addr+3, addr+2);
sqlite3VdbeJumpHere(v, addr+6);
sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
sqlite3VdbeJumpHere(v, addr+4);
sqlite3VdbeChangeP4(v, addr+6,
"wrong # of entries in index ", P4_STATIC);
sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_STATIC);
}
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP1(v, addr+1, mxErr);
sqlite3VdbeJumpHere(v, addr+2);
sqlite3VdbeChangeP2(v, addr, -mxErr);
sqlite3VdbeJumpHere(v, addr+1);
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
}else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -844,7 +988,7 @@ void sqlite3Pragma(
** PRAGMA encoding
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
**
** In it's first form, this pragma returns the encoding of the main
** In its first form, this pragma returns the encoding of the main
** database. If the database is not initialized, it is initialized now.
**
** The second form of this pragma is a no-op if the main database file
@ -881,15 +1025,15 @@ void sqlite3Pragma(
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P4_STATIC);
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( pEnc->enc==ENC(pParse->db) ){
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
sqlite3VdbeChangeP4(v, -1, pEnc->zName, P4_STATIC);
break;
}
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
@ -940,22 +1084,33 @@ void sqlite3Pragma(
** The user-version is not used internally by SQLite. It may be used by
** applications for any purpose.
*/
if( sqlite3StrICmp(zLeft, "schema_version")==0 ||
sqlite3StrICmp(zLeft, "user_version")==0 ){
if( sqlite3StrICmp(zLeft, "schema_version")==0
|| sqlite3StrICmp(zLeft, "user_version")==0
|| sqlite3StrICmp(zLeft, "freelist_count")==0
){
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
if( zLeft[0]=='s' || zLeft[0]=='S' ){
iCookie = 0;
}else{
iCookie = 5;
sqlite3VdbeUsesBtree(v, iDb);
switch( zLeft[0] ){
case 's': case 'S':
iCookie = 0;
break;
case 'f': case 'F':
iCookie = 1;
iDb = (-1*(iDb+1));
assert(iDb<=0);
break;
default:
iCookie = 5;
break;
}
if( zRight ){
if( zRight && iDb>=0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_Integer, 0, 0, 0}, /* 1 */
{ OP_SetCookie, 0, 0, 0}, /* 2 */
{ OP_Integer, 0, 1, 0}, /* 1 */
{ OP_SetCookie, 0, 0, 1}, /* 2 */
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
@ -965,14 +1120,14 @@ void sqlite3Pragma(
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
{ OP_ReadCookie, 0, 0, 0}, /* 0 */
{ OP_Callback, 1, 0, 0}
{ OP_ReadCookie, 0, 1, 0}, /* 0 */
{ OP_ResultRow, 1, 1, 0}
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP2(v, addr, iCookie);
sqlite3VdbeChangeP3(v, addr, iCookie);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P4_TRANSIENT);
}
}else
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
@ -988,22 +1143,25 @@ void sqlite3Pragma(
int i;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
pParse->nMem = 2;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P4_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P4_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
Pager *pPager;
const char *zState = "unknown";
int j;
if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
pBt = db->aDb[i].pBt;
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
}else{
int j = sqlite3PagerLockstate(pPager);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
zState = "closed";
}else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
zState = azLockName[j];
}
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}else
#endif
@ -1048,7 +1206,7 @@ void sqlite3Pragma(
** the VDBE implementing the pragma to expire. Most (all?) pragmas
** are only valid for a single execution.
*/
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
sqlite3VdbeAddOp2(v, OP_Expire, 1, 0);
/*
** Reset the safety level, in case the fullfsync flag or synchronous
@ -1062,8 +1220,8 @@ void sqlite3Pragma(
#endif
}
pragma_out:
sqliteFree(zLeft);
sqliteFree(zRight);
sqlite3_free(zLeft);
sqlite3_free(zRight);
}
#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */