Merge the latest trunk changes into the sessions branch.
FossilOrigin-Name: 6994826c0784280f2e9728dfa4185848846d03df
This commit is contained in:
commit
16fb176814
13
Makefile.in
13
Makefile.in
@ -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
|
||||
|
13
Makefile.msc
13
Makefile.msc
@ -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.
|
||||
#
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
464
ext/fts3/fts3_tokenize_vtab.c
Normal file
464
ext/fts3/fts3_tokenize_vtab.c
Normal 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) */
|
@ -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:
|
||||
#
|
||||
|
@ -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
12
main.mk
@ -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
169
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
67b3c0efa7d5e0cb7cc0fc7606ab3f26ea5419fd
|
||||
6994826c0784280f2e9728dfa4185848846d03df
|
46
mptest/config01.test
Normal file
46
mptest/config01.test
Normal 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
123
mptest/config02.test
Normal 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
102
mptest/crash01.test
Normal 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
53
mptest/crash02.subtest
Normal 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
1401
mptest/mptest.c
Normal file
File diff suppressed because it is too large
Load Diff
405
mptest/multiwrite01.test
Normal file
405
mptest/multiwrite01.test
Normal 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
|
@ -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);
|
||||
|
113
src/btree.c
113
src/btree.c
@ -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,
|
||||
|
@ -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);
|
||||
|
25
src/ctime.c
25
src/ctime.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
12
src/legacy.c
12
src/legacy.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
14
src/main.c
14
src/main.c
@ -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
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
20
src/os.c
20
src/os.c
@ -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.
|
||||
|
10
src/os.h
10
src/os.h
@ -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 *);
|
||||
|
||||
|
||||
/*
|
||||
|
395
src/os_unix.c
395
src/os_unix.c
@ -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++){
|
||||
|
295
src/os_win.c
295
src/os_win.c
@ -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;
|
||||
|
243
src/pager.c
243
src/pager.c
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
44
src/pragma.c
44
src/pragma.c
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
61
src/shell.c
61
src/shell.c
@ -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);
|
||||
|
@ -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
|
||||
**
|
||||
|
@ -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_ */
|
||||
|
@ -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 */
|
||||
|
161
src/test1.c
161
src/test1.c
@ -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;
|
||||
|
54
src/test2.c
54
src/test2.c
@ -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;
|
||||
|
40
src/test3.c
40
src/test3.c
@ -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);
|
||||
|
31
src/test4.c
31
src/test4.c
@ -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;
|
||||
}
|
||||
|
31
src/test7.c
31
src/test7.c
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 ){
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
70
src/wal.c
70
src/wal.c
@ -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. */
|
||||
|
@ -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);
|
||||
|
66
src/where.c
66
src/where.c
@ -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
50
test/btreefault.test
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
#
|
||||
|
@ -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
125
test/fts3tok1.test
Normal 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
49
test/fts3tok_err.test
Normal 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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')
|
||||
|
@ -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
317
test/mmap1.test
Normal 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
86
test/mmap2.test
Normal 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
|
296
test/pager1.test
296
test/pager1.test
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
39
test/resolver01.test
Normal 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
|
@ -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 {}
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:"
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user