Merge the latest trunk changes into the sessions branch.

FossilOrigin-Name: 6994826c0784280f2e9728dfa4185848846d03df
This commit is contained in:
drh 2013-04-22 23:59:06 +00:00
commit 16fb176814
88 changed files with 5964 additions and 550 deletions

View File

@ -169,6 +169,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
expr.lo fault.lo fkey.lo \
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
fts3_tokenize_vtab.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
func.lo global.lo hash.lo \
icu.lo insert.lo journal.lo legacy.lo loadext.lo \
@ -319,6 +320,7 @@ SRC += \
$(TOP)/ext/fts3/fts3_tokenizer.h \
$(TOP)/ext/fts3/fts3_tokenizer.c \
$(TOP)/ext/fts3/fts3_tokenizer1.c \
$(TOP)/ext/fts3/fts3_tokenize_vtab.c \
$(TOP)/ext/fts3/fts3_unicode.c \
$(TOP)/ext/fts3/fts3_unicode2.c \
$(TOP)/ext/fts3/fts3_write.c
@ -511,6 +513,11 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
-o $@ $(TOP)/src/shell.c libsqlite3.la \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
$(TLIBS) -rpath "$(libdir)"
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system. Some of the C source code and header
@ -863,6 +870,9 @@ fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
fts3_tokenizer1.lo: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
fts3_tokenizer_vtab.lo: $(TOP)/ext/fts3/fts3_tokenizer_vtab.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer_vtab.c
fts3_unicode.lo: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c
@ -959,8 +969,11 @@ clean:
rm -f testfixture$(TEXE) test.db
rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
rm -f sqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe
distclean: clean
rm -f config.log config.status libtool Makefile sqlite3.pc

View File

@ -482,7 +482,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
expr.lo fault.lo fkey.lo \
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
func.lo global.lo hash.lo \
icu.lo insert.lo journal.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
@ -643,6 +643,7 @@ SRC = $(SRC) \
$(TOP)\ext\fts3\fts3_tokenizer.h \
$(TOP)\ext\fts3\fts3_tokenizer.c \
$(TOP)\ext\fts3\fts3_tokenizer1.c \
$(TOP)\ext\fts3\fts3_tokenize_vtab.c \
$(TOP)\ext\fts3\fts3_unicode.c \
$(TOP)\ext\fts3\fts3_unicode2.c \
$(TOP)\ext\fts3\fts3_write.c
@ -758,6 +759,7 @@ TESTSRC2 = \
$(TOP)\ext\fts3\fts3_aux.c \
$(TOP)\ext\fts3\fts3_expr.c \
$(TOP)\ext\fts3\fts3_tokenizer.c \
$(TOP)\ext\fts3\fts3_tokenize_vtab.c \
$(TOP)\ext\fts3\fts3_unicode.c \
$(TOP)\ext\fts3\fts3_unicode2.c \
$(TOP)\ext\fts3\fts3_write.c \
@ -832,6 +834,10 @@ sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h
$(TOP)\src\shell.c \
/link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h
$(LTLINK) $(TOP)\mptest\mptest.c \
/link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system. Some of the C source code and header
@ -1192,6 +1198,9 @@ fts3_tokenizer.lo: $(TOP)\ext\fts3\fts3_tokenizer.c $(HDR) $(EXTHDR)
fts3_tokenizer1.lo: $(TOP)\ext\fts3\fts3_tokenizer1.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer1.c
fts3_tokenize_vtab.lo: $(TOP)\ext\fts3\fts3_tokenize_vtab.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenize_vtab.c
fts3_unicode.lo: $(TOP)\ext\fts3\fts3_unicode.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode.c
@ -1273,8 +1282,10 @@ clean:
del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
del /Q sqlite3.c
del /Q sqlite3rc.h
del /Q shell.c sqlite3ext.h
del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c
del /Q sqlite-*-output.vsix
del /Q mptester.exe
# Dynamic link library section.
#

View File

@ -662,4 +662,6 @@ clean:
rm -rf tsrc target_source
rm -f testloadext.dll libtestloadext.so
rm -f sqlite3.c fts?amal.c tclsqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f $(SHPREFIX)sqlite3.$(SO)

View File

@ -3593,6 +3593,9 @@ int sqlite3Fts3Init(sqlite3 *db){
rc = sqlite3Fts3InitAux(db);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3Fts3InitTok(db);
if( rc!=SQLITE_OK ) return rc;
sqlite3Fts3SimpleTokenizerModule(&pSimple);
sqlite3Fts3PorterTokenizerModule(&pPorter);

View File

@ -549,6 +549,9 @@ int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
/* fts3_tokenize_vtab.c */
int sqlite3Fts3InitTok(sqlite3*);
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
int sqlite3FtsUnicodeFold(int, int);

View File

@ -70,17 +70,26 @@ static int fts3auxConnectMethod(
UNUSED_PARAMETER(pUnused);
/* The user should specify a single argument - the name of an fts3 table. */
if( argc!=4 ){
*pzErr = sqlite3_mprintf(
"wrong number of arguments to fts4aux constructor"
);
return SQLITE_ERROR;
}
/* The user should invoke this in one of two forms:
**
** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table);
** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table);
*/
if( argc!=4 && argc!=5 ) goto bad_args;
zDb = argv[1];
nDb = (int)strlen(zDb);
zFts3 = argv[3];
if( argc==5 ){
if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){
zDb = argv[3];
nDb = (int)strlen(zDb);
zFts3 = argv[4];
}else{
goto bad_args;
}
}else{
zFts3 = argv[3];
}
nFts3 = (int)strlen(zFts3);
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
@ -103,6 +112,10 @@ static int fts3auxConnectMethod(
*ppVtab = (sqlite3_vtab *)p;
return SQLITE_OK;
bad_args:
*pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor");
return SQLITE_ERROR;
}
/*

View File

@ -0,0 +1,464 @@
/*
** 2013 Apr 22
**
** 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 for the "fts3tokenize" virtual table module.
** An fts3tokenize virtual table is created as follows:
**
** CREATE VIRTUAL TABLE <tbl> USING fts3tokenize(
** <tokenizer-name>, <arg-1>, ...
** );
**
** The table created has the following schema:
**
** CREATE TABLE <tbl>(input, token, start, end, position)
**
** When queried, the query must include a WHERE clause of type:
**
** input = <string>
**
** The virtual table module tokenizes this <string>, using the FTS3
** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
** statement and returns one row for each token in the result. With
** fields set as follows:
**
** input: Always set to a copy of <string>
** token: A token from the input.
** start: Byte offset of the token within the input <string>.
** end: Byte offset of the byte immediately following the end of the
** token within the input string.
** pos: Token offset of token within input.
**
*/
#include "fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include <string.h>
#include <assert.h>
typedef struct Fts3tokTable Fts3tokTable;
typedef struct Fts3tokCursor Fts3tokCursor;
/*
** Virtual table structure.
*/
struct Fts3tokTable {
sqlite3_vtab base; /* Base class used by SQLite core */
const sqlite3_tokenizer_module *pMod;
sqlite3_tokenizer *pTok;
};
/*
** Virtual table cursor structure.
*/
struct Fts3tokCursor {
sqlite3_vtab_cursor base; /* Base class used by SQLite core */
char *zInput; /* Input string */
sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */
int iRowid; /* Current 'rowid' value */
const char *zToken; /* Current 'token' value */
int nToken; /* Size of zToken in bytes */
int iStart; /* Current 'start' value */
int iEnd; /* Current 'end' value */
int iPos; /* Current 'pos' value */
};
/*
** Query FTS for the tokenizer implementation named zName.
*/
static int fts3tokQueryTokenizer(
sqlite3 *db,
const char *zName,
const sqlite3_tokenizer_module **pp
){
int rc;
sqlite3_stmt *pStmt;
const char *zSql = "SELECT fts3_tokenizer(?)";
*pp = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
memcpy((void*)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
}
}
return sqlite3_finalize(pStmt);
}
/*
** The second argument, argv[], is an array of pointers to nul-terminated
** strings. This function makes a copy of the array and strings into a
** single block of memory. It then dequotes any of the strings that appear
** to be quoted.
**
** If successful, output parameter *pazDequote is set to point at the
** array of dequoted strings and SQLITE_OK is returned. The caller is
** responsible for eventually calling sqlite3_free() to free the array
** in this case. Or, if an error occurs, an SQLite error code is returned.
** The final value of *pazDequote is undefined in this case.
*/
static int fts3tokDequoteArray(
int argc, /* Number of elements in argv[] */
const char * const *argv, /* Input array */
char ***pazDequote /* Output array */
){
int rc = SQLITE_OK; /* Return code */
if( argc==0 ){
*pazDequote = 0;
}else{
int i;
int nByte = 0;
char **azDequote;
for(i=0; i<argc; i++){
nByte += (int)(strlen(argv[i]) + 1);
}
*pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
if( azDequote==0 ){
rc = SQLITE_NOMEM;
}else{
char *pSpace = (char *)&azDequote[argc];
for(i=0; i<argc; i++){
int n = (int)strlen(argv[i]);
azDequote[i] = pSpace;
memcpy(pSpace, argv[i], n+1);
sqlite3Fts3Dequote(pSpace);
pSpace += (n+1);
}
}
}
return rc;
}
/*
** Schema of the tokenizer table.
*/
#define FTS3_TOK_SCHEMA "CREATE TABLE x(input, token, start, end, position)"
/*
** This function does all the work for both the xConnect and xCreate methods.
** These tables have no persistent representation of their own, so xConnect
** and xCreate are identical operations.
**
** argv[0]: module name
** argv[1]: database name
** argv[2]: table name
** argv[3]: first argument (tokenizer name)
*/
static int fts3tokConnectMethod(
sqlite3 *db, /* Database connection */
void *pUnused, /* Unused */
int argc, /* Number of elements in argv array */
const char * const *argv, /* xCreate/xConnect argument array */
sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
char **pzErr /* OUT: sqlite3_malloc'd error message */
){
Fts3tokTable *pTab;
const sqlite3_tokenizer_module *pMod = 0;
sqlite3_tokenizer *pTok = 0;
int rc;
char **azDequote = 0;
int nDequote;
UNUSED_PARAMETER(pUnused);
rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA);
if( rc!=SQLITE_OK ) return rc;
nDequote = argc-3;
rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote);
if( rc==SQLITE_OK ){
const char *zModule;
if( nDequote<1 ){
zModule = "simple";
}else{
zModule = azDequote[0];
}
rc = fts3tokQueryTokenizer(db, zModule, &pMod);
}
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else if( pMod==0 ){
rc = SQLITE_ERROR;
}else{
const char * const *azArg = (const char * const *)&azDequote[1];
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
}
if( rc==SQLITE_OK ){
pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
if( pTab==0 ){
rc = SQLITE_NOMEM;
}
}
if( rc==SQLITE_OK ){
memset(pTab, 0, sizeof(Fts3tokTable));
pTab->pMod = pMod;
pTab->pTok = pTok;
*ppVtab = &pTab->base;
}else{
if( pTok ){
pMod->xDestroy(pTok);
}
}
sqlite3_free(azDequote);
return rc;
}
/*
** This function does the work for both the xDisconnect and xDestroy methods.
** These tables have no persistent representation of their own, so xDisconnect
** and xDestroy are identical operations.
*/
static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){
Fts3tokTable *pTab = (Fts3tokTable *)pVtab;
pTab->pMod->xDestroy(pTab->pTok);
sqlite3_free(pTab);
return SQLITE_OK;
}
/*
** xBestIndex - Analyze a WHERE and ORDER BY clause.
*/
static int fts3tokBestIndexMethod(
sqlite3_vtab *pVTab,
sqlite3_index_info *pInfo
){
int i;
UNUSED_PARAMETER(pVTab);
for(i=0; i<pInfo->nConstraint; i++){
if( pInfo->aConstraint[i].usable
&& pInfo->aConstraint[i].iColumn==0
&& pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
){
pInfo->idxNum = 1;
pInfo->aConstraintUsage[i].argvIndex = 1;
pInfo->aConstraintUsage[i].omit = 1;
pInfo->estimatedCost = 1;
return SQLITE_OK;
}
}
pInfo->idxNum = 0;
assert( pInfo->estimatedCost>1000000.0 );
return SQLITE_OK;
}
/*
** xOpen - Open a cursor.
*/
static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
Fts3tokCursor *pCsr;
UNUSED_PARAMETER(pVTab);
pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor));
if( pCsr==0 ){
return SQLITE_NOMEM;
}
memset(pCsr, 0, sizeof(Fts3tokCursor));
*ppCsr = (sqlite3_vtab_cursor *)pCsr;
return SQLITE_OK;
}
/*
** Reset the tokenizer cursor passed as the only argument. As if it had
** just been returned by fts3tokOpenMethod().
*/
static void fts3tokResetCursor(Fts3tokCursor *pCsr){
if( pCsr->pCsr ){
Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab);
pTab->pMod->xClose(pCsr->pCsr);
pCsr->pCsr = 0;
}
sqlite3_free(pCsr->zInput);
pCsr->zInput = 0;
pCsr->zToken = 0;
pCsr->nToken = 0;
pCsr->iStart = 0;
pCsr->iEnd = 0;
pCsr->iPos = 0;
pCsr->iRowid = 0;
}
/*
** xClose - Close a cursor.
*/
static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
fts3tokResetCursor(pCsr);
sqlite3_free(pCsr);
return SQLITE_OK;
}
/*
** xNext - Advance the cursor to the next row, if any.
*/
static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
int rc; /* Return code */
pCsr->iRowid++;
rc = pTab->pMod->xNext(pCsr->pCsr,
&pCsr->zToken, &pCsr->nToken,
&pCsr->iStart, &pCsr->iEnd, &pCsr->iPos
);
if( rc!=SQLITE_OK ){
fts3tokResetCursor(pCsr);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
return rc;
}
/*
** xFilter - Initialize a cursor to point at the start of its data.
*/
static int fts3tokFilterMethod(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, /* Strategy index */
const char *idxStr, /* Unused */
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
int rc = SQLITE_ERROR;
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(nVal);
fts3tokResetCursor(pCsr);
if( idxNum==1 ){
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
int nByte = sqlite3_value_bytes(apVal[0]);
pCsr->zInput = sqlite3_malloc(nByte+1);
if( pCsr->zInput==0 ){
rc = SQLITE_NOMEM;
}else{
memcpy(pCsr->zInput, zByte, nByte);
pCsr->zInput[nByte] = 0;
rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
if( rc==SQLITE_OK ){
pCsr->pCsr->pTokenizer = pTab->pTok;
}
}
}
if( rc!=SQLITE_OK ) return rc;
return fts3tokNextMethod(pCursor);
}
/*
** xEof - Return true if the cursor is at EOF, or false otherwise.
*/
static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
return (pCsr->zToken==0);
}
/*
** xColumn - Return a column value.
*/
static int fts3tokColumnMethod(
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
int iCol /* Index of column to read value from */
){
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
/* CREATE TABLE x(input, token, start, end, position) */
switch( iCol ){
case 0:
sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT);
break;
case 1:
sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT);
break;
case 2:
sqlite3_result_int(pCtx, pCsr->iStart);
break;
case 3:
sqlite3_result_int(pCtx, pCsr->iEnd);
break;
default:
assert( iCol==4 );
sqlite3_result_int(pCtx, pCsr->iPos);
break;
}
return SQLITE_OK;
}
/*
** xRowid - Return the current rowid for the cursor.
*/
static int fts3tokRowidMethod(
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
sqlite_int64 *pRowid /* OUT: Rowid value */
){
Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
*pRowid = (sqlite3_int64)pCsr->iRowid;
return SQLITE_OK;
}
/*
** Register the fts3tok module with database connection db. Return SQLITE_OK
** if successful or an error code if sqlite3_create_module() fails.
*/
int sqlite3Fts3InitTok(sqlite3 *db){
static const sqlite3_module fts3tok_module = {
0, /* iVersion */
fts3tokConnectMethod, /* xCreate */
fts3tokConnectMethod, /* xConnect */
fts3tokBestIndexMethod, /* xBestIndex */
fts3tokDisconnectMethod, /* xDisconnect */
fts3tokDisconnectMethod, /* xDestroy */
fts3tokOpenMethod, /* xOpen */
fts3tokCloseMethod, /* xClose */
fts3tokFilterMethod, /* xFilter */
fts3tokNextMethod, /* xNext */
fts3tokEofMethod, /* xEof */
fts3tokColumnMethod, /* xColumn */
fts3tokRowidMethod, /* xRowid */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindFunction */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
0 /* xRollbackTo */
};
int rc; /* Return code */
rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, 0);
return rc;
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

View File

@ -17,6 +17,7 @@ if {![info exists testdir]} {
}
source [file join [file dirname [info script]] rtree_util.tcl]
source $testdir/tester.tcl
set testprefix rtree1
# Test plan:
#

View File

@ -61,7 +61,7 @@ do_test rtree5-1.9 {
do_test rtree5-1.10 {
execsql { SELECT (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5 }
} {2147483643 2147483647 -2147483648 -2147483643}
do_test rtree5-1.10 {
do_test rtree5-1.11 {
execsql {
INSERT INTO t1 VALUES(2, (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5)
}

12
main.mk
View File

@ -56,6 +56,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
fts3_tokenize_vtab.o \
fts3_unicode.o fts3_unicode2.o \
fts3_write.o func.o global.o hash.o \
icu.o insert.o journal.o legacy.o loadext.o \
@ -198,6 +199,7 @@ SRC += \
$(TOP)/ext/fts3/fts3_tokenizer.h \
$(TOP)/ext/fts3/fts3_tokenizer.c \
$(TOP)/ext/fts3/fts3_tokenizer1.c \
$(TOP)/ext/fts3/fts3_tokenize_vtab.c \
$(TOP)/ext/fts3/fts3_unicode.c \
$(TOP)/ext/fts3/fts3_unicode2.c \
$(TOP)/ext/fts3/fts3_write.c
@ -371,6 +373,10 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
$(TOP)/src/shell.c \
libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c
$(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
$(TLIBS) $(THREADLIB)
sqlite3.o: sqlite3.c
$(TCCX) -c sqlite3.c
@ -519,6 +525,9 @@ fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
fts3_tokenize_vtab.o: $(TOP)/ext/fts3/fts3_tokenize_vtab.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenize_vtab.c
fts3_unicode.o: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c
@ -633,5 +642,8 @@ clean:
rm -f testfixture testfixture.exe
rm -f threadtest3 threadtest3.exe
rm -f sqlite3.c fts?amal.c tclsqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe

169
manifest
View File

@ -1,10 +1,10 @@
C Fix\sthe\sxCheckReservedLock()\smethod\son\sthe\swindows\sVFS\sso\sthat\sit\scannot\sreturn\sa\sfalse\spositive\swhen\stwo\sor\smore\sprocesses\suse\sit\sat\sthe\ssame\stime\son\sthe\ssame\sfile.\sTicket\s[7ff3120e4fa54abb55].\s\sUpdate\sto\sversion\s3.7.16.2.
D 2013-04-12T13:53:50.045
C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch.
D 2013-04-22T23:59:06.075
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 174bfca74e57f38699e3412a984f6b38106750fa
F Makefile.in 4db477715e5d66fdcbb4f7a0870d10b0adbe007e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc 0ad7d4278a3b7e0c56d3ca7cc607b34acc1df516
F Makefile.vxworks b18ad88e9a8c6a001f5cf4a389116a4f1a7ab45f
F Makefile.msc 95b9e9992abcb32dda9ad7460bb1c4a3e0985909
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 0dee4d2e0c64791ff0085277424fb5c07d79fc9a
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@ -55,10 +55,10 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 0eaedfc6d2eb22563ef1d044dcfed93b70ec79f2
F ext/fts3/fts3.c 784aadfb4c2a217c3eb1feaecac924989f29728f
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h 1e58825246b56259267382d2f9902774c049460a
F ext/fts3/fts3_aux.c 5205182bd8f372782597888156404766edf5781e
F ext/fts3/fts3Int.h 352c8a83ee4c6a14ced1759a39dd890ab947cbe0
F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd
F ext/fts3/fts3_expr.c 6cb4410f87676ae633bd7923bbc78526cb839c4d
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
@ -67,6 +67,7 @@ F ext/fts3/fts3_porter.c a465b49fcb8249a755792f87516eff182efa42b3
F ext/fts3/fts3_snippet.c 5fcfcafff46a2a3a63b8e59fcb51987d01c74695
F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763
F ext/fts3/fts3_test.c f9a1a1702db1bfad3e2d0064746eeb808f125489
F ext/fts3/fts3_tokenize_vtab.c a29f126b9e6c6a6f1021a8f7440bf125e68af1f9
F ext/fts3/fts3_tokenizer.c bbdc731bc91338050675c6d1da9ab82147391e16
F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
@ -85,11 +86,11 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test 9a229678a00f40e6aedb40cb3a07ec5444af892c
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
F ext/rtree/rtree6.test 3ff9113b4a872fa935309e3511cd9b7cdb4d2472
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d
@ -115,13 +116,19 @@ F ext/session/sqlite3session.h f374c9c4c96e08f67ac418871c29d423245c7673
F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk 01f02b625cc1b8609690aaddb00e2fbb1edbeec5
F main.mk 88fb64131032933d96fd65039a6dd9140beb2566
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
F mkopcodec.awk f6fccee29e68493bfd90a2e0466ede5fa94dd2fc
F mkopcodeh.awk 29b84656502eee5f444c3147f331ee686956ab0e
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test a5f31998ed48de8267d6620e8af107ec148e5f12
F mptest/crash02.subtest f4ef05adcd15d60e5d2bd654204f2c008b519df8
F mptest/mptest.c 499a74af4be293b7c1c7c3d40f332b67227dd739
F mptest/multiwrite01.test 81fbc17657964889b60750bd7bbb1deffe8f4d42
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
@ -130,86 +137,86 @@ F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
F src/analyze.c d5f895810e8ff9737c9ec7b76abc3dcff5860335
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c b2cac9f7993f3f9588827b824b1501d0c820fa68
F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 62ba5954765efc711c873a20a53f60d9fc2843ba
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
F src/btree.c 480a6d255cc4f066029daf23dd54acf152cd0e13
F src/btree.h d9490cd37aaeb530a41b07f06e1262950b1be916
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 2a5f251fcd7393808df77ccfc817e7058df08c4c
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 39a770e9729b1acd2de347f8f614584841d0083e
F src/expr.c 48048fca951eedbc74aa32262154410d56c83812
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
F src/func.c 48987c025d69399f59a1c2a553cea5da41bf105d
F src/global.c e59ecd2c553ad0d4bfbc84ca71231336f8993a7a
F src/func.c d3fdcff9274bc161152e67ed3f626841c247f4b9
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 02f8a1867088cb654eb756f98389f10441a65216
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 1422eba4aa2b1fb5f7b3aef574752272477d21e2
F src/main.c 557e456f41646c67ccfe3dae3fa945b5bfb788c5
F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2
F src/main.c f93769cf9fc75c4a5bfa642149c7c9128bc68811
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6
F src/memjournal.c 41a598445c8f249bd9b26ecae700c60dcf34cbf3
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
F src/mutex_w32.c 32a9b3841e2d757355f0012b860b1bc5e01eafa0
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 21a36fa0b3753609b6606b30d9338d4bb6b24696
F src/os_win.c c96990935e7fd799b43a7f0ee74798f45f06e21a
F src/pager.c 3e9a15939684b0af441325f05335331b15979c9d
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0
F src/os_unix.c 5a9ac4a566fb566a2ff9b9e3a9d723075d9d26a7
F src/os_win.c 673b3e3d1fa3040d8d95a7f1f5e0e553aed56cfb
F src/pager.c 6c3a8a5d665498b0344395a2c9f82d5abc4cc771
F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9
F src/pragma.c 9f0ee3d74a7f33eeeff40a4b014fc3abf8182ce2
F src/prepare.c 310eaff1ee5f3c700b3545afb095cfe9346efc3a
F src/pragma.c 3eacf001cbf4becbd494f8d82d08fdf1648cf8cb
F src/prepare.c 743e484233c51109666d402f470523553b41797c
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 9079da7d59aed2bb14ec8315bc7f720dd85b5b65
F src/resolve.c 10a1b332e3eb36e5d561085e18c58a8578cd7d73
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 01540bcd3df3c8f1187158e77986028b1c667258
F src/shell.c 7c41bfcd9e5bf9d96b9215f79b03a5b2b44a3bca
F src/sqlite.h.in ba60664eedbe33fb5f68f17b4cbbcd59af8fc6ad
F src/shell.c aca9d94653decd4496846dee0c7ba83eaf96a46d
F src/sqlite.h.in eddda5f1967e84336e11f3a5c6fd3be3337d66c1
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 7183ab832e23db0f934494f16928da127a571d75
F src/sqliteInt.h a0a6b155f5e9748dfb5876d892e03a07eb056d7b
F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5
F src/sqliteInt.h a9f727c0d568f64f06ae430e55a074d8dd1ccde4
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c a15550a334ca07ac2bc5d32c5f97e3d61be886e8
F src/test1.c ff3e68eedfbd858c9b89cf03e3db233cd29be1d0
F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf
F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d
F src/test4.c bf9fa9bece01de08e6f5e02314e4af5c13590dfa
F src/test1.c 6784fdacb35c33ba564ef749b62c4718fe515484
F src/test2.c 29e7154112f7448d64204e8d31179cf497ecf425
F src/test3.c 96aed72a8e1d542fed127e3e8350ae357712fa82
F src/test4.c cea2c55110241e4674e66d476d29c914627999f5
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
F src/test7.c f4b894b7931f8cf9f5cbf37cfa0727703f526a40
F src/test8.c 58ea1d9698f3947e4662107ef98f429e84ae20e0
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_autoext.c 5c95b5d435eaa09d6c0e7d90371c5ca8cd567701
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
F src/test_config.c 8437cba146aa12c2fddfa5d1a73eb4f5fe0ee8e6
F src/test_config.c 6b614c603cb4db1c996f1b192ca0a46ef0d152cd
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c 8f786bfd0ad48030cf2a06fb1f050e9c60a150d7
@ -235,13 +242,13 @@ F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
F src/test_spellfix.c 56dfa6d583ac34f61af0834d7b58d674e7e18e13
F src/test_sqllog.c bc50e5afeb7fb50e77b4594e42302df9d05446aa
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae
F src/test_syscall.c 7e8293e4e6971b0f44c7f7f37b1315a8cc9f6018
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
F src/test_vfs.c fb16b2d9938cf0c1afc5a423b55b952fcc024275
F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
@ -251,20 +258,20 @@ F src/update.c beef58f5fd66153ac9cdf6e9f6551f09ee68976c
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3
F src/vdbe.c fee31825a8e287bb6ed2dacc33fb276c5e2ab7a5
F src/vdbe.c 349798f630ce49c2e21a6c30863f195c484cfec5
F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683
F src/vdbeInt.h bd76014fa5051b9f33223e4cc6a76d00ce031944
F src/vdbeapi.c 8245e8c2cdcf105871a4ccae365d3bd29bfca6d1
F src/vdbeInt.h a6b7a1fbb2b335fd8c3b4b8a696b1ba28eae2191
F src/vdbeapi.c 5899f359cb51c6949aeff50a806275c94fe73fce
F src/vdbeaux.c 426263e901f19d8fe6bc7124ee5dafc78a2feac3
F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381
F src/vdbeblob.c 1268e0bcb8e21fa32520b0fc376e1bcdfaa0c642
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
F src/vdbesort.c 4fad64071ae120c25f39dcac572d716b9cadeb7f
F src/vdbetrace.c 8bd5da325fc90f28464335e4cc4ad1407fe30835
F src/vdbetrace.c 3ad1b4e92b60c082a02ac563da4a2735cc7d297c
F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 4ad2329c439a30ddb915a780f6f80bdffafe3a64
F src/where.c d54e63087b52c309550aa2defdb20ef27add9f9a
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@ -326,6 +333,7 @@ F test/boundary3.tcl 8901d6a503d0bf64251dd81cc74e5ad3add4b119
F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btreefault.test 06899a377f31a8c1a3048ec69831522d4e5c6045
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a
@ -381,7 +389,7 @@ F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9
F test/dbstatus.test 207e5b63fcb7b9c3bb8e1fdf38ebd4654ad0e54b
F test/dbstatus2.test bf7396af964b89e39435babbcdf296ae8fc5f10a
F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@ -415,7 +423,7 @@ F test/eqp.test 46aa946dd55c90635327898275d3e533d23a9845
F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb
F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6
F test/exclusive2.test 881193eccec225cfed9d7f744b65e57f26adee25
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
@ -483,7 +491,7 @@ F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test e7b80272efcced57d1d087a9da5c690dd7c21fd9
F test/fts3atoken.test fb398ab50aa232489e2a17f9b29d7ad3a3885f36
F test/fts3auto.test 74315a7377403a57ba82a652a33704197fe1e4be
F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
F test/fts3aux1.test 03cec2dea379931c219dd4406817485caa69d1d8
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
@ -511,6 +519,8 @@ F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2
F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2
F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
F test/fts3tok1.test 05ff5c57098282bacba7192507702b17f4061295
F test/fts3tok_err.test 41e5413139c2ef536ffadfcd1584ee50b1665ec0
F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae
F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8
F test/fts4content.test 6efc53b4fd03cab167e6998d2b0b7d4b7d419ee6
@ -520,7 +530,7 @@ F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test b058483c17952eff7797b837bbb61e27e6b05606
F test/func.test b0fc34fdc36897769651975a2b0a606312753643
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
@ -538,7 +548,7 @@ F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
F test/incrblob.test e7ef2a6094d9b5eb7284c21af2c07644eefffe7d
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19
F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7
F test/incrblob4.test 09be37d3dd996a31ea6993bba7837ece549414a8
@ -590,7 +600,7 @@ F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/like.test 0e5412f4dac4a849f613e1ef8b529d56a6e31d08
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
F test/loadext.test 2b5e249c51c986a5aff1f0950cf7ba30976c8f22
F test/loadext.test 92e6dfefd1229c3ef4aaabd87419efd8fa57a7a5
F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
@ -623,7 +633,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 2930895b0962823ec679853e67e58dd6d8198b3c
F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
@ -642,6 +652,8 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
F test/mmap1.test 0b5802cf64acaa509ea889b3c708196cc6eb9d31
F test/mmap2.test a5ba639f90b5fc487400a49e158e14e465943e98
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
@ -660,17 +672,17 @@ F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 31c04bec797dda1bde337810b52efa08d1f1f08e
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
F test/pager1.test 30e63afd425fea12285e9ec5fa1fd000808031f1
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442
F test/pagerfault.test 8483e65d33d5636e5b7656204bb274d826e728d9
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
F test/pagerfault3.test f16e2efcb5fc9996d1356f7cbc44c998318ae1d7
F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0
F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/permutations.test 379cfbb9a5eea2499d05008c04d18ddb4f2c01a9
F test/permutations.test a19a70a80836b5e183e46f4043fb7626446ab5e0
F test/pragma.test 60d29cd3d8098a2c20bf4c072810f99e3bf2757a
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@ -688,6 +700,7 @@ F test/regexp1.test 5cbb6e7122ca51260d71079cf9245b63b8f64e1a
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
F test/resolver01.test d1b487fc567bdb70b5dd09ccaaa877ddc61a233e
F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
@ -744,7 +757,7 @@ F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
F test/speed1p.test c4a469f29f135f4d76c55b1f2a52f36e209466cc
F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
@ -760,15 +773,15 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test bea9bf329bff733c791310244617c2a76974e64a
F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test a7308276aad2e6c0bfb5b0414424dd0d9cc0cad7
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
F test/tester.tcl 4201c6efa80693e5414d4f241bb0f325a124478f
F test/tester.tcl c6dc3ea5b906b3665ab52c82c72237268adf506d
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@ -858,7 +871,7 @@ F test/tkt2686.test 6ee01c9b9e9c48f6d3a1fdd553b1cc4258f903d6
F test/tkt2767.test 569000d842678f9cf2db7e0d1b27cbc9011381b0
F test/tkt2817.test f31839e01f4243cff7399ef654d3af3558cb8d8d
F test/tkt2820.test 39940276b3436d125deb7d8ebeee053e4cf13213
F test/tkt2822.test f391776423a7c0d0949edfce375708bfb0f3141e
F test/tkt2822.test c3589494fba643e039bcf0bfde7554ff6028406d
F test/tkt2832.test a9b0b74a02dca166a04d9e37739c414b10929caa
F test/tkt2854.test e432965db29e27e16f539b2ba7f502eb2ccc49af
F test/tkt2920.test a8737380e4ae6424e00c0273dc12775704efbebf
@ -965,11 +978,11 @@ F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 82f463886e18d7f8395a4b6167c91815efe54839
F test/wal.test a040047d7f2b9f34bc4d597964e5e7c09609c635
F test/wal.test 0b4837cd5e9283c116d30810a6859bed7425a95e
F test/wal2.test d4b470f13c87f6d8268b004380afa04c3c67cb90
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test f58ed4b8b542f71c7441da12fbd769d99b362437
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
F test/wal8.test b3ee739fe8f7586aaebdc2367f477ebcf3e3b034
@ -981,7 +994,7 @@ F test/walcksum.test f5447800a157c9e2234fbb8e80243f0813941bde
F test/walcrash.test 4457436593be8c136f9148487c7dccd5e9013af2
F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
F test/walcrash3.test 595e44c6197f0d0aa509fc135be2fd0209d11a2c
F test/walfault.test 97394d8de82a99f7abf1c12ed229640607fd0ad2
F test/walfault.test 54ad6e849c727f4da463964b9eb8c8e8e155cf82
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
@ -1007,7 +1020,7 @@ F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a
F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d
F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test e7f77fded01dfcdf92ac2c5400f1e35d7a21463c
F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x
@ -1025,7 +1038,7 @@ F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
F tool/mksqlite3c.tcl 521b39c2d2987c4257919b97a3cfb3bd4a394bf1
F tool/mksqlite3c.tcl 3e55715d165688d969392d792c81f79552049add
F tool/mksqlite3h.tcl 2d0f1b3768f8d000b7881217d5fd4c776eb27467
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
F tool/mkvsix.tcl 0be7f7a591f1e83f9199cb82911b66668ca484c9
@ -1054,7 +1067,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P f1eed92b7b0ef4ee22a11d8bb4f9a572b56ce019 cbea02d93865ce0e06789db95fd9168ebac970c7
R 0efc127a79bcb850db00f0f48c643639
P 67b3c0efa7d5e0cb7cc0fc7606ab3f26ea5419fd 1a1cf5aa86734c832d845e07780262a178188d56
R 732bd62d8f3cf92b7ff68a9a14e06f6a
U drh
Z a385c575da3bc80f399700b4e6cb7b5b
Z d4e35c064e319291a70a72e245362c9b

View File

@ -1 +1 @@
67b3c0efa7d5e0cb7cc0fc7606ab3f26ea5419fd
6994826c0784280f2e9728dfa4185848846d03df

46
mptest/config01.test Normal file
View File

@ -0,0 +1,46 @@
/*
** Configure five tasks in different ways, then run tests.
*/
--if vfsname() GLOB 'unix'
PRAGMA page_size=8192;
--task 1
PRAGMA journal_mode=PERSIST;
PRAGMA mmap_size=0;
--end
--task 2
PRAGMA journal_mode=TRUNCATE;
PRAGMA mmap_size=28672;
--end
--task 3
PRAGMA journal_mode=MEMORY;
--end
--task 4
PRAGMA journal_mode=OFF;
--end
--task 4
PRAGMA mmap_size(268435456);
--end
--source multiwrite01.test
--wait all
PRAGMA page_size=16384;
VACUUM;
CREATE TABLE pgsz(taskid, sz INTEGER);
--task 1
INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size'));
--end
--task 2
INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size'));
--end
--task 3
INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size'));
--end
--task 4
INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size'));
--end
--task 5
INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size'));
--end
--source multiwrite01.test
--wait all
SELECT sz FROM pgsz;
--match 16384 16384 16384 16384 16384

123
mptest/config02.test Normal file
View File

@ -0,0 +1,123 @@
/*
** Configure five tasks in different ways, then run tests.
*/
PRAGMA page_size=512;
--task 1
PRAGMA mmap_size=0;
--end
--task 2
PRAGMA mmap_size=28672;
--end
--task 3
PRAGMA mmap_size=8192;
--end
--task 4
PRAGMA mmap_size=65536;
--end
--task 5
PRAGMA mmap_size=268435456;
--end
--source multiwrite01.test
--source crash02.subtest
PRAGMA page_size=1024;
VACUUM;
CREATE TABLE pgsz(taskid, sz INTEGER);
--task 1
INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size'));
--end
--task 2
INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size'));
--end
--task 3
INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size'));
--end
--task 4
INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size'));
--end
--task 5
INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size'));
--end
--source multiwrite01.test
--source crash02.subtest
--wait all
SELECT sz FROM pgsz;
--match 1024 1024 1024 1024 1024
PRAGMA page_size=2048;
VACUUM;
DELETE FROM pgsz;
--task 1
INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size'));
--end
--task 2
INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size'));
--end
--task 3
INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size'));
--end
--task 4
INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size'));
--end
--task 5
INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size'));
--end
--source multiwrite01.test
--source crash02.subtest
--wait all
SELECT sz FROM pgsz;
--match 2048 2048 2048 2048 2048
PRAGMA page_size=8192;
VACUUM;
DELETE FROM pgsz;
--task 1
INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size'));
--end
--task 2
INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size'));
--end
--task 3
INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size'));
--end
--task 4
INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size'));
--end
--task 5
INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size'));
--end
--source multiwrite01.test
--source crash02.subtest
--wait all
SELECT sz FROM pgsz;
--match 8192 8192 8192 8192 8192
PRAGMA page_size=16384;
VACUUM;
DELETE FROM pgsz;
--task 1
INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size'));
--end
--task 2
INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size'));
--end
--task 3
INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size'));
--end
--task 4
INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size'));
--end
--task 5
INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size'));
--end
--source multiwrite01.test
--source crash02.subtest
--wait all
SELECT sz FROM pgsz;
--match 16384 16384 16384 16384 16384
PRAGMA auto_vacuum=FULL;
VACUUM;
--source multiwrite01.test
--source crash02.subtest
--wait all
PRAGMA auto_vacuum=FULL;
PRAGMA page_size=512;
VACUUM;
--source multiwrite01.test
--source crash02.subtest

102
mptest/crash01.test Normal file
View File

@ -0,0 +1,102 @@
/* Test cases involving incomplete transactions that must be rolled back.
*/
--task 1
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t1 VALUES(1, randomblob(2000));
INSERT INTO t1 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1;
INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1;
INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1;
--sleep 1
INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1;
--sleep 1
INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1;
SELECT count(*) FROM t1;
--match 64
SELECT avg(length(b)) FROM t1;
--match 1500.0
--sleep 2
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t1;
--match 247
SELECT a FROM t1 WHERE b='x17y';
--match 17
CREATE INDEX t1b ON t1(b);
SELECT a FROM t1 WHERE b='x17y';
--match 17
SELECT a FROM t1 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--wait 1
--task 2
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
INSERT INTO t2 SELECT a, b FROM t1;
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t2;
--match 247
SELECT a FROM t2 WHERE b='x17y';
--match 17
CREATE INDEX t2b ON t2(b);
SELECT a FROM t2 WHERE b='x17y';
--match 17
SELECT a FROM t2 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 3
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
INSERT INTO t3 SELECT a, b FROM t1;
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t3;
--match 247
SELECT a FROM t3 WHERE b='x17y';
--match 17
CREATE INDEX t3b ON t3(b);
SELECT a FROM t3 WHERE b='x17y';
--match 17
SELECT a FROM t3 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 4
CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
INSERT INTO t4 SELECT a, b FROM t1;
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t4;
--match 247
SELECT a FROM t4 WHERE b='x17y';
--match 17
CREATE INDEX t4b ON t4(b);
SELECT a FROM t4 WHERE b='x17y';
--match 17
SELECT a FROM t4 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 5
CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
INSERT INTO t5 SELECT a, b FROM t1;
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t5;
--match 247
SELECT a FROM t5 WHERE b='x17y';
--match 17
CREATE INDEX t5b ON t5(b);
SELECT a FROM t5 WHERE b='x17y';
--match 17
SELECT a FROM t5 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--wait all
/* After the database file has been set up, run the crash2 subscript
** multiple times. */
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest
--source crash02.subtest

53
mptest/crash02.subtest Normal file
View File

@ -0,0 +1,53 @@
/*
** This script is called from crash01.test and config02.test and perhaps other
** script. After the database file has been set up, make a big rollback
** journal in client 1, then crash client 1.
** Then in the other clients, do an integrity check.
*/
--task 1 leave-hot-journal
--sleep 5
--finish
PRAGMA cache_size=10;
BEGIN;
UPDATE t1 SET b=randomblob(20000);
UPDATE t2 SET b=randomblob(20000);
UPDATE t3 SET b=randomblob(20000);
UPDATE t4 SET b=randomblob(20000);
UPDATE t5 SET b=randomblob(20000);
UPDATE t1 SET b=NULL;
UPDATE t2 SET b=NULL;
UPDATE t3 SET b=NULL;
UPDATE t4 SET b=NULL;
UPDATE t5 SET b=NULL;
--print Task one crashing an incomplete transaction
--exit 1
--end
--task 2 integrity_check-2
SELECT count(*) FROM t1;
--match 64
--sleep 100
PRAGMA integrity_check(10);
--match ok
--end
--task 3 integrity_check-3
SELECT count(*) FROM t1;
--match 64
--sleep 100
PRAGMA integrity_check(10);
--match ok
--end
--task 4 integrity_check-4
SELECT count(*) FROM t1;
--match 64
--sleep 100
PRAGMA integrity_check(10);
--match ok
--end
--task 5 integrity_check-5
SELECT count(*) FROM t1;
--match 64
--sleep 100
PRAGMA integrity_check(10);
--match ok
--end
--wait all

1401
mptest/mptest.c Normal file

File diff suppressed because it is too large Load Diff

405
mptest/multiwrite01.test Normal file
View File

@ -0,0 +1,405 @@
/*
** This script sets up five different tasks all writing and updating
** the database at the same time, but each in its own table.
*/
--task 1 build-t1
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t1 VALUES(1, randomblob(2000));
INSERT INTO t1 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1;
INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1;
INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1;
--sleep 1
INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1;
--sleep 1
INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1;
SELECT count(*) FROM t1;
--match 64
SELECT avg(length(b)) FROM t1;
--match 1500.0
--sleep 2
UPDATE t1 SET b='x'||a||'y';
SELECT total(length(b)) FROM t1;
--match 247
SELECT a FROM t1 WHERE b='x17y';
--match 17
CREATE INDEX t1b ON t1(b);
SELECT a FROM t1 WHERE b='x17y';
--match 17
SELECT a FROM t1 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 2 build-t2
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t2 VALUES(1, randomblob(2000));
INSERT INTO t2 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t2 SELECT a+2, randomblob(1500) FROM t2;
INSERT INTO t2 SELECT a+4, randomblob(1500) FROM t2;
INSERT INTO t2 SELECT a+8, randomblob(1500) FROM t2;
--sleep 1
INSERT INTO t2 SELECT a+16, randomblob(1500) FROM t2;
--sleep 1
INSERT INTO t2 SELECT a+32, randomblob(1500) FROM t2;
SELECT count(*) FROM t2;
--match 64
SELECT avg(length(b)) FROM t2;
--match 1500.0
--sleep 2
UPDATE t2 SET b='x'||a||'y';
SELECT total(length(b)) FROM t2;
--match 247
SELECT a FROM t2 WHERE b='x17y';
--match 17
CREATE INDEX t2b ON t2(b);
SELECT a FROM t2 WHERE b='x17y';
--match 17
SELECT a FROM t2 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 3 build-t3
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t3 VALUES(1, randomblob(2000));
INSERT INTO t3 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t3 SELECT a+2, randomblob(1500) FROM t3;
INSERT INTO t3 SELECT a+4, randomblob(1500) FROM t3;
INSERT INTO t3 SELECT a+8, randomblob(1500) FROM t3;
--sleep 1
INSERT INTO t3 SELECT a+16, randomblob(1500) FROM t3;
--sleep 1
INSERT INTO t3 SELECT a+32, randomblob(1500) FROM t3;
SELECT count(*) FROM t3;
--match 64
SELECT avg(length(b)) FROM t3;
--match 1500.0
--sleep 2
UPDATE t3 SET b='x'||a||'y';
SELECT total(length(b)) FROM t3;
--match 247
SELECT a FROM t3 WHERE b='x17y';
--match 17
CREATE INDEX t3b ON t3(b);
SELECT a FROM t3 WHERE b='x17y';
--match 17
SELECT a FROM t3 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 4 build-t4
DROP TABLE IF EXISTS t4;
CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t4 VALUES(1, randomblob(2000));
INSERT INTO t4 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t4 SELECT a+2, randomblob(1500) FROM t4;
INSERT INTO t4 SELECT a+4, randomblob(1500) FROM t4;
INSERT INTO t4 SELECT a+8, randomblob(1500) FROM t4;
--sleep 1
INSERT INTO t4 SELECT a+16, randomblob(1500) FROM t4;
--sleep 1
INSERT INTO t4 SELECT a+32, randomblob(1500) FROM t4;
SELECT count(*) FROM t4;
--match 64
SELECT avg(length(b)) FROM t4;
--match 1500.0
--sleep 2
UPDATE t4 SET b='x'||a||'y';
SELECT total(length(b)) FROM t4;
--match 247
SELECT a FROM t4 WHERE b='x17y';
--match 17
CREATE INDEX t4b ON t4(b);
SELECT a FROM t4 WHERE b='x17y';
--match 17
SELECT a FROM t4 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--task 5 build-t5
DROP TABLE IF EXISTS t5;
CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
--sleep 1
INSERT INTO t5 VALUES(1, randomblob(2000));
INSERT INTO t5 VALUES(2, randomblob(1000));
--sleep 1
INSERT INTO t5 SELECT a+2, randomblob(1500) FROM t5;
INSERT INTO t5 SELECT a+4, randomblob(1500) FROM t5;
INSERT INTO t5 SELECT a+8, randomblob(1500) FROM t5;
--sleep 1
INSERT INTO t5 SELECT a+16, randomblob(1500) FROM t5;
--sleep 1
INSERT INTO t5 SELECT a+32, randomblob(1500) FROM t5;
SELECT count(*) FROM t5;
--match 64
SELECT avg(length(b)) FROM t5;
--match 1500.0
--sleep 2
UPDATE t5 SET b='x'||a||'y';
SELECT total(length(b)) FROM t5;
--match 247
SELECT a FROM t5 WHERE b='x17y';
--match 17
CREATE INDEX t5b ON t5(b);
SELECT a FROM t5 WHERE b='x17y';
--match 17
SELECT a FROM t5 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5;
--match 29 28 27 26 25
--end
--wait all
SELECT count(*), total(length(b)) FROM t1;
--match 64 247
SELECT count(*), total(length(b)) FROM t2;
--match 64 247
SELECT count(*), total(length(b)) FROM t3;
--match 64 247
SELECT count(*), total(length(b)) FROM t4;
--match 64 247
SELECT count(*), total(length(b)) FROM t5;
--match 64 247
--task 1
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 5
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 3
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 2
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 4
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--wait all
--task 5
DROP INDEX t5b;
--sleep 5
PRAGMA integrity_check(10);
--match ok
CREATE INDEX t5b ON t5(b DESC);
--end
--task 3
DROP INDEX t3b;
--sleep 5
PRAGMA integrity_check(10);
--match ok
CREATE INDEX t3b ON t3(b DESC);
--end
--task 1
DROP INDEX t1b;
--sleep 5
PRAGMA integrity_check(10);
--match ok
CREATE INDEX t1b ON t1(b DESC);
--end
--task 2
DROP INDEX t2b;
--sleep 5
PRAGMA integrity_check(10);
--match ok
CREATE INDEX t2b ON t2(b DESC);
--end
--task 4
DROP INDEX t4b;
--sleep 5
PRAGMA integrity_check(10);
--match ok
CREATE INDEX t4b ON t4(b DESC);
--end
--wait all
--task 1
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 5
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 3
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 2
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 4
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--wait all
VACUUM;
PRAGMA integrity_check(10);
--match ok
--task 1
UPDATE t1 SET b=randomblob(20000);
--sleep 5
UPDATE t1 SET b='x'||a||'y';
SELECT a FROM t1 WHERE b='x63y';
--match 63
--end
--task 2
UPDATE t2 SET b=randomblob(20000);
--sleep 5
UPDATE t2 SET b='x'||a||'y';
SELECT a FROM t2 WHERE b='x63y';
--match 63
--end
--task 3
UPDATE t3 SET b=randomblob(20000);
--sleep 5
UPDATE t3 SET b='x'||a||'y';
SELECT a FROM t3 WHERE b='x63y';
--match 63
--end
--task 4
UPDATE t4 SET b=randomblob(20000);
--sleep 5
UPDATE t4 SET b='x'||a||'y';
SELECT a FROM t4 WHERE b='x63y';
--match 63
--end
--task 5
UPDATE t5 SET b=randomblob(20000);
--sleep 5
UPDATE t5 SET b='x'||a||'y';
SELECT a FROM t5 WHERE b='x63y';
--match 63
--end
--wait all
--task 1
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 5
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 3
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 2
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--task 4
SELECT t1.a FROM t1, t2
WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y')
ORDER BY t1.a LIMIT 4
--match 33 34 35 36
SELECT t3.a FROM t3, t4
WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y')
ORDER BY t3.a LIMIT 7
--match 45 46 47 48 49 50 51
--end
--wait all

View File

@ -397,7 +397,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
DbPage *pSrcPg; /* Source page object */
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
PAGER_ACQUIRE_READONLY);
if( rc==SQLITE_OK ){
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg);

View File

@ -1581,13 +1581,17 @@ static int btreeGetPage(
BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */
int noContent /* Do not load page content if true */
int noContent, /* Do not load page content if true */
int bReadonly /* True if a read-only (mmap) page is ok */
){
int rc;
DbPage *pDbPage;
int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
| (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
assert( noContent==0 || bReadonly==0 );
assert( sqlite3_mutex_held(pBt->mutex) );
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc;
*ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
return SQLITE_OK;
@ -1630,9 +1634,10 @@ u32 sqlite3BtreeLastPage(Btree *p){
** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage /* Write the page pointer here */
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
int bReadonly /* True if a read-only (mmap) page is ok */
){
int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
@ -1640,7 +1645,7 @@ static int getAndInitPage(
if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeGetPage(pBt, pgno, ppPage, 0);
rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){
@ -1871,6 +1876,7 @@ int sqlite3BtreeOpen(
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
EXTRA_SIZE, flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){
sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
}
if( rc!=SQLITE_OK ){
@ -2137,6 +2143,19 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
return SQLITE_OK;
}
/*
** Change the limit on the amount of the database file that may be
** memory mapped.
*/
int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
/*
** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power
@ -2362,7 +2381,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->pPage1==0 );
rc = sqlite3PagerSharedLock(pBt->pPager);
if( rc!=SQLITE_OK ) return rc;
rc = btreeGetPage(pBt, 1, &pPage1, 0);
rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is
@ -2921,7 +2940,7 @@ static int relocatePage(
** iPtrPage.
*/
if( eType!=PTRMAP_ROOTPAGE ){
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@ -3005,7 +3024,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@ -3097,8 +3116,11 @@ int sqlite3BtreeIncrVacuum(Btree *p){
if( nOrig<nFin ){
rc = SQLITE_CORRUPT_BKPT;
}else if( nFree>0 ){
invalidateAllOverflowCache(pBt);
rc = incrVacuumStep(pBt, nFin, nOrig, 0);
rc = saveAllCursors(pBt, 0, 0);
if( rc==SQLITE_OK ){
invalidateAllOverflowCache(pBt);
rc = incrVacuumStep(pBt, nFin, nOrig, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
@ -3146,7 +3168,9 @@ static int autoVacuumCommit(BtShared *pBt){
nFree = get4byte(&pBt->pPage1->aData[36]);
nFin = finalDbSize(pBt, nOrig, nFree);
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
if( nFin<nOrig ){
rc = saveAllCursors(pBt, 0, 0);
}
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
rc = incrVacuumStep(pBt, nFin, iFree, 1);
}
@ -3163,7 +3187,7 @@ static int autoVacuumCommit(BtShared *pBt){
}
}
assert( nRef==sqlite3PagerRefcount(pPager) );
assert( nRef>=sqlite3PagerRefcount(pPager) );
return rc;
}
@ -3419,7 +3443,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
/* The rollback may have destroyed the pPage1->aData value. So
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@ -3853,7 +3877,7 @@ static int getOverflowPage(
assert( next==0 || rc==SQLITE_DONE );
if( rc==SQLITE_OK ){
rc = btreeGetPage(pBt, ovfl, &pPage, 0);
rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
assert( rc==SQLITE_OK || pPage==0 );
if( rc==SQLITE_OK ){
next = get4byte(pPage->aData);
@ -4074,7 +4098,9 @@ static int accessPayload(
{
DbPage *pDbPage;
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
(eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
);
if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
@ -4253,10 +4279,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, newPgno, &pNewPage);
rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0;
@ -4373,7 +4400,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]);
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@ -4987,7 +5014,7 @@ static int allocateBtreePage(
if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
}
if( rc ){
pTrunk = 0;
@ -5051,7 +5078,7 @@ static int allocateBtreePage(
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
if( rc!=SQLITE_OK ){
goto end_allocate_page;
}
@ -5131,7 +5158,7 @@ static int allocateBtreePage(
}
put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@ -5179,7 +5206,7 @@ static int allocateBtreePage(
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
@ -5193,7 +5220,7 @@ static int allocateBtreePage(
*pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@ -5261,7 +5288,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros.
*/
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
){
goto freepage_out;
@ -5288,7 +5315,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
if( rc!=SQLITE_OK ){
goto freepage_out;
}
@ -5334,7 +5361,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list.
*/
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
goto freepage_out;
}
rc = sqlite3PagerWrite(pPage->pDbPage);
@ -6135,7 +6162,7 @@ static int balance_nonroot(
}
pgno = get4byte(pRight);
while( 1 ){
rc = getAndInitPage(pBt, pgno, &apOld[i]);
rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
@ -7223,10 +7250,17 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
u8 eType = 0;
Pgno iPtrPage = 0;
/* Save the positions of any open cursors. This is required in
** case they are holding a reference to an xFetch reference
** corresponding to page pgnoRoot. */
rc = saveAllCursors(pBt, 0, 0);
releasePage(pPageMove);
if( rc!=SQLITE_OK ){
return rc;
}
/* Move the page currently at pgnoRoot to pgnoMove. */
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@ -7247,7 +7281,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
if( rc!=SQLITE_OK ){
return rc;
}
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@ -7323,7 +7357,7 @@ static int clearDatabasePage(
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, pgno, &pPage);
rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
@ -7425,7 +7459,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE;
}
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0);
if( rc ){
@ -7460,7 +7494,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*/
MemPage *pMove;
releasePage(pPage);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@ -7470,7 +7504,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return rc;
}
pMove = 0;
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
freePage(pMove, &rc);
releasePage(pMove);
if( rc!=SQLITE_OK ){
@ -7882,7 +7916,7 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
@ -8354,6 +8388,17 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
return SQLITE_ABORT;
}
/* Save the positions of all other cursors open on this table. This is
** required in case any of them are holding references to an xFetch
** version of the b-tree page modified by the accessPayload call below.
**
** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition()
** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
** saveAllCursors can only return SQLITE_OK.
*/
VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
assert( rc==SQLITE_OK );
/* Check some assumptions:
** (a) the cursor is open for writing,
** (b) there is a read/write transaction open,

View File

@ -63,6 +63,7 @@ int sqlite3BtreeOpen(
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);

View File

@ -48,15 +48,15 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
#ifdef SQLITE_CURDIR
"CURDIR",
#endif
#ifdef SQLITE_DEBUG
"DEBUG",
#endif
#ifdef SQLITE_DEFAULT_LOCKING_MODE
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
#ifdef SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
#endif
@ -147,6 +147,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
"MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
#endif
#ifdef SQLITE_MAX_SCHEMA_RETRY
"MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
#endif
@ -204,11 +207,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_CHECK
"OMIT_CHECK",
#endif
/* // redundant
** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
** "OMIT_COMPILEOPTION_DIAGS",
** #endif
*/
#ifdef SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE",
#endif
@ -350,13 +348,13 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_TCL
"TCL",
#endif
#ifdef SQLITE_TEMP_STORE
#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
#ifdef SQLITE_TEST
"TEST",
#endif
#ifdef SQLITE_THREADSAFE
#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
#ifdef SQLITE_USE_ALLOCA
@ -382,8 +380,11 @@ int sqlite3_compileoption_used(const char *zOptName){
/* Since ArraySize(azCompileOpt) is normally in single digits, a
** linear search is adequate. No need for a binary search. */
for(i=0; i<ArraySize(azCompileOpt); i++){
if( (sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0)
&& ( (azCompileOpt[i][n]==0) || (azCompileOpt[i][n]=='=') ) ) return 1;
if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
&& sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
){
return 1;
}
}
return 0;
}

View File

@ -693,6 +693,13 @@ static int patternCompare(
return *zString==0;
}
/*
** The sqlite3_strglob() interface.
*/
int sqlite3_strglob(const char *zGlobPattern, const char *zString){
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
}
/*
** Count the number of times that the LIKE operator (or GLOB which is
** just a variation of LIKE) gets called. This is used for testing

View File

@ -156,6 +156,8 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
(void*)0, /* pHeap */
0, /* nHeap */
0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
SQLITE_MAX_MMAP_SIZE, /* mxMmap */
(void*)0, /* pScratch */
0, /* szScratch */
0, /* nScratch */

View File

@ -38,7 +38,6 @@ int sqlite3_exec(
const char *zLeftover; /* Tail of unprocessed SQL */
sqlite3_stmt *pStmt = 0; /* The current SQL statement */
char **azCols = 0; /* Names of result columns */
int nRetry = 0; /* Number of retry attempts */
int callbackIsInit; /* True if callback data is initialized */
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
@ -46,12 +45,12 @@ int sqlite3_exec(
sqlite3_mutex_enter(db->mutex);
sqlite3Error(db, SQLITE_OK, 0);
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
while( rc==SQLITE_OK && zSql[0] ){
int nCol;
char **azVals = 0;
pStmt = 0;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
continue;
@ -108,11 +107,8 @@ int sqlite3_exec(
if( rc!=SQLITE_ROW ){
rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
zSql = zLeftover;
while( sqlite3Isspace(zSql[0]) ) zSql++;
}
zSql = zLeftover;
while( sqlite3Isspace(zSql[0]) ) zSql++;
break;
}
}

View File

@ -415,8 +415,23 @@ static int sqlite3LoadExtension(
void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
const char *zEntry;
char *zAltEntry = 0;
void **aHandle;
int nMsg = 300 + sqlite3Strlen30(zFile);
int ii;
/* Shared library endings to try if zFile cannot be loaded as written */
static const char *azEndings[] = {
#if SQLITE_OS_WIN
"dll"
#elif defined(__APPLE__)
"dylib"
#else
"so"
#endif
};
if( pzErrMsg ) *pzErrMsg = 0;
@ -433,11 +448,17 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
if( zProc==0 ){
zProc = "sqlite3_extension_init";
}
zEntry = zProc ? zProc : "sqlite3_extension_init";
handle = sqlite3OsDlOpen(pVfs, zFile);
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
#endif
if( handle==0 ){
if( pzErrMsg ){
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
@ -450,20 +471,57 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlSym(pVfs, handle, zProc);
sqlite3OsDlSym(pVfs, handle, zEntry);
/* If no entry point was specified and the default legacy
** entry point name "sqlite3_extension_init" was not found, then
** construct an entry point name "sqlite3_X_init" where the X is
** replaced by the lowercase value of every ASCII alphabetic
** character in the filename after the last "/" upto the first ".",
** and eliding the first three characters if they are "lib".
** Examples:
**
** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init
*/
if( xInit==0 && zProc==0 ){
int iFile, iEntry, c;
int ncFile = sqlite3Strlen30(zFile);
zAltEntry = sqlite3_malloc(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
return SQLITE_NOMEM;
}
memcpy(zAltEntry, "sqlite3_", 8);
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
iFile++;
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
if( sqlite3Isalpha(c) ){
zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
}
}
memcpy(zAltEntry+iEntry, "_init", 6);
zEntry = zAltEntry;
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlSym(pVfs, handle, zEntry);
}
if( xInit==0 ){
if( pzErrMsg ){
nMsg += sqlite3Strlen30(zProc);
nMsg += sqlite3Strlen30(zEntry);
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"no entry point [%s] in shared library [%s]", zProc,zFile);
"no entry point [%s] in shared library [%s]", zEntry, zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
}
sqlite3OsDlClose(pVfs, handle);
}
sqlite3OsDlClose(pVfs, handle);
sqlite3_free(zAltEntry);
return SQLITE_ERROR;
}else if( xInit(db, &zErrmsg, &sqlite3Apis) ){
}
sqlite3_free(zAltEntry);
if( xInit(db, &zErrmsg, &sqlite3Apis) ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}

View File

@ -496,6 +496,19 @@ int sqlite3_config(int op, ...){
}
#endif
case SQLITE_CONFIG_MMAP_SIZE: {
sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){
mxMmap = SQLITE_MAX_MMAP_SIZE;
}
sqlite3GlobalConfig.mxMmap = mxMmap;
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
if( szMmap>mxMmap) szMmap = mxMmap;
sqlite3GlobalConfig.szMmap = szMmap;
break;
}
default: {
rc = SQLITE_ERROR;
break;
@ -2337,6 +2350,7 @@ static int openDatabase(
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
db->autoCommit = 1;
db->nextAutovac = -1;
db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
#if SQLITE_DEFAULT_FILE_FORMAT<4

View File

@ -230,7 +230,9 @@ static const struct sqlite3_io_methods MemJournalMethods = {
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0 /* xShmUnlock */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/*

View File

@ -141,6 +141,26 @@ int sqlite3OsShmMap(
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xFetch(id, iOff, iAmt, pp);
}
int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
return id->pMethods->xUnfetch(id, iOff, p);
}
#else
/* No-op stubs to use when memory-mapped I/O is disabled */
int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
*pp = 0;
return SQLITE_OK;
}
int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
return SQLITE_OK;
}
#endif
/*
** The next group of routines are convenience wrappers around the
** VFS methods.

View File

@ -99,14 +99,6 @@
# define SQLITE_OS_WINRT 0
#endif
/*
** When compiled for WinCE or WinRT, there is no concept of the current
** directory.
*/
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
# define SQLITE_CURDIR 1
#endif
/* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op
*/
@ -259,6 +251,8 @@ int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
void sqlite3OsShmBarrier(sqlite3_file *id);
int sqlite3OsShmUnmap(sqlite3_file *id, int);
int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
/*

View File

@ -225,6 +225,11 @@ struct unixFile {
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
@ -249,7 +254,9 @@ struct unixFile {
unsigned char transCntrChng; /* True if the transaction counter changed */
unsigned char dbUpdate; /* True if any part of database file changed */
unsigned char inNormalWrite; /* True if in a normal write operation */
#endif
#ifdef SQLITE_TEST
/* In test mode, increase the size of this structure a bit so that
** it is larger than the struct CrashFile defined in test6.c.
@ -273,6 +280,7 @@ struct unixFile {
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */
/*
** Include code that is common to all os_*.c files
@ -306,6 +314,17 @@ struct unixFile {
#define threadid 0
#endif
/*
** HAVE_MREMAP defaults to true on Linux and false everywhere else.
*/
#if !defined(HAVE_MREMAP)
# if defined(__linux__) && defined(_GNU_SOURCE)
# define HAVE_MREMAP 1
# else
# define HAVE_MREMAP 0
# endif
#endif
/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
@ -437,6 +456,19 @@ static struct unix_syscall {
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
#if HAVE_MREMAP
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
}; /* End of the overrideable system calls */
/*
@ -768,7 +800,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
}
/******************************************************************************
****************** Begin Unique File ID Utility Used By VxWorks ***************
**
@ -1104,7 +1135,6 @@ static int unixLogErrorAtLine(
zErr = strerror(iErrno);
#endif
assert( errcode!=SQLITE_OK );
if( zPath==0 ) zPath = "";
sqlite3_log(errcode,
"os_unix.c:%d: (%d) %s(%s) - %s",
@ -1270,6 +1300,50 @@ static int findInodeInfo(
}
/*
** Check a unixFile that is a database. Verify the following:
**
** (1) There is exactly one hard link on the file
** (2) The file is not a symbolic link
** (3) The file has not been renamed or unlinked
**
** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
*/
static void verifyDbFile(unixFile *pFile){
struct stat buf;
int rc;
if( pFile->ctrlFlags & UNIXFILE_WARNED ){
/* One or more of the following warnings have already been issued. Do not
** repeat them so as not to clutter the error log */
return;
}
rc = osFstat(pFile->h, &buf);
if( rc!=0 ){
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( buf.st_nlink>1 ){
sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( pFile->pInode!=0
&& ((rc = osStat(pFile->zPath, &buf))!=0
|| buf.st_ino!=pFile->pInode->fileId.ino)
){
sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
}
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
@ -1800,9 +1874,13 @@ end_unlock:
** the requested locking level, this routine is a no-op.
*/
static int unixUnlock(sqlite3_file *id, int eFileLock){
assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
return posixUnlock(id, eFileLock, 0);
}
static int unixMapfile(unixFile *pFd, i64 nByte);
static void unixUnmapfile(unixFile *pFd);
/*
** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
@ -1815,6 +1893,7 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
*/
static int closeUnixFile(sqlite3_file *id){
unixFile *pFile = (unixFile*)id;
unixUnmapfile(pFile);
if( pFile->h>=0 ){
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
@ -1841,6 +1920,7 @@ static int closeUnixFile(sqlite3_file *id){
static int unixClose(sqlite3_file *id){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile *)id;
verifyDbFile(pFile);
unixUnlock(id, NO_LOCK);
unixEnterMutex();
@ -3082,6 +3162,23 @@ static int unixRead(
);
#endif
#if SQLITE_MAX_MMAP_SIZE>0
/* Deal with as much of this read request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
return SQLITE_OK;
}else{
int nCopy = pFile->mmapSize - offset;
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#endif
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
return SQLITE_OK;
@ -3186,6 +3283,23 @@ static int unixWrite(
}
#endif
#if SQLITE_MAX_MMAP_SIZE>0
/* Deal with as much of this write request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
return SQLITE_OK;
}else{
int nCopy = pFile->mmapSize - offset;
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#endif
while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
amt -= wrote;
offset += wrote;
@ -3468,6 +3582,14 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
}
#endif
/* If the file was just truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
*/
if( nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
}
return SQLITE_OK;
}
}
@ -3556,6 +3678,19 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
}
if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
int rc;
if( pFile->szChunk<=0 ){
if( robust_ftruncate(pFile->h, nByte) ){
pFile->lastErrno = errno;
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
}
rc = unixMapfile(pFile, nByte);
return rc;
}
return SQLITE_OK;
}
@ -3623,6 +3758,18 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 ){
pFile->mmapSizeMax = newLimit;
if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit;
}
return SQLITE_OK;
}
#ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@ -3935,7 +4082,7 @@ static void unixShmPurge(unixFile *pFd){
sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
if( p->h>=0 ){
munmap(p->apRegion[i], p->szRegion);
osMunmap(p->apRegion[i], p->szRegion);
}else{
sqlite3_free(p->apRegion[i]);
}
@ -4208,7 +4355,7 @@ static int unixShmMap(
while(pShmNode->nRegion<=iRegion){
void *pMem;
if( pShmNode->h>=0 ){
pMem = mmap(0, szRegion,
pMem = osMmap(0, szRegion,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
@ -4425,6 +4572,236 @@ static int unixShmUnmap(
# define unixShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */
/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
assert( pFd->nFetchOut==0 );
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->pMapRegion ){
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
pFd->pMapRegion = 0;
pFd->mmapSize = 0;
pFd->mmapSizeActual = 0;
}
#endif
}
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Return the system page size.
*/
static int unixGetPagesize(void){
#if HAVE_MREMAP
return 512;
#elif defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
#endif
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
**
** If successful, this function sets the following variables:
**
** unixFile.pMapRegion
** unixFile.mmapSize
** unixFile.mmapSizeActual
**
** If unsuccessful, an error message is logged via sqlite3_log() and
** the three variables above are zeroed. In this case SQLite should
** continue accessing the database using the xRead() and xWrite()
** methods.
*/
static void unixRemapfile(
unixFile *pFd, /* File descriptor object */
i64 nNew /* Required mapping size */
){
const char *zErr = "mmap";
int h = pFd->h; /* File descriptor open on db file */
u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */
i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
u8 *pNew = 0; /* Location of new mapping */
int flags = PROT_READ; /* Flags to pass to mmap() */
assert( pFd->nFetchOut==0 );
assert( nNew>pFd->mmapSize );
assert( nNew<=pFd->mmapSizeMax );
assert( nNew>0 );
assert( pFd->mmapSizeActual>=pFd->mmapSize );
assert( MAP_FAILED!=0 );
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
const int szSyspage = unixGetPagesize();
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
u8 *pReq = &pOrig[nReuse];
/* Unmap any pages of the existing mapping that cannot be reused. */
if( nReuse!=nOrig ){
osMunmap(pReq, nOrig-nReuse);
}
#if HAVE_MREMAP
pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
zErr = "mremap";
#else
pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
if( pNew!=MAP_FAILED ){
if( pNew!=pReq ){
osMunmap(pNew, nNew - nReuse);
pNew = 0;
}else{
pNew = pOrig;
}
}
#endif
/* The attempt to extend the existing mapping failed. Free it. */
if( pNew==MAP_FAILED || pNew==0 ){
osMunmap(pOrig, nReuse);
}
}
/* If pNew is still NULL, try to create an entirely new mapping. */
if( pNew==0 ){
pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
}
if( pNew==MAP_FAILED ){
pNew = 0;
nNew = 0;
unixLogError(SQLITE_OK, zErr, pFd->zPath);
/* If the mmap() above failed, assume that all subsequent mmap() calls
** will probably fail too. Fall back to using xRead/xWrite exclusively
** in this case. */
pFd->mmapSizeMax = 0;
}
pFd->pMapRegion = (void *)pNew;
pFd->mmapSize = pFd->mmapSizeActual = nNew;
}
#endif
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if
** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of
** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int unixMapfile(unixFile *pFd, i64 nByte){
#if SQLITE_MAX_MMAP_SIZE>0
i64 nMap = nByte;
int rc;
assert( nMap>=0 || pFd->nFetchOut==0 );
if( pFd->nFetchOut>0 ) return SQLITE_OK;
if( nMap<0 ){
struct stat statbuf; /* Low-level file information */
rc = osFstat(pFd->h, &statbuf);
if( rc!=SQLITE_OK ){
return SQLITE_IOERR_FSTAT;
}
nMap = statbuf.st_size;
}
if( nMap>pFd->mmapSizeMax ){
nMap = pFd->mmapSizeMax;
}
if( nMap!=pFd->mmapSize ){
if( nMap>0 ){
unixRemapfile(pFd, nMap);
}else{
unixUnmapfile(pFd);
}
}
#endif
return SQLITE_OK;
}
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
#endif
*pp = 0;
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
if( pFd->pMapRegion==0 ){
int rc = unixMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
if( pFd->mmapSize >= iOff+nAmt ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
}
#endif
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
UNUSED_PARAMETER(iOff);
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
if( p ){
pFd->nFetchOut--;
}else{
unixUnmapfile(pFd);
}
assert( pFd->nFetchOut>=0 );
return SQLITE_OK;
}
/*
** Here ends the implementation of all sqlite3_file methods.
**
@ -4483,7 +4860,9 @@ static const sqlite3_io_methods METHOD = { \
unixShmMap, /* xShmMap */ \
unixShmLock, /* xShmLock */ \
unixShmBarrier, /* xShmBarrier */ \
unixShmUnmap /* xShmUnmap */ \
unixShmUnmap, /* xShmUnmap */ \
unixFetch, /* xFetch */ \
unixUnfetch, /* xUnfetch */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@ -4500,7 +4879,7 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
IOMETHODS(
posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */
2, /* shared memory is enabled */
3, /* shared memory and mmap are enabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@ -4751,6 +5130,7 @@ static int fillInUnixFile(
pNew->pVfs = pVfs;
pNew->zPath = zFilename;
pNew->ctrlFlags = (u8)ctrlFlags;
pNew->mmapSizeMax = sqlite3GlobalConfig.mxMmap;
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW;
@ -4895,6 +5275,7 @@ static int fillInUnixFile(
}else{
pNew->pMethod = pLockingStyle;
OpenCounter(+1);
verifyDbFile(pNew);
}
return rc;
}
@ -6988,7 +7369,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==21 );
assert( ArraySize(aSyscall)==24 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){

View File

@ -150,11 +150,20 @@ struct winFile {
winceLock local; /* Locks obtained by this instance of winFile */
winceLock *shared; /* Global shared lock memory for the file */
#endif
#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch references */
HANDLE hMap; /* Handle for accessing memory mapping */
void *pMapRegion; /* Area memory mapped */
sqlite3_int64 mmapSize; /* Usable size of mapped region */
sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
};
/*
** Allowed values for winFile.ctrlFlags
*/
#define WINFILE_RDONLY 0x02 /* Connection is read only */
#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@ -2061,6 +2070,11 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
#endif
}
#if SQLITE_MAX_MMAP_SIZE>0
/* Forward references to VFS methods */
static int winUnmapfile(winFile*);
#endif
/*
** Close a file.
**
@ -2082,6 +2096,12 @@ static int winClose(sqlite3_file *id){
#endif
OSTRACE(("CLOSE %d\n", pFile->h));
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
#if SQLITE_MAX_MMAP_SIZE>0
rc = winUnmapfile(pFile);
if( rc!=SQLITE_OK ) return rc;
#endif
do{
rc = osCloseHandle(pFile->h);
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
@ -2130,9 +2150,27 @@ static int winRead(
int nRetry = 0; /* Number of retrys */
assert( id!=0 );
assert( amt>0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
/* Deal with as much of this read request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#endif
#if SQLITE_OS_WINCE
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
@ -2182,6 +2220,23 @@ static int winWrite(
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
/* Deal with as much of this write request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#endif
#if SQLITE_OS_WINCE
rc = seekWinFile(pFile, offset);
if( rc==0 ){
@ -2249,6 +2304,7 @@ static int winWrite(
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
DWORD lastErrno;
assert( pFile );
@ -2267,13 +2323,24 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
"winTruncate1", pFile->zPath);
}else if( 0==osSetEndOfFile(pFile->h) ){
pFile->lastErrno = osGetLastError();
"winTruncate1", pFile->zPath);
}else if( 0==osSetEndOfFile(pFile->h) &&
((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
pFile->lastErrno = lastErrno;
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
"winTruncate2", pFile->zPath);
"winTruncate2", pFile->zPath);
}
#if SQLITE_MAX_MMAP_SIZE>0
/* If the file was truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
*/
if( pFile->pMapRegion && nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
}
#endif
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
return rc;
}
@ -2781,6 +2848,17 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 ) pFile->mmapSizeMax = newLimit;
return SQLITE_OK;
}
#endif
}
return SQLITE_NOTFOUND;
}
@ -3451,6 +3529,192 @@ shmpage_out:
# define winShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */
/*
** Cleans up the mapped region of the specified file, if any.
*/
#if SQLITE_MAX_MMAP_SIZE>0
static int winUnmapfile(winFile *pFile){
assert( pFile!=0 );
if( pFile->pMapRegion ){
if( !osUnmapViewOfFile(pFile->pMapRegion) ){
pFile->lastErrno = osGetLastError();
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
"winUnmap1", pFile->zPath);
}
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
pFile->mmapSizeActual = 0;
}
if( pFile->hMap!=NULL ){
if( !osCloseHandle(pFile->hMap) ){
pFile->lastErrno = osGetLastError();
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
"winUnmap2", pFile->zPath);
}
pFile->hMap = NULL;
}
return SQLITE_OK;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if
** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of
** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
sqlite3_int64 nMap = nByte;
int rc;
assert( nMap>=0 || pFd->nFetchOut==0 );
if( pFd->nFetchOut>0 ) return SQLITE_OK;
if( nMap<0 ){
rc = winFileSize((sqlite3_file*)pFd, &nMap);
if( rc ){
return SQLITE_IOERR_FSTAT;
}
}
if( nMap>pFd->mmapSizeMax ){
nMap = pFd->mmapSizeMax;
}
nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
if( nMap==0 && pFd->mmapSize>0 ){
winUnmapfile(pFd);
}
if( nMap!=pFd->mmapSize ){
void *pNew = 0;
DWORD protect = PAGE_READONLY;
DWORD flags = FILE_MAP_READ;
winUnmapfile(pFd);
if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
protect = PAGE_READWRITE;
flags |= FILE_MAP_WRITE;
}
#if SQLITE_OS_WINRT
pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
#elif defined(SQLITE_WIN32_HAS_WIDE)
pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
#elif defined(SQLITE_WIN32_HAS_ANSI)
pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
#endif
if( pFd->hMap==NULL ){
pFd->lastErrno = osGetLastError();
rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile", pFd->zPath);
/* Log the error, but continue normal operation using xRead/xWrite */
return SQLITE_OK;
}
assert( (nMap % winSysInfo.dwPageSize)==0 );
#if SQLITE_OS_WINRT
pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
#else
assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
#endif
if( pNew==NULL ){
osCloseHandle(pFd->hMap);
pFd->hMap = NULL;
pFd->lastErrno = osGetLastError();
winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile", pFd->zPath);
return SQLITE_OK;
}
pFd->pMapRegion = pNew;
pFd->mmapSize = nMap;
pFd->mmapSizeActual = nMap;
}
return SQLITE_OK;
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
#endif
*pp = 0;
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
if( pFd->mmapSize >= iOff+nAmt ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
}
#endif
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
if( p ){
pFd->nFetchOut--;
}else{
/* FIXME: If Windows truly always prevents truncating or deleting a
** file while a mapping is held, then the following winUnmapfile() call
** is unnecessary can can be omitted - potentially improving
** performance. */
winUnmapfile(pFd);
}
assert( pFd->nFetchOut>=0 );
#endif
return SQLITE_OK;
}
/*
** Here ends the implementation of all sqlite3_file methods.
**
@ -3462,7 +3726,7 @@ shmpage_out:
** sqlite3_file for win32.
*/
static const sqlite3_io_methods winIoMethod = {
2, /* iVersion */
3, /* iVersion */
winClose, /* xClose */
winRead, /* xRead */
winWrite, /* xWrite */
@ -3478,7 +3742,9 @@ static const sqlite3_io_methods winIoMethod = {
winShmMap, /* xShmMap */
winShmLock, /* xShmLock */
winShmBarrier, /* xShmBarrier */
winShmUnmap /* xShmUnmap */
winShmUnmap, /* xShmUnmap */
winFetch, /* xFetch */
winUnfetch /* xUnfetch */
};
/****************************************************************************
@ -3654,9 +3920,7 @@ static int winOpen(
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
#ifndef NDEBUG
int isReadonly = (flags & SQLITE_OPEN_READONLY);
#endif
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
@ -3867,11 +4131,21 @@ static int winOpen(
pFile->pMethod = &winIoMethod;
pFile->pVfs = pVfs;
pFile->h = h;
if( isReadonly ){
pFile->ctrlFlags |= WINFILE_RDONLY;
}
if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
pFile->ctrlFlags |= WINFILE_PSOW;
}
pFile->lastErrno = NO_ERROR;
pFile->zPath = zName;
#if SQLITE_MAX_MMAP_SIZE>0
pFile->hMap = NULL;
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
pFile->mmapSizeActual = 0;
pFile->mmapSizeMax = sqlite3GlobalConfig.mxMmap;
#endif
OpenCounter(+1);
return rc;
@ -4500,7 +4774,6 @@ int sqlite3_os_init(void){
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==74 );
#ifndef SQLITE_OMIT_WAL
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT
@ -4508,8 +4781,8 @@ int sqlite3_os_init(void){
#else
osGetSystemInfo(&winSysInfo);
#endif
assert(winSysInfo.dwAllocationGranularity > 0);
#endif
assert( winSysInfo.dwAllocationGranularity>0 );
assert( winSysInfo.dwPageSize>0 );
sqlite3_vfs_register(&winVfs, 1);
return SQLITE_OK;

View File

@ -655,6 +655,11 @@ struct Pager {
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
char dbFileVers[16]; /* Changes whenever database file changes */
u8 bUseFetch; /* True to use xFetch() */
int nMmapOut; /* Number of mmap pages currently outstanding */
sqlite3_int64 szMmap; /* Desired maximum mmap size */
PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
/*
** End of the routinely-changing class members
***************************************************************************/
@ -765,6 +770,16 @@ static const unsigned char aJournalMagic[] = {
# define MEMDB pPager->memDb
#endif
/*
** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch
** interfaces to access the database using memory-mapped I/O.
*/
#if SQLITE_MAX_MMAP_SIZE>0
# define USEFETCH(x) ((x)->bUseFetch)
#else
# define USEFETCH(x) 0
#endif
/*
** The maximum legal page number is (2^31 - 1).
*/
@ -2252,7 +2267,7 @@ static int pager_playback_one_page(
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
assert( !pagerUseWal(pPager) );
rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst);
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
@ -2643,6 +2658,7 @@ static int pager_playback(Pager *pPager, int isHot){
int res = 1; /* Value returned by sqlite3OsAccess() */
char *zMaster = 0; /* Name of master journal file if any */
int needPagerReset; /* True to reset page prior to first page rollback */
int nPlayback = 0; /* Total number of pages restored from journal */
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
@ -2743,7 +2759,9 @@ static int pager_playback(Pager *pPager, int isHot){
needPagerReset = 0;
}
rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_OK ){
nPlayback++;
}else{
if( rc==SQLITE_DONE ){
pPager->journalOff = szJ;
break;
@ -2813,6 +2831,10 @@ end_playback:
rc = pager_delmaster(pPager, zMaster);
testcase( rc!=SQLITE_OK );
}
if( isHot && nPlayback ){
sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
nPlayback, pPager->zJournal);
}
/* The Pager.sectorSize variable may have been updated while rolling
** back a journal created by a process with a different sector size
@ -2834,11 +2856,10 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
static int readDbPage(PgHdr *pPg){
static int readDbPage(PgHdr *pPg, u32 iFrame){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */
int isInWal = 0; /* True if page is in log file */
int pgsz = pPager->pageSize; /* Number of bytes to read */
assert( pPager->eState>=PAGER_READER && !MEMDB );
@ -2850,11 +2871,10 @@ static int readDbPage(PgHdr *pPg){
return SQLITE_OK;
}
if( pagerUseWal(pPager) ){
if( iFrame ){
/* Try to pull the page from the write-ahead log. */
rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
}
if( rc==SQLITE_OK && !isInWal ){
rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
}else{
i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
@ -2933,12 +2953,17 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
Pager *pPager = (Pager *)pCtx;
PgHdr *pPg;
assert( pagerUseWal(pPager) );
pPg = sqlite3PagerLookup(pPager, iPg);
if( pPg ){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
rc = readDbPage(pPg);
u32 iFrame = 0;
rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
if( rc==SQLITE_OK ){
rc = readDbPage(pPg, iFrame);
}
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
@ -3082,6 +3107,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
if( rc!=SQLITE_OK || changed ){
pager_reset(pPager);
if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
}
return rc;
@ -3343,6 +3369,29 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
}
/*
** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
*/
static void pagerFixMaplimit(Pager *pPager){
#if SQLITE_MAX_MMAP_SIZE>0
sqlite3_file *fd = pPager->fd;
if( isOpen(fd) ){
sqlite3_int64 sz;
pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0;
sz = pPager->szMmap;
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
}
#endif
}
/*
** Change the maximum size of any memory mapping made of the database file.
*/
void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){
pPager->szMmap = szMmap;
pagerFixMaplimit(pPager);
}
/*
** Free as much memory as possible from the pager.
*/
@ -3578,6 +3627,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager);
pagerFixMaplimit(pPager);
}
return rc;
}
@ -3803,6 +3853,81 @@ static int pagerSyncHotJournal(Pager *pPager){
return rc;
}
/*
** Obtain a reference to a memory mapped page object for page number pgno.
** The new object will use the pointer pData, obtained from xFetch().
** If successful, set *ppPage to point to the new page reference
** and return SQLITE_OK. Otherwise, return an SQLite error code and set
** *ppPage to zero.
**
** Page references obtained by calling this function should be released
** by calling pagerReleaseMapPage().
*/
static int pagerAcquireMapPage(
Pager *pPager, /* Pager object */
Pgno pgno, /* Page number */
void *pData, /* xFetch()'d data for this page */
PgHdr **ppPage /* OUT: Acquired page object */
){
PgHdr *p; /* Memory mapped page to return */
if( pPager->pMmapFreelist ){
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
p->pDirty = 0;
memset(p->pExtra, 0, pPager->nExtra);
}else{
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
return SQLITE_NOMEM;
}
p->pExtra = (void *)&p[1];
p->flags = PGHDR_MMAP;
p->nRef = 1;
p->pPager = pPager;
}
assert( p->pExtra==(void *)&p[1] );
assert( p->pPage==0 );
assert( p->flags==PGHDR_MMAP );
assert( p->pPager==pPager );
assert( p->nRef==1 );
p->pgno = pgno;
p->pData = pData;
pPager->nMmapOut++;
return SQLITE_OK;
}
/*
** Release a reference to page pPg. pPg must have been returned by an
** earlier call to pagerAcquireMapPage().
*/
static void pagerReleaseMapPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
pPager->nMmapOut--;
pPg->pDirty = pPager->pMmapFreelist;
pPager->pMmapFreelist = pPg;
assert( pPager->fd->pMethods->iVersion>=3 );
sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
}
/*
** Free all PgHdr objects stored in the Pager.pMmapFreelist list.
*/
static void pagerFreeMapHdrs(Pager *pPager){
PgHdr *p;
PgHdr *pNext;
for(p=pPager->pMmapFreelist; p; p=pNext){
pNext = p->pDirty;
sqlite3_free(p);
}
}
/*
** Shutdown the page cache. Free all memory and close all files.
**
@ -3823,6 +3948,7 @@ int sqlite3PagerClose(Pager *pPager){
assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
pagerFreeMapHdrs(pPager);
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
@ -4084,7 +4210,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
** file size will be.
*/
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){
if( rc==SQLITE_OK
&& (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize
){
sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
pPager->dbHintSize = pPager->dbSize;
@ -4638,6 +4766,7 @@ int sqlite3PagerOpen(
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
/* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
*ppPager = pPager;
return SQLITE_OK;
@ -4929,9 +5058,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
);
}
if( !pPager->tempFile
&& (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0)
){
if( !pPager->tempFile && (
pPager->pBackup
|| sqlite3PcachePagecount(pPager->pPCache)>0
|| USEFETCH(pPager)
)){
/* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous
** read or write transaction). Check to see if the database
@ -4957,7 +5088,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
goto failed;
}
}else{
@ -4966,6 +5097,16 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager);
/* Unmap the database file. It is possible that external processes
** may have truncated the database file and then extended it back
** to its original size while this process was not holding a lock.
** In this case there may exist a Pager.pMap mapping that appears
** to be the right size but is not actually valid. Avoid this
** possibility by unmapping the db here. */
if( USEFETCH(pPager) ){
sqlite3OsUnfetch(pPager->fd, 0, 0);
}
}
}
@ -5007,7 +5148,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op.
*/
static void pagerUnlockIfUnused(Pager *pPager){
if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
pagerUnlockAndRollback(pPager);
}
}
@ -5066,13 +5207,27 @@ int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */
int noContent /* Do not bother reading content from disk if true */
int flags /* PAGER_ACQUIRE_XXX flags */
){
int rc;
PgHdr *pPg;
int rc = SQLITE_OK;
PgHdr *pPg = 0;
u32 iFrame = 0; /* Frame to read from WAL file */
const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
/* It is acceptable to use a read-only (mmap) page for any page except
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
** flag was specified by the caller. And so long as the db is not a
** temporary or in-memory database. */
const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
&& (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
#ifdef SQLITE_HAS_CODEC
&& pPager->xCodec==0
#endif
);
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
assert( noContent==0 || bMmapOk==0 );
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
@ -5083,6 +5238,39 @@ int sqlite3PagerAcquire(
if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode;
}else{
if( bMmapOk && pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
if( iFrame==0 && bMmapOk ){
void *pData = 0;
rc = sqlite3OsFetch(pPager->fd,
(i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
);
if( rc==SQLITE_OK && pData ){
if( pPager->eState>PAGER_READER ){
(void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
}else{
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
}
if( pPg ){
assert( rc==SQLITE_OK );
*ppPage = pPg;
return SQLITE_OK;
}
}
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
}
rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
}
@ -5141,9 +5329,13 @@ int sqlite3PagerAcquire(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
if( pagerUseWal(pPager) && bMmapOk==0 ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
rc = readDbPage(pPg);
rc = readDbPage(pPg, iFrame);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
@ -5196,7 +5388,11 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
void sqlite3PagerUnref(DbPage *pPg){
if( pPg ){
Pager *pPager = pPg->pPager;
sqlite3PcacheRelease(pPg);
if( pPg->flags & PGHDR_MMAP ){
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
pagerUnlockIfUnused(pPager);
}
}
@ -5531,6 +5727,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) );
@ -6087,7 +6284,7 @@ int sqlite3PagerRollback(Pager *pPager){
}
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
assert( rc==SQLITE_OK || rc==SQLITE_FULL
assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
|| rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
@ -6821,11 +7018,12 @@ static int pagerOpenWal(Pager *pPager){
** (e.g. due to malloc() failure), return an error code.
*/
if( rc==SQLITE_OK ){
rc = sqlite3WalOpen(pPager->pVfs,
rc = sqlite3WalOpen(pPager->pVfs,
pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal
);
}
pagerFixMaplimit(pPager);
return rc;
}
@ -6916,6 +7114,7 @@ int sqlite3PagerCloseWal(Pager *pPager){
rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
}
}
return rc;

View File

@ -78,6 +78,12 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** Flags that make up the mask passed to sqlite3PagerAcquire().
*/
#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
/*
** The remainder of this file contains the declarations of the functions
** that make up the Pager sub-system API. See source code comments for
@ -102,6 +108,7 @@ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
void sqlite3PagerShrink(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
int sqlite3PagerLockingMode(Pager *, int);

View File

@ -53,6 +53,8 @@ struct PgHdr {
#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
#define PGHDR_MMAP 0x040 /* This is an mmap page object */
/* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void);
void sqlite3PcacheShutdown(void);

View File

@ -319,7 +319,7 @@ void sqlite3Pragma(
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@ -402,11 +402,12 @@ void sqlite3Pragma(
static const VdbeOpList getCacheSize[] = {
{ OP_Transaction, 0, 0, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
{ OP_IfPos, 1, 7, 0},
{ OP_IfPos, 1, 8, 0},
{ OP_Integer, 0, 2, 0},
{ OP_Subtract, 1, 2, 1},
{ OP_IfPos, 1, 7, 0},
{ OP_IfPos, 1, 8, 0},
{ OP_Integer, 0, 1, 0}, /* 6 */
{ OP_Noop, 0, 0, 0},
{ OP_ResultRow, 1, 1, 0},
};
int addr;
@ -744,6 +745,43 @@ void sqlite3Pragma(
}
}else
/*
** PRAGMA [database.]mmap_size(N)
**
** Used to set mapping size limit. The mapping size limit is
** used to limit the aggregate size of all memory mapped regions of the
** database file. If this parameter is set to zero, then memory mapping
** is not used at all. If N is negative, then the default memory map
** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set.
** The parameter N is measured in bytes.
**
** This value is advisory. The underlying VFS is free to memory map
** as little or as much as it wants. Except, if N is set to 0 then the
** upper layers will never invoke the xFetch interfaces to the VFS.
*/
if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){
sqlite3_int64 sz;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8);
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
if( pId2->n==0 ) db->szMmap = sz;
for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
}
}
}
sz = -1;
if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){
#if SQLITE_MAX_MMAP_SIZE==0
sz = 0;
#endif
returnSingleInt(pParse, "mmap_size", sz);
}
}else
/*
** PRAGMA temp_store
** PRAGMA temp_store = "default"|"memory"|"file"

View File

@ -654,7 +654,6 @@ static int sqlite3Prepare(
}
#endif
assert( db->init.busy==0 || saveSqlFlag==0 );
if( db->init.busy==0 ){
Vdbe *pVdbe = pParse->pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);

View File

@ -388,7 +388,10 @@ static int lookupName(
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
*/
if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
if( (pEList = pNC->pEList)!=0
&& zTab==0
&& ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@ -479,7 +482,9 @@ static int lookupName(
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
if( pExpr->op!=TK_AS ){
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
}
/* Increment the nRef value on all name contexts from TopNC up to
** the point where the name matched. */
for(;;){
@ -1154,11 +1159,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** re-evaluated for each reference to it.
*/
sNC.pEList = p->pEList;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ||
sqlite3ResolveExprNames(&sNC, p->pHaving)
){
return WRC_Abort;
}
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
sNC.ncFlags |= NC_AsMaybe;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
sNC.ncFlags &= ~NC_AsMaybe;
/* The ORDER BY and GROUP BY clauses may not refer to terms in
** outer queries

View File

@ -1552,6 +1552,43 @@ static int booleanValue(char *zArg){
return 0;
}
/*
** Interpret zArg as an integer value, possibly with suffixes.
*/
static sqlite3_int64 integerValue(const char *zArg){
sqlite3_int64 v = 0;
static const struct { char *zSuffix; int iMult; } aMult[] = {
{ "KiB", 1024 },
{ "MiB", 1024*1024 },
{ "GiB", 1024*1024*1024 },
{ "KB", 1000 },
{ "MB", 1000000 },
{ "GB", 1000000000 },
{ "K", 1000 },
{ "M", 1000000 },
{ "G", 1000000000 },
};
int i;
int isNeg = 0;
if( zArg[0]=='-' ){
isNeg = 1;
zArg++;
}else if( zArg[0]=='+' ){
zArg++;
}
while( isdigit(zArg[0]) ){
v = v*10 + zArg[0] - '0';
zArg++;
}
for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
v *= aMult[i].iMult;
break;
}
}
return isNeg? -v : v;
}
/*
** Close an output file, assuming it is not stderr or stdout
*/
@ -2469,7 +2506,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
/* sqlite3_test_control(int, uint) */
case SQLITE_TESTCTRL_PENDING_BYTE:
if( nArg==3 ){
unsigned int opt = (unsigned int)atoi(azArg[2]);
unsigned int opt = (unsigned int)integerValue(azArg[2]);
rc = sqlite3_test_control(testctrl, opt);
printf("%d (0x%08x)\n", rc, rc);
} else {
@ -2561,7 +2598,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
extern int sqlite3WhereTrace;
sqlite3WhereTrace = atoi(azArg[1]);
sqlite3WhereTrace = booleanValue(azArg[1]);
}else
#endif
@ -2747,6 +2784,10 @@ static int process_input(struct callback_data *p, FILE *in){
free(zSql);
zSql = 0;
nSql = 0;
}else if( zSql && _all_whitespace(zSql) ){
free(zSql);
zSql = 0;
nSql = 0;
}
}
if( zSql ){
@ -2882,6 +2923,7 @@ static const char zOptions[] =
" -interactive force interactive I/O\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -mmap N default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n"
#endif
@ -3001,12 +3043,7 @@ int main(int argc, char **argv){
sqlite3_int64 szHeap;
zSize = cmdline_option_value(argc, argv, ++i);
szHeap = atoi(zSize);
for(j=0; (c = zSize[j])!=0; j++){
if( c=='M' ){ szHeap *= 1000000; break; }
if( c=='K' ){ szHeap *= 1000; break; }
if( c=='G' ){ szHeap *= 1000000000; break; }
}
szHeap = integerValue(zSize);
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#endif
@ -3026,6 +3063,9 @@ int main(int argc, char **argv){
extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1);
#endif
}else if( strcmp(z,"-mmap")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
}else if( strcmp(z,"-vfs")==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
if( pVfs ){
@ -3111,6 +3151,8 @@ int main(int argc, char **argv){
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
i++;
}else if( strcmp(z,"-mmap")==0 ){
i++;
}else if( strcmp(z,"-vfs")==0 ){
i++;
#ifdef SQLITE_ENABLE_VFSTRACE
@ -3128,7 +3170,7 @@ int main(int argc, char **argv){
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc;
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
open_db(&data);
rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
@ -3152,6 +3194,7 @@ int main(int argc, char **argv){
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
if( rc==2 ) rc = 0;
}else{
open_db(&data);
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);

View File

@ -420,6 +420,8 @@ int sqlite3_exec(
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
@ -470,6 +472,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
@ -489,6 +492,8 @@ int sqlite3_exec(
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@ -728,6 +733,9 @@ struct sqlite3_io_methods {
void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */
int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */
};
@ -864,7 +872,8 @@ struct sqlite3_io_methods {
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^This file-control may be invoked by SQLite on the database file handle
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connections busy-handler callback. The argument is of type (void **)
** - an array of two (void *) values. The first (void *) actually points
@ -875,13 +884,24 @@ struct sqlite3_io_methods {
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Application can invoke this file-control to have SQLite generate a
** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()]. The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**
** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
** maximum number of bytes that will be used for memory-mapped I/O.
** The argument is a pointer to a value of type sqlite3_int64 that
** is an advisory maximum number of bytes in the file to memory map. The
** pointer is overwritten with the old value. The limit is not changed if
** the value originally pointed to is negative, and so the current limit
** can be queried by passing in a pointer to a negative number. This
** file-control is used internally to implement [PRAGMA mmap_size].
**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@ -900,6 +920,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_PRAGMA 14
#define SQLITE_FCNTL_BUSYHANDLER 15
#define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_SIZE 18
/*
** CAPI3REF: Mutex Handle
@ -1612,12 +1633,12 @@ struct sqlite3_mem_methods {
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops.
** </dl>
** </dd>
**
** [[SQLITE_CONFIG_SQLLOG]]
** <dt>SQLITE_CONFIG_SQLLOG
** <dd>This option is only available if sqlite is compiled with the
** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should
** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
** The second should be of type (void*). The callback is invoked by the library
** in three separate circumstances, identified by the value passed as the
@ -1627,7 +1648,23 @@ struct sqlite3_mem_methods {
** fourth parameter is 1, then the SQL statement that the third parameter
** points to has just been executed. Or, if the fourth parameter is 2, then
** the connection being passed as the second parameter is being closed. The
** third parameter is passed NULL In this case.
** third parameter is passed NULL In this case. An example of using this
** configuration option can be seen in the "test_sqllog.c" source file in
** the canonical SQLite source tree.</dd>
**
** [[SQLITE_CONFIG_MMAP_SIZE]]
** <dt>SQLITE_CONFIG_MMAP_SIZE
** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
** that are the default mmap size limit (the default setting for
** [PRAGMA mmap_size]) and the maximum allowed mmap size limit.
** The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size
** cannot be changed at run-time. Nor may the maximum allowed mmap size
** exceed the compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.
** If either argument to this option is negative, then that argument is
** changed to its compile-time default.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@ -1651,6 +1688,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
/*
** CAPI3REF: Database Connection Configuration Options
@ -4182,7 +4220,7 @@ void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
** the content before returning.
**
** The typedef is necessary to work around problems in certain
** C++ compilers. See ticket #2191.
** C++ compilers.
*/
typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ((sqlite3_destructor_type)0)
@ -4981,11 +5019,20 @@ int sqlite3_table_column_metadata(
** ^This interface loads an SQLite extension library from the named file.
**
** ^The sqlite3_load_extension() interface attempts to load an
** SQLite extension library contained in the file zFile.
** [SQLite extension] library contained in the file zFile. If
** the file cannot be loaded directly, attempts are made to load
** with various operating-system specific extensions added.
** So for example, if "samplelib" cannot be loaded, then names like
** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
** be tried also.
**
** ^The entry point is zProc.
** ^zProc may be 0, in which case the name of the entry point
** defaults to "sqlite3_extension_init".
** ^(zProc may be 0, in which case SQLite will try to come up with an
** entry point name on its own. It first tries "sqlite3_extension_init".
** If that does not work, it constructs a name "sqlite3_X_init" where the
** X is consists of the lower-case equivalent of all ASCII alphabetic
** characters in the filename from the last "/" to the first following
** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns
** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
** ^If an error occurs and pzErrMsg is not 0, then the
@ -5011,11 +5058,11 @@ int sqlite3_load_extension(
** CAPI3REF: Enable Or Disable Extension Loading
**
** ^So as not to open security holes in older applications that are
** unprepared to deal with extension loading, and as a means of disabling
** extension loading while evaluating user-entered SQL, the following API
** unprepared to deal with [extension loading], and as a means of disabling
** [extension loading] while evaluating user-entered SQL, the following API
** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
**
** ^Extension loading is off by default. See ticket #1863.
** ^Extension loading is off by default.
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
@ -5027,7 +5074,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
**
** ^This interface causes the xEntryPoint() function to be invoked for
** each new [database connection] that is created. The idea here is that
** xEntryPoint() is the entry point for a statically linked SQLite extension
** xEntryPoint() is the entry point for a statically linked [SQLite extension]
** that is to be automatically loaded into all new database connections.
**
** ^(Even though the function prototype shows that xEntryPoint() takes
@ -6807,6 +6854,21 @@ int sqlite3_unlock_notify(
int sqlite3_stricmp(const char *, const char *);
int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
*
** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
** the glob pattern P, and it returns non-zero if string X does not match
** the glob pattern P. ^The definition of glob pattern matching used in
** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
** sensitive.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
int sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: Error Logging Interface
**

View File

@ -469,7 +469,16 @@ struct sqlite3_api_routines {
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
#ifndef SQLITE_CORE
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
#endif
#endif /* _SQLITE3EXT_H_ */

View File

@ -122,11 +122,11 @@
** We support that for legacy.
*/
#if !defined(SQLITE_THREADSAFE)
#if defined(THREADSAFE)
# define SQLITE_THREADSAFE THREADSAFE
#else
# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
#endif
# if defined(THREADSAFE)
# define SQLITE_THREADSAFE THREADSAFE
# else
# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
# endif
#endif
/*
@ -392,6 +392,7 @@
*/
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 1
# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
#endif
/*
@ -539,6 +540,49 @@ extern const int sqlite3one;
# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
#endif
/*
** Disable MMAP on platforms where it is known to not work
*/
#if defined(__OpenBSD__) || defined(__QNXNTO__)
# undef SQLITE_MAX_MMAP_SIZE
# define SQLITE_MAX_MMAP_SIZE 0
#endif
/*
** Default maximum size of memory used by memory-mapped I/O in the VFS
*/
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# undef SQLITE_MAX_MMAP_SIZE
# define SQLITE_MAX_MMAP_SIZE 0
# endif
#endif
#ifndef SQLITE_MAX_MMAP_SIZE
# if defined(__linux__) \
|| defined(_WIN32) \
|| (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__sun)
# define SQLITE_MAX_MMAP_SIZE 2147483648
# else
# define SQLITE_MAX_MMAP_SIZE 0
# endif
# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
#endif
/*
** The default MMAP_SIZE is zero on all platforms. Or, even if a larger
** default MMAP_SIZE is specified at compile-time, make sure that it does
** not exceed the maximum mmap size.
*/
#ifndef SQLITE_DEFAULT_MMAP_SIZE
# define SQLITE_DEFAULT_MMAP_SIZE 0
# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */
#endif
#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
# undef SQLITE_DEFAULT_MMAP_SIZE
# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
#endif
/*
** An instance of the following structure is used to store the busy-handler
@ -835,6 +879,7 @@ struct sqlite3 {
int nDb; /* Number of backends currently in use */
int flags; /* Miscellaneous flags. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 szMmap; /* Default mmap_size setting */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
@ -2078,6 +2123,8 @@ struct NameContext {
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
#define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
** if no other resolution is available */
/*
** An instance of the following structure contains all information
@ -2517,6 +2564,8 @@ struct Sqlite3Config {
void *pHeap; /* Heap storage space */
int nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max heap requests sizes */
sqlite3_int64 szMmap; /* mmap() space per open file */
sqlite3_int64 mxMmap; /* Maximum value for szMmap */
void *pScratch; /* Scratch memory */
int szScratch; /* Size of each scratch buffer */
int nScratch; /* Number of scratch buffers */

View File

@ -116,71 +116,76 @@ int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
const char *sqlite3TestErrorName(int rc){
const char *zName = 0;
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break;
case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break;
case SQLITE_CONSTRAINT_FOREIGNKEY:
zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break;
case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break;
case SQLITE_CONSTRAINT_PRIMARYKEY:
zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break;
case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break;
case SQLITE_CONSTRAINT_COMMITHOOK:
zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break;
case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break;
case SQLITE_CONSTRAINT_FUNCTION: zName = "SQLITE_CONSTRAINT_FUNCTION";break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break;
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break;
case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break;
case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break;
case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break;
case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break;
case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break;
case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
default: zName = "SQLITE_Unknown"; break;
int i;
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break;
case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break;
case SQLITE_CONSTRAINT_FOREIGNKEY:
zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break;
case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break;
case SQLITE_CONSTRAINT_PRIMARYKEY:
zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break;
case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break;
case SQLITE_CONSTRAINT_COMMITHOOK:
zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break;
case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break;
case SQLITE_CONSTRAINT_FUNCTION: zName = "SQLITE_CONSTRAINT_FUNCTION";break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break;
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break;
case SQLITE_WARNING: zName = "SQLITE_WARNING"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break;
case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break;
case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break;
case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break;
case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break;
case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break;
case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
}
}
if( zName==0 ) zName = "SQLITE_Unknown";
return zName;
}
#define t1ErrorName sqlite3TestErrorName
@ -5844,6 +5849,31 @@ static int test_test_control(
return TCL_OK;
}
#if SQLITE_OS_UNIX
#include <sys/time.h>
#include <sys/resource.h>
static int test_getrusage(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char buf[1024];
struct rusage r;
memset(&r, 0, sizeof(r));
getrusage(RUSAGE_SELF, &r);
sprintf(buf, "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
(int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec,
(int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec,
(int)r.ru_minflt, (int)r.ru_majflt
);
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
return TCL_OK;
}
#endif
#if SQLITE_OS_WIN
/*
** Information passed from the main thread into the windows file locker
@ -6233,6 +6263,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "print_explain_query_plan", test_print_eqp, 0 },
#endif
{ "sqlite3_test_control", test_test_control },
#if SQLITE_OS_UNIX
{ "getrusage", test_getrusage },
#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;

View File

@ -19,35 +19,7 @@
#include <string.h>
#include <ctype.h>
/*
** Interpret an SQLite error number
*/
static char *errorName(int rc){
char *zName;
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
default: zName = "SQLITE_Unknown"; break;
}
return zName;
}
extern const char *sqlite3TestErrorName(int rc);
/*
** Page size and reserved size used for testing.
@ -87,7 +59,7 @@ static int pager_open(
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
pager_test_reiniter);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3PagerSetCachesize(pPager, nPage);
@ -119,7 +91,7 @@ static int pager_close(
pPager = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerClose(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -146,7 +118,7 @@ static int pager_rollback(
pPager = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerRollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -173,12 +145,12 @@ static int pager_commit(
pPager = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
rc = sqlite3PagerCommitPhaseTwo(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -205,7 +177,7 @@ static int pager_stmt_begin(
pPager = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerOpenSavepoint(pPager, 1);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -233,7 +205,7 @@ static int pager_stmt_rollback(
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -260,7 +232,7 @@ static int pager_stmt_commit(
pPager = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -353,7 +325,7 @@ static int page_get(
rc = sqlite3PagerGet(pPager, pgno, &pPage);
}
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
@ -507,7 +479,7 @@ static int page_write(
pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
rc = sqlite3PagerWrite(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
pData = sqlite3PagerGetData(pPage);
@ -556,7 +528,7 @@ static int fake_big_file(
(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
);
if( rc ){
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
Tcl_AppendResult(interp, "open failed: ", sqlite3TestErrorName(rc), 0);
sqlite3_free(zFile);
return TCL_ERROR;
}
@ -566,7 +538,7 @@ static int fake_big_file(
sqlite3OsCloseFree(fd);
sqlite3_free(zFile);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
Tcl_AppendResult(interp, "write failed: ", sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;

View File

@ -19,31 +19,7 @@
#include <stdlib.h>
#include <string.h>
/*
** Interpret an SQLite error number
*/
static char *errorName(int rc){
char *zName;
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
default: zName = "SQLITE_Unknown"; break;
}
return zName;
}
extern const char *sqlite3TestErrorName(int rc);
/*
** A bogus sqlite3 connection structure for use in the btree
@ -89,7 +65,7 @@ static int btree_open(
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
sqlite3_free(zFilename);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3BtreeSetCacheSize(pBt, nCache);
@ -119,7 +95,7 @@ static int btree_close(
pBt = sqlite3TestTextToPtr(argv[1]);
rc = sqlite3BtreeClose(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
nRefSqlite3--;
@ -156,7 +132,7 @@ static int btree_begin_transaction(
rc = sqlite3BtreeBeginTrans(pBt, 1);
sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
@ -250,7 +226,7 @@ static int btree_cursor(
sqlite3BtreeLeave(pBt);
if( rc ){
ckfree((char *)pCur);
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
@ -285,7 +261,7 @@ static int btree_close_cursor(
sqlite3BtreeLeave(pBt);
ckfree((char *)pCur);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
return SQLITE_OK;
@ -319,7 +295,7 @@ static int btree_next(
rc = sqlite3BtreeNext(pCur, &res);
sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
@ -354,7 +330,7 @@ static int btree_first(
rc = sqlite3BtreeFirst(pCur, &res);
sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
return TCL_ERROR;
}
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);

View File

@ -20,6 +20,8 @@
#include <sched.h>
#include <ctype.h>
extern const char *sqlite3TestErrorName(int rc);
/*
** Each thread is controlled by an instance of the following
** structure.
@ -372,34 +374,7 @@ static int tcl_thread_result(
return TCL_ERROR;
}
thread_wait(&threadset[i]);
switch( threadset[i].rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
default: zName = "SQLITE_Unknown"; break;
}
zName = sqlite3TestErrorName(threadset[i].rc);
Tcl_AppendResult(interp, zName, 0);
return TCL_OK;
}

View File

@ -376,6 +376,8 @@ static int tcl_client_colname(
return TCL_OK;
}
extern const char *sqlite3TestErrorName(int rc);
/*
** Usage: client_result ID
**
@ -403,34 +405,7 @@ static int tcl_client_result(
return TCL_ERROR;
}
client_wait(&threadset[i]);
switch( threadset[i].rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
default: zName = "SQLITE_Unknown"; break;
}
zName = sqlite3TestErrorName(threadset[i].rc);
Tcl_AppendResult(interp, zName, 0);
return TCL_OK;
}

View File

@ -15,7 +15,7 @@
#include "sqlite3ext.h"
#ifndef SQLITE_OMIT_LOAD_EXTENSION
static SQLITE_EXTENSION_INIT1
SQLITE_EXTENSION_INIT1
/*
** The sqr() SQL function returns the square of its input value.

View File

@ -57,7 +57,7 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_CURDIR
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY);
@ -87,6 +87,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY);
#endif
#if SQLITE_MAX_MMAP_SIZE>0
Tcl_SetVar2(interp, "sqlite_options", "mmap", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY);
#endif
#if 1 /* def SQLITE_MEMDEBUG */
Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY);
#else

View File

@ -13,22 +13,32 @@
** OVERVIEW
**
** This file contains experimental code used to record data from live
** SQLite applications that may be useful for offline analysis. Specifically:
** SQLite applications that may be useful for offline analysis.
** Specifically, this module can be used to capture the following
** information:
**
** 1) The initial contents of all database files opened by the
** application, and
**
** 2) All SQL statements executed by the application.
**
** The captured information can then be used to run (for example)
** performance analysis looking for slow queries or to look for
** optimization opportunities in either the application or in SQLite
** itself.
**
** USAGE
**
** To use this module, SQLite must be compiled with the SQLITE_ENABLE_SQLLOG
** pre-processor symbol defined and this file linked into the application
** somehow.
** pre-processor symbol defined and this file linked into the application.
** One way to link this file into the application is to append the content
** of this file onto the end of the "sqlite3.c" amalgamation and then
** recompile the application as normal except with the addition of the
** -DSQLITE_ENABLE_SQLLOG option.
**
** At runtime, logging is enabled by setting environment variable
** SQLITE_SQLLOG_DIR to the name of a directory in which to store logged
** data. The directory must already exist.
** data. The logging directory must already exist.
**
** Usually, if the application opens the same database file more than once
** (either by attaching it or by using more than one database handle), only
@ -57,14 +67,16 @@
** logging proceeds as expected. Errors are logged by calling sqlite3_log().
*/
#ifndef _SQLITE3_H_
#include "sqlite3.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "assert.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sys/types.h"
#include "unistd.h"
#include <sys/types.h>
#include <unistd.h>
static int getProcessId(void){
#if SQLITE_OS_WIN
return (int)_getpid();
@ -73,7 +85,7 @@ static int getProcessId(void){
#endif
}
/* Names of environment variables to be used */
#define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR"
#define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES"
@ -86,6 +98,9 @@ static int getProcessId(void){
*/
#define MAX_CONNECTIONS 256
/* There is one instance of this object for each SQLite database connection
** that is being logged.
*/
struct SLConn {
int isErr; /* True if an error has occurred */
sqlite3 *db; /* Connection handle */
@ -93,7 +108,9 @@ struct SLConn {
FILE *fd; /* File descriptor for log file */
};
struct SLGlobal {
/* This object is a singleton that keeps track of all data loggers.
*/
static struct SLGlobal {
/* Protected by MUTEX_STATIC_MASTER */
sqlite3_mutex *mutex; /* Recursive mutex */
int nConn; /* Size of aConn[] array */
@ -388,6 +405,24 @@ static void testSqllogStmt(struct SLConn *p, const char *zSql){
/*
** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog().
**
** The eType parameter has the following values:
**
** 0: Opening a new database connection. zSql is the name of the
** file being opened. db is a pointer to the newly created database
** connection.
**
** 1: An SQL statement has run to completion. zSql is the text of the
** SQL statement with all parameters expanded to their actual values.
**
** 2: Closing a database connection. zSql is NULL. The db pointer to
** the database connection being closed has already been shut down
** and cannot be used for any further SQL.
**
** The pCtx parameter is a copy of the pointer that was originally passed
** into the sqlite3_config(SQLITE_CONFIG_SQLLOG) statement. In this
** particular implementation, pCtx is always a pointer to the
** sqllogglobal global variable define above.
*/
static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
struct SLConn *p = 0;

View File

@ -23,7 +23,7 @@
**
** open close access getcwd stat fstat
** ftruncate fcntl read pread pread64 write
** pwrite pwrite64 fchmod fallocate
** pwrite pwrite64 fchmod fallocate mmap
**
** test_syscall uninstall
** Uninstall all wrapper functions.
@ -81,6 +81,7 @@
/* From test1.c */
extern const char *sqlite3TestErrorName(int);
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>
@ -106,7 +107,8 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_fchmod(int fd, mode_t mode);
static int ts_fallocate(int fd, off_t off, off_t len);
static void *ts_mmap(void *, size_t, int, int, int, off_t);
static void *ts_mremap(void*, size_t, size_t, int, ...);
struct TestSyscallArray {
const char *zName;
@ -131,6 +133,8 @@ struct TestSyscallArray {
/* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 },
/* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 },
/* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
/* 16 */ { "mmap", (sqlite3_syscall_ptr)ts_mmap, 0, 0, 0 },
/* 17 */ { "mremap", (sqlite3_syscall_ptr)ts_mremap, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
@ -152,6 +156,8 @@ struct TestSyscallArray {
aSyscall[13].xOrig)
#define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
#define orig_mmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[16].xOrig)
#define orig_mremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[17].xOrig)
/*
** This function is called exactly once from within each invocation of a
@ -377,6 +383,31 @@ static int ts_fallocate(int fd, off_t off, off_t len){
return orig_fallocate(fd, off, len);
}
static void *ts_mmap(
void *pAddr,
size_t nByte,
int prot,
int flags,
int fd,
off_t iOff
){
if( tsIsFailErrno("mmap") ){
return MAP_FAILED;
}
return orig_mmap(pAddr, nByte, prot, flags, fd, iOff);
}
static void *ts_mremap(void *a, size_t b, size_t c, int d, ...){
va_list ap;
void *pArg;
if( tsIsFailErrno("mremap") ){
return MAP_FAILED;
}
va_start(ap, d);
pArg = va_arg(ap, void *);
return orig_mremap(a, b, c, d, pArg);
}
static int test_syscall_install(
void * clientData,
Tcl_Interp *interp,

View File

@ -125,8 +125,9 @@ struct Testvfs {
#define TESTVFS_ACCESS_MASK 0x00004000
#define TESTVFS_FULLPATHNAME_MASK 0x00008000
#define TESTVFS_READ_MASK 0x00010000
#define TESTVFS_UNLOCK_MASK 0x00020000
#define TESTVFS_ALL_MASK 0x0001FFFF
#define TESTVFS_ALL_MASK 0x0003FFFF
#define TESTVFS_MAX_PAGES 1024
@ -467,8 +468,12 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){
** Unlock an tvfs-file.
*/
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
TestvfsFd *p = tvfsGetFd(pFile);
return sqlite3OsUnlock(p->pReal, eLock);
TestvfsFd *pFd = tvfsGetFd(pFile);
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){
return SQLITE_IOERR_UNLOCK;
}
return sqlite3OsUnlock(pFd->pReal, eLock);
}
/*
@ -1101,6 +1106,7 @@ static int testvfs_obj_cmd(
{ "xClose", TESTVFS_CLOSE_MASK },
{ "xAccess", TESTVFS_ACCESS_MASK },
{ "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
{ "xUnlock", TESTVFS_UNLOCK_MASK },
};
Tcl_Obj **apElem = 0;
int nElem = 0;

View File

@ -3525,7 +3525,7 @@ case OP_SeekGt: { /* jump, in3 */
** r.flags = 0;
** }
*/
r.flags = (u16)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLt)));
r.flags = (u8)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLt)));
assert( oc!=OP_SeekGt || r.flags==UNPACKED_INCRKEY );
assert( oc!=OP_SeekLe || r.flags==UNPACKED_INCRKEY );
assert( oc!=OP_SeekGe || r.flags==0 );

View File

@ -18,6 +18,14 @@
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
/*
** The maximum number of times that a statement will try to reparse
** itself before giving up and returning SQLITE_SCHEMA.
*/
#ifndef SQLITE_MAX_SCHEMA_RETRY
# define SQLITE_MAX_SCHEMA_RETRY 50
#endif
/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance

View File

@ -453,14 +453,6 @@ end_of_step:
return (rc&db->errMask);
}
/*
** The maximum number of times that a statement will try to reparse
** itself before giving up and returning SQLITE_SCHEMA.
*/
#ifndef SQLITE_MAX_SCHEMA_RETRY
# define SQLITE_MAX_SCHEMA_RETRY 5
#endif
/*
** This is the top-level implementation of sqlite3_step(). Call
** sqlite3Step() to do most of the work. If a schema error occurs,

View File

@ -317,7 +317,7 @@ int sqlite3_blob_open(
}
sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
rc = blobSeekToRow(pBlob, iRow, &zErr);
} while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );
} while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
blob_open_out:
if( rc==SQLITE_OK && db->mallocFailed==0 ){

View File

@ -53,6 +53,11 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
** then the returned string holds a copy of zRawSql with "-- " prepended
** to each line of text.
**
** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then
** then long strings and blobs are truncated to that many bytes. This
** can be used to prevent unreasonably large trace strings when dealing
** with large (multi-megabyte) strings and blobs.
**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
**
@ -123,30 +128,49 @@ char *sqlite3VdbeExpandSql(
}else if( pVar->flags & MEM_Real ){
sqlite3XPrintf(&out, "%!.15g", pVar->r);
}else if( pVar->flags & MEM_Str ){
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
u8 enc = ENC(db);
Mem utf8;
if( enc!=SQLITE_UTF8 ){
Mem utf8;
memset(&utf8, 0, sizeof(utf8));
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
sqlite3VdbeMemRelease(&utf8);
}else
#endif
{
sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
pVar = &utf8;
}
#endif
nOut = pVar->n;
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( n>SQLITE_TRACE_SIZE_LIMIT ){
nOut = SQLITE_TRACE_SIZE_LIMIT;
while( nOut<pVar->n && (pVar->z[n]&0xc0)==0x80 ){ n++; }
}
#endif
sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
#endif
#ifndef SQLITE_OMIT_UTF16
if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
#endif
}else if( pVar->flags & MEM_Zero ){
sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
}else{
int nOut; /* Number of bytes of the blob to include in output */
assert( pVar->flags & MEM_Blob );
sqlite3StrAccumAppend(&out, "x'", 2);
for(i=0; i<pVar->n; i++){
nOut = pVar->n;
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
#endif
for(i=0; i<nOut; i++){
sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
}
sqlite3StrAccumAppend(&out, "'", 1);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
#endif
}
}
}

View File

@ -1207,8 +1207,9 @@ finished:
** checkpointing the log file.
*/
if( pWal->hdr.nPage ){
sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
pWal->hdr.nPage, pWal->zWalName
sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
"recovered %d frames from WAL file %s",
pWal->hdr.mxFrame, pWal->zWalName
);
}
}
@ -1722,8 +1723,8 @@ static int walCheckpoint(
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
/* If the database file may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
/* If the database may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
*/
if( rc==SQLITE_OK ){
i64 nReq = ((i64)mxPage * szPage);
@ -1733,6 +1734,7 @@ static int walCheckpoint(
}
}
/* Iterate through the contents of the WAL, copying data to the db file. */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
@ -2287,19 +2289,17 @@ void sqlite3WalEndReadTransaction(Wal *pWal){
}
/*
** Read a page from the WAL, if it is present in the WAL and if the
** current read transaction is configured to use the WAL.
** Search the wal file for page pgno. If found, set *piRead to the frame that
** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
** to zero.
**
** The *pInWal is set to 1 if the requested page is in the WAL and
** has been loaded. Or *pInWal is set to 0 if the page was not in
** the WAL and needs to be read out of the database.
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** error does occur, the final value of *piRead is undefined.
*/
int sqlite3WalRead(
int sqlite3WalFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
int *pInWal, /* OUT: True if data is read from WAL */
int nOut, /* Size of buffer pOut in bytes */
u8 *pOut /* Buffer to write page data to */
u32 *piRead /* OUT: Frame number (or zero) */
){
u32 iRead = 0; /* If !=0, WAL frame to return data from */
u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
@ -2315,7 +2315,7 @@ int sqlite3WalRead(
** WAL were empty.
*/
if( iLast==0 || pWal->readLock==0 ){
*pInWal = 0;
*piRead = 0;
return SQLITE_OK;
}
@ -2386,26 +2386,31 @@ int sqlite3WalRead(
}
#endif
/* If iRead is non-zero, then it is the log frame number that contains the
** required page. Read and return data from the log file.
*/
if( iRead ){
int sz;
i64 iOffset;
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
*pInWal = 0;
*piRead = iRead;
return SQLITE_OK;
}
/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
*/
int sqlite3WalReadFrame(
Wal *pWal, /* WAL handle */
u32 iRead, /* Frame to read */
int nOut, /* Size of buffer pOut in bytes */
u8 *pOut /* Buffer to write page data to */
){
int sz;
i64 iOffset;
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
/*
** Return the size of the database in pages (or zero, if unknown).
@ -2952,6 +2957,9 @@ int sqlite3WalCheckpoint(
/* Read the wal-index header. */
if( rc==SQLITE_OK ){
rc = walIndexReadHdr(pWal, &isChanged);
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
}
}
/* Copy data from the log to the database file. */

View File

@ -31,7 +31,6 @@
# define sqlite3WalClose(w,x,y,z) 0
# define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z)
# define sqlite3WalRead(v,w,x,y,z) 0
# define sqlite3WalDbsize(y) 0
# define sqlite3WalBeginWriteTransaction(y) 0
# define sqlite3WalEndWriteTransaction(x) 0
@ -71,7 +70,8 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
void sqlite3WalEndReadTransaction(Wal *pWal);
/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
/* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal);

View File

@ -2275,9 +2275,8 @@ static void bestVirtualIndex(WhereBestIdx *p){
struct sqlite3_index_constraint *pIdxCons;
struct sqlite3_index_constraint_usage *pUsage;
WhereTerm *pTerm;
int i, j, k;
int i, j;
int nOrderBy;
int sortOrder; /* Sort order for IN clauses */
int bAllowIN; /* Allow IN optimizations */
double rCost;
@ -2376,7 +2375,6 @@ static void bestVirtualIndex(WhereBestIdx *p){
return;
}
sortOrder = SQLITE_SO_ASC;
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
if( pUsage[i].argvIndex>0 ){
@ -2391,17 +2389,28 @@ static void bestVirtualIndex(WhereBestIdx *p){
** repeated in the output. */
break;
}
for(k=0; k<pIdxInfo->nOrderBy; k++){
if( pIdxInfo->aOrderBy[k].iColumn==pIdxCons->iColumn ){
sortOrder = pIdxInfo->aOrderBy[k].desc;
break;
}
}
/* A virtual table that is constrained by an IN clause may not
** consume the ORDER BY clause because (1) the order of IN terms
** is not necessarily related to the order of output terms and
** (2) Multiple outputs from a single IN value will not merge
** together. */
pIdxInfo->orderByConsumed = 0;
}
}
}
if( i>=pIdxInfo->nConstraint ) break;
}
/* The orderByConsumed signal is only valid if all outer loops collectively
** generate just a single row of output.
*/
if( pIdxInfo->orderByConsumed ){
for(i=0; i<p->i; i++){
if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){
pIdxInfo->orderByConsumed = 0;
}
}
}
/* If there is an ORDER BY clause, and the selected virtual table index
** does not satisfy it, increase the cost of the scan accordingly. This
@ -2426,8 +2435,7 @@ static void bestVirtualIndex(WhereBestIdx *p){
}
p->cost.plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
assert( sortOrder==0 || sortOrder==1 );
p->cost.plan.wsFlags |= WHERE_ORDERED + sortOrder*WHERE_REVERSE;
p->cost.plan.wsFlags |= WHERE_ORDERED;
p->cost.plan.nOBSat = nOrderBy;
}else{
p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
@ -4164,6 +4172,7 @@ static Bitmask codeOneLoopStart(
int addrCont; /* Jump here to continue with next cycle */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
Bitmask newNotReady; /* Return value */
pParse = pWInfo->pParse;
v = pParse->pVdbe;
@ -4174,6 +4183,7 @@ static Bitmask codeOneLoopStart(
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0
&& (wctrlFlags & WHERE_FORCE_TABLE)==0;
VdbeNoopComment((v, "Begin Join Loop %d", iLevel));
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@ -4824,7 +4834,7 @@ static Bitmask codeOneLoopStart(
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}
notReady &= ~getMask(pWC->pMaskSet, iCur);
newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur);
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
@ -4838,7 +4848,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ){
if( (pTerm->prereqAll & newNotReady)!=0 ){
testcase( pWInfo->untestedTerms==0
&& (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
pWInfo->untestedTerms = 1;
@ -4853,6 +4863,32 @@ static Bitmask codeOneLoopStart(
pTerm->wtFlags |= TERM_CODED;
}
/* Insert code to test for implied constraints based on transitivity
** of the "==" operator.
**
** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
** and we are coding the t1 loop and the t2 loop has not yet coded,
** then we cannot use the "t1.a=t2.b" constraint, but we can code
** the implied "t1.a=123" constraint.
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
WhereTerm *pAlt;
Expr sEq;
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue;
if( pTerm->leftCursor!=iCur ) continue;
pE = pTerm->pExpr;
assert( !ExprHasProperty(pE, EP_FromJoin) );
assert( (pTerm->prereqRight & newNotReady)!=0 );
pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
if( pAlt==0 ) continue;
VdbeNoopComment((v, "begin transitive constraint"));
sEq = *pAlt->pExpr;
sEq.pLeft = pE->pLeft;
sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL);
}
/* For a LEFT OUTER JOIN, generate code that will record the fact that
** at least one row of the right table has matched the left table.
*/
@ -4865,7 +4901,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ){
if( (pTerm->prereqAll & newNotReady)!=0 ){
assert( pWInfo->untestedTerms );
continue;
}
@ -4876,7 +4912,7 @@ static Bitmask codeOneLoopStart(
}
sqlite3ReleaseTempReg(pParse, iReleaseReg);
return notReady;
return newNotReady;
}
#if defined(SQLITE_TEST)

50
test/btreefault.test Normal file
View File

@ -0,0 +1,50 @@
# 2013 April 02
#
# 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 fault injection tests designed to test the btree.c
# module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix btreefault
do_test 1-pre1 {
execsql {
PRAGMA auto_vacuum = incremental;
PRAGMA journal_mode = DELETE;
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(randomblob(1000), randomblob(100));
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
DELETE FROM t1 WHERE rowid%2;
}
faultsim_save_and_close
} {}
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY]
sqlite3_step $::STMT
sqlite3_step $::STMT
} -body {
execsql { PRAGMA incremental_vacuum = 10 }
} -test {
sqlite3_finalize $::STMT
faultsim_test_result {0 {}}
faultsim_integrity_check
}
finish_test

View File

@ -40,6 +40,7 @@ proc db_write {db {reset 0}} {
do_test 1.1 {
db close
sqlite3 db test.db
execsql { PRAGMA mmap_size = 0 }
expr {[file size test.db] / 1024}
} 6

View File

@ -25,6 +25,14 @@ ifcapable {!pager_pragmas} {
return
}
# Tests in this file verify that locking_mode=exclusive causes SQLite to
# use cached pages even if the database is changed on disk. This doesn't
# work with mmap.
if {[permutation]=="mmap"} {
finish_test
return
}
# This module does not work right if the cache spills at unexpected
# moments. So disable the soft-heap-limit.
#

View File

@ -354,10 +354,10 @@ do_execsql_test 3.1.1 {
do_catchsql_test 3.1.2 {
CREATE VIRTUAL TABLE terms2 USING fts4aux;
} {1 {wrong number of arguments to fts4aux constructor}}
} {1 {invalid arguments to fts4aux constructor}}
do_catchsql_test 3.1.3 {
CREATE VIRTUAL TABLE terms2 USING fts4aux(t2, t2);
} {1 {wrong number of arguments to fts4aux constructor}}
} {1 {invalid arguments to fts4aux constructor}}
do_execsql_test 3.2.1 {
CREATE VIRTUAL TABLE terms3 USING fts4aux(does_not_exist)
@ -444,7 +444,6 @@ do_plansql_test 4.5 {
# odd name (one that requires quoting for use in SQL statements). And that
# the argument to the fts4aux constructor is properly dequoted before use.
#
#
do_execsql_test 5.1 {
CREATE VIRTUAL TABLE "abc '!' def" USING fts4(x, y);
INSERT INTO "abc '!' def" VALUES('XX', 'YY');
@ -458,5 +457,66 @@ do_execsql_test 5.2 {
SELECT * FROM "%%^^%%";
} {xx * 1 1 xx 0 1 1 yy * 1 1 yy 1 1 1}
#-------------------------------------------------------------------------
# Test that we can create an fts4aux table in the temp database.
#
forcedelete test.db2
do_execsql_test 6.1 {
CREATE VIRTUAL TABLE ft1 USING fts4(x, y);
INSERT INTO ft1 VALUES('a b', 'c d');
INSERT INTO ft1 VALUES('e e', 'c d');
INSERT INTO ft1 VALUES('a a', 'b b');
CREATE VIRTUAL TABLE temp.aux1 USING fts4aux(main, ft1);
SELECT * FROM aux1;
} {
a * 2 3 a 0 2 3
b * 2 3 b 0 1 1 b 1 1 2
c * 2 2 c 1 2 2
d * 2 2 d 1 2 2
e * 1 2 e 0 1 2
}
do_execsql_test 6.2 {
ATTACH 'test.db2' AS att;
CREATE VIRTUAL TABLE att.ft1 USING fts4(x, y);
INSERT INTO att.ft1 VALUES('v w', 'x y');
INSERT INTO att.ft1 VALUES('z z', 'x y');
INSERT INTO att.ft1 VALUES('v v', 'w w');
CREATE VIRTUAL TABLE temp.aux2 USING fts4aux(att, ft1);
SELECT * FROM aux2;
} {
v * 2 3 v 0 2 3
w * 2 3 w 0 1 1 w 1 1 2
x * 2 2 x 1 2 2
y * 2 2 y 1 2 2
z * 1 2 z 0 1 2
}
foreach {tn q res1 res2} {
1 { SELECT * FROM %%% WHERE term = 'a' } {a * 2 3 a 0 2 3} {}
2 { SELECT * FROM %%% WHERE term = 'x' } {} {x * 2 2 x 1 2 2}
3 { SELECT * FROM %%% WHERE term >= 'y' }
{} {y * 2 2 y 1 2 2 z * 1 2 z 0 1 2}
4 { SELECT * FROM %%% WHERE term <= 'c' }
{a * 2 3 a 0 2 3 b * 2 3 b 0 1 1 b 1 1 2 c * 2 2 c 1 2 2} {}
} {
set sql1 [string map {%%% aux1} $q]
set sql2 [string map {%%% aux2} $q]
do_execsql_test 7.$tn.1 $sql1 $res1
do_execsql_test 7.$tn.2 $sql2 $res2
}
do_test 8.1 {
catchsql { CREATE VIRTUAL TABLE att.aux3 USING fts4aux(main, ft1) }
} {1 {invalid arguments to fts4aux constructor}}
do_test 8.2 {
execsql {DETACH att}
catchsql { SELECT * FROM aux2 }
} {1 {SQL logic error or missing database}}
finish_test

125
test/fts3tok1.test Normal file
View File

@ -0,0 +1,125 @@
# 2013 April 22
#
# 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 implements regression tests for SQLite library. The
# focus of this script is testing the "fts3tokenize" virtual table
# that is part of the FTS3 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !fts3 { finish_test ; return }
set ::testprefix fts3tok1
#-------------------------------------------------------------------------
# Simple test cases. Using the default (simple) tokenizer.
#
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts3tokenize(simple);
CREATE VIRTUAL TABLE t2 USING fts3tokenize();
CREATE VIRTUAL TABLE t3 USING fts3tokenize(simple, '', 'xyz ');
}
foreach {tn tbl} {1 t1 2 t2 3 t3} {
do_execsql_test 1.$tn.1 "SELECT * FROM $tbl WHERE input = 'one two three'" {
{one two three} one 0 3 0
{one two three} two 4 7 1
{one two three} three 8 13 2
}
do_execsql_test 1.$tn.2 "
SELECT token FROM $tbl WHERE input = 'OnE tWo tHrEe'
" {
one two three
}
}
do_execsql_test 1.4 {
SELECT token FROM t3 WHERE input = '1x2x3x'
} {1 2 3}
do_execsql_test 1.5 {
SELECT token FROM t1 WHERE input = '1x2x3x'
} {1x2x3x}
do_execsql_test 1.6 {
SELECT token FROM t3 WHERE input = '1''2x3x'
} {1'2 3}
do_execsql_test 1.7 {
SELECT token FROM t3 WHERE input = ''
} {}
do_execsql_test 1.8 {
SELECT token FROM t3 WHERE input = NULL
} {}
do_execsql_test 1.9 {
SELECT * FROM t3 WHERE input = 123
} {123 123 0 3 0}
do_execsql_test 1.10 {
SELECT * FROM t1 WHERE input = 'a b c' AND token = 'b';
} {
{a b c} b 2 3 1
}
do_execsql_test 1.11 {
SELECT * FROM t1 WHERE token = 'b' AND input = 'a b c';
} {
{a b c} b 2 3 1
}
do_execsql_test 1.12 {
SELECT * FROM t1 WHERE input < 'b' AND input = 'a b c';
} {
{a b c} a 0 1 0
{a b c} b 2 3 1
{a b c} c 4 5 2
}
do_execsql_test 1.13.1 {
CREATE TABLE c1(x);
INSERT INTO c1(x) VALUES('a b c');
INSERT INTO c1(x) VALUES('d e f');
}
breakpoint
do_execsql_test 1.13.2 {
SELECT * FROM c1, t1 WHERE input = x AND c1.rowid=t1.rowid;
} {
{a b c} {a b c} a 0 1 0
{d e f} {d e f} e 2 3 1
}
#-------------------------------------------------------------------------
# Error cases.
#
do_catchsql_test 2.0 {
CREATE VIRTUAL TABLE tX USING fts3tokenize(nosuchtokenizer);
} {1 {unknown tokenizer: nosuchtokenizer}}
proc fts3_tokenizer {args} { return 1 }
db function fts3_tokenizer -argcount 1 fts3_tokenizer
do_catchsql_test 2.1 {
CREATE VIRTUAL TABLE tX USING fts3tokenize(simple);
} {1 {vtable constructor failed: tX}}
db close
sqlite3 db test.db
do_catchsql_test 2.2 {
CREATE VIRTUAL TABLE t4 USING fts3tokenize;
SELECT * FROM t4;
} {1 {SQL logic error or missing database}}
finish_test

49
test/fts3tok_err.test Normal file
View File

@ -0,0 +1,49 @@
# 2013 April 22
#
# 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 implements regression tests for SQLite library. The
# focus of this script is testing the "fts3tokenize" virtual table
# that is part of the FTS3 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
ifcapable !fts3 { finish_test ; return }
set ::testprefix fts3tok_err
faultsim_save_and_close
do_faultsim_test fts3tok_err-1 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE VIRTUAL TABLE t1 USING fts3tokenize("simple"); }
} -test {
faultsim_test_result {0 {}}
}
do_test fts3tok_err-2.prep {
faultsim_delete_and_reopen
execsql { CREATE VIRTUAL TABLE t1 USING fts3tokenize("simple"); }
faultsim_save_and_close
} {}
do_faultsim_test fts3tok_err-2 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql { SELECT token FROM t1 WHERE input = 'A galaxy far, far away' }
} -test {
faultsim_test_result {0 {a galaxy far far away}}
}
finish_test

View File

@ -1273,11 +1273,13 @@ do_test func-29.3 {
sqlite3_db_status db CACHE_MISS 1
db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
} {integer null real blob text}
do_test func-29.4 {
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
if {$x>100} {set x many}
set x
} {many}
if {[permutation] != "mmap"} {
do_test func-29.4 {
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
if {$x>100} {set x many}
set x
} {many}
}
do_test func-29.5 {
db close
sqlite3 db test.db

View File

@ -123,6 +123,7 @@ foreach AutoVacuumMode [list 0 1] {
forcedelete test.db test.db-journal
sqlite3 db test.db
execsql "PRAGMA mmap_size = 0"
execsql "PRAGMA auto_vacuum = $AutoVacuumMode"
do_test incrblob-2.$AutoVacuumMode.1 {
@ -149,6 +150,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty.
db close
sqlite3 db test.db
execsql "PRAGMA mmap_size = 0"
# Read the last 20 bytes of the blob via a blob handle.
set ::blob [db incrblob blobs v 1]
@ -171,6 +173,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty.
db close
sqlite3 db test.db
execsql "PRAGMA mmap_size = 0"
# Write the second-to-last 20 bytes of the blob via a blob handle.
#
@ -200,6 +203,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty.
db close
sqlite3 db test.db
execsql { PRAGMA mmap_size = 0 }
execsql { SELECT i FROM blobs }
} {45}

View File

@ -139,20 +139,22 @@ do_test loadext-2.1 {
sqlite3_load_extension db "${testextension}xx"
} msg]
list $rc $msg
} [list 1 [format $dlerror_nosuchfile ${testextension}xx]]
} /[list 1 [format $dlerror_nosuchfile ${testextension}xx.*]]/
# Try to load an extension for which the file is not a shared object
#
do_test loadext-2.2 {
set fd [open "${testextension}xx" w]
set fd [open "./notasharedlib.so" w]
puts $fd blah
close $fd
set fd [open "./notasharedlib.dll" w]
puts $fd blah
close $fd
set rc [catch {
sqlite3_load_extension db "${testextension}xx"
sqlite3_load_extension db "./notasharedlib"
} msg]
set expected_error_pattern [format $dlerror_notadll ${testextension}xx]
list $rc [string match $expected_error_pattern $msg]
} [list 1 1]
list $rc $msg
} /[list 1 [format $dlerror_notadll ./notasharedlib.*]]/
# Try to load an extension for which the file is present but the
# entry point is not.
@ -196,7 +198,7 @@ do_test loadext-3.2 {
regsub {0x[1234567890abcdefABCDEF]*} $res XXX res
}
set res
} [list 1 [format $dlerror_nosymbol $testextension sqlite3_extension_init]]
} /[list 1 [format $dlerror_nosymbol $testextension sqlite3_.*_init]]/
do_test loadext-3.3 {
catchsql {
SELECT load_extension($::testextension,'testloadext_init')

View File

@ -264,7 +264,7 @@ proc faultsim_test_result_int {args} {
set t [list $testrc $testresult]
set r $args
if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } {
error "nfail=$testnfail rc=$testrc result=$testresult"
error "nfail=$testnfail rc=$testrc result=$testresult list=$r"
}
}

317
test/mmap1.test Normal file
View File

@ -0,0 +1,317 @@
# 2013 March 20
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !mmap {
finish_test
return
}
source $testdir/lock_common.tcl
set testprefix mmap1
proc nRead {db} {
set bt [btree_from_db $db]
db_enter $db
array set stats [btree_pager_stats $bt]
db_leave $db
# puts [array get stats]
return $stats(read)
}
proc register_rblob_code {dbname seed} {
return [subst -nocommands {
set ::rcnt $seed
proc rblob {n} {
set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF]
set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]]
string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
}
$dbname func rblob rblob
}]
}
foreach {t mmap_size nRead c2init} {
1.1 { PRAGMA mmap_size = 67108864 } 4 {PRAGMA mmap_size = 0}
1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0}
1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0}
1.4 { PRAGMA mmap_size = 67108864 } 4 {PRAGMA mmap_size = 67108864 }
1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 }
1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 }
} {
do_multiclient_test tn {
sql1 {PRAGMA page_size=1024}
sql1 $mmap_size
sql2 $c2init
code2 [register_rblob_code db2 0]
sql2 {
PRAGMA page_size=1024;
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
}
do_test $t.$tn.1 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {32 ok 77}
# Have connection 2 shrink the file. Check connection 1 can still read it.
sql2 { DELETE FROM t1 WHERE rowid%2; }
do_test $t.$tn.2 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {16 ok 42}
# Have connection 2 grow the file. Check connection 1 can still read it.
sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
do_test $t.$tn.3 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {32 ok 79}
# Have connection 2 grow the file again. Check connection 1 is still ok.
sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
do_test $t.$tn.4 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {64 ok 149}
# Check that the number of pages read by connection 1 indicates that the
# "PRAGMA mmap_size" command worked.
do_test $t.$tn.5 { nRead db } $nRead
}
}
set ::rcnt 0
proc rblob {n} {
set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
string range [string repeat $str [expr $n/4]] 1 $n
}
reset_db
db func rblob rblob
do_execsql_test 2.1 {
PRAGMA auto_vacuum = 1;
PRAGMA mmap_size = 67108864;
PRAGMA journal_mode = wal;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
PRAGMA wal_checkpoint;
} {67108864 wal 0 103 103}
do_execsql_test 2.2 {
PRAGMA auto_vacuum;
SELECT count(*) FROM t1;
} {1 32}
do_test 2.3 {
sqlite3 db2 test.db
db2 func rblob rblob
db2 eval {
DELETE FROM t1 WHERE (rowid%4);
PRAGMA wal_checkpoint;
}
db2 eval {
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
SELECT count(*) FROM t1;
}
} {16}
do_execsql_test 2.4 {
PRAGMA wal_checkpoint;
} {0 24 24}
db2 close
reset_db
db func rblob rblob
do_execsql_test 3.1 {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
CREATE TABLE t2(a, b, UNIQUE(a, b));
INSERT INTO t2 SELECT * FROM t1;
} {}
do_test 3.2 {
set nRow 0
db eval {SELECT * FROM t2 ORDER BY a, b} {
if {$nRow==4} { db eval { DELETE FROM t1 } }
incr nRow
}
set nRow
} {8}
#-------------------------------------------------------------------------
# Ensure that existing cursors using xFetch() pages see changes made
# to rows using the incrblob API.
#
reset_db
set aaa [string repeat a 400]
set bbb [string repeat b 400]
set ccc [string repeat c 400]
set ddd [string repeat d 400]
set eee [string repeat e 400]
do_execsql_test 4.1 {
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES($aaa);
INSERT INTO t1 VALUES($bbb);
INSERT INTO t1 VALUES($ccc);
INSERT INTO t1 VALUES($ddd);
SELECT * FROM t1;
BEGIN;
} [list $aaa $bbb $ccc $ddd]
do_test 4.2 {
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $aaa
do_test 4.3 {
foreach r {2 3 4} {
set fd [db incrblob t1 x $r]
puts -nonewline $fd $eee
close $fd
}
set res [list]
while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
lappend res [sqlite3_column_text $::STMT 0]
}
set res
} [list $eee $eee $eee]
do_test 4.4 {
sqlite3_finalize $::STMT
} SQLITE_OK
do_execsql_test 4.5 { COMMIT }
#-------------------------------------------------------------------------
# Ensure that existing cursors holding xFetch() references are not
# confused if those pages are moved to make way for the root page of a
# new table or index.
#
reset_db
do_execsql_test 5.1 {
PRAGMA auto_vacuum = 2;
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES($aaa);
INSERT INTO t1 VALUES($bbb);
INSERT INTO t1 VALUES($ccc);
INSERT INTO t1 VALUES($ddd);
PRAGMA auto_vacuum;
SELECT * FROM t1;
} [list 2 $aaa $bbb $ccc $ddd]
do_test 5.2 {
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $aaa
do_execsql_test 5.3 {
CREATE TABLE t2(x);
INSERT INTO t2 VALUES('tricked you!');
INSERT INTO t2 VALUES('tricked you!');
}
do_test 5.4 {
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $bbb
do_test 5.5 {
sqlite3_finalize $::STMT
} SQLITE_OK
#-------------------------------------------------------------------------
# Test various mmap_size settings.
#
foreach {tn1 mmap1 mmap2} {
1 6144 167773
2 18432 140399
3 43008 401302
4 92160 253899
5 190464 2
6 387072 752431
7 780288 291143
8 1566720 594306
9 3139584 829137
10 6285312 793963
11 12576768 1015590
} {
do_multiclient_test tn {
sql1 {
CREATE TABLE t1(a PRIMARY KEY);
CREATE TABLE t2(x);
INSERT INTO t2 VALUES('');
}
code1 [register_rblob_code db 0]
code2 [register_rblob_code db2 444]
sql1 "PRAGMA mmap_size = $mmap1"
sql2 "PRAGMA mmap_size = $mmap2"
do_test $tn1.$tn {
for {set i 1} {$i <= 100} {incr i} {
if {$i % 2} {
set c1 sql1
set c2 sql2
} else {
set c1 sql2
set c2 sql1
}
$c1 {
INSERT INTO t1 VALUES( rblob(5000) );
UPDATE t2 SET x = (SELECT md5sum(a) FROM t1);
}
set res [$c2 {
SELECT count(*) FROM t1;
SELECT x == (SELECT md5sum(a) FROM t1) FROM t2;
PRAGMA integrity_check;
}]
if {$res != [list $i 1 ok]} {
do_test $tn1.$tn.$i {
set ::res
} [list $i 1 ok]
}
}
set res 1
} {1}
}
}
finish_test

86
test/mmap2.test Normal file
View File

@ -0,0 +1,86 @@
# 2013 March 20
#
# 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 tests the effect of the mmap() or mremap() system calls
# returning an error on the library.
#
# If either mmap() or mremap() fails, SQLite should log an error
# message, then continue accessing the database using read() and
# write() exclusively.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix mmap2
if {$::tcl_platform(platform)!="unix" || [test_syscall defaultvfs] != "unix"} {
finish_test
return
}
ifcapable !mmap {
finish_test
return
}
db close
sqlite3_shutdown
test_sqlite3_log xLog
proc xLog {error_code msg} {
if {[string match os_unix.c* $msg]} {
lappend ::log $msg
}
}
foreach syscall {mmap mremap} {
test_syscall uninstall
if {[catch {test_syscall install $syscall}]} continue
for {set i 1} {$i < 20} {incr i} {
reset_db
test_syscall fault $i 1
test_syscall errno $syscall ENOMEM
set ::log ""
do_execsql_test 1.$syscall.$i.1 {
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000));
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
}
set nFail [test_syscall fault 0 0]
do_execsql_test 1.$syscall.$i.2 {
SELECT count(*) FROM t1;
PRAGMA integrity_check;
} {64 ok}
do_test 1.$syscall.$i.3 {
expr {$nFail==0 || $nFail==1}
} {1}
do_test 1.$syscall.$i.4.nFail=$nFail {
regexp ".*${syscall}.*" $::log
} [expr $nFail>0]
}
}
db close
test_syscall uninstall
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test

View File

@ -15,6 +15,7 @@ source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl
set testprefix pager1
# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
@ -1382,6 +1383,7 @@ db2 close
#
testvfs tv -default 1
foreach sectorsize {
16
32 64 128 256 512 1024 2048
4096 8192 16384 32768 65536 131072 262144
} {
@ -1404,7 +1406,7 @@ foreach sectorsize {
COMMIT;
}
file size test.db-journal
} [expr $sectorsize > 65536 ? 65536 : $sectorsize]
} [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)]
do_test pager1-10.$sectorsize.2 {
execsql {
@ -2243,7 +2245,6 @@ do_test pager1-25-1 {
}
db close
} {}
breakpoint
do_test pager1-25-2 {
faultsim_delete_and_reopen
execsql {
@ -2523,4 +2524,295 @@ if {$::tcl_platform(platform)=="unix"} {
} {one two}
}
#-------------------------------------------------------------------------
# Test that appending pages to the database file then moving those pages
# to the free-list before the transaction is committed does not cause
# an error.
#
foreach {tn pragma strsize} {
1 { PRAGMA mmap_size = 0 } 2400
2 { } 2400
3 { PRAGMA mmap_size = 0 } 4400
4 { } 4400
} {
reset_db
db func a_string a_string
db eval $pragma
do_execsql_test 34.$tn.1 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
}
do_execsql_test 34.$tn.2 {
BEGIN;
INSERT INTO t1 VALUES(2, a_string($strsize));
DELETE FROM t1 WHERE oid=2;
COMMIT;
PRAGMA integrity_check;
} {ok}
}
#-------------------------------------------------------------------------
#
reset_db
do_test 35 {
sqlite3 db test.db
execsql {
CREATE TABLE t1(x, y);
PRAGMA journal_mode = WAL;
INSERT INTO t1 VALUES(1, 2);
}
execsql {
BEGIN;
CREATE TABLE t2(a, b);
}
hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
catchsql ROLLBACK
} {0 {}}
do_multiclient_test tn {
sql1 {
PRAGMA auto_vacuum = 0;
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1, 2);
}
do_test 36.$tn.1 {
sql2 { PRAGMA max_page_count = 2 }
list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg
} {1 {database or disk is full}}
sql1 { PRAGMA checkpoint_fullfsync = 1 }
sql1 { CREATE TABLE t2(x) }
do_test 36.$tn.2 {
sql2 { INSERT INTO t2 VALUES('xyz') }
list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg
} {1 {database or disk is full}}
}
forcedelete test1 test2
foreach {tn uri} {
1 {file:?mode=memory&cache=shared}
2 {file:one?mode=memory&cache=shared}
3 {file:test1?cache=shared}
4 {file:test2?another=parameter&yet=anotherone}
} {
do_test 37.$tn {
catch { db close }
sqlite3_shutdown
sqlite3_config_uri 1
sqlite3 db $uri
db eval {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
SELECT * FROM t1;
}
} {1}
do_execsql_test 37.$tn.2 {
VACUUM;
SELECT * FROM t1;
} {1}
db close
sqlite3_shutdown
sqlite3_config_uri 0
}
do_test 38.1 {
catch { db close }
forcedelete test.db
set fd [open test.db w]
puts $fd "hello world"
close $fd
sqlite3 db test.db
catchsql { CREATE TABLE t1(x) }
} {1 {file is encrypted or is not a database}}
do_test 38.2 {
catch { db close }
forcedelete test.db
} {}
do_test 39.1 {
sqlite3 db test.db
execsql {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('xxx');
INSERT INTO t1 VALUES('two');
INSERT INTO t1 VALUES(randomblob(400));
INSERT INTO t1 VALUES(randomblob(400));
INSERT INTO t1 VALUES(randomblob(400));
INSERT INTO t1 VALUES(randomblob(400));
BEGIN;
UPDATE t1 SET x = 'one' WHERE rowid=1;
}
set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
sqlite3_step $::stmt
sqlite3_column_text $::stmt 0
} {one}
do_test 39.2 {
execsql { CREATE TABLE t2(x) }
sqlite3_step $::stmt
sqlite3_column_text $::stmt 0
} {two}
do_test 39.3 {
sqlite3_finalize $::stmt
execsql COMMIT
} {}
do_execsql_test 39.4 {
PRAGMA auto_vacuum = 2;
CREATE TABLE t3(x);
CREATE TABLE t4(x);
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
}
do_test 39.5 {
db close
sqlite3 db test.db
execsql {
PRAGMA cache_size = 1;
PRAGMA incremental_vacuum;
PRAGMA integrity_check;
}
} {ok}
do_test 40.1 {
reset_db
execsql {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(x PRIMARY KEY);
INSERT INTO t1 VALUES(randomblob(1200));
PRAGMA page_count;
}
} {6}
do_test 40.2 {
execsql {
INSERT INTO t1 VALUES(randomblob(1200));
INSERT INTO t1 VALUES(randomblob(1200));
INSERT INTO t1 VALUES(randomblob(1200));
}
} {}
do_test 40.3 {
db close
sqlite3 db test.db
execsql {
PRAGMA cache_size = 1;
CREATE TABLE t2(x);
PRAGMA integrity_check;
}
} {ok}
do_test 41.1 {
reset_db
execsql {
CREATE TABLE t1(x PRIMARY KEY);
INSERT INTO t1 VALUES(randomblob(200));
INSERT INTO t1 SELECT randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200) FROM t1;
}
} {}
do_test 41.2 {
testvfs tv -default 1
tv sectorsize 16384;
tv devchar [list]
db close
sqlite3 db test.db
execsql {
PRAGMA cache_size = 1;
DELETE FROM t1 WHERE rowid%4;
PRAGMA integrity_check;
}
} {ok}
db close
tv delete
set pending_prev [sqlite3_test_control_pending_byte 0x1000000]
do_test 42.1 {
reset_db
execsql {
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
}
db close
sqlite3_test_control_pending_byte 0x0010000
sqlite3 db test.db
db eval { PRAGMA mmap_size = 0 }
catchsql { SELECT sum(length(y)) FROM t1 }
} {1 {database disk image is malformed}}
do_test 42.2 {
reset_db
execsql {
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
}
db close
testvfs tv -default 1
tv sectorsize 16384;
tv devchar [list]
sqlite3 db test.db -vfs tv
execsql { UPDATE t1 SET x = randomblob(200) }
} {}
db close
tv delete
sqlite3_test_control_pending_byte $pending_prev
do_test 43.1 {
reset_db
execsql {
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1, 2);
CREATE TABLE t2(x, y);
INSERT INTO t2 VALUES(1, 2);
CREATE TABLE t3(x, y);
INSERT INTO t3 VALUES(1, 2);
}
db close
sqlite3 db test.db
db eval { PRAGMA mmap_size = 0 }
db eval { SELECT * FROM t1 }
sqlite3_db_status db CACHE_MISS 0
} {0 2 0}
do_test 43.2 {
db eval { SELECT * FROM t2 }
sqlite3_db_status db CACHE_MISS 1
} {0 3 0}
do_test 43.3 {
db eval { SELECT * FROM t3 }
sqlite3_db_status db CACHE_MISS 0
} {0 1 0}
finish_test

View File

@ -118,7 +118,6 @@ tv delete
#-------------------------------------------------------------------------
#
# pager2-2.1: Test a ROLLBACK with journal_mode=off.
# pager2-2.2: Test shrinking the database (auto-vacuum) with
# journal_mode=off
@ -148,4 +147,22 @@ do_test pager2-2.2 {
file size test.db
} {3072}
#-------------------------------------------------------------------------
# Test that shared in-memory databases seem to work.
#
db close
do_test pager2-3.1 {
forcedelete test.db
sqlite3_shutdown
sqlite3_config_uri 1
sqlite3 db1 {file:test.db?mode=memory&cache=shared}
sqlite3 db2 {file:test.db?mode=memory&cache=shared}
sqlite3 db3 test.db
db1 eval { CREATE TABLE t1(a, b) }
db2 eval { INSERT INTO t1 VALUES(1, 2) }
list [catch { db3 eval { INSERT INTO t1 VALUES(3, 4) } } msg] $msg
} {1 {no such table: t1}}
finish_test

View File

@ -1246,5 +1246,304 @@ do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep {
faultsim_integrity_check
}
#-------------------------------------------------------------------------
#
do_test pagerfault-28-pre {
faultsim_delete_and_reopen
db func a_string a_string
execsql {
PRAGMA page_size = 512;
PRAGMA journal_mode = wal;
PRAGMA wal_autocheckpoint = 0;
PRAGMA cache_size = 100000;
BEGIN;
CREATE TABLE t2(a UNIQUE, b UNIQUE);
INSERT INTO t2 VALUES( a_string(800), a_string(800) );
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
COMMIT;
CREATE TABLE t1(a PRIMARY KEY, b);
}
expr {[file size test.db-shm] >= 96*1024}
} {1}
faultsim_save_and_close
do_faultsim_test pagerfault-28a -faults oom* -prep {
faultsim_restore_and_reopen
execsql { PRAGMA mmap_size=0 }
sqlite3 db2 test.db
db2 eval { SELECT count(*) FROM t2 }
db func a_string a_string
execsql {
BEGIN;
INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
}
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY]
sqlite3_step $::STMT
} -body {
execsql { ROLLBACK }
} -test {
db2 close
sqlite3_finalize $::STMT
catchsql { ROLLBACK }
faultsim_integrity_check
}
faultsim_restore_and_reopen
sqlite3 db2 test.db
db2 eval {SELECT count(*) FROM t2}
db close
do_faultsim_test pagerfault-28b -faults oom* -prep {
sqlite3 db test.db
} -body {
execsql { SELECT count(*) FROM t2 }
} -test {
faultsim_test_result {0 2048}
db close
}
db2 close
#-------------------------------------------------------------------------
# Try this:
#
# 1) Put the pager in ERROR state (error during rollback)
#
# 2) Next time the connection is used inject errors into all xWrite() and
# xUnlock() calls. This causes the hot-journal rollback to fail and
# the pager to declare its locking state UNKNOWN.
#
# 3) Same again.
#
# 4a) Stop injecting errors. Allow the rollback to succeed. Check that
# the database is Ok. Or,
#
# 4b) Close and reopen the db. Check that the db is Ok.
#
proc custom_injectinstall {} {
testvfs custom -default true
custom filter {xWrite xUnlock}
}
proc custom_injectuninstall {} {
catch {db close}
catch {db2 close}
custom delete
}
proc custom_injectstart {iFail} {
custom ioerr $iFail 1
}
proc custom_injectstop {} {
custom ioerr
}
set ::FAULTSIM(custom) [list \
-injectinstall custom_injectinstall \
-injectstart custom_injectstart \
-injectstop custom_injectstop \
-injecterrlist {{1 {disk I/O error}}} \
-injectuninstall custom_injectuninstall \
]
do_test pagerfault-29-pre {
faultsim_delete_and_reopen
db func a_string a_string
execsql {
PRAGMA page_size = 1024;
PRAGMA cache_size = 5;
BEGIN;
CREATE TABLE t2(a UNIQUE, b UNIQUE);
INSERT INTO t2 VALUES( a_string(800), a_string(800) );
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
COMMIT;
}
expr {[file size test.db] >= 50*1024}
} {1}
faultsim_save_and_close
foreach {tn tt} {
29 { catchsql ROLLBACK }
30 { db close ; sqlite3 db test.db }
} {
do_faultsim_test pagerfault-$tn -faults custom -prep {
faultsim_restore_and_reopen
db func a_string a_string
execsql {
PRAGMA cache_size = 5;
BEGIN;
UPDATE t2 SET a = a_string(799);
}
} -body {
catchsql ROLLBACK
catchsql ROLLBACK
catchsql ROLLBACK
} -test {
eval $::tt
if {"ok" != [db one {PRAGMA integrity_check}]} {
error "integrity check failed"
}
}
}
do_test pagerfault-31-pre {
sqlite3_shutdown
sqlite3_config_uri 1
} {SQLITE_OK}
do_faultsim_test pagerfault-31 -faults oom* -body {
sqlite3 db {file:one?mode=memory&cache=shared}
db eval {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
SELECT * FROM t1;
}
} -test {
faultsim_test_result {0 1} {1 {}}
catch { db close }
}
sqlite3_shutdown
sqlite3_config_uri 0
do_test pagerfault-32-pre {
reset_db
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('one');
}
} {}
faultsim_save_and_close
do_faultsim_test pagerfault-32 -prep {
faultsim_restore_and_reopen
db eval { SELECT * FROM t1; }
} -body {
execsql { SELECT * FROM t1; }
} -test {
faultsim_test_result {0 one}
}
sqlite3_shutdown
sqlite3_config_uri 0
do_faultsim_test pagerfault-33a -prep {
sqlite3 db :memory:
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
}
} -body {
execsql { VACUUM }
} -test {
faultsim_test_result {0 {}}
}
do_faultsim_test pagerfault-33b -prep {
sqlite3 db ""
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
}
} -body {
execsql { VACUUM }
} -test {
faultsim_test_result {0 {}}
}
do_test pagerfault-34-pre {
reset_db
execsql {
CREATE TABLE t1(x PRIMARY KEY);
}
} {}
faultsim_save_and_close
do_faultsim_test pagerfault-34 -prep {
faultsim_restore_and_reopen
execsql {
BEGIN;
INSERT INTO t1 VALUES( randomblob(4000) );
DELETE FROM t1;
}
} -body {
execsql COMMIT
} -test {
faultsim_test_result {0 {}}
}
do_test pagerfault-35-pre {
faultsim_delete_and_reopen
execsql {
CREATE TABLE t1(x PRIMARY KEY, y);
INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
}
faultsim_save_and_close
} {}
testvfs tv -default 1
tv sectorsize 8192;
tv devchar [list]
do_faultsim_test pagerfault-35 -prep {
faultsim_restore_and_reopen
} -body {
execsql { UPDATE t1 SET x=randomblob(200) }
} -test {
faultsim_test_result {0 {}}
}
catch {db close}
tv delete
sqlite3_shutdown
sqlite3_config_uri 1
do_test pagerfault-36-pre {
faultsim_delete_and_reopen
execsql {
CREATE TABLE t1(x PRIMARY KEY, y);
INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
}
faultsim_save_and_close
} {}
do_faultsim_test pagerfault-36 -prep {
faultsim_restore
sqlite3 db file:test.db?cache=shared
sqlite3 db2 file:test.db?cache=shared
db2 eval {
BEGIN;
SELECT count(*) FROM sqlite_master;
}
db eval {
PRAGMA cache_size = 1;
BEGIN;
UPDATE t1 SET x = randomblob(200);
}
} -body {
execsql ROLLBACK db
} -test {
catch { db eval {UPDATE t1 SET x = randomblob(200)} }
faultsim_test_result {0 {}}
catch { db close }
catch { db2 close }
}
sqlite3_shutdown
sqlite3_config_uri 0
finish_test

View File

@ -87,12 +87,17 @@ do_test pageropt-1.4 {
# But if the other thread modifies the database, then the cache
# must refill.
#
ifcapable mmap {
set x [expr {[permutation]=="mmap" ? 1 : 6}]
} else {
set x 6
}
do_test pageropt-1.5 {
db2 eval {CREATE TABLE t2(y)}
pagercount_sql {
SELECT hex(x) FROM t1
}
} [list 6 0 0 $blobcontent]
} [list $x 0 0 $blobcontent]
do_test pageropt-1.6 {
pagercount_sql {
SELECT hex(x) FROM t1

View File

@ -141,6 +141,14 @@ test_suite "veryquick" -prefix "" -description {
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]
test_suite "mmap" -prefix "mm-" -description {
Similar to veryquick. Except with memory mapping disabled.
} -presql {
pragma mmap_size = 268435456;
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* -include malloc.test
]
test_suite "valgrind" -prefix "" -description {
Run the "veryquick" test suite with a couple of multi-process tests (that
fail under valgrind) omitted.

39
test/resolver01.test Normal file
View File

@ -0,0 +1,39 @@
# 2013-04-13
#
# 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 tests features of the name resolver (the component that
# figures out what identifiers in the SQL statement refer to) that
# were fixed by ticket [2500cdb9be]
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test resolver01-1.1 {
catchsql {
CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(11,22);
CREATE TABLE t2(y, z); INSERT INTO t2 VALUES(33,44);
SELECT 1 AS y FROM t1, t2 ORDER BY y;
}
} {0 1}
do_test resolver01-1.2 {
catchsql {
SELECT 2 AS y FROM t1, t2 ORDER BY y COLLATE nocase;
}
} {0 2}
do_test resolver01-1.3 {
catchsql {
SELECT 3 AS y FROM t1, t2 ORDER BY +y;
}
} {0 3}
finish_test

View File

@ -24,6 +24,8 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
speed_trial_init speed1
sqlite3_memdebug_vfs_oom_test 0
# Set a uniform random seed
expr srand(0)
@ -78,7 +80,6 @@ do_test speed1p-1.0 {
}
} {i2a i2b t1 t2}
# 50000 INSERTs on an unindexed table
#
set list {}

View File

@ -60,7 +60,7 @@ foreach s {
open close access getcwd stat fstat ftruncate
fcntl read pread write pwrite fchmod fallocate
pread64 pwrite64 unlink openDirectory mkdir rmdir
statvfs fchown umask
statvfs fchown umask mmap munmap mremap
} {
if {[test_syscall exists $s]} {lappend syscall_list $s}
}

View File

@ -243,5 +243,35 @@ do_faultsim_test 3 -faults vfsfault-* -prep {
faultsim_test_result {0 20000}
}
finish_test
#-------------------------------------------------------------------------
# Test errors in mmap().
#
proc vfsfault_install {} {
test_syscall reset
test_syscall install {mmap}
}
faultsim_delete_and_reopen
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
}
faultsim_save_and_close
do_faultsim_test 4 -faults vfsfault-* -prep {
faultsim_restore_and_reopen
file_control_chunksize_test db main 8192
execsql {
PRAGMA mmap_size = 1000000;
}
} -body {
test_syscall errno mmap EACCES
execsql {
SELECT * FROM t1;
}
} -test {
faultsim_test_result {0 {1 2}} {1 {disk I/O error}}
}
finish_test

View File

@ -462,6 +462,7 @@ if {0==[info exists ::SLAVE]} {
set TC(count) 0
set TC(fail_list) [list]
set TC(omit_list) [list]
set TC(warn_list) [list]
proc set_test_counter {counter args} {
if {[llength $args]} {
@ -496,6 +497,18 @@ proc fail_test {name} {
}
}
# Remember a warning message to be displayed at the conclusion of all testing
#
proc warning {msg {append 1}} {
puts "Warning: $msg"
set warnList [set_test_counter warn_list]
if {$append} {
lappend warnList $msg
}
set_test_counter warn_list $warnList
}
# Increment the number of tests run
#
proc incr_ntest {} {
@ -790,6 +803,9 @@ proc finalize_testing {} {
if {$nErr>0} {
puts "Failures on these tests: [set_test_counter fail_list]"
}
foreach warning [set_test_counter warn_list] {
puts "Warning: $warning"
}
run_thread_tests 1
if {[llength $omitList]>0} {
puts "Omitted test cases:"

View File

@ -208,12 +208,15 @@ do_test tkt2822-5.4 {
# In "ORDER BY +b" the term is now an expression rather than
# a label. It therefore matches by rule (3) instead of rule (2).
#
# 2013-04-13: This is busted. Changed to conform to PostgreSQL and
# MySQL and Oracle behavior.
#
do_test tkt2822-5.5 {
execsql {
SELECT a AS b FROM t3 ORDER BY +b;
}
} {9 1}
} {1 9}
# Tests for rule 2 in compound queries
#

View File

@ -727,6 +727,9 @@ do_test wal-11.9 {
list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db
set nWal 39
if {[permutation]!="mmap"} {set nWal 37}
ifcapable !mmap {set nWal 37}
do_test wal-11.10 {
execsql {
PRAGMA cache_size = 10;
@ -735,7 +738,7 @@ do_test wal-11.10 {
SELECT count(*) FROM t1;
}
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.11 {
execsql {
SELECT count(*) FROM t1;
@ -745,7 +748,7 @@ do_test wal-11.11 {
} {32 16}
do_test wal-11.12 {
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]]
} [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.13 {
execsql {
INSERT INTO t1 VALUES( blob(900) );
@ -755,7 +758,7 @@ do_test wal-11.13 {
} {17 ok}
do_test wal-11.14 {
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]]
} [list 37 [wal_file_size $nWal 1024]]
#-------------------------------------------------------------------------
@ -1512,7 +1515,7 @@ do_test wal-23.3 {
set nPage [expr 2+$AUTOVACUUM]
do_test wal-23.4 {
set ::log
} [list SQLITE_OK "Recovered $nPage frames from WAL file $walfile"]
} [list SQLITE_NOTICE "recovered $nPage frames from WAL file $walfile"]
ifcapable autovacuum {

View File

@ -235,7 +235,16 @@ foreach {testprefix do_wal_checkpoint} {
do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
do_test 2.3.$tn.6 { file_page_counts } {1 4 1 4}
do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 4 3}
do_test 2.3.$tn.8 { file_page_counts } {1 4 2 4}
# The checkpoint above only writes page 1 of the db file. The other
# page (page 2) is locked by the read-transaction opened by the
# [sql2] commmand above. So normally, the db is 1 page in size here.
# However, in mmap() mode, the db is pre-allocated to 2 pages at the
# start of the checkpoint, even though page 2 cannot be written.
set nDb 2
if {[permutation]!="mmap"} {set nDb 1}
ifcapable !mmap {set nDb 1}
do_test 2.3.$tn.8 { file_page_counts } [list $nDb 4 2 4]
}
# Check that checkpoints block on the correct locks. And respond correctly
@ -343,4 +352,3 @@ foreach {testprefix do_wal_checkpoint} {
finish_test

View File

@ -548,6 +548,44 @@ do_faultsim_test walfault-14 -prep {
set nRow [db eval {SELECT count(*) FROM abc}]
if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
}
finish_test
#-------------------------------------------------------------------------
# Test fault-handling when switching out of exclusive-locking mode.
#
do_test walfault-14-pre {
faultsim_delete_and_reopen
execsql {
PRAGMA auto_vacuum = 0;
PRAGMA journal_mode = WAL;
BEGIN;
CREATE TABLE abc(a PRIMARY KEY);
INSERT INTO abc VALUES(randomblob(1500));
INSERT INTO abc VALUES(randomblob(1500));
COMMIT;
}
faultsim_save_and_close
} {}
do_faultsim_test walfault-14 -prep {
faultsim_restore_and_reopen
breakpoint
execsql {
SELECT count(*) FROM abc;
PRAGMA locking_mode = exclusive;
BEGIN;
INSERT INTO abc VALUES(randomblob(1500));
COMMIT;
}
} -body {
db eval {
PRAGMA locking_mode = normal;
BEGIN;
INSERT INTO abc VALUES(randomblob(1500));
COMMIT;
}
} -test {
faultsim_integrity_check
set nRow [db eval {SELECT count(*) FROM abc}]
if {$nRow!=3 && $nRow!=4} { error "Bad db content" }
}
finish_test

View File

@ -27,6 +27,7 @@ proc xLog {error_code msg} {
lappend ::log $msg
}
sqlite3 db test.db
db eval {PRAGMA mmap_size=0}
do_test win32lock-1.1 {
db eval {

View File

@ -313,6 +313,7 @@ foreach file {
fts3_porter.c
fts3_tokenizer.c
fts3_tokenizer1.c
fts3_tokenize_vtab.c
fts3_write.c
fts3_snippet.c
fts3_unicode.c