Merge branch 'sqlite-release' into release-integration
This commit is contained in:
commit
11a0e2bb8f
@ -174,7 +174,7 @@ NAWK = @AWK@
|
||||
# Object files for the SQLite library (non-amalgamation).
|
||||
#
|
||||
OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \
|
||||
btree.lo build.lo callback.lo complete.lo date.lo \
|
||||
btree.lo build.lo callback.lo complete.lo ctime.lo date.lo \
|
||||
delete.lo expr.lo fault.lo fkey.lo func.lo global.lo \
|
||||
hash.lo journal.lo insert.lo legacy.lo loadext.lo \
|
||||
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
|
||||
@ -215,6 +215,7 @@ SRC = \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/callback.c \
|
||||
$(TOP)/src/complete.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/delete.c \
|
||||
$(TOP)/src/expr.c \
|
||||
@ -350,6 +351,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
$(TOP)/src/insert.c \
|
||||
@ -558,6 +560,9 @@ callback.lo: $(TOP)/src/callback.c $(HDR)
|
||||
complete.lo: $(TOP)/src/complete.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/complete.c
|
||||
|
||||
ctime.lo: $(TOP)/src/ctime.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/ctime.c
|
||||
|
||||
date.lo: $(TOP)/src/date.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c
|
||||
|
||||
|
||||
@ -231,6 +231,7 @@ SRC = \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/callback.c \
|
||||
$(TOP)/src/complete.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/delete.c \
|
||||
$(TOP)/src/expr.c \
|
||||
@ -392,7 +393,7 @@ TESTSRC = \
|
||||
|
||||
TESTSRC2 = \
|
||||
$(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c $(TOP)/src/date.c \
|
||||
$(TOP)/src/build.c $(TOP)/src/ctime.c $(TOP)/src/date.c \
|
||||
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/os.c \
|
||||
$(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \
|
||||
$(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \
|
||||
|
||||
18
configure
vendored
18
configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.6.21.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.6.23.1.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.6.21'
|
||||
PACKAGE_STRING='sqlite 3.6.21'
|
||||
PACKAGE_VERSION='3.6.23.1'
|
||||
PACKAGE_STRING='sqlite 3.6.23.1'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@ -1487,7 +1487,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.6.21 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.6.23.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1552,7 +1552,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.6.21:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.6.23.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1670,7 +1670,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.6.21
|
||||
sqlite configure 3.6.23.1
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@ -1684,7 +1684,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.6.21, which was
|
||||
It was created by sqlite $as_me 3.6.23.1, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -13972,7 +13972,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.6.21, which was
|
||||
This file was extended by sqlite $as_me 3.6.23.1, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -14025,7 +14025,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.6.21
|
||||
sqlite config.status 3.6.23.1
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
722
ext/fts3/fts3.c
722
ext/fts3/fts3.c
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,8 @@
|
||||
*/
|
||||
typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */
|
||||
typedef short int i16; /* 2-byte (or larger) signed integer */
|
||||
typedef unsigned int u32; /* 4-byte unsigned integer */
|
||||
typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */
|
||||
/*
|
||||
** Macro used to suppress compiler warnings for unused parameters.
|
||||
*/
|
||||
@ -102,7 +104,7 @@ struct Fts3Table {
|
||||
/* Precompiled statements used by the implementation. Each of these
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
*/
|
||||
sqlite3_stmt *aStmt[18];
|
||||
sqlite3_stmt *aStmt[25];
|
||||
|
||||
/* Pointer to string containing the SQL:
|
||||
**
|
||||
@ -116,14 +118,17 @@ struct Fts3Table {
|
||||
sqlite3_stmt **aLeavesStmt; /* Array of prepared zSelectLeaves stmts */
|
||||
|
||||
int nNodeSize; /* Soft limit for node size */
|
||||
u8 bHasContent; /* True if %_content table exists */
|
||||
u8 bHasDocsize; /* True if %_docsize table exists */
|
||||
|
||||
/* The following hash table is used to buffer pending index updates during
|
||||
** transactions. Variable nPendingData estimates the memory size of the
|
||||
** pending data, including hash table overhead, but not malloc overhead.
|
||||
** When nPendingData exceeds FTS3_MAX_PENDING_DATA, the buffer is flushed
|
||||
** When nPendingData exceeds nMaxPendingData, the buffer is flushed
|
||||
** automatically. Variable iPrevDocid is the docid of the most recently
|
||||
** inserted record.
|
||||
*/
|
||||
int nMaxPendingData;
|
||||
int nPendingData;
|
||||
sqlite_int64 iPrevDocid;
|
||||
Fts3Hash pendingTerms;
|
||||
@ -145,6 +150,8 @@ struct Fts3Cursor {
|
||||
char *pNextId; /* Pointer into the body of aDoclist */
|
||||
char *aDoclist; /* List of docids for full-text queries */
|
||||
int nDoclist; /* Size of buffer at aDoclist */
|
||||
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
|
||||
u32 *aMatchinfo; /* Information about most recent match */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -185,6 +192,16 @@ struct Fts3Phrase {
|
||||
|
||||
/*
|
||||
** A tree of these objects forms the RHS of a MATCH operator.
|
||||
**
|
||||
** If Fts3Expr.eType is either FTSQUERY_NEAR or FTSQUERY_PHRASE and isLoaded
|
||||
** is true, then aDoclist points to a malloced buffer, size nDoclist bytes,
|
||||
** containing the results of the NEAR or phrase query in FTS3 doclist
|
||||
** format. As usual, the initial "Length" field found in doclists stored
|
||||
** on disk is omitted from this buffer.
|
||||
**
|
||||
** Variable pCurrent always points to the start of a docid field within
|
||||
** aDoclist. Since the doclist is usually scanned in docid order, this can
|
||||
** be used to accelerate seeking to the required docid within the doclist.
|
||||
*/
|
||||
struct Fts3Expr {
|
||||
int eType; /* One of the FTSQUERY_XXX values defined below */
|
||||
@ -193,6 +210,13 @@ struct Fts3Expr {
|
||||
Fts3Expr *pLeft; /* Left operand */
|
||||
Fts3Expr *pRight; /* Right operand */
|
||||
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
|
||||
|
||||
int isLoaded; /* True if aDoclist/nDoclist are initialized. */
|
||||
char *aDoclist; /* Buffer containing doclist */
|
||||
int nDoclist; /* Size of aDoclist in bytes */
|
||||
|
||||
sqlite3_int64 iCurrent;
|
||||
char *pCurrent;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -225,6 +249,7 @@ void sqlite3Fts3PendingTermsClear(Fts3Table *);
|
||||
int sqlite3Fts3Optimize(Fts3Table *);
|
||||
int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
|
||||
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
|
||||
int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
|
||||
void sqlite3Fts3SegReaderFree(Fts3Table *, Fts3SegReader *);
|
||||
int sqlite3Fts3SegReaderIterate(
|
||||
Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
|
||||
@ -232,6 +257,8 @@ int sqlite3Fts3SegReaderIterate(
|
||||
);
|
||||
int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
|
||||
int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
|
||||
int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
|
||||
int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
|
||||
|
||||
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
|
||||
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
|
||||
@ -254,6 +281,10 @@ int sqlite3Fts3GetVarint32(const char *, int *);
|
||||
int sqlite3Fts3VarintLen(sqlite3_uint64);
|
||||
void sqlite3Fts3Dequote(char *);
|
||||
|
||||
char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
|
||||
int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
|
||||
int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
|
||||
|
||||
/* fts3_tokenizer.c */
|
||||
const char *sqlite3Fts3NextToken(const char *, int *);
|
||||
int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
|
||||
@ -263,9 +294,10 @@ int sqlite3Fts3InitTokenizer(Fts3Hash *pHash,
|
||||
|
||||
/* fts3_snippet.c */
|
||||
void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
|
||||
void sqlite3Fts3Snippet(sqlite3_context*, Fts3Cursor*,
|
||||
const char *, const char *, const char *
|
||||
void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
|
||||
const char *, const char *, int, int
|
||||
);
|
||||
void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
|
||||
|
||||
/* fts3_expr.c */
|
||||
int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
|
||||
@ -273,7 +305,7 @@ int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
|
||||
);
|
||||
void sqlite3Fts3ExprFree(Fts3Expr *);
|
||||
#ifdef SQLITE_TEST
|
||||
void sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
|
||||
int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
|
||||
#endif
|
||||
|
||||
#endif /* _FTSINT_H */
|
||||
|
||||
@ -181,7 +181,7 @@ static int getNextToken(
|
||||
** Enlarge a memory allocation. If an out-of-memory allocation occurs,
|
||||
** then free the old allocation.
|
||||
*/
|
||||
void *fts3ReallocOrFree(void *pOrig, int nNew){
|
||||
static void *fts3ReallocOrFree(void *pOrig, int nNew){
|
||||
void *pRet = sqlite3_realloc(pOrig, nNew);
|
||||
if( !pRet ){
|
||||
sqlite3_free(pOrig);
|
||||
@ -735,6 +735,7 @@ void sqlite3Fts3ExprFree(Fts3Expr *p){
|
||||
if( p ){
|
||||
sqlite3Fts3ExprFree(p->pLeft);
|
||||
sqlite3Fts3ExprFree(p->pRight);
|
||||
sqlite3_free(p->aDoclist);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
@ -913,8 +914,8 @@ exprtest_out:
|
||||
** Register the query expression parser test function fts3_exprtest()
|
||||
** with database connection db.
|
||||
*/
|
||||
void sqlite3Fts3ExprInitTestInterface(sqlite3* db){
|
||||
sqlite3_create_function(
|
||||
int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
|
||||
return sqlite3_create_function(
|
||||
db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
|
||||
);
|
||||
}
|
||||
|
||||
@ -279,13 +279,12 @@ static void fts3RemoveElementByHash(
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){
|
||||
int h; /* A hash on key */
|
||||
Fts3HashElem *elem; /* The element that matches key */
|
||||
Fts3HashElem *sqlite3Fts3HashFindElem(
|
||||
const Fts3Hash *pH,
|
||||
const void *pKey,
|
||||
int nKey
|
||||
){
|
||||
int h; /* A hash on key */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
if( pH==0 || pH->ht==0 ) return 0;
|
||||
@ -293,8 +292,19 @@ void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){
|
||||
assert( xHash!=0 );
|
||||
h = (*xHash)(pKey,nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
elem = fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
|
||||
return elem ? elem->data : 0;
|
||||
return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){
|
||||
Fts3HashElem *pElem; /* The element that matches key (if any) */
|
||||
|
||||
pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey);
|
||||
return pElem ? pElem->data : 0;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
|
||||
@ -75,14 +75,16 @@ void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey);
|
||||
void *sqlite3Fts3HashInsert(Fts3Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqlite3Fts3HashFind(const Fts3Hash*, const void *pKey, int nKey);
|
||||
void sqlite3Fts3HashClear(Fts3Hash*);
|
||||
Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const void *, int);
|
||||
|
||||
/*
|
||||
** Shorthand for the functions above
|
||||
*/
|
||||
#define fts3HashInit sqlite3Fts3HashInit
|
||||
#define fts3HashInsert sqlite3Fts3HashInsert
|
||||
#define fts3HashFind sqlite3Fts3HashFind
|
||||
#define fts3HashClear sqlite3Fts3HashClear
|
||||
#define fts3HashInit sqlite3Fts3HashInit
|
||||
#define fts3HashInsert sqlite3Fts3HashInsert
|
||||
#define fts3HashFind sqlite3Fts3HashFind
|
||||
#define fts3HashClear sqlite3Fts3HashClear
|
||||
#define fts3HashFindElem sqlite3Fts3HashFindElem
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
|
||||
@ -605,9 +605,11 @@ static int porterNext(
|
||||
if( c->iOffset>iStartOffset ){
|
||||
int n = c->iOffset-iStartOffset;
|
||||
if( n>c->nAllocated ){
|
||||
char *pNew;
|
||||
c->nAllocated = n+20;
|
||||
c->zToken = sqlite3_realloc(c->zToken, c->nAllocated);
|
||||
if( c->zToken==NULL ) return SQLITE_NOMEM;
|
||||
pNew = sqlite3_realloc(c->zToken, c->nAllocated);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
c->zToken = pNew;
|
||||
}
|
||||
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
|
||||
*pzToken = c->zToken;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -119,14 +119,14 @@ const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
|
||||
/* Find the start of the next token. */
|
||||
z1 = zStr;
|
||||
while( z2==0 ){
|
||||
switch( *z1 ){
|
||||
char c = *z1;
|
||||
switch( c ){
|
||||
case '\0': return 0; /* No more tokens here */
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`': {
|
||||
z2 = &z1[1];
|
||||
while( *z2 && (z2[0]!=*z1 || z2[1]==*z1) ) z2++;
|
||||
if( *z2 ) z2++;
|
||||
z2 = z1;
|
||||
while( *++z2 && (*z2!=c || *++z2==c) );
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
@ -466,10 +466,10 @@ int sqlite3Fts3InitHashTable(
|
||||
int rc = SQLITE_OK;
|
||||
void *p = (void *)pHash;
|
||||
const int any = SQLITE_ANY;
|
||||
char *zTest = 0;
|
||||
char *zTest2 = 0;
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
char *zTest = 0;
|
||||
char *zTest2 = 0;
|
||||
void *pdb = (void *)db;
|
||||
zTest = sqlite3_mprintf("%s_test", zName);
|
||||
zTest2 = sqlite3_mprintf("%s_internal_test", zName);
|
||||
@ -486,10 +486,13 @@ int sqlite3Fts3InitHashTable(
|
||||
|| SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))
|
||||
|| SQLITE_OK!=(rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_free(zTest);
|
||||
sqlite3_free(zTest2);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -145,4 +145,8 @@ struct sqlite3_tokenizer_cursor {
|
||||
/* Tokenizer implementations will typically add additional fields */
|
||||
};
|
||||
|
||||
int fts3_global_term_cnt(int iTerm, int iCol);
|
||||
int fts3_term_cnt(int iTerm, int iCol);
|
||||
|
||||
|
||||
#endif /* _FTS3_TOKENIZER_H_ */
|
||||
|
||||
@ -182,9 +182,11 @@ static int simpleNext(
|
||||
if( c->iOffset>iStartOffset ){
|
||||
int i, n = c->iOffset-iStartOffset;
|
||||
if( n>c->nTokenAllocated ){
|
||||
char *pNew;
|
||||
c->nTokenAllocated = n+20;
|
||||
c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated);
|
||||
if( c->pToken==NULL ) return SQLITE_NOMEM;
|
||||
pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
c->pToken = pNew;
|
||||
}
|
||||
for(i=0; i<n; i++){
|
||||
/* TODO(shess) This needs expansion to handle UTF-8
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -454,7 +454,7 @@ int sqlite3IcuInit(sqlite3 *db){
|
||||
void *pContext; /* sqlite3_user_data() context */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"regexp",-1, SQLITE_ANY, 0, icuRegexpFunc},
|
||||
{"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc},
|
||||
|
||||
{"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16},
|
||||
|
||||
@ -423,6 +423,7 @@ nodeAcquire(
|
||||
rc = sqlite3_step(pRtree->pReadNode);
|
||||
if( rc==SQLITE_ROW ){
|
||||
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
|
||||
assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
|
||||
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
|
||||
nodeReference(pParent);
|
||||
}else{
|
||||
@ -2619,31 +2620,69 @@ static int rtreeSqlInit(
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine queries database handle db for the page-size used by
|
||||
** database zDb. If successful, the page-size in bytes is written to
|
||||
** *piPageSize and SQLITE_OK returned. Otherwise, and an SQLite error
|
||||
** code is returned.
|
||||
** The second argument to this function contains the text of an SQL statement
|
||||
** that returns a single integer value. The statement is compiled and executed
|
||||
** using database connection db. If successful, the integer value returned
|
||||
** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
|
||||
** code is returned and the value of *piVal after returning is not defined.
|
||||
*/
|
||||
static int getPageSize(sqlite3 *db, const char *zDb, int *piPageSize){
|
||||
static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
|
||||
int rc = SQLITE_NOMEM;
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
*piVal = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called from within the xConnect() or xCreate() method to
|
||||
** determine the node-size used by the rtree table being created or connected
|
||||
** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
|
||||
** Otherwise, an SQLite error code is returned.
|
||||
**
|
||||
** If this function is being called as part of an xConnect(), then the rtree
|
||||
** table already exists. In this case the node-size is determined by inspecting
|
||||
** the root node of the tree.
|
||||
**
|
||||
** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
|
||||
** This ensures that each node is stored on a single database page. If the
|
||||
** database page-size is so large that more than RTREE_MAXCELLS entries
|
||||
** would fit in a single node, use a smaller node-size.
|
||||
*/
|
||||
static int getNodeSize(
|
||||
sqlite3 *db, /* Database handle */
|
||||
Rtree *pRtree, /* Rtree handle */
|
||||
int isCreate /* True for xCreate, false for xConnect */
|
||||
){
|
||||
int rc;
|
||||
char *zSql;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
if( isCreate ){
|
||||
int iPageSize;
|
||||
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
|
||||
rc = getIntFromStmt(db, zSql, &iPageSize);
|
||||
if( rc==SQLITE_OK ){
|
||||
pRtree->iNodeSize = iPageSize-64;
|
||||
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
|
||||
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
|
||||
pRtree->zDb, pRtree->zName
|
||||
);
|
||||
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
|
||||
}
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
*piPageSize = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
return sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2664,7 +2703,6 @@ static int rtreeInit(
|
||||
int isCreate /* True for xCreate, false for xConnect */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int iPageSize = 0;
|
||||
Rtree *pRtree;
|
||||
int nDb; /* Length of string argv[1] */
|
||||
int nName; /* Length of string argv[2] */
|
||||
@ -2683,11 +2721,6 @@ static int rtreeInit(
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
rc = getPageSize(db, argv[1], &iPageSize);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate the sqlite3_vtab structure */
|
||||
nDb = strlen(argv[1]);
|
||||
nName = strlen(argv[2]);
|
||||
@ -2706,44 +2739,37 @@ static int rtreeInit(
|
||||
memcpy(pRtree->zDb, argv[1], nDb);
|
||||
memcpy(pRtree->zName, argv[2], nName);
|
||||
|
||||
/* Figure out the node size to use. By default, use 64 bytes less than
|
||||
** the database page-size. This ensures that each node is stored on
|
||||
** a single database page.
|
||||
**
|
||||
** If the databasd page-size is so large that more than RTREE_MAXCELLS
|
||||
** entries would fit in a single node, use a smaller node-size.
|
||||
*/
|
||||
pRtree->iNodeSize = iPageSize-64;
|
||||
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
|
||||
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
|
||||
}
|
||||
/* Figure out the node size to use. */
|
||||
rc = getNodeSize(db, pRtree, isCreate);
|
||||
|
||||
/* Create/Connect to the underlying relational database schema. If
|
||||
** that is successful, call sqlite3_declare_vtab() to configure
|
||||
** the r-tree table schema.
|
||||
*/
|
||||
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}else{
|
||||
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
|
||||
char *zTmp;
|
||||
int ii;
|
||||
for(ii=4; zSql && ii<argc; ii++){
|
||||
zTmp = zSql;
|
||||
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
|
||||
sqlite3_free(zTmp);
|
||||
}
|
||||
if( zSql ){
|
||||
zTmp = zSql;
|
||||
zSql = sqlite3_mprintf("%s);", zTmp);
|
||||
sqlite3_free(zTmp);
|
||||
}
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}else{
|
||||
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
|
||||
char *zTmp;
|
||||
int ii;
|
||||
for(ii=4; zSql && ii<argc; ii++){
|
||||
zTmp = zSql;
|
||||
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
|
||||
sqlite3_free(zTmp);
|
||||
}
|
||||
if( zSql ){
|
||||
zTmp = zSql;
|
||||
zSql = sqlite3_mprintf("%s);", zTmp);
|
||||
sqlite3_free(zTmp);
|
||||
}
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
58
ext/rtree/rtree7.test
Normal file
58
ext/rtree/rtree7.test
Normal file
@ -0,0 +1,58 @@
|
||||
# 2010 February 16
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test that nothing goes wrong if an rtree table is created, then the
|
||||
# database page-size is modified. At one point (3.6.22), this was causing
|
||||
# malfunctions.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname $argv0] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !rtree||!vacuum {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_test rtree7-1.1 {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2);
|
||||
INSERT INTO rt VALUES(1, 1, 2, 3, 4);
|
||||
}
|
||||
} {}
|
||||
do_test rtree7-1.2 {
|
||||
execsql { SELECT * FROM rt }
|
||||
} {1 1.0 2.0 3.0 4.0}
|
||||
do_test rtree7-1.3 {
|
||||
execsql {
|
||||
PRAGMA page_size = 2048;
|
||||
VACUUM;
|
||||
SELECT * FROM rt;
|
||||
}
|
||||
} {1 1.0 2.0 3.0 4.0}
|
||||
do_test rtree7-1.4 {
|
||||
for {set i 2} {$i <= 51} {incr i} {
|
||||
execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
|
||||
}
|
||||
execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
|
||||
} {51.0 102.0 153.0 204.0}
|
||||
do_test rtree7-1.5 {
|
||||
execsql {
|
||||
PRAGMA page_size = 512;
|
||||
VACUUM;
|
||||
SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt
|
||||
}
|
||||
} {51.0 102.0 153.0 204.0}
|
||||
|
||||
finish_test
|
||||
5
main.mk
5
main.mk
@ -52,7 +52,7 @@ TCCX += -I$(TOP)/ext/async
|
||||
#
|
||||
LIBOBJ+= alter.o analyze.o attach.o auth.o \
|
||||
backup.o bitvec.o btmutex.o btree.o build.o \
|
||||
callback.o complete.o date.o delete.o expr.o fault.o fkey.o \
|
||||
callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
|
||||
fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
|
||||
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o fts3_write.o \
|
||||
func.o global.o hash.o \
|
||||
@ -86,6 +86,7 @@ SRC = \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/callback.c \
|
||||
$(TOP)/src/complete.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/delete.c \
|
||||
$(TOP)/src/expr.c \
|
||||
@ -262,7 +263,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c $(TOP)/ext/fts3/fts3_expr.c \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.c \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.c $(TOP)/ext/fts3/fts3_write.c \
|
||||
$(TOP)/ext/async/sqlite3async.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
|
||||
266
manifest
266
manifest
@ -1,14 +1,14 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Version\s3.6.21\srelease\scandidate\s3.
|
||||
D 2009-12-07T16:39:13
|
||||
C Update\sthe\sversion\snumber\sto\s3.6.23.1.
|
||||
D 2010-03-26T22:28:06
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
|
||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
F Makefile.vxworks 10010ddbf52e2503c7c49c7c0b7c7a096f8638a6
|
||||
F Makefile.vxworks ab005d301296c40e021ccd0133ce49ca811e319f
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION aa30c4b131a981624ab576df19eb4c5c9cd582ac
|
||||
F VERSION 09d2dfb6a4a47d07b3b2091e349eedef78fb0f77
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@ -22,7 +22,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure beb6a7b293d15978ac274e6b43b37b356d3070b2
|
||||
F configure 17dee87ba9b797ea22940dc0fb5b08147bfb246a
|
||||
F configure.ac 14740970ddb674d92a9f5da89083dff1179014ff
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
@ -59,25 +59,25 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 684a55d603f11c8432323171082ff8a9437b4681
|
||||
F ext/fts3/fts3.c 2bb2045d1412184e9eea71eb151b159168be5131
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h cc716c74afa7da8e0f8ef39404f33ea62a823eb3
|
||||
F ext/fts3/fts3_expr.c c18794a62c257d3456d3314c5a18e348ae0d84bd
|
||||
F ext/fts3/fts3_hash.c 18feef38fca216992725e9eae775a0c7735e6724
|
||||
F ext/fts3/fts3_hash.h d410ff2c93c81a56b927fcf07b2099ccbfa7a479
|
||||
F ext/fts3/fts3Int.h df812ef35f1b47a44ec68a44ec0c2a769c973d85
|
||||
F ext/fts3/fts3_expr.c f4ff02ebe854e97ac03ff00b38b728a9ab57fd4b
|
||||
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
||||
F ext/fts3/fts3_porter.c a651e287e02b49b565a6ccf9441959d434489156
|
||||
F ext/fts3/fts3_snippet.c 6c2eb6d872d66b2a9aa5663f2662e993f18a6496
|
||||
F ext/fts3/fts3_tokenizer.c 52112e7b50fbf24eb68e356081c5969917406cc6
|
||||
F ext/fts3/fts3_tokenizer.h 7ff73caa3327589bf6550f60d93ebdd1f6a0fb5c
|
||||
F ext/fts3/fts3_tokenizer1.c 11a604a53cff5e8c28882727bf794e5252e5227b
|
||||
F ext/fts3/fts3_write.c ec51fb6886f910e78ae32158ec0301aa675f52d8
|
||||
F ext/fts3/fts3_porter.c 7546e4503e286a67fd4f2a82159620e3e9c7a1bc
|
||||
F ext/fts3/fts3_snippet.c 538bd27a76e465cb4ef6bfcb5479d897e4d5a536
|
||||
F ext/fts3/fts3_tokenizer.c 1a49ee3d79cbf0b9386250370d9cbfe4bb89c8ff
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c b6d86d1d750787db5c168c73da4e87670ed890a1
|
||||
F ext/fts3/fts3_write.c 4b21a0c6f2772b261f14e3a2e80e1e3e849268b0
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
||||
F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2
|
||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 038d59b05783c2e6c927a7352bb118a76c31065a
|
||||
F ext/rtree/rtree.c a354f6be11a91706680936fdf77b4588f0b34dbe
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test f72885ed80a329d6bd7991043016d74b51edf2c5
|
||||
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
|
||||
@ -85,13 +85,14 @@ F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
|
||||
F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
|
||||
F ext/rtree/rtree5.test 92508f5152a50110af6551fa5b769d1bbd7c4ef3
|
||||
F ext/rtree/rtree6.test 11aade5311789068ca659be24a47cc0d852b1971
|
||||
F ext/rtree/rtree7.test 6fd29fb8e13795c822f4ceeea92ab5d61c96976d
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk a92b99b264c3b277f8cf74d50aadc22c55967ef0
|
||||
F main.mk a36a05a481afcc00388c4d6d4db0e12cacb546e3
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@ -104,79 +105,80 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 92ba938565d7cc6bfe92aad6cc90c00800ff21d3
|
||||
F src/analyze.c 55155f05ee9ab4ce33b7a4d19c449053f8935200
|
||||
F src/attach.c 0ba38b38252a34bb9721de35514a1d14058a8e49
|
||||
F src/alter.c e6f4d11b1c0b23642fc46bac9abe0753c4294e05
|
||||
F src/analyze.c 92a65a5a402898a52b03695c7f0cd383724d711f
|
||||
F src/attach.c 7abe1607c2054585377cdba3c219e8572f84ca5e
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 744e98359dfc79fed43e8dec911e33e108b06aae
|
||||
F src/backup.c b293534bc2df23c57668a585b17ee7faaaef0939
|
||||
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c efdef3953c49e28f8b8fa9cc0ac5754cc1a7489a
|
||||
F src/btree.h 7944a9dac59eb3e541aad45fd2747f1051e7c63d
|
||||
F src/btreeInt.h 54f4245decd0409ea52cf9aee422d3d761d7ac10
|
||||
F src/build.c a48e74d24897100017d39ceba5de255e53ec9488
|
||||
F src/btree.c 0d6e44d664b1775b269ea7e6f66fdffcfc32ceb3
|
||||
F src/btree.h 0e193b7e90f1d78b79c79474040e3d66a553a4fa
|
||||
F src/btreeInt.h 71ed5e7f009caf17b7dc304350b3cb64b5970135
|
||||
F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
|
||||
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
|
||||
F src/complete.c 417df1ef5ea798532bb6290b0cc4265fef82980a
|
||||
F src/date.c a79c0a8f219370b972e320741f995a3bef9df33f
|
||||
F src/delete.c 8b8afb9cd7783d573eae55a3f4208bc0637a2bb8
|
||||
F src/expr.c 50385ed51f1cd7f1ab289629cd0f87d5b2fcca52
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ceb247eb31620bba66a94c3f697db489a1652353
|
||||
F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9
|
||||
F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581
|
||||
F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
|
||||
F src/func.c bf54e1202cbfb28bf4b1fd9b58899009ae76716f
|
||||
F src/global.c 75946a4a2ab41c6ae58f10ca0ed31b3449694b26
|
||||
F src/func.c 5dca069d98eca0ff70c9a8fb8ab9e1d6467187b5
|
||||
F src/global.c 5a9c1e3c93213ca574786ac1caa976ce8f709105
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c f9c6098988675ac258b2f98ea5f7e370fc9990fa
|
||||
F src/insert.c 76d6b44a9f9050134fd81205f4b792cbdac7c925
|
||||
F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
|
||||
F src/legacy.c 9304428e71b1d622b764913e1432e69156814755
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
||||
F src/main.c aae32d5af35b88faff0664e0f937ee7133d77c8d
|
||||
F src/main.c 7d89bb6dcc6993a8d32f4f22dae3e57c50a41399
|
||||
F src/malloc.c 5fa175797f982b178eaf38afba9c588a866be729
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 552f7e11486272f27948d2de9c012884d1f52908
|
||||
F src/mem2.c 3f196f6fd3f4320035eb4acbe4530686da2f14b1
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
F src/mem2.c ee752297650632935218dcf3b20c5ed5899cb4b5
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c 4837b795ebdecc0cfe1522cd0c8b2c5d84ea490d
|
||||
F src/mem5.c eb7a5cb98915dd7a086fa415ce3a5a0f20d0acff
|
||||
F src/memjournal.c 5bfc2f33c914946e2f77ed3f882aff14dfc9355d
|
||||
F src/mutex.c 581a272e09098040ca3ef543cb5f3d643eff7d50
|
||||
F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
|
||||
F src/mutex_noop.c 5f58eaa31f2d742cb8957a747f7887ae98f16053
|
||||
F src/mutex_os2.c 20477db50cf3817c2f1cd3eb61e5c177e50231db
|
||||
F src/mutex_unix.c 04a25238abce7e3d06b358dcf706e26624270809
|
||||
F src/mutex_w32.c 9ec75bcef0ca722821be7968c320fd725abfb984
|
||||
F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
|
||||
F src/notify.c f799bbda67ab6619b36b0a24153b49518874a203
|
||||
F src/os.c 4500ff276e277730776fe9b6c6c5930383ec4000
|
||||
F src/os.c 8bc63cf91e9802e2b807198e54e50227fa889306
|
||||
F src/os.h 534b082c3cb349ad05fa6fa0b06087e022af282c
|
||||
F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
||||
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
||||
F src/os_unix.c fe85acfeded5cc13c2340ab73c9baf841de4e6d9
|
||||
F src/os_win.c 5ffab20249a61e0625f869efe157fa009747039b
|
||||
F src/pager.c a0ed14b86de9d012a962b83389ca01003b6acccb
|
||||
F src/os_unix.c 148d2f625db3727250c0b880481ae7630b6d0eb0
|
||||
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
||||
F src/pager.c 1915e3ec1a2157d0c29086b7fc0c936a2d97029e
|
||||
F src/pager.h 1b32faf2e578ac3e7bcf9c9d11217128261c5c54
|
||||
F src/parse.y b172fba9a954855502271556497c440506b6daf4
|
||||
F src/pcache.c 3b079306376e0e04c0d3df40c0a4b750a1839310
|
||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c 4956b41d6ba913f7a8a56fbf32be78caed0e45c2
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 2bb2261190b42a348038f5b1c285c8cef415fcc8
|
||||
F src/pragma.c 6936d7df5e04b9f996f8f320d15e65b6944b2caa
|
||||
F src/prepare.c ad90970bba3aead154266d8bb6faf9fbb5233b94
|
||||
F src/printf.c 644bc7d59df3dc56d6d8b9a510914bfc6b51bc69
|
||||
F src/pragma.c 56d95f76154a5f873c32eae485bb625f3c70be46
|
||||
F src/prepare.c 18292e5f365655cd5c5693e09508e90668f7d547
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c d052e5c44bab34f83b3c1741aaa07478d18b5dd5
|
||||
F src/resolve.c a1648d98e869937b29f4f697461fe4d60f220a7b
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 2f9ed7482e7a25b0b127fc41693bbdbe1caf5647
|
||||
F src/shell.c f4948cb6d30665d755a6b5e0ec313d1094aab828
|
||||
F src/sqlite.h.in 2d34605565e021851255e0bbcb15f8c1930d1f6f
|
||||
F src/select.c 4113ef360430ed4e7533690ef46d06c20204adce
|
||||
F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4
|
||||
F src/sqlite.h.in 08a2d9a278ff0dfd65055a7ec9c599f7ae1a3c18
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h e946a6a3f2df015cdbc7668e9626987e8badbb5f
|
||||
F src/sqliteInt.h 6873f7f4c24fcdceece8777f2a1cbec049df77a0
|
||||
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
|
||||
F src/status.c e651be6b30d397d86384c6867bc016e4913bcac7
|
||||
F src/status.c d329385a2cba3ea49d9d68af0ad84b22d46b4f40
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c bad6570a005b234ea670b9f7b48256da19a032d3
|
||||
F src/test1.c db4d8fd2849ab9aca0f27fd3773b8d68d078cf86
|
||||
F src/test1.c aa9b1e10e834330e7759afb639420117e2422ded
|
||||
F src/test2.c b6b43413d495addd039a88b87d65c839f86b18cb
|
||||
F src/test3.c f17eeaf8114205844d76f4e69bab27ea341087af
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
|
||||
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
|
||||
F src/test6.c a8ece4284d0e34477f349ac05655db73c48e0926
|
||||
@ -187,10 +189,10 @@ F src/test_async.c c1656facbaf43cb2e71b62621e5b9eb080e2621c
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 220a67047af393756f55760fdf442d935d0d88f3
|
||||
F src/test_config.c 5844274bf6cec4af3e6461fb3e2d349082635e81
|
||||
F src/test_devsym.c de3c9af2bb9a8b1e44525c449e4ec3f88e3d4110
|
||||
F src/test_func.c 1c94388a23d4a9e7cd62ec79d612d1bae2451fa2
|
||||
F src/test_hexio.c 415adbdb88cd9388831ce10edff76cb9e73d8a0b
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
|
||||
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
@ -206,23 +208,23 @@ F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 00fed80690ae7f1525483a35861511c48bc579f2
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 9f7d39da1a1346fa0cf106ea0bf10bb6b8b61ddf
|
||||
F src/trigger.c d46f9389e3bf3dd1cc1d288aba2f289c96b34200
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 340c9eca0fb24b1197468d96ba059f867c9834c7
|
||||
F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
|
||||
F src/utf.c dad16adcc0c35ef2437dca125a4b07419d361052
|
||||
F src/util.c ad4f03079ba0fe83590d1cc9197e8e4844e38592
|
||||
F src/vacuum.c 03309a08d549f9389cc3a3589afd4fadbdaf0679
|
||||
F src/vdbe.c 5ed06318aac5d57849170a8bf39e807c22c5fedd
|
||||
F src/vdbe.h bea1f0cd530775bdb58a340265f3cf3ee920e9b2
|
||||
F src/vdbeInt.h d7ea821ac7813c9bea0fe87558c35e07b2c7c44d
|
||||
F src/vdbeapi.c bb128b819b9ef1a2ce211a36a6cb70a1643fa239
|
||||
F src/vdbeaux.c 0981dcb5b933b74ae7bc9bfa7770df5e4da849b3
|
||||
F src/vdbeblob.c 84f924700a7a889152aeebef77ca5f4e3875ffb4
|
||||
F src/vdbemem.c 1e16e3a16e55f4c3452834f0e041726021aa66e0
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
|
||||
F src/vdbe.c 8acca6dab2505e9650f6f014ada6ef30570cba99
|
||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||
F src/vdbeInt.h ae1e6ba0dd3fb4a886898d2829d748be701b01f8
|
||||
F src/vdbeapi.c 74c25680046a116b24b95393914d3669c23305dc
|
||||
F src/vdbeaux.c 0f352f63be78138bd94275aa3c8361e760ecc639
|
||||
F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c 456fc226614569f0e46f216e33265bea268bd917
|
||||
F src/vtab.c 606adf51cd6d4ba51a8c6dccede06a6f7b0dd72d
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 11b5b00c49d53e767a7eb855bc60790edeca6185
|
||||
F src/where.c 399ea4c090284c9d16f76d685b9b44e8b9b4442b
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||
@ -233,24 +235,24 @@ F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test ad5329098fe4de4a96852231d53e3e9e6283ad4b
|
||||
F test/analyze2.test a2ad7b0a4e13801ee3968fe70f22aff52326569c
|
||||
F test/analyze3.test ae06e0f8b3eaae0dd644ac9ac9d617058b5ac131
|
||||
F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8
|
||||
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
F test/async4.test aafa6328c559d3e4bb587de770cbdecfca06f0da
|
||||
F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf
|
||||
F test/attach.test 826f7676c41c12b035181d257299b8c8a17d64f3
|
||||
F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc
|
||||
F test/attachmalloc.test cf8cf17d183de357b1147a9baacbdfc85b940b61
|
||||
F test/attachmalloc.test 38d2da5fdaf09ba0add57296967a3061e5842584
|
||||
F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf
|
||||
F test/auth2.test ee3ba272e2b975e913afc9b041ee75706e190005
|
||||
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
|
||||
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
|
||||
F test/backup.test 9b184cc3cccb153e73387a88c6e6d23210212f86
|
||||
F test/backup.test 3549ea8f541a08205c0eb813b21e81ea8301f6ed
|
||||
F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
|
||||
@ -275,10 +277,10 @@ F test/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
|
||||
F test/capi2.test 172c717ed101e78e0798dd21b9896a22366f35b4
|
||||
F test/capi3.test 168e2cd66c58c510955b0f299750e4de73b8d952
|
||||
F test/capi3b.test 664eb55318132f292f2c436f90906f578cad6b97
|
||||
F test/capi3c.test d9d293ce8fd4dc2944ce2dae5718fc7a6184a567
|
||||
F test/capi3c.test 493385107dcedfaf4f2b1c3738c8c1fa00362006
|
||||
F test/capi3d.test 57d83b690d7364bde02cddbf8339a4b50d80ce23
|
||||
F test/cast.test 166951664a0b0a2e0f8fb5997a152490c6363932
|
||||
F test/check.test b897cd3cc839b34b31cdd073e9882ccd03da977b
|
||||
F test/check.test db2b29d557544347d28e25b8406f5d5ecc3d1bc3
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
@ -293,19 +295,20 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/colmeta.test 087c42997754b8c648819832241daf724f813322
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 0ed68b11f22721052d880ee80bd528a0e0828236
|
||||
F test/corrupt.test 85c3fececa01bc6d24ff5d7bf1373844840c0b98
|
||||
F test/corrupt.test 0d346c9fe064ca71281685a8a732fcc83461bb99
|
||||
F test/corrupt2.test a571e30ea4e82318f319a24b6cc55935ce862079
|
||||
F test/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32
|
||||
F test/corrupt4.test acdb01afaedf529004b70e55de1a6f5a05ae7fff
|
||||
F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
|
||||
F test/corrupt6.test e69b877d478224deab7b66844566258cecacd25e
|
||||
F test/corrupt7.test e66cb109ed64e7ac985d8b4a3422c213d074c62d
|
||||
F test/corrupt7.test 1eb2214f29474fa6b155aa3da8a7d46bf52089e1
|
||||
F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51
|
||||
F test/corrupt9.test 4aa1cb1ef091cb0e13e89a819c72911631b5176a
|
||||
F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff
|
||||
F test/corruptB.test 66b4544104dd03d0f33ea69ddac3fa4a682cd3c2
|
||||
F test/corruptC.test 691ed070baef5e1345939caadf270a52837a5064
|
||||
F test/corruptD.test 3ae6e2dc6e2226c6935a8a40d4b5ee3eba75f8c0
|
||||
F test/corruptE.test dbf66cae4c0e977ca9625a9114cdd01df8967bef
|
||||
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
|
||||
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
|
||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||
@ -314,10 +317,11 @@ F test/crash4.test 02ff4f15c149ca1e88a5c299b4896c84d9450c3b
|
||||
F test/crash5.test 80a2f7073381837fc082435c97df52a830abcd80
|
||||
F test/crash6.test 9c730cf06335003cb1f5cfceddacd044155336e0
|
||||
F test/crash7.test e20a7b9ee1d16eaef7c94a4cb7ed2191b4d05970
|
||||
F test/crash8.test 5b32966fcb58fd616d24ce94303420351d076eb9
|
||||
F test/crash8.test 3af0fc90c3e593b85e810b8d6c50fc7d0df30008
|
||||
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||
F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test f5040beef89c1b2bdb6a9edb7358a519213ff80c
|
||||
F test/date.test 0b8473ed9ab6fd4283b4a01f035e1067762ba734
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
|
||||
@ -328,8 +332,8 @@ F test/descidx2.test 1310ed1326cdfed4ea2c55169631579f082d174f
|
||||
F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f
|
||||
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_fkey.test fd1fcf89badd5f2773d7ac04775b5ff3488eda17
|
||||
F test/e_fts3.test 8907e25b2c7d6bda9f7077356f64bc5e26c251a7
|
||||
F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
|
||||
F test/e_fts3.test 5adb033fae6e07002d11f4a7c8f8e8ff9f31e8ec
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
|
||||
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
|
||||
@ -341,7 +345,7 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
|
||||
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test add654160d1b066f7b866d63d4435954ccbcab7d
|
||||
F test/fkey2.test e71f5baf9bb42cdba4700d73cba6f4d82fd6b925
|
||||
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@ -380,36 +384,40 @@ F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682
|
||||
F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
|
||||
F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
|
||||
F test/fts3.test ae0433b09b12def08105640e57693726c4949338
|
||||
F test/fts3_common.tcl 31935839b1b601a5955572cb4e8060513c96bde0
|
||||
F test/fts3_common.tcl 1d887ded06dac9b993cfb175618df7f70c796de2
|
||||
F test/fts3aa.test 5327d4c1d9b6c61021696746cc9a6cdc5bf159c0
|
||||
F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
|
||||
F test/fts3ac.test 356280144a2c92aa7b11474afadfe62a437fcd69
|
||||
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
|
||||
F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49
|
||||
F test/fts3ae.test ce32a13b34b0260928e4213b4481acf801533bda
|
||||
F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c
|
||||
F test/fts3ag.test 38d9c7dd4b607929498e8e0b32299af5665da1ab
|
||||
F test/fts3ag.test 0b7d303f61ae5d620c4efb5e825713ea34ff9441
|
||||
F test/fts3ah.test ba181d6a3dee0c929f0d69df67cac9c47cda6bff
|
||||
F test/fts3ai.test d29cee6ed653e30de478066881cec8aa766531b2
|
||||
F test/fts3aj.test 584facbc9ac4381a7ec624bfde677340ffc2a5a4
|
||||
F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 6d19619402d2133773262652fc3f185cdf6be667
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test 931fa21bd80641ca594bfa32e105250a8a07918b
|
||||
F test/fts3ao.test 0aa29dd4fc1c8d46b1f7cfe5926f7ac97551bea9
|
||||
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
||||
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
||||
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
||||
F test/fts3cov.test 3a9d8618a3107166530c447e808f8992372e0415
|
||||
F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
|
||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
F test/fts3expr.test 05dab77387801e4900009917bb18f556037d82da
|
||||
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3malloc.test d02ee86b21edd2b43044e0d6dfdcd26cb6efddcb
|
||||
F test/fts3near.test dc196dd17b4606f440c580d45b3d23aa975fd077
|
||||
F test/fts3rnd.test ec82795eb358b7a4d6ce79e764d8d55556197584
|
||||
F test/func.test af106ed834001738246d276659406823e35cde7b
|
||||
F test/fts3malloc.test 059592c4f37ccd30138bbf8e3e5b7982cb5c8f2e
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3query.test 154fe4b015fd61af523ee083570a134f508f5be7
|
||||
F test/fts3rnd.test 2f5761db9dd92f6fe09d08976ac658ef521846ed
|
||||
F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f
|
||||
F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f
|
||||
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/fuzz.test a4174c3009a3e2c2e14b31b364ebf7ddb49de2c9
|
||||
F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb
|
||||
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 4eca9d345f06d5b0b0105f7a2ef9e7f22658827b
|
||||
@ -433,7 +441,7 @@ F test/init.test 3f9e97948cf2335c08a5e3edc3df3a26cdaa76f2
|
||||
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test 6e382eaf7295a4463e6f29ea20fcd8e63d097eeb
|
||||
F test/insert4.test c1469999a58e86a85b74df645a820f4cc7a8273b
|
||||
F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
|
||||
@ -449,6 +457,7 @@ F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/jrnlmode.test a765844f22b3f6d72d78a68d5decd26c64bb859c
|
||||
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
|
||||
@ -469,7 +478,7 @@ F test/lock5.test 6b1f78f09ad1522843dad571b76b321e6f439bf7
|
||||
F test/lock6.test 862aa71e97b288d6b3f92ba3313f51bd0b003776
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
|
||||
F test/main.test 347ab987f16167858781383427476b33dc69fdb7
|
||||
F test/main.test 2be2352ac77ac5b238c6337a5469aeeef57677e6
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test d23580e15c33ee0353717129421b077541e910dc
|
||||
F test/malloc3.test 4bc57f850b212f706f3e1b37c4eced1d5a727cd1
|
||||
@ -499,7 +508,7 @@ F test/memsubsys1.test fd8a33046b6e758e3eb93747dc4eec21fe56bf64
|
||||
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
F test/minmax3.test 94742aa922153953ce3562702815e4f1f079bdb8
|
||||
F test/minmax3.test a38686c33b07d595e98a2fc6d3aa84a5e886a972
|
||||
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
|
||||
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
|
||||
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
|
||||
@ -517,10 +526,10 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
|
||||
F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 1ce2874df8fec876d0b963c7a3ef61c4e9df8827
|
||||
F test/permutations.test 91928573ca2db2c88dbc50ab34e4a585d912b580
|
||||
F test/pragma.test 5aeb48a442dba3c3e8e38773b121371814ab3b17
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
@ -536,22 +545,22 @@ F test/rollback.test 73355ad4492ff9a3a31e61c7e5eb5e01a1de94ca
|
||||
F test/rowhash.test 97f56043ba11f0679920416c0cdbc72e5272267b
|
||||
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
|
||||
F test/rtree.test 55466a200af3591946c5da77ad5dbfbc1e5e05f9
|
||||
F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
|
||||
F test/savepoint.test f2ede4b643ad87ead36c041c72d774a1f5c8a564
|
||||
F test/savepoint2.test 427c8b20f43d3edf17a290c6788ae9e2703ac51c
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test 2df1d093e59e78d688c64eb20e0457aaea7d08f9
|
||||
F test/schema.test 3d8b19e3cf1105929940d387e3577da5a58d8fc0
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/securedel.test 328d2921c0ca49bdd3352e516b0377fc07143254
|
||||
F test/select1.test f67ca2dfc05df41c7b86eb32ca409b427a5f43b0
|
||||
F test/select2.test 9735da20ccd41e42bf2b4c19fd939141b591adae
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test 2b5e8500d8ec3dd4c8e0c99eb1431b3d11fcc24c
|
||||
F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f
|
||||
F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test b4007b15396cb7ba2615cab31e1973b572e43210
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
@ -580,6 +589,7 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0
|
||||
F test/stmt.test ac97e59879fd3bd52ecd60ef4efb03ba16292829
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
@ -590,7 +600,7 @@ F test/tclsqlite.test bf4227eb236a4c097aa7974a2bf7d3225acf34be
|
||||
F test/tempdb.test 1bf52da28a9c24e29717362a87722dff08feb72b
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl 02f671e71d1646440d226bed2dde8433f0a7bfa9
|
||||
F test/tester.tcl e1f581c7a2648a0aaa51135c4d2e7be68f4b9292
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@ -602,11 +612,13 @@ F test/thread_common.tcl b65e6b1d1d90dc885e10ad080896c6c56eef0819
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
|
||||
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
F test/tkt-3fe897352e.test 8084dad39807eac10b10720c84193bd1a5980973
|
||||
F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
|
||||
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
|
||||
F test/tkt-d82e3f3721.txt cbed12b1a1e4740382de43ef1bb45c6bc0f8f473
|
||||
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
|
||||
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
|
||||
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
|
||||
F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368
|
||||
@ -693,7 +705,7 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/trace.test 2739f8dcc6739a9235523819c4cd30e78c44985c
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trans.test d887cb07630dc39879a322d958ad8b006137485c
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
@ -709,6 +721,7 @@ F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 4083c64d80854d271bad211268a08985f3d61cbd
|
||||
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
|
||||
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
|
||||
@ -718,6 +731,7 @@ F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test 68e39b2228b4b772166debef4a82accf6ddd32f3
|
||||
F test/vacuum2.test ec57f21d394b7b72249b11f8e4b5d487bab56539
|
||||
F test/vacuum3.test f39ad1428347c5808cd2da7578c470f186a4d0ce
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test e265401afefa994cdf2fe4b6f286b1e87c2f9b9d
|
||||
F test/view.test 45f518205ecdb6dd23a86dd4a99bb4ae945e625d
|
||||
@ -730,7 +744,7 @@ F test/vtab6.test c7f290d172609d636fbfc58166eadcb55d5c117c
|
||||
F test/vtab7.test a8c3c3cb3eb60be364991bd714e4927e26c4cd85
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
F test/vtabA.test 0dcd4c81ffb56649f47d1b5fb9c5ae807ccf41f7
|
||||
F test/vtabA.test c86e1990b7e1e2bb34602a06fffa4c69f2b516dc
|
||||
F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796
|
||||
F test/vtabC.test 1cf7896ab6859bfe3074244b2b0e12de5cbdd766
|
||||
F test/vtabD.test 74167b1578e5886fe4c886d6bef2fd1406444c42
|
||||
@ -743,12 +757,12 @@ F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820
|
||||
F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test fdd58ab9dec9f97679e65d4414bf5e07d725d79f
|
||||
F test/where8.test 434f08974964b10378d67867773a2c3aedaf1d4b
|
||||
F test/where8.test 2bb8ea44b745fcc93db150fac9ce33d12e499760
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
|
||||
F test/whereA.test 1d1674254614147c866ab9b59af6582f454a858c
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
@ -756,18 +770,20 @@ F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/lemon.c 3088e4dec7f93c6b0925cf5bac04c8b7c8688835
|
||||
F tool/lemon.c 6958cb9935be265bf51dbc718ef325e3b77685b6
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/mkkeywordhash.c 9216336085e7a7c226a35c0bd780239968f8304f
|
||||
F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl 1da28229695fdebdfe8a7d19902ef6c76d6c1c2d
|
||||
F tool/mksqlite3c.tcl 4c6924c7e877defa8f9a12ef1e6867de614acf3f
|
||||
F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/shell1.test f85b976bef45f435fa39bf3690501cd5c0bdbb86
|
||||
F tool/shell2.test c985140ca75d96dad5bef8a5f49ed51b9c002dfb
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test ef08a3e738b9fee4fc228920956950bc35db0575
|
||||
F tool/shell2.test 8f51f61c13b88618e71c17439fe0847c2421c5d1
|
||||
F tool/shell3.test ff663e83100670a295d473515c12beb8103a78b6
|
||||
F tool/showdb.c 8ab8b3b53884312aafb7ef60982e255a6c31d238
|
||||
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
@ -779,14 +795,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P cd50acf37fd1e3b388f98fb2df7ed03cff454b24
|
||||
R 5d0b6a47a50c8a9cdc60d3d4d61a8cf2
|
||||
P b1f342a6643829020beef542a0700d90822e6467
|
||||
R 590a011d9441875bded2c173c371f1c1
|
||||
U drh
|
||||
Z 8b76b0c0726e570aef93558fa0c3fdc7
|
||||
Z f7171db765620a4ccff85bc2ced22202
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFLHS+0oxKgR168RlERArAKAJ97NTyJvzQHmWC2GXt2Xt7D52m04QCeLeQt
|
||||
HYPTNDWgvT/KRZ19RtHNjDQ=
|
||||
=tE2+
|
||||
iD8DBQFLrTT6oxKgR168RlERArP2AJ0UeA3bKxomgH1prR7M+4tHuMlN7wCfXBZE
|
||||
Jr7IGDFSJ/vsM6VpeiKkkf4=
|
||||
=diSA
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
@ -1 +1 @@
|
||||
1ed88e9d01e9eda5cbc622e7614277f29bcc551c
|
||||
b078b588d617e07886ad156e9f54ade6d823568e
|
||||
|
||||
@ -479,9 +479,9 @@ void sqlite3AlterRenameTable(
|
||||
** for which the renamed table is the parent table. */
|
||||
if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_master SET "
|
||||
"UPDATE \"%w\".%s SET "
|
||||
"sql = sqlite_rename_parent(sql, %Q, %Q) "
|
||||
"WHERE %s;", zTabName, zName, zWhere);
|
||||
"WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
|
||||
sqlite3DbFree(db, zWhere);
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,9 +559,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3DbFree(db, zSql);
|
||||
}
|
||||
|
||||
@ -579,14 +577,11 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3DbFree(db, zSql);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
(void)sqlite3SafetyOff(db);
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
@ -636,7 +631,6 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
}
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
12
src/attach.c
12
src/attach.c
@ -144,11 +144,17 @@ static void attachFunc(
|
||||
pPager = sqlite3BtreePager(aNew->pBt);
|
||||
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
|
||||
sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
|
||||
sqlite3BtreeSecureDelete(aNew->pBt,
|
||||
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
|
||||
}
|
||||
aNew->zName = sqlite3DbStrDup(db, zName);
|
||||
aNew->safety_level = 3;
|
||||
aNew->zName = sqlite3DbStrDup(db, zName);
|
||||
if( rc==SQLITE_OK && aNew->zName==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( rc==SQLITE_OK ){
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
@ -184,11 +190,9 @@ static void attachFunc(
|
||||
** we found it.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
}
|
||||
if( rc ){
|
||||
int iDb = db->nDb - 1;
|
||||
|
||||
@ -98,10 +98,10 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
}else{
|
||||
pParse->db = pDb;
|
||||
if( sqlite3OpenTempDatabase(pParse) ){
|
||||
sqlite3ErrorClear(pParse);
|
||||
sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3DbFree(pErrorDb, pParse->zErrMsg);
|
||||
sqlite3StackFree(pErrorDb, pParse);
|
||||
}
|
||||
if( rc ){
|
||||
|
||||
164
src/btree.c
164
src/btree.c
@ -1247,11 +1247,11 @@ static int freeSpace(MemPage *pPage, int start, int size){
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( size>=0 ); /* Minimum cell size is 4 */
|
||||
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
/* Overwrite deleted information with zeros when the SECURE_DELETE
|
||||
** option is enabled at compile-time */
|
||||
memset(&data[start], 0, size);
|
||||
#endif
|
||||
if( pPage->pBt->secureDelete ){
|
||||
/* Overwrite deleted information with zeros when the secure_delete
|
||||
** option is enabled */
|
||||
memset(&data[start], 0, size);
|
||||
}
|
||||
|
||||
/* Add the space back into the linked list of freeblocks. Note that
|
||||
** even though the freeblock list was checked by btreeInitPage(),
|
||||
@ -1483,9 +1483,9 @@ static void zeroPage(MemPage *pPage, int flags){
|
||||
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
memset(&data[hdr], 0, pBt->usableSize - hdr);
|
||||
#endif
|
||||
if( pBt->secureDelete ){
|
||||
memset(&data[hdr], 0, pBt->usableSize - hdr);
|
||||
}
|
||||
data[hdr] = (char)flags;
|
||||
first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0);
|
||||
memset(&data[hdr+1], 0, 4);
|
||||
@ -1805,6 +1805,9 @@ int sqlite3BtreeOpen(
|
||||
pBt->pCursor = 0;
|
||||
pBt->pPage1 = 0;
|
||||
pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
pBt->secureDelete = 1;
|
||||
#endif
|
||||
pBt->pageSize = get2byte(&zDbHeader[16]);
|
||||
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
|
||||
@ -2161,6 +2164,23 @@ int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
|
||||
sqlite3BtreeLeave(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1,
|
||||
** then make no changes. Always return the value of the secureDelete
|
||||
** setting after the change.
|
||||
*/
|
||||
int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
|
||||
int b;
|
||||
if( p==0 ) return 0;
|
||||
sqlite3BtreeEnter(p);
|
||||
if( newFlag>=0 ){
|
||||
p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
|
||||
}
|
||||
b = p->pBt->secureDelete;
|
||||
sqlite3BtreeLeave(p);
|
||||
return b;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
|
||||
|
||||
/*
|
||||
@ -4904,17 +4924,17 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
nFree = get4byte(&pPage1->aData[36]);
|
||||
put4byte(&pPage1->aData[36], nFree+1);
|
||||
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
/* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
|
||||
** always fully overwrite deleted information with zeros.
|
||||
*/
|
||||
if( (!pPage && (rc = btreeGetPage(pBt, iPage, &pPage, 0)))
|
||||
|| (rc = sqlite3PagerWrite(pPage->pDbPage))
|
||||
){
|
||||
goto freepage_out;
|
||||
if( pBt->secureDelete ){
|
||||
/* If the secure_delete option is enabled, then
|
||||
** always fully overwrite deleted information with zeros.
|
||||
*/
|
||||
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
|
||||
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
|
||||
){
|
||||
goto freepage_out;
|
||||
}
|
||||
memset(pPage->aData, 0, pPage->pBt->pageSize);
|
||||
}
|
||||
memset(pPage->aData, 0, pPage->pBt->pageSize);
|
||||
#endif
|
||||
|
||||
/* If the database supports auto-vacuum, write an entry in the pointer-map
|
||||
** to indicate that the page is free.
|
||||
@ -4965,11 +4985,9 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
if( rc==SQLITE_OK ){
|
||||
put4byte(&pTrunk->aData[4], nLeaf+1);
|
||||
put4byte(&pTrunk->aData[8+nLeaf*4], iPage);
|
||||
#ifndef SQLITE_SECURE_DELETE
|
||||
if( pPage ){
|
||||
if( pPage && !pBt->secureDelete ){
|
||||
sqlite3PagerDontWrite(pPage->pDbPage);
|
||||
}
|
||||
#endif
|
||||
rc = btreeSetHasContent(pBt, iPage);
|
||||
}
|
||||
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
|
||||
@ -5043,7 +5061,25 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
||||
rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
rc = freePage2(pBt, pOvfl, ovflPgno);
|
||||
|
||||
if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
|
||||
&& sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
|
||||
){
|
||||
/* There is no reason any cursor should have an outstanding reference
|
||||
** to an overflow page belonging to a cell that is being deleted/updated.
|
||||
** So if there exists more than one reference to this page, then it
|
||||
** must not really be an overflow page and the database must be corrupt.
|
||||
** It is helpful to detect this before calling freePage2(), as
|
||||
** freePage2() may zero the page contents if secure-delete mode is
|
||||
** enabled. If this 'overflow' page happens to be a page that the
|
||||
** caller is iterating through or using in some other way, this
|
||||
** can be problematic.
|
||||
*/
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = freePage2(pBt, pOvfl, ovflPgno);
|
||||
}
|
||||
|
||||
if( pOvfl ){
|
||||
sqlite3PagerUnref(pOvfl->pDbPage);
|
||||
}
|
||||
@ -5287,7 +5323,7 @@ static void insertCell(
|
||||
Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
|
||||
int *pRC /* Read and write return code from here */
|
||||
){
|
||||
int idx; /* Where to write new cell content in data[] */
|
||||
int idx = 0; /* Where to write new cell content in data[] */
|
||||
int j; /* Loop counter */
|
||||
int end; /* First byte past the last cell pointer in data[] */
|
||||
int ins; /* Index in data[] where new cell pointer is inserted */
|
||||
@ -5778,10 +5814,17 @@ static int balance_nonroot(
|
||||
** In this case, temporarily copy the cell into the aOvflSpace[]
|
||||
** buffer. It will be copied out again as soon as the aSpace[] buffer
|
||||
** is allocated. */
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]);
|
||||
apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
|
||||
#endif
|
||||
if( pBt->secureDelete ){
|
||||
int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
||||
if( (iOff+szNew[i])>pBt->usableSize ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
goto balance_cleanup;
|
||||
}else{
|
||||
memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]);
|
||||
apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
|
||||
}
|
||||
}
|
||||
dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc);
|
||||
}
|
||||
}
|
||||
@ -5901,7 +5944,7 @@ static int balance_nonroot(
|
||||
if( leafData ){ i--; }
|
||||
subtotal = 0;
|
||||
k++;
|
||||
if( k>NB+1 ){ rc = SQLITE_CORRUPT; goto balance_cleanup; }
|
||||
if( k>NB+1 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
|
||||
}
|
||||
}
|
||||
szNew[k] = subtotal;
|
||||
@ -5955,7 +5998,7 @@ static int balance_nonroot(
|
||||
** Allocate k new pages. Reuse old pages where possible.
|
||||
*/
|
||||
if( apOld[0]->pgno<=1 ){
|
||||
rc = SQLITE_CORRUPT;
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto balance_cleanup;
|
||||
}
|
||||
pageFlags = apOld[0]->aData[0];
|
||||
@ -7393,7 +7436,9 @@ static void checkList(
|
||||
static int checkTreePage(
|
||||
IntegrityCk *pCheck, /* Context for the sanity check */
|
||||
int iPage, /* Page number of the page to check */
|
||||
char *zParentContext /* Parent context */
|
||||
char *zParentContext, /* Parent context */
|
||||
i64 *pnParentMinKey,
|
||||
i64 *pnParentMaxKey
|
||||
){
|
||||
MemPage *pPage;
|
||||
int i, rc, depth, d2, pgno, cnt;
|
||||
@ -7404,6 +7449,8 @@ static int checkTreePage(
|
||||
int usableSize;
|
||||
char zContext[100];
|
||||
char *hit = 0;
|
||||
i64 nMinKey = 0;
|
||||
i64 nMaxKey = 0;
|
||||
|
||||
sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage);
|
||||
|
||||
@ -7446,6 +7493,16 @@ static int checkTreePage(
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
sz = info.nData;
|
||||
if( !pPage->intKey ) sz += (int)info.nKey;
|
||||
/* For intKey pages, check that the keys are in order.
|
||||
*/
|
||||
else if( i==0 ) nMinKey = nMaxKey = info.nKey;
|
||||
else{
|
||||
if( info.nKey <= nMaxKey ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
|
||||
}
|
||||
nMaxKey = info.nKey;
|
||||
}
|
||||
assert( sz==info.nPayload );
|
||||
if( (sz>info.nLocal)
|
||||
&& (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
|
||||
@ -7469,25 +7526,62 @@ static int checkTreePage(
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
|
||||
}
|
||||
#endif
|
||||
d2 = checkTreePage(pCheck, pgno, zContext);
|
||||
d2 = checkTreePage(pCheck, pgno, zContext, &nMinKey, i==0 ? NULL : &nMaxKey);
|
||||
if( i>0 && d2!=depth ){
|
||||
checkAppendMsg(pCheck, zContext, "Child page depth differs");
|
||||
}
|
||||
depth = d2;
|
||||
}
|
||||
}
|
||||
|
||||
if( !pPage->leaf ){
|
||||
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
sqlite3_snprintf(sizeof(zContext), zContext,
|
||||
"On page %d at right child: ", iPage);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum ){
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
|
||||
}
|
||||
#endif
|
||||
checkTreePage(pCheck, pgno, zContext);
|
||||
checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey);
|
||||
}
|
||||
|
||||
/* For intKey leaf pages, check that the min/max keys are in order
|
||||
** with any left/parent/right pages.
|
||||
*/
|
||||
if( pPage->leaf && pPage->intKey ){
|
||||
/* if we are a left child page */
|
||||
if( pnParentMinKey ){
|
||||
/* if we are the left most child page */
|
||||
if( !pnParentMaxKey ){
|
||||
if( nMaxKey > *pnParentMinKey ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"Rowid %lld out of order (max larger than parent min of %lld)",
|
||||
nMaxKey, *pnParentMinKey);
|
||||
}
|
||||
}else{
|
||||
if( nMinKey <= *pnParentMinKey ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"Rowid %lld out of order (min less than parent min of %lld)",
|
||||
nMinKey, *pnParentMinKey);
|
||||
}
|
||||
if( nMaxKey > *pnParentMaxKey ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"Rowid %lld out of order (max larger than parent max of %lld)",
|
||||
nMaxKey, *pnParentMaxKey);
|
||||
}
|
||||
*pnParentMinKey = nMaxKey;
|
||||
}
|
||||
/* else if we're a right child page */
|
||||
} else if( pnParentMaxKey ){
|
||||
if( nMinKey <= *pnParentMaxKey ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"Rowid %lld out of order (min less than parent max of %lld)",
|
||||
nMinKey, *pnParentMaxKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for complete coverage of the page
|
||||
*/
|
||||
data = pPage->aData;
|
||||
@ -7511,7 +7605,7 @@ static int checkTreePage(
|
||||
}
|
||||
if( (pc+size-1)>=usableSize ){
|
||||
checkAppendMsg(pCheck, 0,
|
||||
"Corruption detected in cell %d on page %d",i,iPage,0);
|
||||
"Corruption detected in cell %d on page %d",i,iPage);
|
||||
}else{
|
||||
for(j=pc+size-1; j>=pc; j--) hit[j]++;
|
||||
}
|
||||
@ -7617,7 +7711,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
|
||||
}
|
||||
#endif
|
||||
checkTreePage(&sCheck, aRoot[i], "List of tree roots: ");
|
||||
checkTreePage(&sCheck, aRoot[i], "List of tree roots: ", NULL, NULL);
|
||||
}
|
||||
|
||||
/* Make sure every page in the file is referenced
|
||||
|
||||
@ -81,6 +81,7 @@ int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
|
||||
@ -407,6 +407,7 @@ struct BtShared {
|
||||
MemPage *pPage1; /* First page of the database */
|
||||
u8 readOnly; /* True if the underlying file is readonly */
|
||||
u8 pageSizeFixed; /* True if the page size can no longer be changed */
|
||||
u8 secureDelete; /* True if secure_delete is enabled */
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
|
||||
23
src/build.c
23
src/build.c
@ -202,7 +202,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
pParse->isMultiWrite && pParse->mayAbort);
|
||||
pParse->rc = SQLITE_DONE;
|
||||
pParse->colNamesSet = 0;
|
||||
}else if( pParse->rc==SQLITE_OK ){
|
||||
}else{
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
pParse->nTab = 0;
|
||||
@ -549,7 +549,8 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
||||
|
||||
assert( db!=0 );
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( zTabName && zTabName[0] );
|
||||
assert( zTabName );
|
||||
testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
|
||||
pDb = &db->aDb[iDb];
|
||||
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
|
||||
sqlite3Strlen30(zTabName),0);
|
||||
@ -1973,13 +1974,12 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( noErr ) db->suppressErr++;
|
||||
pTab = sqlite3LocateTable(pParse, isView,
|
||||
pName->a[0].zName, pName->a[0].zDatabase);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3ErrorClear(pParse);
|
||||
}
|
||||
goto exit_drop_table;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
@ -3401,6 +3401,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->aDb[1].pBt==0 && !pParse->explain ){
|
||||
int rc;
|
||||
Btree *pBt;
|
||||
static const int flags =
|
||||
SQLITE_OPEN_READWRITE |
|
||||
SQLITE_OPEN_CREATE |
|
||||
@ -3408,18 +3409,20 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
SQLITE_OPEN_DELETEONCLOSE |
|
||||
SQLITE_OPEN_TEMP_DB;
|
||||
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags,
|
||||
&db->aDb[1].pBt);
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
||||
"file for storing temporary tables");
|
||||
pParse->rc = rc;
|
||||
return 1;
|
||||
}
|
||||
assert( (db->flags & SQLITE_InTrans)==0 || db->autoCommit );
|
||||
db->aDb[1].pBt = pBt;
|
||||
assert( db->aDb[1].pSchema );
|
||||
sqlite3PagerJournalMode(sqlite3BtreePager(db->aDb[1].pBt),
|
||||
db->dfltJournalMode);
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
||||
db->mallocFailed = 1;
|
||||
return 1;
|
||||
}
|
||||
sqlite3PagerJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -40,11 +40,13 @@ extern const char sqlite3IsEbcdicIdChar[];
|
||||
#define tkSEMI 0
|
||||
#define tkWS 1
|
||||
#define tkOTHER 2
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
#define tkEXPLAIN 3
|
||||
#define tkCREATE 4
|
||||
#define tkTEMP 5
|
||||
#define tkTRIGGER 6
|
||||
#define tkEND 7
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return TRUE if the given SQL string ends in a semicolon.
|
||||
@ -53,36 +55,38 @@ extern const char sqlite3IsEbcdicIdChar[];
|
||||
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
||||
** must end with ";END;".
|
||||
**
|
||||
** This implementation uses a state machine with 7 states:
|
||||
** This implementation uses a state machine with 8 states:
|
||||
**
|
||||
** (0) START At the beginning or end of an SQL statement. This routine
|
||||
** (0) INVALID We have not yet seen a non-whitespace character.
|
||||
**
|
||||
** (1) START At the beginning or end of an SQL statement. This routine
|
||||
** returns 1 if it ends in the START state and 0 if it ends
|
||||
** in any other state.
|
||||
**
|
||||
** (1) NORMAL We are in the middle of statement which ends with a single
|
||||
** (2) NORMAL We are in the middle of statement which ends with a single
|
||||
** semicolon.
|
||||
**
|
||||
** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** a statement.
|
||||
**
|
||||
** (3) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** (4) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** statement, possibly preceeded by EXPLAIN and/or followed by
|
||||
** TEMP or TEMPORARY
|
||||
**
|
||||
** (4) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** (5) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** ended by a semicolon, the keyword END, and another semicolon.
|
||||
**
|
||||
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
||||
** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
||||
** the end of a trigger definition.
|
||||
**
|
||||
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** (7) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** of a trigger difinition.
|
||||
**
|
||||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
**
|
||||
** (0) tkSEMI A semicolon.
|
||||
** (1) tkWS Whitespace
|
||||
** (1) tkWS Whitespace.
|
||||
** (2) tkOTHER Any other SQL token.
|
||||
** (3) tkEXPLAIN The "explain" keyword.
|
||||
** (4) tkCREATE The "create" keyword.
|
||||
@ -91,6 +95,7 @@ extern const char sqlite3IsEbcdicIdChar[];
|
||||
** (7) tkEND The "end" keyword.
|
||||
**
|
||||
** Whitespace never causes a state transition and is always ignored.
|
||||
** This means that a SQL string of all whitespace is invalid.
|
||||
**
|
||||
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
|
||||
** to recognize the end of a trigger can be omitted. All we have to do
|
||||
@ -104,26 +109,28 @@ int sqlite3_complete(const char *zSql){
|
||||
/* A complex statement machine used to detect the end of a CREATE TRIGGER
|
||||
** statement. This is the normal case.
|
||||
*/
|
||||
static const u8 trans[7][8] = {
|
||||
static const u8 trans[8][8] = {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
|
||||
/* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, },
|
||||
/* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, },
|
||||
/* 2 EXPLAIN: */ { 0, 2, 2, 1, 3, 1, 1, 1, },
|
||||
/* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, },
|
||||
/* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, },
|
||||
/* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, },
|
||||
/* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, },
|
||||
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
|
||||
/* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, },
|
||||
/* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, },
|
||||
/* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, },
|
||||
/* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, },
|
||||
/* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, },
|
||||
/* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, },
|
||||
/* 6 SEMI: */ { 6, 6, 5, 5, 5, 5, 5, 7, },
|
||||
/* 7 END: */ { 1, 7, 5, 5, 5, 5, 5, 5, },
|
||||
};
|
||||
#else
|
||||
/* If triggers are not suppored by this compile then the statement machine
|
||||
/* If triggers are not supported by this compile then the statement machine
|
||||
** used to detect the end of a statement is much simplier
|
||||
*/
|
||||
static const u8 trans[2][3] = {
|
||||
static const u8 trans[3][3] = {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER */
|
||||
/* 0 START: */ { 0, 0, 1, },
|
||||
/* 1 NORMAL: */ { 0, 1, 1, },
|
||||
/* 0 INVALID: */ { 1, 0, 2, },
|
||||
/* 1 START: */ { 1, 1, 2, },
|
||||
/* 2 NORMAL: */ { 1, 2, 2, },
|
||||
};
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
|
||||
@ -159,7 +166,7 @@ int sqlite3_complete(const char *zSql){
|
||||
break;
|
||||
}
|
||||
while( *zSql && *zSql!='\n' ){ zSql++; }
|
||||
if( *zSql==0 ) return state==0;
|
||||
if( *zSql==0 ) return state==1;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
@ -243,7 +250,7 @@ int sqlite3_complete(const char *zSql){
|
||||
state = trans[state][token];
|
||||
zSql++;
|
||||
}
|
||||
return state==0;
|
||||
return state==1;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
|
||||
385
src/ctime.c
Normal file
385
src/ctime.c
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
** 2010 February 23
|
||||
**
|
||||
** 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 routines used to report what compile-time options
|
||||
** SQLite was built with.
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** An array of names of all compile-time options. This array should
|
||||
** be sorted A-Z.
|
||||
**
|
||||
** This array looks large, but in a typical installation actually uses
|
||||
** only a handful of compile-time options, so most times this array is usually
|
||||
** rather short and uses little memory space.
|
||||
*/
|
||||
static const char * const azCompileOpt[] = {
|
||||
|
||||
/* These macros are provided to "stringify" the value of the define
|
||||
** for those options in which the value is meaningful. */
|
||||
#define CTIMEOPT_VAL_(opt) #opt
|
||||
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
|
||||
|
||||
#ifdef SQLITE_32BIT_ROWID
|
||||
"32BIT_ROWID",
|
||||
#endif
|
||||
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
|
||||
"4_BYTE_ALIGNED_MALLOC",
|
||||
#endif
|
||||
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
||||
"CASE_SENSITIVE_LIKE",
|
||||
#endif
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
"CHECK_PAGES",
|
||||
#endif
|
||||
#ifdef SQLITE_COVERAGE_TEST
|
||||
"COVERAGE_TEST",
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
"DEBUG",
|
||||
#endif
|
||||
#ifdef SQLITE_DEFAULT_LOCKING_MODE
|
||||
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
|
||||
#endif
|
||||
#ifdef SQLITE_DISABLE_DIRSYNC
|
||||
"DISABLE_DIRSYNC",
|
||||
#endif
|
||||
#ifdef SQLITE_DISABLE_LFS
|
||||
"DISABLE_LFS",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
"ENABLE_ATOMIC_WRITE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CEROD
|
||||
"ENABLE_CEROD",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
"ENABLE_COLUMN_METADATA",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
"ENABLE_EXPENSIVE_ASSERT",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
"ENABLE_FTS1",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS2
|
||||
"ENABLE_FTS2",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS3
|
||||
"ENABLE_FTS3",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
"ENABLE_FTS3_PARENTHESIS",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS4
|
||||
"ENABLE_FTS4",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_ICU
|
||||
"ENABLE_ICU",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
"ENABLE_IOTRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
|
||||
"ENABLE_LOAD_EXTENSION",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
||||
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
"ENABLE_MEMORY_MANAGEMENT",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MEMSYS3
|
||||
"ENABLE_MEMSYS3",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MEMSYS5
|
||||
"ENABLE_MEMSYS5",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
|
||||
"ENABLE_OVERSIZE_CELL_CHECK",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
"ENABLE_RTREE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
"ENABLE_STAT2",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
"ENABLE_UNLOCK_NOTIFY",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
"ENABLE_UPDATE_DELETE_LIMIT",
|
||||
#endif
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
"HAS_CODEC",
|
||||
#endif
|
||||
#ifdef SQLITE_HAVE_ISNAN
|
||||
"HAVE_ISNAN",
|
||||
#endif
|
||||
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
|
||||
"HOMEGROWN_RECURSIVE_MUTEX",
|
||||
#endif
|
||||
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
|
||||
"IGNORE_AFP_LOCK_ERRORS",
|
||||
#endif
|
||||
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
||||
"IGNORE_FLOCK_LOCK_ERRORS",
|
||||
#endif
|
||||
#ifdef SQLITE_INT64_TYPE
|
||||
"INT64_TYPE",
|
||||
#endif
|
||||
#ifdef SQLITE_LOCK_TRACE
|
||||
"LOCK_TRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
"MEMDEBUG",
|
||||
#endif
|
||||
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
||||
"MIXED_ENDIAN_64BIT_FLOAT",
|
||||
#endif
|
||||
#ifdef SQLITE_NO_SYNC
|
||||
"NO_SYNC",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_ALTERTABLE
|
||||
"OMIT_ALTERTABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_ANALYZE
|
||||
"OMIT_ANALYZE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_ATTACH
|
||||
"OMIT_ATTACH",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTHORIZATION
|
||||
"OMIT_AUTHORIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOINCREMENT
|
||||
"OMIT_AUTOINCREMENT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOINIT
|
||||
"OMIT_AUTOINIT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
"OMIT_AUTOVACUUM",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
|
||||
"OMIT_BETWEEN_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_BLOB_LITERAL
|
||||
"OMIT_BLOB_LITERAL",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_BTREECOUNT
|
||||
"OMIT_BTREECOUNT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_BUILTIN_TEST
|
||||
"OMIT_BUILTIN_TEST",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_CAST
|
||||
"OMIT_CAST",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_CHECK
|
||||
"OMIT_CHECK",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
"OMIT_COMPILEOPTION_DIAGS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_COMPLETE
|
||||
"OMIT_COMPLETE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
"OMIT_COMPOUND_SELECT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DATETIME_FUNCS
|
||||
"OMIT_DATETIME_FUNCS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DECLTYPE
|
||||
"OMIT_DECLTYPE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DEPRECATED
|
||||
"OMIT_DEPRECATED",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
"OMIT_DISKIO",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_EXPLAIN
|
||||
"OMIT_EXPLAIN",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_FLAG_PRAGMAS
|
||||
"OMIT_FLAG_PRAGMAS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
"OMIT_FLOATING_POINT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_FOREIGN_KEY
|
||||
"OMIT_FOREIGN_KEY",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_GET_TABLE
|
||||
"OMIT_GET_TABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_GLOBALRECOVER
|
||||
"OMIT_GLOBALRECOVER",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
"OMIT_INCRBLOB",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
"OMIT_INTEGRITY_CHECK",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
|
||||
"OMIT_LIKE_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
||||
"OMIT_LOAD_EXTENSION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_LOCALTIME
|
||||
"OMIT_LOCALTIME",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_LOOKASIDE
|
||||
"OMIT_LOOKASIDE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
"OMIT_MEMORYDB",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
|
||||
"OMIT_OR_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
"OMIT_PAGER_PRAGMAS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_PRAGMA
|
||||
"OMIT_PRAGMA",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
"OMIT_PROGRESS_CALLBACK",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_QUICKBALANCE
|
||||
"OMIT_QUICKBALANCE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_REINDEX
|
||||
"OMIT_REINDEX",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
|
||||
"OMIT_SCHEMA_PRAGMAS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
|
||||
"OMIT_SCHEMA_VERSION_PRAGMAS",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
"OMIT_SHARED_CACHE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_SUBQUERY
|
||||
"OMIT_SUBQUERY",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_TCL_VARIABLE
|
||||
"OMIT_TCL_VARIABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_TEMPDB
|
||||
"OMIT_TEMPDB",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
"OMIT_TRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_TRIGGER
|
||||
"OMIT_TRIGGER",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
||||
"OMIT_TRUNCATE_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
"OMIT_UTF16",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VACUUM
|
||||
"OMIT_VACUUM",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VIEW
|
||||
"OMIT_VIEW",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
"OMIT_VIRTUALTABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_WSD
|
||||
"OMIT_WSD",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_XFER_OPT
|
||||
"OMIT_XFER_OPT",
|
||||
#endif
|
||||
#ifdef SQLITE_PERFORMANCE_TRACE
|
||||
"PERFORMANCE_TRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_PROXY_DEBUG
|
||||
"PROXY_DEBUG",
|
||||
#endif
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
"SECURE_DELETE",
|
||||
#endif
|
||||
#ifdef SQLITE_SMALL_STACK
|
||||
"SMALL_STACK",
|
||||
#endif
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
"SOUNDEX",
|
||||
#endif
|
||||
#ifdef SQLITE_TCL
|
||||
"TCL",
|
||||
#endif
|
||||
#ifdef SQLITE_TEMP_STORE
|
||||
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
"TEST",
|
||||
#endif
|
||||
#ifdef SQLITE_THREADSAFE
|
||||
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
|
||||
#endif
|
||||
#ifdef SQLITE_USE_ALLOCA
|
||||
"USE_ALLOCA",
|
||||
#endif
|
||||
#ifdef SQLITE_ZERO_MALLOC
|
||||
"ZERO_MALLOC"
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Given the name of a compile-time option, return true if that option
|
||||
** was used and false if not.
|
||||
**
|
||||
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
|
||||
** is not required for a match.
|
||||
*/
|
||||
int sqlite3_compileoption_used(const char *zOptName){
|
||||
int i, n;
|
||||
if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
|
||||
n = sqlite3Strlen30(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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the N-th compile-time option string. If N is out of range,
|
||||
** return a NULL pointer.
|
||||
*/
|
||||
const char *sqlite3_compileoption_get(int N){
|
||||
if( N>=0 && N<ArraySize(azCompileOpt) ){
|
||||
return azCompileOpt[N];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
@ -1092,8 +1092,8 @@ void sqlite3RegisterDateTimeFunctions(void){
|
||||
FUNCTION(current_date, 0, 0, 0, cdateFunc ),
|
||||
#else
|
||||
STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
|
||||
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d", 0, currentTimeFunc),
|
||||
STR_FUNCTION(current_date, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
|
||||
STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
|
||||
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
@ -364,7 +364,7 @@ void sqlite3DeleteFrom(
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
|
||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
||||
@ -630,7 +630,6 @@ int sqlite3GenerateIndexKey(
|
||||
if( doMakeRec ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regBase, nCol+1);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
|
||||
return regBase;
|
||||
|
||||
199
src/expr.c
199
src/expr.c
@ -227,30 +227,6 @@ CollSeq *sqlite3BinaryCompareCollSeq(
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate the operands for a comparison operation. Before
|
||||
** generating the code for each operand, set the EP_AnyAff
|
||||
** flag on the expression so that it will be able to used a
|
||||
** cached column value that has previously undergone an
|
||||
** affinity change.
|
||||
*/
|
||||
static void codeCompareOperands(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
Expr *pLeft, /* The left operand */
|
||||
int *pRegLeft, /* Register where left operand is stored */
|
||||
int *pFreeLeft, /* Free this register when done */
|
||||
Expr *pRight, /* The right operand */
|
||||
int *pRegRight, /* Register where right operand is stored */
|
||||
int *pFreeRight /* Write temp register for right operand there */
|
||||
){
|
||||
while( pLeft->op==TK_UPLUS ) pLeft = pLeft->pLeft;
|
||||
pLeft->flags |= EP_AnyAff;
|
||||
*pRegLeft = sqlite3ExprCodeTemp(pParse, pLeft, pFreeLeft);
|
||||
while( pRight->op==TK_UPLUS ) pRight = pRight->pLeft;
|
||||
pRight->flags |= EP_AnyAff;
|
||||
*pRegRight = sqlite3ExprCodeTemp(pParse, pRight, pFreeRight);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for a comparison operator.
|
||||
*/
|
||||
@ -272,10 +248,6 @@ static int codeCompare(
|
||||
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
|
||||
(void*)p4, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
|
||||
if( (p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_NONE ){
|
||||
sqlite3ExprCacheAffinityChange(pParse, in1, 1);
|
||||
sqlite3ExprCacheAffinityChange(pParse, in2, 1);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
@ -1906,6 +1878,7 @@ static char *dup8bytes(Vdbe *v, const char *in){
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** Generate an instruction that will put the floating point
|
||||
** value described by z[0..n-1] into register iMem.
|
||||
@ -1925,6 +1898,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
|
||||
sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@ -1935,7 +1909,8 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
|
||||
** z[n] character is guaranteed to be something that does not look
|
||||
** like the continuation of the number.
|
||||
*/
|
||||
static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
|
||||
static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( pExpr->flags & EP_IntValue ){
|
||||
int i = pExpr->u.iValue;
|
||||
if( negFlag ) i = -i;
|
||||
@ -1951,7 +1926,11 @@ static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
|
||||
zV = dup8bytes(v, (char*)&value);
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
|
||||
}else{
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
|
||||
#else
|
||||
codeReal(v, z, negFlag, iMem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1982,17 +1961,31 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||
assert( iReg>0 ); /* Register numbers are always positive */
|
||||
assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
|
||||
|
||||
/* First replace any existing entry */
|
||||
/* The SQLITE_ColumnCache flag disables the column cache. This is used
|
||||
** for testing only - to verify that SQLite always gets the same answer
|
||||
** with and without the column cache.
|
||||
*/
|
||||
if( pParse->db->flags & SQLITE_ColumnCache ) return;
|
||||
|
||||
/* First replace any existing entry.
|
||||
**
|
||||
** Actually, the way the column cache is currently used, we are guaranteed
|
||||
** that the object will never already be in cache. Verify this guarantee.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
#if 0 /* This code wold remove the entry from the cache if it existed */
|
||||
if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
|
||||
cacheEntryClear(pParse, p);
|
||||
p->iLevel = pParse->iCacheLevel;
|
||||
p->iReg = iReg;
|
||||
p->affChange = 0;
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find an empty slot and replace it */
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
@ -2001,7 +1994,6 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||
p->iTable = iTab;
|
||||
p->iColumn = iCol;
|
||||
p->iReg = iReg;
|
||||
p->affChange = 0;
|
||||
p->tempReg = 0;
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
return;
|
||||
@ -2023,7 +2015,6 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||
p->iTable = iTab;
|
||||
p->iColumn = iCol;
|
||||
p->iReg = iReg;
|
||||
p->affChange = 0;
|
||||
p->tempReg = 0;
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
return;
|
||||
@ -2031,14 +2022,16 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||
}
|
||||
|
||||
/*
|
||||
** Indicate that a register is being overwritten. Purge the register
|
||||
** from the column cache.
|
||||
** Indicate that registers between iReg..iReg+nReg-1 are being overwritten.
|
||||
** Purge the range of registers from the column cache.
|
||||
*/
|
||||
void sqlite3ExprCacheRemove(Parse *pParse, int iReg){
|
||||
void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
|
||||
int i;
|
||||
int iLast = iReg + nReg - 1;
|
||||
struct yColCache *p;
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
if( p->iReg==iReg ){
|
||||
int r = p->iReg;
|
||||
if( r>=iReg && r<=iLast ){
|
||||
cacheEntryClear(pParse, p);
|
||||
p->iReg = 0;
|
||||
}
|
||||
@ -2097,28 +2090,20 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
|
||||
**
|
||||
** There must be an open cursor to pTab in iTable when this routine
|
||||
** is called. If iColumn<0 then code is generated that extracts the rowid.
|
||||
**
|
||||
** This routine might attempt to reuse the value of the column that
|
||||
** has already been loaded into a register. The value will always
|
||||
** be used if it has not undergone any affinity changes. But if
|
||||
** an affinity change has occurred, then the cached value will only be
|
||||
** used if allowAffChng is true.
|
||||
*/
|
||||
int sqlite3ExprCodeGetColumn(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
Table *pTab, /* Description of the table we are reading from */
|
||||
int iColumn, /* Index of the table column */
|
||||
int iTable, /* The cursor pointing to the table */
|
||||
int iReg, /* Store results here */
|
||||
int allowAffChng /* True if prior affinity changes are OK */
|
||||
int iReg /* Store results here */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn
|
||||
&& (!p->affChange || allowAffChng) ){
|
||||
if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
|
||||
p->lru = pParse->iCacheCnt++;
|
||||
sqlite3ExprCachePinRegister(pParse, p->iReg);
|
||||
return p->iReg;
|
||||
@ -2156,15 +2141,7 @@ void sqlite3ExprCacheClear(Parse *pParse){
|
||||
** registers starting with iStart.
|
||||
*/
|
||||
void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
|
||||
int iEnd = iStart + iCount - 1;
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int r = p->iReg;
|
||||
if( r>=iStart && r<=iEnd ){
|
||||
p->affChange = 1;
|
||||
}
|
||||
}
|
||||
sqlite3ExprCacheRemove(pParse, iStart, iCount);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2196,19 +2173,24 @@ void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
/*
|
||||
** Return true if any register in the range iFrom..iTo (inclusive)
|
||||
** is used as part of the column cache.
|
||||
**
|
||||
** This routine is used within assert() and testcase() macros only
|
||||
** and does not appear in a normal build.
|
||||
*/
|
||||
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int r = p->iReg;
|
||||
if( r>=iFrom && r<=iTo ) return 1;
|
||||
if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
|
||||
|
||||
/*
|
||||
** If the last instruction coded is an ephemeral copy of any of
|
||||
@ -2329,22 +2311,22 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
assert( pParse->ckBase>0 );
|
||||
inReg = pExpr->iColumn + pParse->ckBase;
|
||||
}else{
|
||||
testcase( (pExpr->flags & EP_AnyAff)!=0 );
|
||||
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
|
||||
pExpr->iColumn, pExpr->iTable, target,
|
||||
pExpr->flags & EP_AnyAff);
|
||||
pExpr->iColumn, pExpr->iTable, target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
codeInteger(v, pExpr, 0, target);
|
||||
codeInteger(pParse, pExpr, 0, target);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
case TK_FLOAT: {
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
codeReal(v, pExpr->u.zToken, 0, target);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_STRING: {
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
|
||||
@ -2449,8 +2431,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
testcase( op==TK_GE );
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, inReg, SQLITE_STOREP2);
|
||||
testcase( regFree1==0 );
|
||||
@ -2461,8 +2443,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_ISNOT: {
|
||||
testcase( op==TK_IS );
|
||||
testcase( op==TK_ISNOT );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
|
||||
@ -2514,11 +2496,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_UMINUS: {
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
assert( pLeft );
|
||||
if( pLeft->op==TK_FLOAT ){
|
||||
if( pLeft->op==TK_INTEGER ){
|
||||
codeInteger(pParse, pLeft, 1, target);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
}else if( pLeft->op==TK_FLOAT ){
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
codeReal(v, pLeft->u.zToken, 1, target);
|
||||
}else if( pLeft->op==TK_INTEGER ){
|
||||
codeInteger(v, pLeft, 1, target);
|
||||
#endif
|
||||
}else{
|
||||
regFree1 = r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
|
||||
@ -2606,7 +2590,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
for(i=1; i<nFarg; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
|
||||
sqlite3ExprCacheRemove(pParse, target);
|
||||
sqlite3ExprCacheRemove(pParse, target, 1);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
@ -2661,7 +2645,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
if( nFarg ){
|
||||
sqlite3ReleaseTempRange(pParse, r1, nFarg);
|
||||
}
|
||||
sqlite3ExprCacheAffinityChange(pParse, r1, nFarg);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
@ -2702,8 +2685,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
struct ExprList_item *pLItem = pExpr->x.pList->a;
|
||||
Expr *pRight = pLItem->pExpr;
|
||||
|
||||
codeCompareOperands(pParse, pLeft, &r1, ®Free1,
|
||||
pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
r3 = sqlite3GetTempReg(pParse);
|
||||
@ -2767,6 +2750,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
target
|
||||
));
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* If the column has REAL affinity, it may currently be stored as an
|
||||
** integer. Use OP_RealAffinity to make sure it is really real. */
|
||||
if( pExpr->iColumn>=0
|
||||
@ -2774,6 +2758,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
){
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3238,8 +3223,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
testcase( jumpIfNull==0 );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
testcase( regFree1==0 );
|
||||
@ -3250,8 +3235,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
case TK_ISNOT: {
|
||||
testcase( op==TK_IS );
|
||||
testcase( op==TK_ISNOT );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
@ -3381,8 +3366,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
testcase( jumpIfNull==0 );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
testcase( regFree1==0 );
|
||||
@ -3393,8 +3378,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
case TK_ISNOT: {
|
||||
testcase( pExpr->op==TK_IS );
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
@ -3439,57 +3424,61 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
}
|
||||
|
||||
/*
|
||||
** Do a deep comparison of two expression trees. Return TRUE (non-zero)
|
||||
** if they are identical and return FALSE if they differ in any way.
|
||||
** Do a deep comparison of two expression trees. Return 0 if the two
|
||||
** expressions are completely identical. Return 1 if they differ only
|
||||
** by a COLLATE operator at the top level. Return 2 if there are differences
|
||||
** other than the top-level COLLATE operator.
|
||||
**
|
||||
** Sometimes this routine will return FALSE even if the two expressions
|
||||
** Sometimes this routine will return 2 even if the two expressions
|
||||
** really are equivalent. If we cannot prove that the expressions are
|
||||
** identical, we return FALSE just to be safe. So if this routine
|
||||
** returns false, then you do not really know for certain if the two
|
||||
** expressions are the same. But if you get a TRUE return, then you
|
||||
** identical, we return 2 just to be safe. So if this routine
|
||||
** returns 2, then you do not really know for certain if the two
|
||||
** expressions are the same. But if you get a 0 or 1 return, then you
|
||||
** can be sure the expressions are the same. In the places where
|
||||
** this routine is used, it does not hurt to get an extra FALSE - that
|
||||
** this routine is used, it does not hurt to get an extra 2 - that
|
||||
** just might result in some slightly slower code. But returning
|
||||
** an incorrect TRUE could lead to a malfunction.
|
||||
** an incorrect 0 or 1 could lead to a malfunction.
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int i;
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA;
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
|
||||
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
||||
if( pA->op!=pB->op ) return 0;
|
||||
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
||||
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
|
||||
if( pA->op!=pB->op ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
|
||||
|
||||
if( pA->x.pList && pB->x.pList ){
|
||||
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
|
||||
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 2;
|
||||
for(i=0; i<pA->x.pList->nExpr; i++){
|
||||
Expr *pExprA = pA->x.pList->a[i].pExpr;
|
||||
Expr *pExprB = pB->x.pList->a[i].pExpr;
|
||||
if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 2;
|
||||
}
|
||||
}else if( pA->x.pList || pB->x.pList ){
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( ExprHasProperty(pA, EP_IntValue) ){
|
||||
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){
|
||||
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 0;
|
||||
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
|
||||
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
|
||||
if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -3620,7 +3609,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||
if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
|
||||
if( sqlite3ExprCompare(pItem->pExpr, pExpr)==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3741,7 +3730,8 @@ int sqlite3GetTempRange(Parse *pParse, int nReg){
|
||||
int i, n;
|
||||
i = pParse->iRangeReg;
|
||||
n = pParse->nRangeReg;
|
||||
if( nReg<=n && !usedAsColumnCache(pParse, i, i+n-1) ){
|
||||
if( nReg<=n ){
|
||||
assert( !usedAsColumnCache(pParse, i, i+n-1) );
|
||||
pParse->iRangeReg += nReg;
|
||||
pParse->nRangeReg -= nReg;
|
||||
}else{
|
||||
@ -3751,6 +3741,7 @@ int sqlite3GetTempRange(Parse *pParse, int nReg){
|
||||
return i;
|
||||
}
|
||||
void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
|
||||
sqlite3ExprCacheRemove(pParse, iReg, nReg);
|
||||
if( nReg>pParse->nRangeReg ){
|
||||
pParse->nRangeReg = nReg;
|
||||
pParse->iRangeReg = iReg;
|
||||
|
||||
112
src/func.c
112
src/func.c
@ -117,7 +117,10 @@ static void lengthFunc(
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the abs() function
|
||||
** Implementation of the abs() function.
|
||||
**
|
||||
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
|
||||
** the numeric argument X.
|
||||
*/
|
||||
static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
assert( argc==1 );
|
||||
@ -127,6 +130,9 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
i64 iVal = sqlite3_value_int64(argv[0]);
|
||||
if( iVal<0 ){
|
||||
if( (iVal<<1)==0 ){
|
||||
/* IMP: R-35460-15084 If X is the integer -9223372036854775807 then
|
||||
** abs(X) throws an integer overflow error since there is no
|
||||
** equivalent positive 64-bit two complement value. */
|
||||
sqlite3_result_error(context, "integer overflow", -1);
|
||||
return;
|
||||
}
|
||||
@ -136,10 +142,16 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL: {
|
||||
/* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */
|
||||
sqlite3_result_null(context);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* Because sqlite3_value_double() returns 0.0 if the argument is not
|
||||
** something that can be converted into a number, we have:
|
||||
** IMP: R-57326-31541 Abs(X) return 0.0 if X is a string or blob that
|
||||
** cannot be converted to a numeric value.
|
||||
*/
|
||||
double rVal = sqlite3_value_double(argv[0]);
|
||||
if( rVal<0 ) rVal = -rVal;
|
||||
sqlite3_result_double(context, rVal);
|
||||
@ -259,14 +271,24 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
r = sqlite3_value_double(argv[0]);
|
||||
zBuf = sqlite3_mprintf("%.*f",n,r);
|
||||
if( zBuf==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
/* If Y==0 and X will fit in a 64-bit int,
|
||||
** handle the rounding directly,
|
||||
** otherwise use printf.
|
||||
*/
|
||||
if( n==0 && r>=0 && r<LARGEST_INT64-1 ){
|
||||
r = (double)((sqlite_int64)(r+0.5));
|
||||
}else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){
|
||||
r = -(double)((sqlite_int64)((-r)+0.5));
|
||||
}else{
|
||||
zBuf = sqlite3_mprintf("%.*f",n,r);
|
||||
if( zBuf==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
sqlite3AtoF(zBuf, &r);
|
||||
sqlite3_free(zBuf);
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -428,12 +450,18 @@ static void last_insert_rowid(
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
/* IMP: R-51513-12026 The last_insert_rowid() SQL function is a
|
||||
** wrapper around the sqlite3_last_insert_rowid() C/C++ interface
|
||||
** function. */
|
||||
sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the changes() SQL function. The return value is the
|
||||
** same as the sqlite3_changes() API function.
|
||||
** Implementation of the changes() SQL function.
|
||||
**
|
||||
** IMP: R-62073-11209 The changes() SQL function is a wrapper
|
||||
** around the sqlite3_changes() C/C++ function and hence follows the same
|
||||
** rules for counting changes.
|
||||
*/
|
||||
static void changes(
|
||||
sqlite3_context *context,
|
||||
@ -456,6 +484,8 @@ static void total_changes(
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
/* IMP: R-52756-41993 This function is a wrapper around the
|
||||
** sqlite3_total_changes() C/C++ interface. */
|
||||
sqlite3_result_int(context, sqlite3_total_changes(db));
|
||||
}
|
||||
|
||||
@ -723,7 +753,9 @@ static void versionFunc(
|
||||
sqlite3_value **NotUsed2
|
||||
){
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
|
||||
/* IMP: R-48699-48617 This function is an SQL wrapper around the
|
||||
** sqlite3_libversion() C-interface. */
|
||||
sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -737,9 +769,54 @@ static void sourceidFunc(
|
||||
sqlite3_value **NotUsed2
|
||||
){
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
sqlite3_result_text(context, SQLITE_SOURCE_ID, -1, SQLITE_STATIC);
|
||||
/* IMP: R-24470-31136 This function is an SQL wrapper around the
|
||||
** sqlite3_sourceid() C interface. */
|
||||
sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_compileoption_used() function.
|
||||
** The result is an integer that identifies if the compiler option
|
||||
** was used to build SQLite.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
static void compileoptionusedFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zOptName;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
/* IMP: R-xxxx This function is an SQL wrapper around the
|
||||
** sqlite3_compileoption_used() C interface. */
|
||||
if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){
|
||||
sqlite3_result_int(context, sqlite3_compileoption_used(zOptName));
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_compileoption_get() function.
|
||||
** The result is a string that identifies the compiler options
|
||||
** used to build SQLite.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
static void compileoptiongetFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int n;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
/* IMP: R-xxxx This function is an SQL wrapper around the
|
||||
** sqlite3_compileoption_get() C interface. */
|
||||
n = sqlite3_value_int(argv[0]);
|
||||
sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
|
||||
/* Array for converting from half-bytes (nybbles) into ASCII hex
|
||||
** digits. */
|
||||
static const char hexdigits[] = {
|
||||
@ -866,7 +943,7 @@ static void zeroblobFunc(
|
||||
if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
}else{
|
||||
sqlite3_result_zeroblob(context, (int)n);
|
||||
sqlite3_result_zeroblob(context, (int)n); /* IMP: R-00293-64994 */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1041,9 +1118,16 @@ static void trimFunc(
|
||||
}
|
||||
|
||||
|
||||
/* IMP: R-25361-16150 This function is omitted from SQLite by default. It
|
||||
** is only available if the SQLITE_SOUNDEX compile-time option is used
|
||||
** when SQLite is built.
|
||||
*/
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
/*
|
||||
** Compute the soundex encoding of a word.
|
||||
**
|
||||
** IMP: R-59782-00072 The soundex(X) function returns a string that is the
|
||||
** soundex encoding of the string X.
|
||||
*/
|
||||
static void soundexFunc(
|
||||
sqlite3_context *context,
|
||||
@ -1087,10 +1171,12 @@ static void soundexFunc(
|
||||
zResult[j] = 0;
|
||||
sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
/* IMP: R-64894-50321 The string "?000" is returned if the argument
|
||||
** is NULL or contains no ASCII alphabetic characters. */
|
||||
sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_SOUNDEX */
|
||||
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
/*
|
||||
@ -1462,6 +1548,10 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
||||
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
||||
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
FUNCTION(quote, 1, 0, 0, quoteFunc ),
|
||||
FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
|
||||
FUNCTION(changes, 0, 0, 0, changes ),
|
||||
|
||||
@ -164,6 +164,8 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* isPCacheInit */
|
||||
0, /* pInitMutex */
|
||||
0, /* nRefInitMutex */
|
||||
0, /* xLog */
|
||||
0, /* pLogArg */
|
||||
};
|
||||
|
||||
|
||||
|
||||
26
src/insert.c
26
src/insert.c
@ -1261,19 +1261,33 @@ void sqlite3GenerateConstraintChecks(
|
||||
** the triggers and remove both the table and index b-tree entries.
|
||||
**
|
||||
** Otherwise, if there are no triggers or the recursive-triggers
|
||||
** flag is not set, call GenerateRowIndexDelete(). This removes
|
||||
** the index b-tree entries only. The table b-tree entry will be
|
||||
** replaced by the new entry when it is inserted. */
|
||||
** flag is not set, but the table has one or more indexes, call
|
||||
** GenerateRowIndexDelete(). This removes the index b-tree entries
|
||||
** only. The table b-tree entry will be replaced by the new entry
|
||||
** when it is inserted.
|
||||
**
|
||||
** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
|
||||
** also invoke MultiWrite() to indicate that this VDBE may require
|
||||
** statement rollback (if the statement is aborted after the delete
|
||||
** takes place). Earlier versions called sqlite3MultiWrite() regardless,
|
||||
** but being more selective here allows statements like:
|
||||
**
|
||||
** REPLACE INTO t(rowid) VALUES($newrowid)
|
||||
**
|
||||
** to run without a statement journal if there are no indexes on the
|
||||
** table.
|
||||
*/
|
||||
Trigger *pTrigger = 0;
|
||||
if( pParse->db->flags&SQLITE_RecTriggers ){
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
||||
}
|
||||
sqlite3MultiWrite(pParse);
|
||||
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3GenerateRowDelete(
|
||||
pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace
|
||||
);
|
||||
}else{
|
||||
}else if( pTab->pIndex ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
|
||||
}
|
||||
seenReplace = 1;
|
||||
@ -1715,7 +1729,7 @@ static int xferOptimization(
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -41,6 +41,7 @@ int sqlite3_exec(
|
||||
int nRetry = 0; /* Number of retry attempts */
|
||||
int callbackIsInit; /* True if callback data is initialized */
|
||||
|
||||
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
||||
if( zSql==0 ) zSql = "";
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
101
src/main.c
101
src/main.c
@ -257,7 +257,7 @@ int sqlite3_config(int op, ...){
|
||||
|
||||
/* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
|
||||
** the SQLite library is in use. */
|
||||
if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE;
|
||||
if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT;
|
||||
|
||||
va_start(ap, op);
|
||||
switch( op ){
|
||||
@ -265,7 +265,7 @@ int sqlite3_config(int op, ...){
|
||||
/* Mutex configuration options are only available in a threadsafe
|
||||
** compile.
|
||||
*/
|
||||
#if SQLITE_THREADSAFE
|
||||
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0
|
||||
case SQLITE_CONFIG_SINGLETHREAD: {
|
||||
/* Disable all mutexing */
|
||||
sqlite3GlobalConfig.bCoreMutex = 0;
|
||||
@ -378,6 +378,21 @@ int sqlite3_config(int op, ...){
|
||||
sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Record a pointer to the logger funcction and its first argument.
|
||||
** The default is NULL. Logging is disabled if the function pointer is
|
||||
** NULL.
|
||||
*/
|
||||
case SQLITE_CONFIG_LOG: {
|
||||
/* MSVC is picky about pulling func ptrs from va lists.
|
||||
** http://support.microsoft.com/kb/47961
|
||||
** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
|
||||
*/
|
||||
typedef void(*LOGFUNC_t)(void*,int,const char*);
|
||||
sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
|
||||
sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
rc = SQLITE_ERROR;
|
||||
@ -591,7 +606,7 @@ int sqlite3_close(sqlite3 *db){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( !sqlite3SafetyCheckSickOrOk(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
@ -938,7 +953,7 @@ int sqlite3CreateFunc(
|
||||
(!xFunc && (!xFinal && xStep)) ||
|
||||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
|
||||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@ -1035,7 +1050,7 @@ int sqlite3_create_function16(
|
||||
char *zFunc8;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
|
||||
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
|
||||
sqlite3DbFree(db, zFunc8);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
@ -1269,7 +1284,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
|
||||
return sqlite3ErrStr(SQLITE_NOMEM);
|
||||
}
|
||||
if( !sqlite3SafetyCheckSickOrOk(db) ){
|
||||
return sqlite3ErrStr(SQLITE_MISUSE);
|
||||
return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( db->mallocFailed ){
|
||||
@ -1338,7 +1353,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
|
||||
*/
|
||||
int sqlite3_errcode(sqlite3 *db){
|
||||
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
if( !db || db->mallocFailed ){
|
||||
return SQLITE_NOMEM;
|
||||
@ -1347,7 +1362,7 @@ int sqlite3_errcode(sqlite3 *db){
|
||||
}
|
||||
int sqlite3_extended_errcode(sqlite3 *db){
|
||||
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
if( !db || db->mallocFailed ){
|
||||
return SQLITE_NOMEM;
|
||||
@ -1385,7 +1400,7 @@ static int createCollation(
|
||||
enc2 = SQLITE_UTF16NATIVE;
|
||||
}
|
||||
if( enc2<SQLITE_UTF8 || enc2>SQLITE_UTF16BE ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
|
||||
/* Check if this call is removing or replacing an existing collation
|
||||
@ -1858,7 +1873,7 @@ int sqlite3_create_collation16(
|
||||
char *zName8;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
zName8 = sqlite3Utf16to8(db, zName, -1);
|
||||
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
|
||||
if( zName8 ){
|
||||
rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
|
||||
sqlite3DbFree(db, zName8);
|
||||
@ -1929,16 +1944,34 @@ int sqlite3_get_autocommit(sqlite3 *db){
|
||||
return db->autoCommit;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** The following routine is subtituted for constant SQLITE_CORRUPT in
|
||||
** debugging builds. This provides a way to set a breakpoint for when
|
||||
** corruption is first detected.
|
||||
** The following routines are subtitutes for constants SQLITE_CORRUPT,
|
||||
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
|
||||
** constants. They server two purposes:
|
||||
**
|
||||
** 1. Serve as a convenient place to set a breakpoint in a debugger
|
||||
** to detect when version error conditions occurs.
|
||||
**
|
||||
** 2. Invoke sqlite3_log() to provide the source code location where
|
||||
** a low-level error is first detected.
|
||||
*/
|
||||
int sqlite3Corrupt(void){
|
||||
int sqlite3CorruptError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_CORRUPT,
|
||||
"database corruption found by source line %d", lineno);
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
int sqlite3MisuseError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_MISUSE, "misuse detected by source line %d", lineno);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
int sqlite3CantopenError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_CANTOPEN, "cannot open file at source line %d", lineno);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
@ -1982,7 +2015,6 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
/* Ensure the database schema has been loaded */
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
if( SQLITE_OK!=rc ){
|
||||
@ -2041,7 +2073,6 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
error_out:
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
|
||||
/* Whether the function call succeeded or failed, set the output parameters
|
||||
** to whatever their local counterparts contain. If an error did occur,
|
||||
@ -2281,6 +2312,40 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
|
||||
**
|
||||
** Enable or disable various optimizations for testing purposes. The
|
||||
** argument N is a bitmask of optimizations to be disabled. For normal
|
||||
** operation N should be 0. The idea is that a test program (like the
|
||||
** SQL Logic Test or SLT test module) can run the same SQL multiple times
|
||||
** with various optimizations disabled to verify that the same answer
|
||||
** is obtained in every case.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
int x = va_arg(ap,int);
|
||||
db->flags = (x & SQLITE_OptMask) | (db->flags & ~SQLITE_OptMask);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_N_KEYWORD
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord)
|
||||
**
|
||||
** If zWord is a keyword recognized by the parser, then return the
|
||||
** number of keywords. Or if zWord is not a keyword, return 0.
|
||||
**
|
||||
** This test feature is only available in the amalgamation since
|
||||
** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite
|
||||
** is built using separate source files.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_ISKEYWORD: {
|
||||
const char *zWord = va_arg(ap, const char*);
|
||||
int n = sqlite3Strlen30(zWord);
|
||||
rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
||||
33
src/mem1.c
33
src/mem1.c
@ -42,6 +42,9 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
}else{
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
||||
@ -61,6 +64,18 @@ static void sqlite3MemFree(void *pPrior){
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Report the allocated size of a prior return from xMalloc()
|
||||
** or xRealloc().
|
||||
*/
|
||||
static int sqlite3MemSize(void *pPrior){
|
||||
sqlite3_int64 *p;
|
||||
if( pPrior==0 ) return 0;
|
||||
p = (sqlite3_int64*)pPrior;
|
||||
p--;
|
||||
return (int)p[0];
|
||||
}
|
||||
|
||||
/*
|
||||
** Like realloc(). Resize an allocation previously obtained from
|
||||
** sqlite3MemMalloc().
|
||||
@ -75,28 +90,20 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
|
||||
assert( pPrior!=0 && nByte>0 );
|
||||
nByte = ROUND8(nByte);
|
||||
p = (sqlite3_int64*)pPrior;
|
||||
p--;
|
||||
p = realloc(p, nByte+8 );
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
}else{
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM,
|
||||
"failed memory resize %u to %u bytes",
|
||||
sqlite3MemSize(pPrior), nByte);
|
||||
}
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Report the allocated size of a prior return from xMalloc()
|
||||
** or xRealloc().
|
||||
*/
|
||||
static int sqlite3MemSize(void *pPrior){
|
||||
sqlite3_int64 *p;
|
||||
if( pPrior==0 ) return 0;
|
||||
p = (sqlite3_int64*)pPrior;
|
||||
p--;
|
||||
return (int)p[0];
|
||||
}
|
||||
|
||||
/*
|
||||
** Round up a request size to the next valid allocation size.
|
||||
*/
|
||||
|
||||
37
src/mem2.c
37
src/mem2.c
@ -210,6 +210,31 @@ static int sqlite3MemRoundup(int n){
|
||||
return ROUND8(n);
|
||||
}
|
||||
|
||||
/*
|
||||
** Fill a buffer with pseudo-random bytes. This is used to preset
|
||||
** the content of a new memory allocation to unpredictable values and
|
||||
** to clear the content of a freed allocation to unpredictable values.
|
||||
*/
|
||||
static void randomFill(char *pBuf, int nByte){
|
||||
unsigned int x, y, r;
|
||||
x = SQLITE_PTR_TO_INT(pBuf);
|
||||
y = nByte | 1;
|
||||
while( nByte >= 4 ){
|
||||
x = (x>>1) ^ (-(x&1) & 0xd0000001);
|
||||
y = y*1103515245 + 12345;
|
||||
r = x ^ y;
|
||||
*(int*)pBuf = r;
|
||||
pBuf += 4;
|
||||
nByte -= 4;
|
||||
}
|
||||
while( nByte-- > 0 ){
|
||||
x = (x>>1) ^ (-(x&1) & 0xd0000001);
|
||||
y = y*1103515245 + 12345;
|
||||
r = x ^ y;
|
||||
*(pBuf++) = r & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate nByte bytes of memory.
|
||||
*/
|
||||
@ -260,7 +285,8 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
adjustStats(nByte, +1);
|
||||
pInt = (int*)&pHdr[1];
|
||||
pInt[nReserve/sizeof(int)] = REARGUARD;
|
||||
memset(pInt, 0x65, nReserve);
|
||||
randomFill((char*)pInt, nByte);
|
||||
memset(((char*)pInt)+nByte, 0x65, nReserve-nByte);
|
||||
p = (void*)pInt;
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
@ -274,7 +300,8 @@ static void sqlite3MemFree(void *pPrior){
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
char *z;
|
||||
assert( sqlite3GlobalConfig.bMemstat || mem.mutex!=0 );
|
||||
assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
|
||||
|| mem.mutex!=0 );
|
||||
pHdr = sqlite3MemsysGetHeader(pPrior);
|
||||
pBt = (void**)pHdr;
|
||||
pBt -= pHdr->nBacktraceSlots;
|
||||
@ -296,8 +323,8 @@ static void sqlite3MemFree(void *pPrior){
|
||||
z = (char*)pBt;
|
||||
z -= pHdr->nTitle;
|
||||
adjustStats(pHdr->iSize, -1);
|
||||
memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
|
||||
pHdr->iSize + sizeof(int) + pHdr->nTitle);
|
||||
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
|
||||
pHdr->iSize + sizeof(int) + pHdr->nTitle);
|
||||
free(z);
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
@ -320,7 +347,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
if( pNew ){
|
||||
memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
|
||||
if( nByte>pOldHdr->iSize ){
|
||||
memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize);
|
||||
randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - pOldHdr->iSize);
|
||||
}
|
||||
sqlite3MemFree(pPrior);
|
||||
}
|
||||
|
||||
@ -268,7 +268,11 @@ static void *memsys5MallocUnsafe(int nByte){
|
||||
** two in order to create a new free block of size iLogsize.
|
||||
*/
|
||||
for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
|
||||
if( iBin>LOGMAX ) return 0;
|
||||
if( iBin>LOGMAX ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
|
||||
return 0;
|
||||
}
|
||||
i = memsys5UnlinkFirst(iBin);
|
||||
while( iBin>iLogsize ){
|
||||
int newSize;
|
||||
|
||||
@ -27,7 +27,16 @@ struct sqlite3_mutex {
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of enterances */
|
||||
DWORD owner; /* Thread holding this mutex */
|
||||
#ifdef SQLITE_DEBUG
|
||||
int trace; /* True to trace changes */
|
||||
#endif
|
||||
};
|
||||
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
|
||||
#else
|
||||
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0 }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
|
||||
@ -71,8 +80,12 @@ struct sqlite3_mutex {
|
||||
static int winMutexHeld(sqlite3_mutex *p){
|
||||
return p->nRef!=0 && p->owner==GetCurrentThreadId();
|
||||
}
|
||||
static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
|
||||
return p->nRef==0 || p->owner!=tid;
|
||||
}
|
||||
static int winMutexNotheld(sqlite3_mutex *p){
|
||||
return p->nRef==0 || p->owner!=GetCurrentThreadId();
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
return winMutexNotheld2(p, tid);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -80,7 +93,14 @@ static int winMutexNotheld(sqlite3_mutex *p){
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
static sqlite3_mutex winMutex_staticMutexes[6];
|
||||
static sqlite3_mutex winMutex_staticMutexes[6] = {
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER
|
||||
};
|
||||
static int winMutex_isInit = 0;
|
||||
/* As winMutexInit() and winMutexEnd() are called as part
|
||||
** of the sqlite3_initialize and sqlite3_shutdown()
|
||||
@ -214,14 +234,23 @@ static void winMutexFree(sqlite3_mutex *p){
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
static void winMutexEnter(sqlite3_mutex *p){
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
|
||||
EnterCriticalSection(&p->mutex);
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
static int winMutexTry(sqlite3_mutex *p){
|
||||
#ifndef NDEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
int rc = SQLITE_BUSY;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
|
||||
/*
|
||||
** The sqlite3_mutex_try() routine is very rarely used, and when it
|
||||
** is used it is merely an optimization. So it is OK for it to always
|
||||
@ -235,12 +264,17 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
*/
|
||||
#if 0
|
||||
if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(p);
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( rc==SQLITE_OK && p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
@ -252,11 +286,19 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
static void winMutexLeave(sqlite3_mutex *p){
|
||||
#ifndef NDEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
assert( p->nRef>0 );
|
||||
assert( p->owner==GetCurrentThreadId() );
|
||||
assert( p->owner==tid );
|
||||
p->nRef--;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
|
||||
4
src/os.c
4
src/os.c
@ -112,11 +112,11 @@ int sqlite3OsOpen(
|
||||
){
|
||||
int rc;
|
||||
DO_OS_MALLOC_TEST(0);
|
||||
/* 0x7f1f is a mask of SQLITE_OPEN_ flags that are valid to be passed
|
||||
/* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
|
||||
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
|
||||
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
|
||||
** reaching the VFS. */
|
||||
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f1f, pFlagsOut);
|
||||
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f3f, pFlagsOut);
|
||||
assert( rc==SQLITE_OK || pFile->pMethods==0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
1355
src/os_unix.c
1355
src/os_unix.c
File diff suppressed because it is too large
Load Diff
@ -1417,7 +1417,7 @@ static int winOpen(
|
||||
return winOpen(pVfs, zName, id,
|
||||
((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
|
||||
}else{
|
||||
return SQLITE_CANTOPEN;
|
||||
return SQLITE_CANTOPEN_BKPT;
|
||||
}
|
||||
}
|
||||
if( pOutFlags ){
|
||||
@ -1439,7 +1439,7 @@ static int winOpen(
|
||||
){
|
||||
CloseHandle(h);
|
||||
free(zConverted);
|
||||
return SQLITE_CANTOPEN;
|
||||
return SQLITE_CANTOPEN_BKPT;
|
||||
}
|
||||
if( isTemp ){
|
||||
pFile->zDeleteOnClose = zConverted;
|
||||
|
||||
64
src/pager.c
64
src/pager.c
@ -2019,6 +2019,9 @@ end_playback:
|
||||
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
|
||||
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
|
||||
testcase( rc!=SQLITE_OK );
|
||||
@ -2875,9 +2878,7 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
** any such pages to the file.
|
||||
**
|
||||
** Also, do not write out any page that has the PGHDR_DONT_WRITE flag
|
||||
** set (set by sqlite3PagerDontWrite()). Note that if compiled with
|
||||
** SQLITE_SECURE_DELETE the PGHDR_DONT_WRITE bit is never set and so
|
||||
** the second test is always true.
|
||||
** set (set by sqlite3PagerDontWrite()).
|
||||
*/
|
||||
if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
|
||||
i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
|
||||
@ -3164,7 +3165,7 @@ int sqlite3PagerOpen(
|
||||
** as it will not be possible to open the journal file or even
|
||||
** check for a hot-journal before reading.
|
||||
*/
|
||||
rc = SQLITE_CANTOPEN;
|
||||
rc = SQLITE_CANTOPEN_BKPT;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(zPathname);
|
||||
@ -3341,6 +3342,7 @@ int sqlite3PagerOpen(
|
||||
/* pPager->pBusyHandlerArg = 0; */
|
||||
pPager->xReiniter = xReinit;
|
||||
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
|
||||
|
||||
*ppPager = pPager;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -3490,8 +3492,24 @@ static int readDbPage(PgHdr *pPg){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( pgno==1 ){
|
||||
u8 *dbFileVers = &((u8*)pPg->pData)[24];
|
||||
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
|
||||
if( rc ){
|
||||
/* If the read is unsuccessful, set the dbFileVers[] to something
|
||||
** that will never be a valid file version. dbFileVers[] is a copy
|
||||
** of bytes 24..39 of the database. Bytes 28..31 should always be
|
||||
** zero. Bytes 32..35 and 35..39 should be page numbers which are
|
||||
** never 0xffffffff. So filling pPager->dbFileVers[] with all 0xff
|
||||
** bytes should suffice.
|
||||
**
|
||||
** For an encrypted database, the situation is more complex: bytes
|
||||
** 24..39 of the database are white noise. But the probability of
|
||||
** white noising equaling 16 bytes of 0xff is vanishingly small so
|
||||
** we should still be ok.
|
||||
*/
|
||||
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
|
||||
}else{
|
||||
u8 *dbFileVers = &((u8*)pPg->pData)[24];
|
||||
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
|
||||
}
|
||||
}
|
||||
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
|
||||
|
||||
@ -3623,7 +3641,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
|
||||
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
|
||||
if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
rc = SQLITE_CANTOPEN_BKPT;
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
}else{
|
||||
@ -3842,7 +3860,7 @@ int sqlite3PagerAcquire(
|
||||
goto pager_acquire_err;
|
||||
}
|
||||
|
||||
if( MEMDB || nMax<(int)pgno || noContent ){
|
||||
if( MEMDB || nMax<(int)pgno || noContent || !isOpen(pPager->fd) ){
|
||||
if( pgno>pPager->mxPgno ){
|
||||
rc = SQLITE_FULL;
|
||||
goto pager_acquire_err;
|
||||
@ -3862,9 +3880,8 @@ int sqlite3PagerAcquire(
|
||||
TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
|
||||
testcase( rc==SQLITE_NOMEM );
|
||||
sqlite3EndBenignMalloc();
|
||||
}else{
|
||||
memset(pPg->pData, 0, pPager->pageSize);
|
||||
}
|
||||
memset(pPg->pData, 0, pPager->pageSize);
|
||||
IOTRACE(("ZERO %p %d\n", pPager, pgno));
|
||||
}else{
|
||||
assert( pPg->pPager==pPager );
|
||||
@ -4386,7 +4403,6 @@ int sqlite3PagerIswriteable(DbPage *pPg){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_SECURE_DELETE
|
||||
/*
|
||||
** A call to this routine tells the pager that it is not necessary to
|
||||
** write the information on page pPg back to the disk, even though
|
||||
@ -4412,7 +4428,6 @@ void sqlite3PagerDontWrite(PgHdr *pPg){
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_SECURE_DELETE) */
|
||||
|
||||
/*
|
||||
** This routine is called to increment the value of the database file
|
||||
@ -4982,30 +4997,35 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
||||
** operation. Store this value in nNew. Then free resources associated
|
||||
** with any savepoints that are destroyed by this operation.
|
||||
*/
|
||||
nNew = iSavepoint + (op==SAVEPOINT_ROLLBACK);
|
||||
nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
|
||||
for(ii=nNew; ii<pPager->nSavepoint; ii++){
|
||||
sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
|
||||
}
|
||||
pPager->nSavepoint = nNew;
|
||||
|
||||
/* If this is a rollback operation, playback the specified savepoint.
|
||||
/* If this is a release of the outermost savepoint, truncate
|
||||
** the sub-journal to zero bytes in size. */
|
||||
if( op==SAVEPOINT_RELEASE ){
|
||||
if( nNew==0 && isOpen(pPager->sjfd) ){
|
||||
/* Only truncate if it is an in-memory sub-journal. */
|
||||
if( sqlite3IsMemJournal(pPager->sjfd) ){
|
||||
rc = sqlite3OsTruncate(pPager->sjfd, 0);
|
||||
assert( rc==SQLITE_OK );
|
||||
}
|
||||
pPager->nSubRec = 0;
|
||||
}
|
||||
}
|
||||
/* Else this is a rollback operation, playback the specified savepoint.
|
||||
** If this is a temp-file, it is possible that the journal file has
|
||||
** not yet been opened. In this case there have been no changes to
|
||||
** the database file, so the playback operation can be skipped.
|
||||
*/
|
||||
if( op==SAVEPOINT_ROLLBACK && isOpen(pPager->jfd) ){
|
||||
else if( isOpen(pPager->jfd) ){
|
||||
PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
|
||||
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
|
||||
assert(rc!=SQLITE_DONE);
|
||||
}
|
||||
|
||||
/* If this is a release of the outermost savepoint, truncate
|
||||
** the sub-journal to zero bytes in size. */
|
||||
if( nNew==0 && op==SAVEPOINT_RELEASE && isOpen(pPager->sjfd) ){
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = sqlite3OsTruncate(pPager->sjfd, 0);
|
||||
pPager->nSubRec = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -316,6 +316,7 @@ refargs(A) ::= . { A = OE_None*0x0101; /* EV: R-19803-45884 */}
|
||||
refargs(A) ::= refargs(X) refarg(Y). { A = (X & ~Y.mask) | Y.value; }
|
||||
%type refarg {struct {int value; int mask;}}
|
||||
refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
|
||||
refarg(A) ::= ON INSERT refact. { A.value = 0; A.mask = 0x000000; }
|
||||
refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; }
|
||||
refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; }
|
||||
%type refact {int}
|
||||
|
||||
@ -189,6 +189,7 @@ void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
|
||||
if( pCache->pCache ){
|
||||
sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
|
||||
pCache->pCache = 0;
|
||||
pCache->pPage1 = 0;
|
||||
}
|
||||
pCache->szPage = szPage;
|
||||
}
|
||||
@ -242,6 +243,7 @@ int sqlite3PcacheFetch(
|
||||
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
||||
pPg=pPg->pDirtyPrev
|
||||
);
|
||||
pCache->pSynced = pPg;
|
||||
if( !pPg ){
|
||||
for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
|
||||
}
|
||||
|
||||
60
src/pragma.c
60
src/pragma.c
@ -285,6 +285,7 @@ void sqlite3Pragma(
|
||||
Db *pDb;
|
||||
Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);
|
||||
if( v==0 ) return;
|
||||
sqlite3VdbeRunOnlyOnce(v);
|
||||
pParse->nMem = 2;
|
||||
|
||||
/* Interpret the [database.] part of the pragma statement. iDb is the
|
||||
@ -416,6 +417,31 @@ void sqlite3Pragma(
|
||||
returnSingleInt(pParse, "max_page_count", newMax);
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]secure_delete
|
||||
** PRAGMA [database.]secure_delete=ON/OFF
|
||||
**
|
||||
** The first form reports the current setting for the
|
||||
** secure_delete flag. The second form changes the secure_delete
|
||||
** flag setting and reports thenew value.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
|
||||
Btree *pBt = pDb->pBt;
|
||||
int b = -1;
|
||||
assert( pBt!=0 );
|
||||
if( zRight ){
|
||||
b = getBoolean(zRight);
|
||||
}
|
||||
if( pId2->n==0 && b>=0 ){
|
||||
int ii;
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
|
||||
}
|
||||
}
|
||||
b = sqlite3BtreeSecureDelete(pBt, b);
|
||||
returnSingleInt(pParse, "secure_delete", b);
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]page_count
|
||||
**
|
||||
@ -1334,6 +1360,26 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
/*
|
||||
** PRAGMA compile_options
|
||||
**
|
||||
** Return the names of all compile-time options used in this build,
|
||||
** one option per row.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "compile_options")==0 ){
|
||||
int i = 0;
|
||||
const char *zOpt;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
pParse->nMem = 1;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "compile_option", SQLITE_STATIC);
|
||||
while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Report the current state of file logs for all databases
|
||||
@ -1368,7 +1414,7 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){
|
||||
sqlite3_key(db, zRight, sqlite3Strlen30(zRight));
|
||||
}else
|
||||
@ -1409,17 +1455,15 @@ void sqlite3Pragma(
|
||||
}else
|
||||
/** END CRYPTO **/
|
||||
#endif
|
||||
#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
|
||||
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
||||
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
|
||||
#if SQLITE_HAS_CODEC
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
|
||||
extern void sqlite3_activate_see(const char*);
|
||||
sqlite3_activate_see(&zRight[4]);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CEROD
|
||||
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
|
||||
extern void sqlite3_activate_cerod(const char*);
|
||||
sqlite3_activate_cerod(&zRight[6]);
|
||||
}
|
||||
#endif
|
||||
@ -1429,12 +1473,6 @@ void sqlite3Pragma(
|
||||
|
||||
{/* Empty ELSE clause */}
|
||||
|
||||
/* Code an OP_Expire at the end of each PRAGMA program to cause
|
||||
** the VDBE implementing the pragma to expire. Most (all?) pragmas
|
||||
** are only valid for a single execution.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 1, 0);
|
||||
|
||||
/*
|
||||
** Reset the safety level, in case the fullfsync flag or synchronous
|
||||
** setting changed.
|
||||
|
||||
@ -192,9 +192,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
initData.iDb = iDb;
|
||||
initData.rc = SQLITE_OK;
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
(void)sqlite3SafetyOff(db);
|
||||
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
if( initData.rc ){
|
||||
rc = initData.rc;
|
||||
goto error_out;
|
||||
@ -315,9 +313,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s",
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
|
||||
db->aDb[iDb].zName, zMasterName);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
@ -330,7 +327,6 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}
|
||||
#endif
|
||||
if( rc==SQLITE_OK ) rc = initData.rc;
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3DbFree(db, zSql);
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -469,7 +465,7 @@ static void schemaIsValid(Parse *pParse){
|
||||
}
|
||||
|
||||
/* Read the schema cookie from the database. If it does not match the
|
||||
** value stored as part of the in the in-memory schema representation,
|
||||
** value stored as part of the in-memory schema representation,
|
||||
** set Parse.rc to SQLITE_SCHEMA. */
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
|
||||
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
@ -539,11 +535,6 @@ static int sqlite3Prepare(
|
||||
goto end_prepare;
|
||||
}
|
||||
pParse->pReprepare = pReprepare;
|
||||
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
goto end_prepare;
|
||||
}
|
||||
assert( ppStmt && *ppStmt==0 );
|
||||
assert( !db->mallocFailed );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
@ -579,7 +570,6 @@ static int sqlite3Prepare(
|
||||
if( rc ){
|
||||
const char *zDb = db->aDb[i].zName;
|
||||
sqlite3Error(db, rc, "database schema is locked: %s", zDb);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
testcase( db->flags & SQLITE_ReadUncommitted );
|
||||
goto end_prepare;
|
||||
}
|
||||
@ -596,7 +586,6 @@ static int sqlite3Prepare(
|
||||
testcase( nBytes==mxLen+1 );
|
||||
if( nBytes>mxLen ){
|
||||
sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
|
||||
goto end_prepare;
|
||||
}
|
||||
@ -653,10 +642,6 @@ static int sqlite3Prepare(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
assert( db->init.busy==0 || saveSqlFlag==0 );
|
||||
if( db->init.busy==0 ){
|
||||
Vdbe *pVdbe = pParse->pVdbe;
|
||||
@ -704,7 +689,7 @@ static int sqlite3LockAndPrepare(
|
||||
assert( ppStmt!=0 );
|
||||
*ppStmt = 0;
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
@ -743,7 +728,7 @@ int sqlite3Reprepare(Vdbe *p){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
assert( pNew==0 );
|
||||
return (rc==SQLITE_LOCKED) ? SQLITE_LOCKED : SQLITE_SCHEMA;
|
||||
return rc;
|
||||
}else{
|
||||
assert( pNew!=0 );
|
||||
}
|
||||
@ -812,10 +797,10 @@ static int sqlite3Prepare16(
|
||||
assert( ppStmt );
|
||||
*ppStmt = 0;
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
|
||||
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
|
||||
}
|
||||
|
||||
40
src/printf.c
40
src/printf.c
@ -460,7 +460,9 @@ void sqlite3VXPrintf(
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap,double);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
length = 0;
|
||||
#else
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
|
||||
if( realvalue<0.0 ){
|
||||
@ -606,7 +608,7 @@ void sqlite3VXPrintf(
|
||||
while( nPad-- ) bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
#endif
|
||||
#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
|
||||
break;
|
||||
case etSIZE:
|
||||
*(va_arg(ap,int*)) = pAccum->nChar;
|
||||
@ -653,7 +655,7 @@ void sqlite3VXPrintf(
|
||||
isnull = escarg==0;
|
||||
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
k = precision;
|
||||
for(i=n=0; (ch=escarg[i])!=0 && k!=0; i++, k--){
|
||||
for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
|
||||
if( ch==q ) n++;
|
||||
}
|
||||
needQuote = !isnull && xtype==etSQLESCAPE2;
|
||||
@ -937,6 +939,38 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the routine that actually formats the sqlite3_log() message.
|
||||
** We house it in a separate routine from sqlite3_log() to avoid using
|
||||
** stack space on small-stack systems when logging is disabled.
|
||||
**
|
||||
** sqlite3_log() must render into a static buffer. It cannot dynamically
|
||||
** allocate memory because it might be called while the memory allocator
|
||||
** mutex is held.
|
||||
*/
|
||||
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
|
||||
StrAccum acc; /* String accumulator */
|
||||
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
|
||||
|
||||
sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
|
||||
sqlite3StrAccumFinish(&acc));
|
||||
}
|
||||
|
||||
/*
|
||||
** Format and write a message to the log if logging is enabled.
|
||||
*/
|
||||
void sqlite3_log(int iErrCode, const char *zFormat, ...){
|
||||
va_list ap; /* Vararg list */
|
||||
if( sqlite3GlobalConfig.xLog ){
|
||||
va_start(ap, zFormat);
|
||||
renderLogMsg(iErrCode, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** A version of printf() that understands %lld. Used for debugging.
|
||||
|
||||
@ -243,19 +243,18 @@ static int lookupName(
|
||||
int iCol;
|
||||
pSchema = pTab->pSchema;
|
||||
cntTab++;
|
||||
if( sqlite3IsRowid(zCol) ){
|
||||
iCol = -1;
|
||||
}else{
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
Column *pCol = &pTab->aCol[iCol];
|
||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||
if( iCol==pTab->iPKey ){
|
||||
iCol = -1;
|
||||
}
|
||||
break;
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
Column *pCol = &pTab->aCol[iCol];
|
||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||
if( iCol==pTab->iPKey ){
|
||||
iCol = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) ){
|
||||
iCol = -1; /* IMP: R-44911-55124 */
|
||||
}
|
||||
if( iCol<pTab->nCol ){
|
||||
cnt++;
|
||||
if( iCol<0 ){
|
||||
@ -282,7 +281,7 @@ static int lookupName(
|
||||
*/
|
||||
if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
|
||||
cnt = 1;
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->iColumn = -1; /* IMP: R-44911-55124 */
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
}
|
||||
|
||||
@ -665,6 +664,9 @@ static int resolveOrderByTermToExprList(
|
||||
int i; /* Loop counter */
|
||||
ExprList *pEList; /* The columns of the result set */
|
||||
NameContext nc; /* Name context for resolving pE */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int rc; /* Return code from subprocedures */
|
||||
u8 savedSuppErr; /* Saved value of db->suppressErr */
|
||||
|
||||
assert( sqlite3ExprIsInteger(pE, &i)==0 );
|
||||
pEList = pSelect->pEList;
|
||||
@ -677,17 +679,19 @@ static int resolveOrderByTermToExprList(
|
||||
nc.pEList = pEList;
|
||||
nc.allowAgg = 1;
|
||||
nc.nErr = 0;
|
||||
if( sqlite3ResolveExprNames(&nc, pE) ){
|
||||
sqlite3ErrorClear(pParse);
|
||||
return 0;
|
||||
}
|
||||
db = pParse->db;
|
||||
savedSuppErr = db->suppressErr;
|
||||
db->suppressErr = 1;
|
||||
rc = sqlite3ResolveExprNames(&nc, pE);
|
||||
db->suppressErr = savedSuppErr;
|
||||
if( rc ) return 0;
|
||||
|
||||
/* Try to match the ORDER BY expression against an expression
|
||||
** in the result set. Return an 1-based index of the matching
|
||||
** result-set entry.
|
||||
*/
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( sqlite3ExprCompare(pEList->a[i].pExpr, pE) ){
|
||||
if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
|
||||
122
src/select.c
122
src/select.c
@ -189,6 +189,39 @@ static int columnIndex(Table *pTab, const char *zCol){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search the first N tables in pSrc, from left to right, looking for a
|
||||
** table that has a column named zCol.
|
||||
**
|
||||
** When found, set *piTab and *piCol to the table index and column index
|
||||
** of the matching column and return TRUE.
|
||||
**
|
||||
** If not found, return FALSE.
|
||||
*/
|
||||
static int tableAndColumnIndex(
|
||||
SrcList *pSrc, /* Array of tables to search */
|
||||
int N, /* Number of tables in pSrc->a[] to search */
|
||||
const char *zCol, /* Name of the column we are looking for */
|
||||
int *piTab, /* Write index of pSrc->a[] here */
|
||||
int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
|
||||
){
|
||||
int i; /* For looping over tables in pSrc */
|
||||
int iCol; /* Index of column matching zCol */
|
||||
|
||||
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
|
||||
for(i=0; i<N; i++){
|
||||
iCol = columnIndex(pSrc->a[i].pTab, zCol);
|
||||
if( iCol>=0 ){
|
||||
if( piTab ){
|
||||
*piTab = i;
|
||||
*piCol = iCol;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to add terms implied by JOIN syntax to the
|
||||
** WHERE clause expression of a SELECT statement. The new term, which
|
||||
@ -203,8 +236,9 @@ static int columnIndex(Table *pTab, const char *zCol){
|
||||
static void addWhereTerm(
|
||||
Parse *pParse, /* Parsing context */
|
||||
SrcList *pSrc, /* List of tables in FROM clause */
|
||||
int iSrc, /* Index of first table to join in pSrc */
|
||||
int iLeft, /* Index of first table to join in pSrc */
|
||||
int iColLeft, /* Index of column in first table */
|
||||
int iRight, /* Index of second table in pSrc */
|
||||
int iColRight, /* Index of column in second table */
|
||||
int isOuterJoin, /* True if this is an OUTER join */
|
||||
Expr **ppWhere /* IN/OUT: The WHERE clause to add to */
|
||||
@ -214,12 +248,13 @@ static void addWhereTerm(
|
||||
Expr *pE2;
|
||||
Expr *pEq;
|
||||
|
||||
assert( pSrc->nSrc>(iSrc+1) );
|
||||
assert( pSrc->a[iSrc].pTab );
|
||||
assert( pSrc->a[iSrc+1].pTab );
|
||||
assert( iLeft<iRight );
|
||||
assert( pSrc->nSrc>iRight );
|
||||
assert( pSrc->a[iLeft].pTab );
|
||||
assert( pSrc->a[iRight].pTab );
|
||||
|
||||
pE1 = sqlite3CreateColumnExpr(db, pSrc, iSrc, iColLeft);
|
||||
pE2 = sqlite3CreateColumnExpr(db, pSrc, iSrc+1, iColRight);
|
||||
pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
|
||||
pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
|
||||
|
||||
pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
|
||||
if( pEq && isOuterJoin ){
|
||||
@ -308,11 +343,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
"an ON or USING clause", 0);
|
||||
return 1;
|
||||
}
|
||||
for(j=0; j<pLeftTab->nCol; j++){
|
||||
char *zName = pLeftTab->aCol[j].zName;
|
||||
int iRightCol = columnIndex(pRightTab, zName);
|
||||
if( iRightCol>=0 ){
|
||||
addWhereTerm(pParse, pSrc, i, j, iRightCol, isOuter, &p->pWhere);
|
||||
for(j=0; j<pRightTab->nCol; j++){
|
||||
char *zName; /* Name of column in the right table */
|
||||
int iLeft; /* Matching left table */
|
||||
int iLeftCol; /* Matching column in the left table */
|
||||
|
||||
zName = pRightTab->aCol[j].zName;
|
||||
if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){
|
||||
addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
|
||||
isOuter, &p->pWhere);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -344,15 +383,22 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
if( pRight->pUsing ){
|
||||
IdList *pList = pRight->pUsing;
|
||||
for(j=0; j<pList->nId; j++){
|
||||
char *zName = pList->a[j].zName;
|
||||
int iLeftCol = columnIndex(pLeftTab, zName);
|
||||
int iRightCol = columnIndex(pRightTab, zName);
|
||||
if( iLeftCol<0 || iRightCol<0 ){
|
||||
char *zName; /* Name of the term in the USING clause */
|
||||
int iLeft; /* Table on the left with matching column name */
|
||||
int iLeftCol; /* Column number of matching column on the left */
|
||||
int iRightCol; /* Column number of matching column on the right */
|
||||
|
||||
zName = pList->a[j].zName;
|
||||
iRightCol = columnIndex(pRightTab, zName);
|
||||
if( iRightCol<0
|
||||
|| !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
|
||||
"not present in both tables", zName);
|
||||
return 1;
|
||||
}
|
||||
addWhereTerm(pParse, pSrc, i, iLeftCol, iRightCol, isOuter, &p->pWhere);
|
||||
addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
|
||||
isOuter, &p->pWhere);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -911,7 +957,7 @@ static const char *columnType(
|
||||
** of the SELECT statement. Return the declaration type and origin
|
||||
** data for the result-set column of the sub-select.
|
||||
*/
|
||||
if( ALWAYS(iCol>=0 && iCol<pS->pEList->nExpr) ){
|
||||
if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
|
||||
/* If iCol is less than zero, then the expression requests the
|
||||
** rowid of the sub-select or view. This expression is legal (see
|
||||
** test case misc2.2.2) - it always evaluates to NULL.
|
||||
@ -2472,7 +2518,7 @@ static void substSelect(
|
||||
**
|
||||
** (11) The subquery and the outer query do not both have ORDER BY clauses.
|
||||
**
|
||||
** (12) Not implemented. Subsumed into restriction (3). Was previously
|
||||
** (**) Not implemented. Subsumed into restriction (3). Was previously
|
||||
** a separate restriction deriving from ticket #350.
|
||||
**
|
||||
** (13) The subquery and outer query do not both use LIMIT
|
||||
@ -2546,6 +2592,7 @@ static int flattenSubquery(
|
||||
*/
|
||||
assert( p!=0 );
|
||||
assert( p->pPrior==0 ); /* Unable to flatten compound queries */
|
||||
if( db->flags & SQLITE_QueryFlattener ) return 0;
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
|
||||
pSubitem = &pSrc->a[iFrom];
|
||||
@ -3169,14 +3216,14 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
|
||||
if( i>0 && zTName==0 ){
|
||||
struct SrcList_item *pLeft = &pTabList->a[i-1];
|
||||
if( (pLeft[1].jointype & JT_NATURAL)!=0 &&
|
||||
columnIndex(pLeft->pTab, zName)>=0 ){
|
||||
if( (pFrom->jointype & JT_NATURAL)!=0
|
||||
&& tableAndColumnIndex(pTabList, i, zName, 0, 0)
|
||||
){
|
||||
/* In a NATURAL join, omit the join columns from the
|
||||
** table on the right */
|
||||
** table to the right of the join */
|
||||
continue;
|
||||
}
|
||||
if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){
|
||||
if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
|
||||
/* In a join with a USING clause, omit columns in the
|
||||
** using clause from the table on the right. */
|
||||
continue;
|
||||
@ -3280,18 +3327,19 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
||||
struct SrcList_item *pFrom;
|
||||
|
||||
assert( p->selFlags & SF_Resolved );
|
||||
assert( (p->selFlags & SF_HasTypeInfo)==0 );
|
||||
p->selFlags |= SF_HasTypeInfo;
|
||||
pParse = pWalker->pParse;
|
||||
pTabList = p->pSrc;
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab = pFrom->pTab;
|
||||
if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
|
||||
/* A sub-query in the FROM clause of a SELECT */
|
||||
Select *pSel = pFrom->pSelect;
|
||||
assert( pSel );
|
||||
while( pSel->pPrior ) pSel = pSel->pPrior;
|
||||
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
|
||||
if( (p->selFlags & SF_HasTypeInfo)==0 ){
|
||||
p->selFlags |= SF_HasTypeInfo;
|
||||
pParse = pWalker->pParse;
|
||||
pTabList = p->pSrc;
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab = pFrom->pTab;
|
||||
if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
|
||||
/* A sub-query in the FROM clause of a SELECT */
|
||||
Select *pSel = pFrom->pSelect;
|
||||
assert( pSel );
|
||||
while( pSel->pPrior ) pSel = pSel->pPrior;
|
||||
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
@ -3443,8 +3491,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
|
||||
(void*)pF->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
||||
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
|
||||
if( addrNext ){
|
||||
sqlite3VdbeResolveLabel(v, addrNext);
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
@ -3870,7 +3918,7 @@ int sqlite3Select(
|
||||
int r2;
|
||||
|
||||
r2 = sqlite3ExprCodeGetColumn(pParse,
|
||||
pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
|
||||
pCol->pTab, pCol->iColumn, pCol->iTable, r1);
|
||||
if( r1!=r2 ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
|
||||
}
|
||||
|
||||
1016
src/shell.c
1016
src/shell.c
File diff suppressed because it is too large
Load Diff
2933
src/sqlite.h.in
2933
src/sqlite.h.in
File diff suppressed because it is too large
Load Diff
217
src/sqliteInt.h
217
src/sqliteInt.h
@ -76,41 +76,43 @@
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The number of samples of an index that SQLite takes in order to
|
||||
** construct a histogram of the table content when running ANALYZE
|
||||
** and with SQLITE_ENABLE_STAT2
|
||||
*/
|
||||
#define SQLITE_INDEX_SAMPLES 10
|
||||
|
||||
/*
|
||||
** This macro is used to "hide" some ugliness in casting an int
|
||||
** value to a ptr value under the MSVC 64-bit compiler. Casting
|
||||
** non 64-bit values to ptr types results in a "hard" error with
|
||||
** the MSVC 64-bit compiler which this attempts to avoid.
|
||||
** The following macros are used to cast pointers to integers and
|
||||
** integers to pointers. The way you do this varies from one compiler
|
||||
** to the next, so we have developed the following set of #if statements
|
||||
** to generate appropriate macros for a wide range of compilers.
|
||||
**
|
||||
** A simple compiler pragma or casting sequence could not be found
|
||||
** to correct this in all situations, so this macro was introduced.
|
||||
**
|
||||
** It could be argued that the intptr_t type could be used in this
|
||||
** case, but that type is not available on all compilers, or
|
||||
** requires the #include of specific headers which differs between
|
||||
** platforms.
|
||||
** The correct "ANSI" way to do this is to use the intptr_t type.
|
||||
** Unfortunately, that typedef is not available on all compilers, or
|
||||
** if it is available, it requires an #include of specific headers
|
||||
** that very from one machine to the next.
|
||||
**
|
||||
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
|
||||
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
|
||||
** So we have to define the macros in different ways depending on the
|
||||
** compiler.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
# if defined(HAVE_STDINT_H)
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
|
||||
# else
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(X))
|
||||
# endif
|
||||
#else
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
|
||||
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
|
||||
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
|
||||
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
|
||||
#else /* Generates a warning - but it always works */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(X))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
|
||||
** Older versions of SQLite used an optional THREADSAFE macro.
|
||||
@ -140,23 +142,18 @@
|
||||
**
|
||||
** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
|
||||
** SQLITE_MEMDEBUG // Debugging version of system malloc()
|
||||
** SQLITE_MEMORY_SIZE // internal allocator #1
|
||||
** SQLITE_MMAP_HEAP_SIZE // internal mmap() allocator
|
||||
** SQLITE_POW2_MEMORY_SIZE // internal power-of-two allocator
|
||||
**
|
||||
** (Historical note: There used to be several other options, but we've
|
||||
** pared it down to just these two.)
|
||||
**
|
||||
** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
|
||||
** the default.
|
||||
*/
|
||||
#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
|
||||
defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
|
||||
defined(SQLITE_POW2_MEMORY_SIZE)>1
|
||||
#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)>1
|
||||
# error "At most one of the following compile-time configuration options\
|
||||
is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG, SQLITE_MEMORY_SIZE,\
|
||||
SQLITE_MMAP_HEAP_SIZE, SQLITE_POW2_MEMORY_SIZE"
|
||||
is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG"
|
||||
#endif
|
||||
#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
|
||||
defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
|
||||
defined(SQLITE_POW2_MEMORY_SIZE)==0
|
||||
#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)==0
|
||||
# define SQLITE_SYSTEM_MALLOC 1
|
||||
#endif
|
||||
|
||||
@ -328,20 +325,6 @@
|
||||
#define OMIT_TEMPDB 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If the following macro is set to 1, then NULL values are considered
|
||||
** distinct when determining whether or not two entries are the same
|
||||
** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL,
|
||||
** OCELOT, and Firebird all work. The SQL92 spec explicitly says this
|
||||
** is the way things are suppose to work.
|
||||
**
|
||||
** If the following macro is set to 0, the NULLs are indistinct for
|
||||
** a UNIQUE index. In this mode, you can only have a single NULL entry
|
||||
** for a column declared UNIQUE. This is the way Informix and SQL Server
|
||||
** work.
|
||||
*/
|
||||
#define NULL_DISTINCT_FOR_UNIQUE 1
|
||||
|
||||
/*
|
||||
** The "file format" number is an integer that is incremented whenever
|
||||
** the VDBE-level file format changes. The following macros define the
|
||||
@ -353,6 +336,10 @@
|
||||
# define SQLITE_DEFAULT_FILE_FORMAT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine whether triggers are recursive by default. This can be
|
||||
** changed at run-time using a pragma.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS
|
||||
# define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0
|
||||
#endif
|
||||
@ -597,7 +584,6 @@ typedef struct AggInfo AggInfo;
|
||||
typedef struct AuthContext AuthContext;
|
||||
typedef struct AutoincInfo AutoincInfo;
|
||||
typedef struct Bitvec Bitvec;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Db Db;
|
||||
@ -618,6 +604,7 @@ typedef struct LookasideSlot LookasideSlot;
|
||||
typedef struct Module Module;
|
||||
typedef struct NameContext NameContext;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
typedef struct SrcList SrcList;
|
||||
@ -625,9 +612,9 @@ typedef struct StrAccum StrAccum;
|
||||
typedef struct Table Table;
|
||||
typedef struct TableLock TableLock;
|
||||
typedef struct Token Token;
|
||||
typedef struct Trigger Trigger;
|
||||
typedef struct TriggerPrg TriggerPrg;
|
||||
typedef struct TriggerStep TriggerStep;
|
||||
typedef struct Trigger Trigger;
|
||||
typedef struct UnpackedRecord UnpackedRecord;
|
||||
typedef struct VTable VTable;
|
||||
typedef struct Walker Walker;
|
||||
@ -693,7 +680,7 @@ struct Schema {
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
** Db.flags field.
|
||||
** Db.pSchema->flags field.
|
||||
*/
|
||||
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
|
||||
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
|
||||
@ -701,7 +688,7 @@ struct Schema {
|
||||
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
|
||||
|
||||
/*
|
||||
** Allowed values for the DB.flags field.
|
||||
** Allowed values for the DB.pSchema->flags field.
|
||||
**
|
||||
** The DB_SchemaLoaded flag is set after the database schema has been
|
||||
** read into internal hash tables.
|
||||
@ -765,7 +752,7 @@ struct FuncDefHash {
|
||||
};
|
||||
|
||||
/*
|
||||
** Each database is an instance of the following structure.
|
||||
** Each database connection is an instance of the following structure.
|
||||
**
|
||||
** The sqlite.lastRowid records the last insert rowid generated by an
|
||||
** insert statement. Inserts on views do not affect its value. Each
|
||||
@ -804,6 +791,7 @@ struct sqlite3 {
|
||||
u8 dfltLockMode; /* Default locking-mode for attached dbs */
|
||||
u8 dfltJournalMode; /* Default journal mode for attached dbs */
|
||||
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
|
||||
u8 suppressErr; /* Do not issue error messages if true */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
int nTable; /* Number of tables in the database */
|
||||
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
|
||||
@ -898,37 +886,43 @@ struct sqlite3 {
|
||||
#define ENC(db) ((db)->aDb[0].pSchema->enc)
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.flags and or Db.flags fields.
|
||||
**
|
||||
** On sqlite.flags, the SQLITE_InTrans value means that we have
|
||||
** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement
|
||||
** transaction is active on that particular database file.
|
||||
** Possible values for the sqlite3.flags.
|
||||
*/
|
||||
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
|
||||
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
|
||||
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
|
||||
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
|
||||
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
|
||||
#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
|
||||
#define SQLITE_VdbeTrace 0x00000100 /* True to trace VDBE execution */
|
||||
#define SQLITE_InternChanges 0x00000200 /* Uncommitted Hash table changes */
|
||||
#define SQLITE_FullColNames 0x00000400 /* Show full column names on SELECT */
|
||||
#define SQLITE_ShortColNames 0x00000800 /* Show short columns names */
|
||||
#define SQLITE_CountRows 0x00001000 /* Count rows changed by INSERT, */
|
||||
/* DELETE, or UPDATE and return */
|
||||
/* the count using a callback. */
|
||||
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
|
||||
#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */
|
||||
/* result set is empty */
|
||||
#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
|
||||
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when
|
||||
#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
|
||||
#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_NoReadlock 0x00020000 /* Readlocks are omitted when
|
||||
** accessing read-only databases */
|
||||
#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
|
||||
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
|
||||
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
|
||||
#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */
|
||||
#define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */
|
||||
#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
|
||||
#define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */
|
||||
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
|
||||
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
|
||||
|
||||
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
|
||||
#define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_RecTriggers 0x00200000 /* Enable recursive triggers */
|
||||
#define SQLITE_ForeignKeys 0x00400000 /* Enforce foreign key constraints */
|
||||
/*
|
||||
** Bits of the sqlite3.flags field that are used by the
|
||||
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
|
||||
** These must be the low-order bits of the flags field.
|
||||
*/
|
||||
#define SQLITE_QueryFlattener 0x01 /* Disable query flattening */
|
||||
#define SQLITE_ColumnCache 0x02 /* Disable the column cache */
|
||||
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
|
||||
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
|
||||
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
|
||||
#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
@ -1642,14 +1636,13 @@ struct Expr {
|
||||
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
|
||||
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
|
||||
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x0800 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
|
||||
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
|
||||
#define EP_Reduced 0x1000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x2000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x4000 /* Held in memory not obtained from malloc() */
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags2 field.
|
||||
@ -1894,6 +1887,7 @@ struct WhereLevel {
|
||||
#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
|
||||
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
|
||||
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
|
||||
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
|
||||
|
||||
/*
|
||||
** The WHERE clause processing routine has two halves. The
|
||||
@ -1906,6 +1900,7 @@ struct WhereInfo {
|
||||
Parse *pParse; /* Parsing and code generating context */
|
||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
SrcList *pTabList; /* List of tables in the join */
|
||||
int iTop; /* The very beginning of the WHERE loop */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
@ -2125,7 +2120,6 @@ struct Parse {
|
||||
struct yColCache {
|
||||
int iTable; /* Table cursor number */
|
||||
int iColumn; /* Table column number */
|
||||
u8 affChange; /* True if this register has had an affinity change */
|
||||
u8 tempReg; /* iReg is a temp register that needs to be freed */
|
||||
int iLevel; /* Nesting level */
|
||||
int iReg; /* Reg with value of this column. 0 means none. */
|
||||
@ -2374,6 +2368,8 @@ struct Sqlite3Config {
|
||||
int isPCacheInit; /* True after malloc is initialized */
|
||||
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
|
||||
int nRefInitMutex; /* Number of users of pInitMutex */
|
||||
void (*xLog)(void*,int,const char*); /* Function for logging */
|
||||
void *pLogArg; /* First argument to xLog() */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2415,16 +2411,27 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
|
||||
}
|
||||
|
||||
/*
|
||||
** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production
|
||||
** builds) or a function call (for debugging). If it is a function call,
|
||||
** it allows the operator to set a breakpoint at the spot where database
|
||||
** corruption is first detected.
|
||||
** The SQLITE_*_BKPT macros are substitutes for the error codes with
|
||||
** the same name but without the _BKPT suffix. These macros invoke
|
||||
** routines that report the line-number on which the error originated
|
||||
** using sqlite3_log(). The routines also provide a convenient place
|
||||
** to set a debugger breakpoint.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3Corrupt(void);
|
||||
# define SQLITE_CORRUPT_BKPT sqlite3Corrupt()
|
||||
#else
|
||||
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
|
||||
int sqlite3CorruptError(int);
|
||||
int sqlite3MisuseError(int);
|
||||
int sqlite3CantopenError(int);
|
||||
#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
|
||||
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
|
||||
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
|
||||
|
||||
|
||||
/*
|
||||
** FTS4 is really an extension for FTS3. It is enabled using the
|
||||
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
|
||||
** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
|
||||
# define SQLITE_ENABLE_FTS3
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -2526,7 +2533,11 @@ int sqlite3StatusValue(int);
|
||||
void sqlite3StatusAdd(int, int);
|
||||
void sqlite3StatusSet(int, int);
|
||||
|
||||
int sqlite3IsNaN(double);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int sqlite3IsNaN(double);
|
||||
#else
|
||||
# define sqlite3IsNaN(X) 0
|
||||
#endif
|
||||
|
||||
void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
@ -2543,7 +2554,6 @@ char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
|
||||
#endif
|
||||
void sqlite3SetString(char **, sqlite3*, const char*, ...);
|
||||
void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
void sqlite3ErrorClear(Parse*);
|
||||
int sqlite3Dequote(char*);
|
||||
int sqlite3KeywordCode(const unsigned char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*, char **);
|
||||
@ -2644,13 +2654,13 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||
void sqlite3ExprCodeCopy(Parse*, int, int, int);
|
||||
void sqlite3ExprCacheStore(Parse*, int, int, int);
|
||||
void sqlite3ExprCachePush(Parse*);
|
||||
void sqlite3ExprCachePop(Parse*, int);
|
||||
void sqlite3ExprCacheRemove(Parse*, int);
|
||||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
void sqlite3ExprHardCopy(Parse*,int,int);
|
||||
@ -2713,13 +2723,6 @@ FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
|
||||
void sqlite3RegisterBuiltinFunctions(sqlite3*);
|
||||
void sqlite3RegisterDateTimeFunctions(void);
|
||||
void sqlite3RegisterGlobalFunctions(void);
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3SafetyOn(sqlite3*);
|
||||
int sqlite3SafetyOff(sqlite3*);
|
||||
#else
|
||||
# define sqlite3SafetyOn(A) 0
|
||||
# define sqlite3SafetyOff(A) 0
|
||||
#endif
|
||||
int sqlite3SafetyCheckOk(sqlite3*);
|
||||
int sqlite3SafetyCheckSickOrOk(sqlite3*);
|
||||
void sqlite3ChangeCookie(Parse*, int);
|
||||
@ -2855,7 +2858,7 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
|
||||
void(*)(void*));
|
||||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew(sqlite3 *);
|
||||
char *sqlite3Utf16to8(sqlite3 *, const void*, int);
|
||||
char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *);
|
||||
#endif
|
||||
|
||||
@ -83,7 +83,7 @@ void sqlite3StatusSet(int op, int X){
|
||||
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
|
||||
wsdStatInit;
|
||||
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
*pCurrent = wsdStat.nowValue[op];
|
||||
*pHighwater = wsdStat.mxValue[op];
|
||||
|
||||
@ -4909,7 +4909,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3_open_file_count;
|
||||
extern int sqlite3_sort_count;
|
||||
extern int sqlite3_current_time;
|
||||
#if SQLITE_OS_UNIX && defined(__APPLE__)
|
||||
#if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
extern int sqlite3_hostid_num;
|
||||
#endif
|
||||
extern int sqlite3_max_blobsize;
|
||||
@ -5140,7 +5140,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite3_open_file_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_current_time",
|
||||
(char*)&sqlite3_current_time, TCL_LINK_INT);
|
||||
#if SQLITE_OS_UNIX && defined(__APPLE__)
|
||||
#if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
Tcl_LinkVar(interp, "sqlite_hostid_num",
|
||||
(char*)&sqlite3_hostid_num, TCL_LINK_INT);
|
||||
#endif
|
||||
|
||||
@ -219,7 +219,7 @@ static int btree_cursor(
|
||||
Btree *pBt;
|
||||
int iTable;
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
int wrFlag;
|
||||
char zBuf[30];
|
||||
|
||||
@ -234,7 +234,9 @@ static int btree_cursor(
|
||||
pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
|
||||
memset(pCur, 0, sqlite3BtreeCursorSize());
|
||||
sqlite3BtreeEnter(pBt);
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
|
||||
#endif
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
|
||||
}
|
||||
|
||||
@ -183,7 +183,11 @@ static void set_options(Tcl_Interp *interp){
|
||||
TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "compileoption_diags", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "compileoption_diags", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_COMPLETE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
|
||||
|
||||
@ -341,6 +341,7 @@ static void testHexToBin(const char *zIn, char *zOut){
|
||||
** Convert the input string from HEX into binary. Then return the
|
||||
** result using sqlite3_result_text16le().
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
static void testHexToUtf16be(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
@ -360,6 +361,7 @@ static void testHexToUtf16be(
|
||||
sqlite3_result_text16be(pCtx, zOut, n/2, sqlite3_free);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** hex_to_utf8(HEX)
|
||||
@ -393,6 +395,7 @@ static void testHexToUtf8(
|
||||
** Convert the input string from HEX into binary. Then return the
|
||||
** result using sqlite3_result_text16le().
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
static void testHexToUtf16le(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
@ -412,6 +415,7 @@ static void testHexToUtf16le(
|
||||
sqlite3_result_text16le(pCtx, zOut, n/2, sqlite3_free);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int registerTestFunctions(sqlite3 *db){
|
||||
static const struct {
|
||||
|
||||
@ -330,12 +330,12 @@ static int getFts3Varint(const char *p, sqlite_int64 *v){
|
||||
|
||||
|
||||
/*
|
||||
** USAGE: read_varint BLOB VARNAME
|
||||
** USAGE: read_fts3varint BLOB VARNAME
|
||||
**
|
||||
** Read a varint from the start of BLOB. Set variable VARNAME to contain
|
||||
** the interpreted value. Return the number of bytes of BLOB consumed.
|
||||
*/
|
||||
static int read_varint(
|
||||
static int read_fts3varint(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
@ -373,7 +373,7 @@ int Sqlitetest_hexio_Init(Tcl_Interp *interp){
|
||||
{ "hexio_render_int16", hexio_render_int16 },
|
||||
{ "hexio_render_int32", hexio_render_int32 },
|
||||
{ "utf8_to_utf8", utf8_to_utf8 },
|
||||
{ "read_varint", read_varint },
|
||||
{ "read_fts3varint", read_fts3varint },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
||||
@ -123,8 +123,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
}
|
||||
case '-': {
|
||||
if( z[1]=='-' ){
|
||||
/* IMP: R-15891-05542 -- syntax diagram for comments */
|
||||
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
|
||||
*tokenType = TK_SPACE;
|
||||
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
|
||||
return i;
|
||||
}
|
||||
*tokenType = TK_MINUS;
|
||||
@ -155,9 +156,10 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
*tokenType = TK_SLASH;
|
||||
return 1;
|
||||
}
|
||||
/* IMP: R-15891-05542 -- syntax diagram for comments */
|
||||
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
|
||||
if( c ) i++;
|
||||
*tokenType = TK_SPACE;
|
||||
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
|
||||
return i;
|
||||
}
|
||||
case '%': {
|
||||
@ -478,6 +480,7 @@ abort_parse:
|
||||
assert( pzErrMsg!=0 );
|
||||
if( pParse->zErrMsg ){
|
||||
*pzErrMsg = pParse->zErrMsg;
|
||||
sqlite3_log(pParse->rc, "%s", *pzErrMsg);
|
||||
pParse->zErrMsg = 0;
|
||||
nErr++;
|
||||
}
|
||||
|
||||
@ -126,7 +126,8 @@ void sqlite3BeginTrigger(
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
|
||||
if( db->init.busy==0 && pName2->n==0 && pTab
|
||||
&& pTab->pSchema==db->aDb[1].pSchema ){
|
||||
iDb = 1;
|
||||
}
|
||||
|
||||
@ -254,12 +255,12 @@ void sqlite3FinishTrigger(
|
||||
TriggerStep *pStepList, /* The triggered program */
|
||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||
){
|
||||
Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
|
||||
char *zName; /* Name of trigger */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
int iDb; /* Database containing the trigger */
|
||||
Token nameToken; /* Trigger name for error reporting */
|
||||
Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
|
||||
char *zName; /* Name of trigger */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix; /* Fixer object */
|
||||
int iDb; /* Database containing the trigger */
|
||||
Token nameToken; /* Trigger name for error reporting */
|
||||
|
||||
pTrig = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
@ -278,7 +279,7 @@ void sqlite3FinishTrigger(
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
|
||||
/* if we are not initializing, and this trigger is not on a TEMP table,
|
||||
/* if we are not initializing,
|
||||
** build the sqlite_master entry
|
||||
*/
|
||||
if( !db->init.busy ){
|
||||
|
||||
@ -437,11 +437,11 @@ int sqlite3Utf8To8(unsigned char *zIn){
|
||||
**
|
||||
** NULL is returned if there is an allocation error.
|
||||
*/
|
||||
char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
|
||||
char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.db = db;
|
||||
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
@ -449,7 +449,9 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
|
||||
}
|
||||
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
|
||||
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
|
||||
return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z);
|
||||
assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
|
||||
assert( m.z || db->mallocFailed );
|
||||
return m.z;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
168
src/util.c
168
src/util.c
@ -31,6 +31,7 @@ void sqlite3Coverage(int x){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** Return true if the floating point value is Not a Number (NaN).
|
||||
**
|
||||
@ -75,6 +76,7 @@ int sqlite3IsNaN(double x){
|
||||
testcase( rc );
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** Compute a string length that is limited to what can be stored in
|
||||
@ -146,23 +148,20 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
|
||||
** (sqlite3_step() etc.).
|
||||
*/
|
||||
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
char *zMsg;
|
||||
va_list ap;
|
||||
sqlite3 *db = pParse->db;
|
||||
pParse->nErr++;
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
va_start(ap, zFormat);
|
||||
pParse->zErrMsg = sqlite3VMPrintf(db, zFormat, ap);
|
||||
zMsg = sqlite3VMPrintf(db, zFormat, ap);
|
||||
va_end(ap);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the error message in pParse, if any
|
||||
*/
|
||||
void sqlite3ErrorClear(Parse *pParse){
|
||||
sqlite3DbFree(pParse->db, pParse->zErrMsg);
|
||||
pParse->zErrMsg = 0;
|
||||
pParse->nErr = 0;
|
||||
if( db->suppressErr ){
|
||||
sqlite3DbFree(db, zMsg);
|
||||
}else{
|
||||
pParse->nErr++;
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
pParse->zErrMsg = zMsg;
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -255,6 +254,7 @@ int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
|
||||
z += incr;
|
||||
*realnum = 0;
|
||||
while( sqlite3Isdigit(*z) ){ z += incr; }
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( *z=='.' ){
|
||||
z += incr;
|
||||
if( !sqlite3Isdigit(*z) ) return 0;
|
||||
@ -268,6 +268,7 @@ int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
|
||||
while( sqlite3Isdigit(*z) ){ z += incr; }
|
||||
*realnum = 1;
|
||||
}
|
||||
#endif
|
||||
return *z==0;
|
||||
}
|
||||
|
||||
@ -429,6 +430,9 @@ static int compare2pow63(const char *zNum){
|
||||
c = memcmp(zNum,"922337203685477580",18)*10;
|
||||
if( c==0 ){
|
||||
c = zNum[18] - '8';
|
||||
testcase( c==(-1) );
|
||||
testcase( c==0 );
|
||||
testcase( c==(+1) );
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@ -465,6 +469,9 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
|
||||
v = v*10 + c - '0';
|
||||
}
|
||||
*pNum = neg ? -v : v;
|
||||
testcase( i==18 );
|
||||
testcase( i==19 );
|
||||
testcase( i==20 );
|
||||
if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
|
||||
/* zNum is empty or contains non-numeric text or is longer
|
||||
** than 19 digits (thus guaranting that it is too large) */
|
||||
@ -508,6 +515,9 @@ int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
|
||||
zNum++; /* Skip leading zeros. Ticket #2454 */
|
||||
}
|
||||
for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
|
||||
testcase( i==18 );
|
||||
testcase( i==19 );
|
||||
testcase( i==20 );
|
||||
if( i<19 ){
|
||||
/* Guaranteed to fit if less than 19 digits */
|
||||
return 1;
|
||||
@ -548,9 +558,11 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
** 1234567890
|
||||
** 2^31 -> 2147483648
|
||||
*/
|
||||
testcase( i==10 );
|
||||
if( i>10 ){
|
||||
return 0;
|
||||
}
|
||||
testcase( v-neg==2147483647 );
|
||||
if( v-neg>2147483647 ){
|
||||
return 0;
|
||||
}
|
||||
@ -638,6 +650,19 @@ int sqlite3PutVarint32(unsigned char *p, u32 v){
|
||||
return sqlite3PutVarint(p, v);
|
||||
}
|
||||
|
||||
/*
|
||||
** Bitmasks used by sqlite3GetVarint(). These precomputed constants
|
||||
** are defined here rather than simply putting the constant expressions
|
||||
** inline in order to work around bugs in the RVT compiler.
|
||||
**
|
||||
** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
|
||||
**
|
||||
** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
|
||||
*/
|
||||
#define SLOT_2_0 0x001fc07f
|
||||
#define SLOT_4_2_0 0xf01fc07f
|
||||
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read. The value is stored in *v.
|
||||
@ -665,13 +690,17 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Verify that constants are precomputed correctly */
|
||||
assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
|
||||
assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
|
||||
|
||||
p++;
|
||||
a = a<<14;
|
||||
a |= *p;
|
||||
/* a: p0<<14 | p2 (unmasked) */
|
||||
if (!(a&0x80))
|
||||
{
|
||||
a &= (0x7f<<14)|(0x7f);
|
||||
a &= SLOT_2_0;
|
||||
b &= 0x7f;
|
||||
b = b<<7;
|
||||
a |= b;
|
||||
@ -680,14 +709,14 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
}
|
||||
|
||||
/* CSE1 from below */
|
||||
a &= (0x7f<<14)|(0x7f);
|
||||
a &= SLOT_2_0;
|
||||
p++;
|
||||
b = b<<14;
|
||||
b |= *p;
|
||||
/* b: p1<<14 | p3 (unmasked) */
|
||||
if (!(b&0x80))
|
||||
{
|
||||
b &= (0x7f<<14)|(0x7f);
|
||||
b &= SLOT_2_0;
|
||||
/* moved CSE1 up */
|
||||
/* a &= (0x7f<<14)|(0x7f); */
|
||||
a = a<<7;
|
||||
@ -701,7 +730,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
/* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
|
||||
/* moved CSE1 up */
|
||||
/* a &= (0x7f<<14)|(0x7f); */
|
||||
b &= (0x7f<<14)|(0x7f);
|
||||
b &= SLOT_2_0;
|
||||
s = a;
|
||||
/* s: p0<<14 | p2 (masked) */
|
||||
|
||||
@ -734,7 +763,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
{
|
||||
/* we can skip this cause it was (effectively) done above in calc'ing s */
|
||||
/* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
|
||||
a &= (0x7f<<14)|(0x7f);
|
||||
a &= SLOT_2_0;
|
||||
a = a<<7;
|
||||
a |= b;
|
||||
s = s>>18;
|
||||
@ -748,8 +777,8 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
|
||||
if (!(a&0x80))
|
||||
{
|
||||
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
|
||||
b &= (0x7f<<14)|(0x7f);
|
||||
a &= SLOT_4_2_0;
|
||||
b &= SLOT_2_0;
|
||||
b = b<<7;
|
||||
a |= b;
|
||||
s = s>>11;
|
||||
@ -758,14 +787,14 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
}
|
||||
|
||||
/* CSE2 from below */
|
||||
a &= (0x7f<<14)|(0x7f);
|
||||
a &= SLOT_2_0;
|
||||
p++;
|
||||
b = b<<14;
|
||||
b |= *p;
|
||||
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
|
||||
if (!(b&0x80))
|
||||
{
|
||||
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
|
||||
b &= SLOT_4_2_0;
|
||||
/* moved CSE2 up */
|
||||
/* a &= (0x7f<<14)|(0x7f); */
|
||||
a = a<<7;
|
||||
@ -782,7 +811,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
|
||||
/* moved CSE2 up */
|
||||
/* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
|
||||
b &= (0x7f<<14)|(0x7f);
|
||||
b &= SLOT_2_0;
|
||||
b = b<<8;
|
||||
a |= b;
|
||||
|
||||
@ -902,9 +931,9 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
||||
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
|
||||
if (!(a&0x80))
|
||||
{
|
||||
/* Walues between 268435456 and 34359738367 */
|
||||
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
|
||||
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
|
||||
/* Values between 268435456 and 34359738367 */
|
||||
a &= SLOT_4_2_0;
|
||||
b &= SLOT_4_2_0;
|
||||
b = b<<7;
|
||||
*v = a | b;
|
||||
return 5;
|
||||
@ -997,64 +1026,17 @@ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
|
||||
|
||||
|
||||
/*
|
||||
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
|
||||
** when this routine is called.
|
||||
**
|
||||
** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN
|
||||
** value indicates that the database connection passed into the API is
|
||||
** open and is not being used by another thread. By changing the value
|
||||
** to SQLITE_MAGIC_BUSY we indicate that the connection is in use.
|
||||
** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN
|
||||
** when the API exits.
|
||||
**
|
||||
** This routine is a attempt to detect if two threads use the
|
||||
** same sqlite* pointer at the same time. There is a race
|
||||
** condition so it is possible that the error is not detected.
|
||||
** But usually the problem will be seen. The result will be an
|
||||
** error which can be used to debug the application that is
|
||||
** using SQLite incorrectly.
|
||||
**
|
||||
** Ticket #202: If db->magic is not a valid open value, take care not
|
||||
** to modify the db structure at all. It could be that db is a stale
|
||||
** pointer. In other words, it could be that there has been a prior
|
||||
** call to sqlite3_close(db) and db has been deallocated. And we do
|
||||
** not want to write into deallocated memory.
|
||||
** Log an error that is an API call on a connection pointer that should
|
||||
** not have been used. The "type" of connection pointer is given as the
|
||||
** argument. The zType is a word like "NULL" or "closed" or "invalid".
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3SafetyOn(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_OPEN ){
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
return 0;
|
||||
}else if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->u1.isInterrupted = 1;
|
||||
}
|
||||
return 1;
|
||||
static void logBadConnection(const char *zType){
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"API call with %s database connection pointer",
|
||||
zType
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
|
||||
** when this routine is called.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3SafetyOff(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
return 0;
|
||||
}else{
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->u1.isInterrupted = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Check to make sure we have a valid db pointer. This test is not
|
||||
@ -1072,13 +1054,16 @@ int sqlite3SafetyOff(sqlite3 *db){
|
||||
*/
|
||||
int sqlite3SafetyCheckOk(sqlite3 *db){
|
||||
u32 magic;
|
||||
if( db==0 ) return 0;
|
||||
if( db==0 ){
|
||||
logBadConnection("NULL");
|
||||
return 0;
|
||||
}
|
||||
magic = db->magic;
|
||||
if( magic!=SQLITE_MAGIC_OPEN
|
||||
#ifdef SQLITE_DEBUG
|
||||
&& magic!=SQLITE_MAGIC_BUSY
|
||||
#endif
|
||||
){
|
||||
if( magic!=SQLITE_MAGIC_OPEN ){
|
||||
if( sqlite3SafetyCheckSickOrOk(db) ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
logBadConnection("unopened");
|
||||
}
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
@ -1089,6 +1074,11 @@ int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
|
||||
magic = db->magic;
|
||||
if( magic!=SQLITE_MAGIC_SICK &&
|
||||
magic!=SQLITE_MAGIC_OPEN &&
|
||||
magic!=SQLITE_MAGIC_BUSY ) return 0;
|
||||
return 1;
|
||||
magic!=SQLITE_MAGIC_BUSY ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
logBadConnection("invalid");
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
59
src/vacuum.c
59
src/vacuum.c
@ -18,28 +18,42 @@
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/*
|
||||
** Finalize a prepared statement. If there was an error, store the
|
||||
** text of the error message in *pzErrMsg. Return the result code.
|
||||
*/
|
||||
static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
|
||||
int rc;
|
||||
rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
*/
|
||||
static int execSql(sqlite3 *db, const char *zSql){
|
||||
static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
VVA_ONLY( int rc; )
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
VVA_ONLY( rc = ) sqlite3_step(pStmt);
|
||||
assert( rc!=SQLITE_ROW );
|
||||
return sqlite3_finalize(pStmt);
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. The statement returns exactly
|
||||
** one column. Execute this as SQL on the same database.
|
||||
*/
|
||||
static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
@ -47,14 +61,14 @@ static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
|
||||
rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_finalize(pStmt);
|
||||
vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlite3_finalize(pStmt);
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -86,6 +100,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
int saved_nChange; /* Saved value of db->nChange */
|
||||
int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
||||
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
int isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nRes;
|
||||
@ -101,8 +116,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
saved_flags = db->flags;
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
saved_xTrace = db->xTrace;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
db->flags &= ~SQLITE_ForeignKeys;
|
||||
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
|
||||
db->xTrace = 0;
|
||||
|
||||
pMain = db->aDb[0].pBt;
|
||||
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
|
||||
@ -121,8 +138,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** time to parse and run the PRAGMA to turn journalling off than it does
|
||||
** to write the journal header file.
|
||||
*/
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
rc = execSql(db, zSql);
|
||||
if( sqlite3TempInMemory(db) ){
|
||||
zSql = "ATTACH ':memory:' AS vacuum_db;";
|
||||
}else{
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
@ -154,7 +175,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
@ -165,23 +186,23 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
#endif
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, "BEGIN EXCLUSIVE;");
|
||||
rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
|
||||
" AND rootpage>0"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
@ -190,24 +211,23 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'"
|
||||
"FROM main.sqlite_master "
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND rootpage>0"
|
||||
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
|
||||
@ -220,7 +240,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execSql(db,
|
||||
rc = execSql(db, pzErrMsg,
|
||||
"INSERT INTO vacuum_db.sqlite_master "
|
||||
" SELECT type, name, tbl_name, rootpage, sql"
|
||||
" FROM main.sqlite_master"
|
||||
@ -283,6 +303,7 @@ end_of_vacuum:
|
||||
db->flags = saved_flags;
|
||||
db->nChange = saved_nChange;
|
||||
db->nTotalChange = saved_nTotalChange;
|
||||
db->xTrace = saved_xTrace;
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
|
||||
129
src/vdbe.c
129
src/vdbe.c
@ -239,17 +239,30 @@ static VdbeCursor *allocateCursor(
|
||||
static void applyNumericAffinity(Mem *pRec){
|
||||
if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
|
||||
int realnum;
|
||||
u8 enc = pRec->enc;
|
||||
sqlite3VdbeMemNulTerminate(pRec);
|
||||
if( (pRec->flags&MEM_Str)
|
||||
&& sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
|
||||
if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
|
||||
i64 value;
|
||||
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
|
||||
if( !realnum && sqlite3Atoi64(pRec->z, &value) ){
|
||||
char *zUtf8 = pRec->z;
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
assert( pRec->db );
|
||||
zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
|
||||
if( !zUtf8 ) return;
|
||||
}
|
||||
#endif
|
||||
if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
|
||||
pRec->u.i = value;
|
||||
MemSetTypeFlag(pRec, MEM_Int);
|
||||
}else{
|
||||
sqlite3VdbeMemRealify(pRec);
|
||||
sqlite3AtoF(zUtf8, &pRec->r);
|
||||
MemSetTypeFlag(pRec, MEM_Real);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
sqlite3DbFree(pRec->db, zUtf8);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -538,7 +551,7 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
int sqlite3VdbeExec(
|
||||
Vdbe *p /* The VDBE */
|
||||
){
|
||||
int pc; /* The program counter */
|
||||
int pc=0; /* The program counter */
|
||||
Op *aOp = p->aOp; /* Copy of p->aOp */
|
||||
Op *pOp; /* Current operation */
|
||||
int rc = SQLITE_OK; /* Value to return */
|
||||
@ -563,7 +576,6 @@ int sqlite3VdbeExec(
|
||||
/*** INSERT STACK UNION HERE ***/
|
||||
|
||||
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
||||
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||
sqlite3VdbeMutexArrayEnter(p);
|
||||
if( p->rc==SQLITE_NOMEM ){
|
||||
/* This happens if a malloc() inside a call to sqlite3_column_text() or
|
||||
@ -648,9 +660,7 @@ int sqlite3VdbeExec(
|
||||
if( checkProgress ){
|
||||
if( db->nProgressOps==nProgressOps ){
|
||||
int prc;
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
prc =db->xProgress(db->pProgressArg);
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
prc = db->xProgress(db->pProgressArg);
|
||||
if( prc!=0 ){
|
||||
rc = SQLITE_INTERRUPT;
|
||||
goto vdbe_error_halt;
|
||||
@ -850,7 +860,13 @@ case OP_Halt: {
|
||||
p->errorAction = (u8)pOp->p2;
|
||||
p->pc = pc;
|
||||
if( pOp->p4.z ){
|
||||
assert( p->rc!=SQLITE_OK );
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z);
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pc, p->zSql, pOp->p4.z);
|
||||
}else if( p->rc ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql);
|
||||
}
|
||||
rc = sqlite3VdbeHalt(p);
|
||||
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
|
||||
@ -884,6 +900,7 @@ case OP_Int64: { /* out2-prerelease */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* Opcode: Real * P2 * P4 *
|
||||
**
|
||||
** P4 is a pointer to a 64-bit floating point value.
|
||||
@ -895,6 +912,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
pOut->r = *pOp->p4.pReal;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: String8 * P2 * P4 *
|
||||
**
|
||||
@ -1295,6 +1313,10 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
pOut->u.i = rB;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
#else
|
||||
if( sqlite3IsNaN(rB) ){
|
||||
goto arithmetic_result_is_null;
|
||||
}
|
||||
@ -1303,6 +1325,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
if( (flags & MEM_Real)==0 ){
|
||||
sqlite3VdbeIntegerAffinity(pOut);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1393,21 +1416,12 @@ case OP_Function: {
|
||||
assert( pOp[-1].opcode==OP_CollSeq );
|
||||
ctx.pColl = pOp[-1].p4.pColl;
|
||||
}
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
(*ctx.pFunc->xFunc)(&ctx, n, apVal);
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
sqlite3VdbeMemRelease(&ctx.s);
|
||||
goto abort_due_to_misuse;
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
/* Even though a malloc() has failed, the implementation of the
|
||||
** user function may have called an sqlite3_result_XXX() function
|
||||
** to return a value. The following call releases any resources
|
||||
** associated with such a value.
|
||||
**
|
||||
** Note: Maybe MemRelease() should be called if sqlite3SafetyOn()
|
||||
** fails also (the if(...) statement above). But if people are
|
||||
** misusing sqlite, they have bigger problems than a leaked value.
|
||||
*/
|
||||
sqlite3VdbeMemRelease(&ctx.s);
|
||||
goto no_mem;
|
||||
@ -1530,6 +1544,7 @@ case OP_MustBeInt: { /* jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* Opcode: RealAffinity P1 * * * *
|
||||
**
|
||||
** If register P1 holds an integer convert it to a real value.
|
||||
@ -1546,6 +1561,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
/* Opcode: ToText P1 * * * *
|
||||
@ -1629,7 +1645,7 @@ case OP_ToInt: { /* same as TK_TO_INT, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
/* Opcode: ToReal P1 * * * *
|
||||
**
|
||||
** Force the value in register P1 to be a floating point number.
|
||||
@ -1646,7 +1662,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CAST */
|
||||
#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
|
||||
|
||||
/* Opcode: Lt P1 P2 P3 P4 P5
|
||||
**
|
||||
@ -1728,9 +1744,13 @@ case OP_Gt: /* same as TK_GT, jump, in1, in3 */
|
||||
case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
int res; /* Result of the comparison of pIn1 against pIn3 */
|
||||
char affinity; /* Affinity to use for comparison */
|
||||
u16 flags1; /* Copy of initial value of pIn1->flags */
|
||||
u16 flags3; /* Copy of initial value of pIn3->flags */
|
||||
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
flags1 = pIn1->flags;
|
||||
flags3 = pIn3->flags;
|
||||
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
|
||||
/* One or both operands are NULL */
|
||||
if( pOp->p5 & SQLITE_NULLEQ ){
|
||||
@ -1785,6 +1805,10 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
}else if( res ){
|
||||
pc = pOp->p2-1;
|
||||
}
|
||||
|
||||
/* Undo any changes made by applyAffinity() to the input registers. */
|
||||
pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask);
|
||||
pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2059,7 +2083,7 @@ case OP_Column: {
|
||||
u8 *zIdx; /* Index into header */
|
||||
u8 *zEndHdr; /* Pointer to first byte after the header */
|
||||
u32 offset; /* Offset into the data */
|
||||
u64 offset64; /* 64-bit offset. 64 bits needed to catch overflow */
|
||||
u32 szField; /* Number of bytes in the content of a field */
|
||||
int szHdr; /* Size of the header size field at start of record */
|
||||
int avail; /* Number of bytes of available data */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
@ -2234,12 +2258,16 @@ case OP_Column: {
|
||||
** column and aOffset[i] will contain the offset from the beginning
|
||||
** of the record to the start of the data for the i-th column
|
||||
*/
|
||||
offset64 = offset;
|
||||
for(i=0; i<nField; i++){
|
||||
if( zIdx<zEndHdr ){
|
||||
aOffset[i] = (u32)offset64;
|
||||
aOffset[i] = offset;
|
||||
zIdx += getVarint32(zIdx, aType[i]);
|
||||
offset64 += sqlite3VdbeSerialTypeLen(aType[i]);
|
||||
szField = sqlite3VdbeSerialTypeLen(aType[i]);
|
||||
offset += szField;
|
||||
if( offset<szField ){ /* True if offset overflows */
|
||||
zIdx = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
/* If i is less that nField, then there are less fields in this
|
||||
** record than SetNumColumns indicated there are columns in the
|
||||
@ -2259,8 +2287,8 @@ case OP_Column: {
|
||||
** of the record (when all fields present), then we must be dealing
|
||||
** with a corrupt database.
|
||||
*/
|
||||
if( (zIdx > zEndHdr)|| (offset64 > payloadSize)
|
||||
|| (zIdx==zEndHdr && offset64!=(u64)payloadSize) ){
|
||||
if( (zIdx > zEndHdr) || (offset > payloadSize)
|
||||
|| (zIdx==zEndHdr && offset!=payloadSize) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto op_column_out;
|
||||
}
|
||||
@ -3106,7 +3134,7 @@ case OP_OpenEphemeral: {
|
||||
** register P2. In other words, cursor P1 becomes an alias for the
|
||||
** MEM_Blob content contained in register P2.
|
||||
**
|
||||
** A pseudo-table created by this opcode is used to hold the a single
|
||||
** A pseudo-table created by this opcode is used to hold a single
|
||||
** row output from the sorter so that the row can be decomposed into
|
||||
** individual columns using the OP_Column opcode. The OP_Column opcode
|
||||
** is the only cursor opcode that works with a pseudo-table.
|
||||
@ -3663,7 +3691,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( res ){
|
||||
v = 1;
|
||||
v = 1; /* IMP: R-61914-48074 */
|
||||
}else{
|
||||
assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
|
||||
rc = sqlite3BtreeKeySize(pC->pCursor, &v);
|
||||
@ -3671,7 +3699,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
if( v==MAX_ROWID ){
|
||||
pC->useRandomRowid = 1;
|
||||
}else{
|
||||
v++;
|
||||
v++; /* IMP: R-29538-34987 */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3695,7 +3723,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
|
||||
if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
|
||||
rc = SQLITE_FULL;
|
||||
rc = SQLITE_FULL; /* IMP: R-12275-61338 */
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( v<pMem->u.i+1 ){
|
||||
@ -3708,6 +3736,11 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
sqlite3BtreeSetCachedRowid(pC->pCursor, v<MAX_ROWID ? v+1 : 0);
|
||||
}
|
||||
if( pC->useRandomRowid ){
|
||||
/* IMPLEMENTATION-OF: R-48598-02938 If the largest ROWID is equal to the
|
||||
** largest possible integer (9223372036854775807) then the database
|
||||
** engine starts picking candidate ROWIDs at random until it finds one
|
||||
** that is not previously used.
|
||||
*/
|
||||
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
|
||||
** an AUTOINCREMENT table. */
|
||||
v = db->lastRowid;
|
||||
@ -3723,7 +3756,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
cnt++;
|
||||
}while( cnt<100 && rc==SQLITE_OK && res==0 );
|
||||
if( rc==SQLITE_OK && res==0 ){
|
||||
rc = SQLITE_FULL;
|
||||
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
@ -4031,12 +4064,10 @@ case OP_Rowid: { /* out2-prerelease */
|
||||
pVtab = pC->pVtabCursor->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xRowid );
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = pModule->xRowid(pC->pVtabCursor, &v);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}else{
|
||||
assert( pC->pCursor!=0 );
|
||||
@ -4567,12 +4598,11 @@ case OP_ParseSchema: {
|
||||
initData.iDb = pOp->p1;
|
||||
initData.pzErrMsg = &p->zErrMsg;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
|
||||
db->aDb[iDb].zName, zMaster, pOp->p4.z);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
(void)sqlite3SafetyOff(db);
|
||||
assert( db->init.busy==0 );
|
||||
db->init.busy = 1;
|
||||
initData.rc = SQLITE_OK;
|
||||
@ -4581,7 +4611,6 @@ case OP_ParseSchema: {
|
||||
if( rc==SQLITE_OK ) rc = initData.rc;
|
||||
sqlite3DbFree(db, zSql);
|
||||
db->init.busy = 0;
|
||||
(void)sqlite3SafetyOn(db);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
@ -5151,9 +5180,7 @@ case OP_AggFinal: {
|
||||
** a transaction.
|
||||
*/
|
||||
case OP_Vacuum: {
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = sqlite3RunVacuum(&p->zErrMsg, db);
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -5297,12 +5324,10 @@ case OP_VOpen: {
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
pModule = (sqlite3_module *)pVtab->pModule;
|
||||
assert(pVtab && pModule);
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = pModule->xOpen(pVtab, &pVtabCursor);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
if( SQLITE_OK==rc ){
|
||||
/* Initialize sqlite3_vtab_cursor base class */
|
||||
pVtabCursor->pVtab = pVtab;
|
||||
@ -5376,7 +5401,6 @@ case OP_VFilter: { /* jump */
|
||||
sqlite3VdbeMemStoreType(apArg[i]);
|
||||
}
|
||||
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
p->inVtabMethod = 0;
|
||||
@ -5386,7 +5410,6 @@ case OP_VFilter: { /* jump */
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
}
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
@ -5432,7 +5455,6 @@ case OP_VColumn: {
|
||||
sqlite3VdbeMemMove(&sContext.s, pDest);
|
||||
MemSetTypeFlag(&sContext.s, MEM_Null);
|
||||
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
@ -5450,9 +5472,6 @@ case OP_VColumn: {
|
||||
REGISTER_TRACE(pOp->p3, pDest);
|
||||
UPDATE_MAX_BLOBSIZE(pDest);
|
||||
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
goto abort_due_to_misuse;
|
||||
}
|
||||
if( sqlite3VdbeMemTooBig(pDest) ){
|
||||
goto too_big;
|
||||
}
|
||||
@ -5489,7 +5508,6 @@ case OP_VNext: { /* jump */
|
||||
** data is available) and the error code returned when xColumn or
|
||||
** some other method is next invoked on the save virtual table cursor.
|
||||
*/
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xNext(pCur->pVtabCursor);
|
||||
p->inVtabMethod = 0;
|
||||
@ -5499,7 +5517,6 @@ case OP_VNext: { /* jump */
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pCur->pVtabCursor);
|
||||
}
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
|
||||
if( !res ){
|
||||
/* If there is data, jump to P2 */
|
||||
@ -5525,12 +5542,10 @@ case OP_VRename: {
|
||||
assert( pVtab->pModule->xRename );
|
||||
REGISTER_TRACE(pOp->p1, pName);
|
||||
assert( pName->flags & MEM_Str );
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -5581,12 +5596,10 @@ case OP_VUpdate: {
|
||||
apArg[i] = pX;
|
||||
pX++;
|
||||
}
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
if( rc==SQLITE_OK && pOp->p1 ){
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = rowid;
|
||||
@ -5659,6 +5672,7 @@ case OP_Trace: {
|
||||
** the same as a no-op. This opcodesnever appears in a real VM program.
|
||||
*/
|
||||
default: { /* This is really OP_Noop and OP_Explain */
|
||||
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5710,6 +5724,9 @@ default: { /* This is really OP_Noop and OP_Explain */
|
||||
vdbe_error_halt:
|
||||
assert( rc );
|
||||
p->rc = rc;
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
||||
pc, p->zSql, p->zErrMsg);
|
||||
sqlite3VdbeHalt(p);
|
||||
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
|
||||
rc = SQLITE_ERROR;
|
||||
@ -5738,12 +5755,6 @@ no_mem:
|
||||
rc = SQLITE_NOMEM;
|
||||
goto vdbe_error_halt;
|
||||
|
||||
/* Jump to here for an SQLITE_MISUSE error.
|
||||
*/
|
||||
abort_due_to_misuse:
|
||||
rc = SQLITE_MISUSE;
|
||||
/* Fall thru into abort_due_to_error */
|
||||
|
||||
/* Jump to here for any other kind of fatal error. The "rc" variable
|
||||
** should hold the error number.
|
||||
*/
|
||||
|
||||
@ -182,6 +182,7 @@ void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
|
||||
void sqlite3VdbeUsesBtree(Vdbe*, int);
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
|
||||
@ -301,6 +301,7 @@ struct Vdbe {
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
u8 runOnlyOnce; /* Automatically expire on reset */
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
u8 inVtabMethod; /* See comments above */
|
||||
u8 usesStmtJournal; /* True if uses a statement journal */
|
||||
@ -362,7 +363,11 @@ void sqlite3VdbeMemMove(Mem*, Mem*);
|
||||
int sqlite3VdbeMemNulTerminate(Mem*);
|
||||
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
|
||||
void sqlite3VdbeMemSetInt64(Mem*, i64);
|
||||
void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
|
||||
#else
|
||||
void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
#endif
|
||||
void sqlite3VdbeMemSetNull(Mem*);
|
||||
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
||||
void sqlite3VdbeMemSetRowSet(Mem*);
|
||||
|
||||
127
src/vdbeapi.c
127
src/vdbeapi.c
@ -31,6 +31,28 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Check on a Vdbe to make sure it has not been finalized. Log
|
||||
** an error and return true if it has been finalized (or is otherwise
|
||||
** invalid). Return false if it is ok.
|
||||
*/
|
||||
static int vdbeSafety(Vdbe *p){
|
||||
if( p->db==0 ){
|
||||
sqlite3_log(SQLITE_MISUSE, "API called with finalized prepared statement");
|
||||
return 1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int vdbeSafetyNotNull(Vdbe *p){
|
||||
if( p==0 ){
|
||||
sqlite3_log(SQLITE_MISUSE, "API called with NULL prepared statement");
|
||||
return 1;
|
||||
}else{
|
||||
return vdbeSafety(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routine destroys a virtual machine that is created by
|
||||
** the sqlite3_compile() routine. The integer returned is an SQLITE_
|
||||
@ -48,7 +70,11 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
sqlite3 *db = v->db;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = v->db->mutex;
|
||||
sqlite3_mutex *mutex;
|
||||
#endif
|
||||
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
|
||||
#if SQLITE_THREADSAFE
|
||||
mutex = v->db->mutex;
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
rc = sqlite3VdbeFinalize(v);
|
||||
@ -295,26 +321,23 @@ static int sqlite3Step(Vdbe *p){
|
||||
|
||||
assert(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_MISUSE;
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"attempt to step a halted statement: [%s]", p->zSql);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
|
||||
/* Assert that malloc() has not failed */
|
||||
/* Check that malloc() has not failed. If it has, return early. */
|
||||
db = p->db;
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
if( p->pc<=0 && p->expired ){
|
||||
if( ALWAYS(p->rc==SQLITE_OK || p->rc==SQLITE_SCHEMA) ){
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
}
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
rc = SQLITE_ERROR;
|
||||
goto end_of_step;
|
||||
}
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( p->pc<0 ){
|
||||
/* If there are no other statements currently running, then
|
||||
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
||||
@ -347,10 +370,6 @@ static int sqlite3Step(Vdbe *p){
|
||||
rc = sqlite3VdbeExec(p);
|
||||
}
|
||||
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Invoke the profile callback if there is one
|
||||
*/
|
||||
@ -397,39 +416,44 @@ end_of_step:
|
||||
** call sqlite3Reprepare() and try again.
|
||||
*/
|
||||
int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
int rc = SQLITE_MISUSE;
|
||||
if( pStmt ){
|
||||
int cnt = 0;
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
sqlite3 *db = v->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
||||
&& cnt++ < 5
|
||||
&& (rc = sqlite3Reprepare(v))==SQLITE_OK ){
|
||||
sqlite3_reset(pStmt);
|
||||
v->expired = 0;
|
||||
}
|
||||
if( rc==SQLITE_SCHEMA && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
|
||||
/* This case occurs after failing to recompile an sql statement.
|
||||
** The error message from the SQL compiler has already been loaded
|
||||
** into the database handle. This block copies the error message
|
||||
** from the database handle into the statement and sets the statement
|
||||
** program counter to 0 to ensure that when the statement is
|
||||
** finalized or reset the parser error message is available via
|
||||
** sqlite3_errmsg() and sqlite3_errcode().
|
||||
*/
|
||||
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
||||
sqlite3DbFree(db, v->zErrMsg);
|
||||
if( !db->mallocFailed ){
|
||||
v->zErrMsg = sqlite3DbStrDup(db, zErr);
|
||||
} else {
|
||||
v->zErrMsg = 0;
|
||||
v->rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
int rc = SQLITE_OK; /* Result from sqlite3Step() */
|
||||
int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
|
||||
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
|
||||
int cnt = 0; /* Counter to prevent infinite loop of reprepares */
|
||||
sqlite3 *db; /* The database connection */
|
||||
|
||||
if( vdbeSafetyNotNull(v) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
db = v->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
||||
&& cnt++ < 5
|
||||
&& (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
|
||||
sqlite3_reset(pStmt);
|
||||
v->expired = 0;
|
||||
}
|
||||
if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
|
||||
/* This case occurs after failing to recompile an sql statement.
|
||||
** The error message from the SQL compiler has already been loaded
|
||||
** into the database handle. This block copies the error message
|
||||
** from the database handle into the statement and sets the statement
|
||||
** program counter to 0 to ensure that when the statement is
|
||||
** finalized or reset the parser error message is available via
|
||||
** sqlite3_errmsg() and sqlite3_errcode().
|
||||
*/
|
||||
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
||||
sqlite3DbFree(db, v->zErrMsg);
|
||||
if( !db->mallocFailed ){
|
||||
v->zErrMsg = sqlite3DbStrDup(db, zErr);
|
||||
v->rc = rc2;
|
||||
} else {
|
||||
v->zErrMsg = 0;
|
||||
v->rc = rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -483,8 +507,9 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
assert( sqlite3_mutex_held(p->s.db->mutex) );
|
||||
pMem = p->pMem;
|
||||
testcase( nByte<0 );
|
||||
if( (pMem->flags & MEM_Agg)==0 ){
|
||||
if( nByte==0 ){
|
||||
if( nByte<=0 ){
|
||||
sqlite3VdbeMemReleaseExternal(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->z = 0;
|
||||
@ -898,12 +923,16 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
|
||||
*/
|
||||
static int vdbeUnbind(Vdbe *p, int i){
|
||||
Mem *pVar;
|
||||
if( p==0 ) return SQLITE_MISUSE;
|
||||
if( vdbeSafetyNotNull(p) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(p->db->mutex);
|
||||
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0);
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
return SQLITE_MISUSE;
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"bind on a busy prepared statement: [%s]", p->zSql);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
if( i<1 || i>p->nVar ){
|
||||
sqlite3Error(p->db, SQLITE_RANGE, 0);
|
||||
|
||||
145
src/vdbeaux.c
145
src/vdbeaux.c
@ -66,7 +66,7 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
||||
*/
|
||||
const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
return (p->isPrepareV2 ? p->zSql : 0);
|
||||
return (p && p->isPrepareV2) ? p->zSql : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -255,6 +255,13 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark the VDBE as one that can only be run one time.
|
||||
*/
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe *p){
|
||||
p->runOnlyOnce = 1;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
|
||||
|
||||
/*
|
||||
@ -1041,22 +1048,24 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
||||
** p->explain==2, only OP_Explain instructions are listed and these
|
||||
** are shown in a different format. p->explain==2 is used to implement
|
||||
** EXPLAIN QUERY PLAN.
|
||||
**
|
||||
** When p->explain==1, first the main program is listed, then each of
|
||||
** the trigger subprograms are listed one by one.
|
||||
*/
|
||||
int sqlite3VdbeList(
|
||||
Vdbe *p /* The VDBE */
|
||||
){
|
||||
int nRow; /* Total number of rows to return */
|
||||
int nRow; /* Stop when row count reaches this */
|
||||
int nSub = 0; /* Number of sub-vdbes seen so far */
|
||||
SubProgram **apSub = 0; /* Array of sub-vdbes */
|
||||
Mem *pSub = 0;
|
||||
sqlite3 *db = p->db;
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
Mem *pMem = p->pResultSet = &p->aMem[1];
|
||||
Mem *pSub = 0; /* Memory cell hold array of subprogs */
|
||||
sqlite3 *db = p->db; /* The database connection */
|
||||
int i; /* Loop counter */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Mem *pMem = p->pResultSet = &p->aMem[1]; /* First Mem of result set */
|
||||
|
||||
assert( p->explain );
|
||||
assert( p->magic==VDBE_MAGIC_RUN );
|
||||
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
|
||||
|
||||
/* Even though this opcode does not use dynamic strings for
|
||||
@ -1072,12 +1081,24 @@ int sqlite3VdbeList(
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Figure out total number of rows that will be returned by this
|
||||
** EXPLAIN program. */
|
||||
/* When the number of output rows reaches nRow, that means the
|
||||
** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
||||
** nRow is the sum of the number of rows in the main program, plus
|
||||
** the sum of the number of rows in all trigger subprograms encountered
|
||||
** so far. The nRow value will increase as new trigger subprograms are
|
||||
** encountered, but p->pc will eventually catch up to nRow.
|
||||
*/
|
||||
nRow = p->nOp;
|
||||
if( p->explain==1 ){
|
||||
/* The first 8 memory cells are used for the result set. So we will
|
||||
** commandeer the 9th cell to use as storage for an array of pointers
|
||||
** to trigger subprograms. The VDBE is guaranteed to have at least 9
|
||||
** cells. */
|
||||
assert( p->nMem>9 );
|
||||
pSub = &p->aMem[9];
|
||||
if( pSub->flags&MEM_Blob ){
|
||||
/* On the first call to sqlite3_step(), pSub will hold a NULL. It is
|
||||
** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
|
||||
nSub = pSub->n/sizeof(Vdbe*);
|
||||
apSub = (SubProgram **)pSub->z;
|
||||
}
|
||||
@ -1100,8 +1121,12 @@ int sqlite3VdbeList(
|
||||
char *z;
|
||||
Op *pOp;
|
||||
if( i<p->nOp ){
|
||||
/* The output line number is small enough that we are still in the
|
||||
** main program. */
|
||||
pOp = &p->aOp[i];
|
||||
}else{
|
||||
/* We are currently listing subprograms. Figure out which one and
|
||||
** pick up the appropriate opcode. */
|
||||
int j;
|
||||
i -= p->nOp;
|
||||
for(j=0; i>=apSub[j]->nOp; j++){
|
||||
@ -1123,6 +1148,11 @@ int sqlite3VdbeList(
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
/* When an OP_Program opcode is encounter (the only opcode that has
|
||||
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
||||
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
||||
** has not already been seen.
|
||||
*/
|
||||
if( pOp->p4type==P4_SUBPROGRAM ){
|
||||
int nByte = (nSub+1)*sizeof(SubProgram*);
|
||||
int j;
|
||||
@ -1254,38 +1284,43 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
||||
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
|
||||
|
||||
/*
|
||||
** Allocate space from a fixed size buffer. Make *pp point to the
|
||||
** allocated space. (Note: pp is a char* rather than a void** to
|
||||
** work around the pointer aliasing rules of C.) *pp should initially
|
||||
** be zero. If *pp is not zero, that means that the space has already
|
||||
** been allocated and this routine is a noop.
|
||||
** Allocate space from a fixed size buffer and return a pointer to
|
||||
** that space. If insufficient space is available, return NULL.
|
||||
**
|
||||
** The pBuf parameter is the initial value of a pointer which will
|
||||
** receive the new memory. pBuf is normally NULL. If pBuf is not
|
||||
** NULL, it means that memory space has already been allocated and that
|
||||
** this routine should not allocate any new memory. When pBuf is not
|
||||
** NULL simply return pBuf. Only allocate new memory space when pBuf
|
||||
** is NULL.
|
||||
**
|
||||
** nByte is the number of bytes of space needed.
|
||||
**
|
||||
** *ppFrom point to available space and pEnd points to the end of the
|
||||
** available space.
|
||||
** *ppFrom points to available space and pEnd points to the end of the
|
||||
** available space. When space is allocated, *ppFrom is advanced past
|
||||
** the end of the allocated space.
|
||||
**
|
||||
** *pnByte is a counter of the number of bytes of space that have failed
|
||||
** to allocate. If there is insufficient space in *ppFrom to satisfy the
|
||||
** request, then increment *pnByte by the amount of the request.
|
||||
*/
|
||||
static void allocSpace(
|
||||
char *pp, /* IN/OUT: Set *pp to point to allocated buffer */
|
||||
static void *allocSpace(
|
||||
void *pBuf, /* Where return pointer will be stored */
|
||||
int nByte, /* Number of bytes to allocate */
|
||||
u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
|
||||
u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
|
||||
int *pnByte /* If allocation cannot be made, increment *pnByte */
|
||||
){
|
||||
assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
|
||||
if( (*(void**)pp)==0 ){
|
||||
nByte = ROUND8(nByte);
|
||||
if( &(*ppFrom)[nByte] <= pEnd ){
|
||||
*(void**)pp = (void *)*ppFrom;
|
||||
*ppFrom += nByte;
|
||||
}else{
|
||||
*pnByte += nByte;
|
||||
}
|
||||
if( pBuf ) return pBuf;
|
||||
nByte = ROUND8(nByte);
|
||||
if( &(*ppFrom)[nByte] <= pEnd ){
|
||||
pBuf = (void*)*ppFrom;
|
||||
*ppFrom += nByte;
|
||||
}else{
|
||||
*pnByte += nByte;
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1344,9 +1379,10 @@ void sqlite3VdbeMakeReady(
|
||||
** being called from sqlite3_reset() to reset the virtual machine.
|
||||
*/
|
||||
if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
|
||||
u8 *zCsr = (u8 *)&p->aOp[p->nOp];
|
||||
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];
|
||||
int nByte;
|
||||
u8 *zCsr = (u8 *)&p->aOp[p->nOp]; /* Memory avaliable for alloation */
|
||||
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; /* First byte past available mem */
|
||||
int nByte; /* How much extra memory needed */
|
||||
|
||||
resolveP2Values(p, &nArg);
|
||||
p->usesStmtJournal = (u8)usesStmtJournal;
|
||||
if( isExplain && nMem<10 ){
|
||||
@ -1356,15 +1392,24 @@ void sqlite3VdbeMakeReady(
|
||||
zCsr += (zCsr - (u8*)0)&7;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
||||
|
||||
/* Memory for registers, parameters, cursor, etc, is allocated in two
|
||||
** passes. On the first pass, we try to reuse unused space at the
|
||||
** end of the opcode array. If we are unable to satisfy all memory
|
||||
** requirements by reusing the opcode array tail, then the second
|
||||
** pass will fill in the rest using a fresh allocation.
|
||||
**
|
||||
** This two-pass approach that reuses as much memory as possible from
|
||||
** the leftover space at the end of the opcode array can significantly
|
||||
** reduce the amount of memory held by a prepared statement.
|
||||
*/
|
||||
do {
|
||||
nByte = 0;
|
||||
allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
allocSpace((char*)&p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
||||
allocSpace((char*)&p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
allocSpace((char*)&p->apCsr,
|
||||
nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte
|
||||
);
|
||||
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
||||
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
||||
&zCsr, zEnd, &nByte);
|
||||
if( nByte ){
|
||||
p->pFree = sqlite3DbMallocZero(db, nByte);
|
||||
}
|
||||
@ -1435,9 +1480,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
|
||||
const sqlite3_module *pModule = pCx->pModule;
|
||||
p->inVtabMethod = 1;
|
||||
(void)sqlite3SafetyOff(p->db);
|
||||
pModule->xClose(pVtabCursor);
|
||||
(void)sqlite3SafetyOn(p->db);
|
||||
p->inVtabMethod = 0;
|
||||
}
|
||||
#endif
|
||||
@ -1618,9 +1661,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
|
||||
/* If there are any write-transactions at all, invoke the commit hook */
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = db->xCommitCallback(db->pCommitArg);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
if( rc ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
@ -1706,10 +1747,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
*/
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( i==1 ) continue; /* Ignore the TEMP database */
|
||||
if( sqlite3BtreeIsInTrans(pBt) ){
|
||||
char const *zFile = sqlite3BtreeGetJournalname(pBt);
|
||||
if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
|
||||
if( zFile==0 || zFile[0]==0 ){
|
||||
continue; /* Ignore TEMP and :memory: databases */
|
||||
}
|
||||
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
|
||||
needSync = 1;
|
||||
}
|
||||
@ -2085,12 +2127,17 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
/* If eStatementOp is non-zero, then a statement transaction needs to
|
||||
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
|
||||
** do so. If this operation returns an error, and the current statement
|
||||
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
|
||||
** code to the new value.
|
||||
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
|
||||
** current statement error code.
|
||||
**
|
||||
** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
|
||||
** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
|
||||
** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
|
||||
** the following code.
|
||||
*/
|
||||
if( eStatementOp ){
|
||||
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
|
||||
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
|
||||
if( rc && (NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT) ){
|
||||
p->rc = rc;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
@ -2173,9 +2220,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
** error, then it might not have been halted properly. So halt
|
||||
** it now.
|
||||
*/
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3VdbeHalt(p);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
|
||||
/* If the VDBE has be run even partially, then transfer the error code
|
||||
** and error message from the VDBE into the main database structure. But
|
||||
@ -2195,6 +2240,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}else{
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
}
|
||||
if( p->runOnlyOnce ) p->expired = 1;
|
||||
}else if( p->rc && p->expired ){
|
||||
/* The expired flag was set on the VDBE before the first call
|
||||
** to sqlite3_step(). For consistency (since sqlite3_step() was
|
||||
@ -2296,6 +2342,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
p->db = 0;
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
@ -2976,7 +3023,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
||||
if( nCellKey<=0 || nCellKey>0x7fffffff ){
|
||||
*res = 0;
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
memset(&m, 0, sizeof(m));
|
||||
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (int)nCellKey, 1, &m);
|
||||
|
||||
@ -95,13 +95,6 @@ int sqlite3_blob_open(
|
||||
memset(pParse, 0, sizeof(Parse));
|
||||
pParse->db = db;
|
||||
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3StackFree(db, pParse);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
|
||||
if( pTab && IsVirtual(pTab) ){
|
||||
@ -121,7 +114,6 @@ int sqlite3_blob_open(
|
||||
pParse->zErrMsg = 0;
|
||||
}
|
||||
rc = SQLITE_ERROR;
|
||||
(void)sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
@ -136,7 +128,6 @@ int sqlite3_blob_open(
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
|
||||
rc = SQLITE_ERROR;
|
||||
(void)sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
@ -177,7 +168,6 @@ int sqlite3_blob_open(
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);
|
||||
rc = SQLITE_ERROR;
|
||||
(void)sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
@ -227,8 +217,7 @@ int sqlite3_blob_open(
|
||||
}
|
||||
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
rc = sqlite3SafetyOff(db);
|
||||
if( NEVER(rc!=SQLITE_OK) || db->mallocFailed ){
|
||||
if( db->mallocFailed ){
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
@ -329,7 +318,7 @@ static int blobReadWrite(
|
||||
Vdbe *v;
|
||||
sqlite3 *db;
|
||||
|
||||
if( p==0 ) return SQLITE_MISUSE;
|
||||
if( p==0 ) return SQLITE_MISUSE_BKPT;
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = (Vdbe*)p->pStmt;
|
||||
|
||||
@ -315,6 +315,10 @@ void sqlite3VdbeMemRelease(Mem *p){
|
||||
** before attempting the conversion.
|
||||
*/
|
||||
static i64 doubleToInt64(double r){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
/* When floating-point is omitted, double and int64 are the same thing */
|
||||
return r;
|
||||
#else
|
||||
/*
|
||||
** Many compilers we encounter do not define constants for the
|
||||
** minimum and maximum 64-bit integers, or they define them
|
||||
@ -336,6 +340,7 @@ static i64 doubleToInt64(double r){
|
||||
}else{
|
||||
return (i64)r;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -463,21 +468,26 @@ int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
/*
|
||||
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
|
||||
** Invalidate any prior representations.
|
||||
**
|
||||
** Every effort is made to force the conversion, even if the input
|
||||
** is a string that does not look completely like a number. Convert
|
||||
** as much of the string as we can and ignore the rest.
|
||||
*/
|
||||
int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
double r1, r2;
|
||||
i64 i;
|
||||
int rc;
|
||||
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
|
||||
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
r1 = sqlite3VdbeRealValue(pMem);
|
||||
i = doubleToInt64(r1);
|
||||
r2 = (double)i;
|
||||
if( r1==r2 ){
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3VdbeMemNulTerminate(pMem);
|
||||
if( rc ) return rc;
|
||||
if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}else{
|
||||
pMem->r = r1;
|
||||
pMem->r = sqlite3VdbeRealValue(pMem);
|
||||
MemSetTypeFlag(pMem, MEM_Real);
|
||||
sqlite3VdbeIntegerAffinity(pMem);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -529,6 +539,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to val,
|
||||
** manifest type REAL.
|
||||
@ -543,6 +554,7 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value of pMem to be an
|
||||
@ -597,7 +609,7 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
|
||||
sqlite3VdbeMemReleaseExternal(pTo);
|
||||
memcpy(pTo, pFrom, MEMCELLSIZE);
|
||||
pTo->xDel = 0;
|
||||
if( (pFrom->flags&MEM_Dyn)!=0 || pFrom->z==pFrom->zMalloc ){
|
||||
if( (pFrom->flags&MEM_Static)==0 ){
|
||||
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
|
||||
assert( srcType==MEM_Ephem || srcType==MEM_Static );
|
||||
pTo->flags |= srcType;
|
||||
|
||||
36
src/vtab.c
36
src/vtab.c
@ -123,16 +123,7 @@ void sqlite3VtabUnlock(VTable *pVTab){
|
||||
if( pVTab->nRef==0 ){
|
||||
sqlite3_vtab *p = pVTab->pVtab;
|
||||
if( p ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pVTab->db->magic==SQLITE_MAGIC_BUSY ){
|
||||
(void)sqlite3SafetyOff(db);
|
||||
p->pModule->xDisconnect(p);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
p->pModule->xDisconnect(p);
|
||||
}
|
||||
p->pModule->xDisconnect(p);
|
||||
}
|
||||
sqlite3DbFree(db, pVTab);
|
||||
}
|
||||
@ -468,9 +459,7 @@ static int vtabCallConstructor(
|
||||
db->pVTab = pTab;
|
||||
|
||||
/* Invoke the virtual table constructor */
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
@ -658,7 +647,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
if( !pTab ){
|
||||
sqlite3Error(db, SQLITE_MISUSE, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
assert( (pTab->tabFlags & TF_Virtual)!=0 );
|
||||
|
||||
@ -669,11 +658,11 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pParse->declareVtab = 1;
|
||||
pParse->db = db;
|
||||
|
||||
if(
|
||||
SQLITE_OK == sqlite3RunParser(pParse, zCreateTable, &zErr) &&
|
||||
pParse->pNewTable &&
|
||||
!pParse->pNewTable->pSelect &&
|
||||
(pParse->pNewTable->tabFlags & TF_Virtual)==0
|
||||
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
|
||||
&& pParse->pNewTable
|
||||
&& !db->mallocFailed
|
||||
&& !pParse->pNewTable->pSelect
|
||||
&& (pParse->pNewTable->tabFlags & TF_Virtual)==0
|
||||
){
|
||||
if( !pTab->aCol ){
|
||||
pTab->aCol = pParse->pNewTable->aCol;
|
||||
@ -682,7 +671,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pParse->pNewTable->aCol = 0;
|
||||
}
|
||||
db->pVTab = 0;
|
||||
} else {
|
||||
}else{
|
||||
sqlite3Error(db, SQLITE_ERROR, zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
rc = SQLITE_ERROR;
|
||||
@ -717,10 +706,8 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
||||
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
|
||||
VTable *p = vtabDisconnectAll(db, pTab);
|
||||
|
||||
rc = sqlite3SafetyOff(db);
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = p->pMod->pModule->xDestroy(p->pVtab);
|
||||
(void)sqlite3SafetyOn(db);
|
||||
|
||||
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -772,10 +759,8 @@ static void callFinaliser(sqlite3 *db, int offset){
|
||||
int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
int rcsafety;
|
||||
VTable **aVTrans = db->aVTrans;
|
||||
|
||||
rc = sqlite3SafetyOff(db);
|
||||
db->aVTrans = 0;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
||||
int (*x)(sqlite3_vtab *);
|
||||
@ -788,11 +773,6 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
}
|
||||
}
|
||||
db->aVTrans = aVTrans;
|
||||
rcsafety = sqlite3SafetyOn(db);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rcsafety;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
109
src/where.c
109
src/where.c
@ -653,7 +653,7 @@ static int isLikeOrGlob(
|
||||
}
|
||||
assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
|
||||
pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
assert( pColl!=0 ); /* Every non-IPK column has a collating sequence */
|
||||
if( pColl==0 ) return 0; /* Happens when LHS has an undefined collation */
|
||||
if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
|
||||
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
|
||||
/* IMP: R-09003-32046 For the GLOB operator, the column must use the
|
||||
@ -1096,7 +1096,7 @@ static void exprAnalyze(
|
||||
Expr *pExpr; /* The expression to be analyzed */
|
||||
Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
|
||||
Bitmask prereqAll; /* Prerequesites of pExpr */
|
||||
Bitmask extraRight = 0; /* */
|
||||
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
|
||||
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
|
||||
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
|
||||
int noCase = 0; /* LIKE/GLOB distinguishes case */
|
||||
@ -1168,7 +1168,8 @@ static void exprAnalyze(
|
||||
pLeft = pDup->pLeft;
|
||||
pNew->leftCursor = pLeft->iTable;
|
||||
pNew->u.leftColumn = pLeft->iColumn;
|
||||
pNew->prereqRight = prereqLeft;
|
||||
testcase( (prereqLeft | extraRight) != prereqLeft );
|
||||
pNew->prereqRight = prereqLeft | extraRight;
|
||||
pNew->prereqAll = prereqAll;
|
||||
pNew->eOperator = operatorMask(pDup->op);
|
||||
}
|
||||
@ -1758,12 +1759,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
(void)sqlite3SafetyOff(pParse->db);
|
||||
WHERETRACE(("xBestIndex for %s\n", pTab->zName));
|
||||
TRACE_IDX_INPUTS(p);
|
||||
rc = pVtab->pModule->xBestIndex(pVtab, p);
|
||||
TRACE_IDX_OUTPUTS(p);
|
||||
(void)sqlite3SafetyOn(pParse->db);
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
@ -3160,7 +3159,7 @@ static Bitmask codeOneLoopStart(
|
||||
nConstraint = nEq;
|
||||
if( pRangeEnd ){
|
||||
Expr *pRight = pRangeEnd->pExpr->pRight;
|
||||
sqlite3ExprCacheRemove(pParse, regBase+nEq);
|
||||
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
|
||||
if( zAff ){
|
||||
@ -3265,13 +3264,14 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
||||
WhereTerm *pFinal; /* Final subterm within the OR-clause. */
|
||||
SrcList oneTab; /* Shortened table list */
|
||||
SrcList *pOrTab; /* Shortened table list or OR-clause generation */
|
||||
|
||||
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
|
||||
int regRowset = 0; /* Register for RowSet object */
|
||||
int regRowid = 0; /* Register holding rowid */
|
||||
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
|
||||
int iRetInit; /* Address of regReturn init */
|
||||
int untestedTerms = 0; /* Some terms not completely tested */
|
||||
int ii;
|
||||
|
||||
pTerm = pLevel->plan.u.pTerm;
|
||||
@ -3280,11 +3280,30 @@ static Bitmask codeOneLoopStart(
|
||||
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
||||
pOrWc = &pTerm->u.pOrInfo->wc;
|
||||
pFinal = &pOrWc->a[pOrWc->nTerm-1];
|
||||
pLevel->op = OP_Return;
|
||||
pLevel->p1 = regReturn;
|
||||
|
||||
/* Set up a SrcList containing just the table being scanned by this loop. */
|
||||
oneTab.nSrc = 1;
|
||||
oneTab.nAlloc = 1;
|
||||
oneTab.a[0] = *pTabItem;
|
||||
/* Set up a new SrcList ni pOrTab containing the table being scanned
|
||||
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
|
||||
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
|
||||
*/
|
||||
if( pWInfo->nLevel>1 ){
|
||||
int nNotReady; /* The number of notReady tables */
|
||||
struct SrcList_item *origSrc; /* Original list of tables */
|
||||
nNotReady = pWInfo->nLevel - iLevel - 1;
|
||||
pOrTab = sqlite3StackAllocRaw(pParse->db,
|
||||
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
||||
if( pOrTab==0 ) return notReady;
|
||||
pOrTab->nAlloc = (i16)(nNotReady + 1);
|
||||
pOrTab->nSrc = pOrTab->nAlloc;
|
||||
memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
|
||||
origSrc = pWInfo->pTabList->a;
|
||||
for(k=1; k<=nNotReady; k++){
|
||||
memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
|
||||
}
|
||||
}else{
|
||||
pOrTab = pWInfo->pTabList;
|
||||
}
|
||||
|
||||
/* Initialize the rowset register to contain NULL. An SQL NULL is
|
||||
** equivalent to an empty rowset.
|
||||
@ -3309,32 +3328,38 @@ static Bitmask codeOneLoopStart(
|
||||
if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
|
||||
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
|
||||
/* Loop through table entries that match term pOrTerm. */
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
|
||||
WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE);
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0,
|
||||
WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
|
||||
if( pSubWInfo ){
|
||||
if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
|
||||
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
|
||||
int r;
|
||||
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
|
||||
regRowid, 0);
|
||||
regRowid);
|
||||
sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
|
||||
sqlite3VdbeCurrentAddr(v)+2, r, iSet);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
|
||||
|
||||
/* The pSubWInfo->untestedTerms flag means that this OR term
|
||||
** contained one or more AND term from a notReady table. The
|
||||
** terms from the notReady table could not be tested and will
|
||||
** need to be tested later.
|
||||
*/
|
||||
if( pSubWInfo->untestedTerms ) untestedTerms = 1;
|
||||
|
||||
/* Finish the loop through table entries that match term pOrTerm. */
|
||||
sqlite3WhereEnd(pSubWInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
|
||||
/* sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); */
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
|
||||
sqlite3VdbeResolveLabel(v, iLoopBody);
|
||||
|
||||
pLevel->op = OP_Return;
|
||||
pLevel->p1 = regReturn;
|
||||
disableTerm(pLevel, pTerm);
|
||||
if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab);
|
||||
if( !untestedTerms ) disableTerm(pLevel, pTerm);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||
|
||||
@ -3362,7 +3387,12 @@ static Bitmask codeOneLoopStart(
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
continue;
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
@ -3385,7 +3415,10 @@ static Bitmask codeOneLoopStart(
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ){
|
||||
assert( pWInfo->untestedTerms );
|
||||
continue;
|
||||
}
|
||||
assert( pTerm->pExpr );
|
||||
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
@ -3528,6 +3561,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
|
||||
int nTabList; /* Number of elements in pTabList */
|
||||
WhereInfo *pWInfo; /* Will become the return value of this function */
|
||||
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
|
||||
Bitmask notReady; /* Cursors that are not yet positioned */
|
||||
@ -3547,6 +3581,13 @@ WhereInfo *sqlite3WhereBegin(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function normally generates a nested loop for all tables in
|
||||
** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should
|
||||
** only generate code for the first table in pTabList and assume that
|
||||
** any cursors associated with subsequent tables are uninitialized.
|
||||
*/
|
||||
nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
|
||||
|
||||
/* Allocate and initialize the WhereInfo structure that will become the
|
||||
** return value. A single allocation is used to store the WhereInfo
|
||||
** struct, the contents of WhereInfo.a[], the WhereClause structure
|
||||
@ -3555,7 +3596,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** some architectures. Hence the ROUND8() below.
|
||||
*/
|
||||
db = pParse->db;
|
||||
nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel));
|
||||
nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
||||
pWInfo = sqlite3DbMallocZero(db,
|
||||
nByteWInfo +
|
||||
sizeof(WhereClause) +
|
||||
@ -3564,7 +3605,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( db->mallocFailed ){
|
||||
goto whereBeginError;
|
||||
}
|
||||
pWInfo->nLevel = pTabList->nSrc;
|
||||
pWInfo->nLevel = nTabList;
|
||||
pWInfo->pParse = pParse;
|
||||
pWInfo->pTabList = pTabList;
|
||||
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
||||
@ -3583,7 +3624,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
/* Special case: a WHERE clause that is constant. Evaluate the
|
||||
** expression and either jump over all of the code or fall thru.
|
||||
*/
|
||||
if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
|
||||
if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
|
||||
sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
|
||||
pWhere = 0;
|
||||
}
|
||||
@ -3603,6 +3644,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** to virtual table cursors are set. This is used to selectively disable
|
||||
** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
|
||||
** with virtual tables.
|
||||
**
|
||||
** Note that bitmasks are created for all pTabList->nSrc tables in
|
||||
** pTabList, not just the first nTabList tables. nTabList is normally
|
||||
** equal to pTabList->nSrc but might be shortened to 1 if the
|
||||
** WHERE_ONETABLE_ONLY flag is set.
|
||||
*/
|
||||
assert( pWC->vmask==0 && pMaskSet->n==0 );
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
@ -3654,7 +3700,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pLevel = pWInfo->a;
|
||||
andFlags = ~0;
|
||||
WHERETRACE(("*** Optimizer Start ***\n"));
|
||||
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||
for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
||||
WhereCost bestPlan; /* Most efficient plan seen so far */
|
||||
Index *pIdx; /* Index for FROM table at pTabItem */
|
||||
int j; /* For looping over FROM tables */
|
||||
@ -3699,8 +3745,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
*/
|
||||
for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
|
||||
Bitmask mask = (isOptimal ? 0 : notReady);
|
||||
assert( (pTabList->nSrc-iFrom)>1 || isOptimal );
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
|
||||
assert( (nTabList-iFrom)>1 || isOptimal );
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
|
||||
int doNotReorder; /* True if this table should not be reordered */
|
||||
WhereCost sCost; /* Cost information from best[Virtual]Index() */
|
||||
ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
|
||||
@ -3797,7 +3843,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** searching those tables.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
||||
Table *pTab; /* Table to open */
|
||||
int iDb; /* Index of database containing table/index */
|
||||
|
||||
@ -3876,7 +3922,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** program.
|
||||
*/
|
||||
notReady = ~(Bitmask)0;
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
for(i=0; i<nTabList; i++){
|
||||
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
|
||||
pWInfo->iContinue = pWInfo->a[i].addrCont;
|
||||
}
|
||||
@ -3888,7 +3934,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** the index is listed as "{}". If the primary key is used the
|
||||
** index name is '*'.
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
for(i=0; i<nTabList; i++){
|
||||
char *z;
|
||||
int n;
|
||||
pLevel = &pWInfo->a[i];
|
||||
@ -3956,7 +4002,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
/* Generate loop termination code.
|
||||
*/
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
for(i=pTabList->nSrc-1; i>=0; i--){
|
||||
for(i=pWInfo->nLevel-1; i>=0; i--){
|
||||
pLevel = &pWInfo->a[i];
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
@ -4002,7 +4048,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
||||
*/
|
||||
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||
assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc );
|
||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
|
||||
@ -481,10 +481,10 @@ do_test analyze3-4.1.2 {
|
||||
sqlite3_bind_text $S 2 "abc" 3
|
||||
execsql { DROP TABLE t1 }
|
||||
sqlite3_step $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_ERROR}
|
||||
do_test analyze3-4.1.3 {
|
||||
sqlite3_finalize $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_ERROR}
|
||||
|
||||
# Check an authorization error.
|
||||
#
|
||||
@ -511,10 +511,10 @@ do_test analyze3-4.2.2 {
|
||||
sqlite3_reset $S
|
||||
sqlite3_bind_text $S 2 "abc" 3
|
||||
sqlite3_step $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_AUTH}
|
||||
do_test analyze3-4.2.4 {
|
||||
sqlite3_finalize $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_AUTH}
|
||||
|
||||
# Check the effect of an authorization error that occurs in a re-prepare
|
||||
# performed by sqlite3_step() is the same as one that occurs within
|
||||
@ -526,10 +526,10 @@ do_test analyze3-4.3.1 {
|
||||
execsql { CREATE TABLE t2(d, e, f) }
|
||||
db auth auth
|
||||
sqlite3_step $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_AUTH}
|
||||
do_test analyze3-4.3.2 {
|
||||
sqlite3_finalize $S
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_AUTH}
|
||||
db auth {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -814,5 +814,25 @@ do_test attach-9.3 {
|
||||
}
|
||||
} {1 2 3 4}
|
||||
|
||||
|
||||
# Ticket [abe728bbc311d81334dae9762f0db87c07a98f79].
|
||||
# Multi-database commit on an attached TEMP database.
|
||||
#
|
||||
do_test attach-10.1 {
|
||||
execsql {
|
||||
ATTACH '' AS noname;
|
||||
ATTACH ':memory:' AS inmem;
|
||||
BEGIN;
|
||||
CREATE TABLE noname.noname(x);
|
||||
CREATE TABLE inmem.inmem(y);
|
||||
CREATE TABLE main.main(z);
|
||||
COMMIT;
|
||||
SELECT name FROM noname.sqlite_master;
|
||||
SELECT name FROM inmem.sqlite_master;
|
||||
}
|
||||
} {noname inmem}
|
||||
do_test attach-10.2 {
|
||||
lrange [execsql {
|
||||
PRAGMA database_list;
|
||||
}] 9 end
|
||||
} {4 noname {} 5 inmem {}}
|
||||
finish_test
|
||||
|
||||
@ -60,4 +60,17 @@ do_malloc_test attachmalloc-2 -tclprep {
|
||||
ATTACH 'test2.db' AS db1;
|
||||
}
|
||||
|
||||
set enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
sqlite3 dbaux test2.db
|
||||
dbaux eval {SELECT * FROM sqlite_master}
|
||||
do_malloc_test attachmalloc-3 -sqlbody {
|
||||
SELECT * FROM sqlite_master;
|
||||
ATTACH 'test2.db' AS two;
|
||||
} -cleanup {
|
||||
db eval { DETACH two }
|
||||
}
|
||||
dbaux close
|
||||
sqlite3_enable_shared_cache $enable_shared_cache
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@ -102,6 +102,7 @@ SQLITE_READ sqlite_master name main {}
|
||||
SQLITE_READ sqlite_master rootpage main {}
|
||||
SQLITE_READ sqlite_master sql main {}
|
||||
SQLITE_READ sqlite_master tbl_name main {}
|
||||
SQLITE_READ sqlite_master ROWID main {}
|
||||
}
|
||||
do_test auth2-2.2 {
|
||||
set ::authargs {}
|
||||
@ -121,6 +122,7 @@ SQLITE_READ sqlite_master name main {}
|
||||
SQLITE_READ sqlite_master rootpage main {}
|
||||
SQLITE_READ sqlite_master sql main {}
|
||||
SQLITE_READ sqlite_master tbl_name main {}
|
||||
SQLITE_READ sqlite_master ROWID main {}
|
||||
}
|
||||
do_test auth2-2.3 {
|
||||
set ::authargs {}
|
||||
|
||||
@ -904,4 +904,63 @@ ifcapable memorymanage {
|
||||
db3 close
|
||||
}
|
||||
|
||||
|
||||
# Test that if the database is written to via the same database handle being
|
||||
# used as the source by a backup operation:
|
||||
#
|
||||
# 10.1.*: If the db is in-memory, the backup is restarted.
|
||||
# 10.2.*: If the db is a file, the backup is not restarted.
|
||||
#
|
||||
db close
|
||||
file delete -force test.db test.db-journal
|
||||
foreach {tn file rc} {
|
||||
1 test.db SQLITE_DONE
|
||||
2 :memory: SQLITE_OK
|
||||
} {
|
||||
do_test backup-10.$tn.1 {
|
||||
sqlite3 db $file
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(NULL, randomblob(200));
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
INSERT INTO t1 SELECT NULL, randomblob(200) FROM t1;
|
||||
COMMIT;
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {256}
|
||||
|
||||
do_test backup-10.$tn.2 {
|
||||
set pgs [execsql {pragma page_count}]
|
||||
expr {$pgs > 50 && $pgs < 75}
|
||||
} {1}
|
||||
|
||||
do_test backup-10.$tn.3 {
|
||||
file delete -force bak.db bak.db-journal
|
||||
sqlite3 db2 bak.db
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 50
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test backup-10.$tn.4 {
|
||||
execsql { UPDATE t1 SET b = randomblob(200) WHERE a IN (1, 250) }
|
||||
} {}
|
||||
|
||||
do_test backup-10.$tn.5 {
|
||||
B step 50
|
||||
} $rc
|
||||
|
||||
do_test backup-10.$tn.6 {
|
||||
B finish
|
||||
} {SQLITE_OK}
|
||||
|
||||
db2 close
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@ -1176,7 +1176,7 @@ do_test capi3c-19.4 {
|
||||
sqlite3_reset $STMT
|
||||
db eval {DROP TABLE t3}
|
||||
sqlite3_step $STMT
|
||||
} SQLITE_SCHEMA
|
||||
} SQLITE_ERROR
|
||||
do_test capi3c-19.4.1 {
|
||||
sqlite3_errmsg $DB
|
||||
} {no such table: t3}
|
||||
|
||||
@ -239,43 +239,43 @@ do_test check-4.3 {
|
||||
SELECT * FROM t4
|
||||
}
|
||||
} {4 3}
|
||||
do_test check-4.3 {
|
||||
do_test check-4.4 {
|
||||
execsql {
|
||||
UPDATE t4 SET x=12, y=2;
|
||||
SELECT * FROM t4
|
||||
}
|
||||
} {12 2}
|
||||
do_test check-4.4 {
|
||||
do_test check-4.5 {
|
||||
execsql {
|
||||
UPDATE t4 SET x=12, y=-22;
|
||||
SELECT * FROM t4
|
||||
}
|
||||
} {12 -22}
|
||||
do_test check-4.5 {
|
||||
do_test check-4.6 {
|
||||
catchsql {
|
||||
UPDATE t4 SET x=0, y=1;
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test check-4.6 {
|
||||
do_test check-4.7 {
|
||||
execsql {
|
||||
SELECT * FROM t4;
|
||||
}
|
||||
} {12 -22}
|
||||
do_test check-4.7 {
|
||||
do_test check-4.8 {
|
||||
execsql {
|
||||
PRAGMA ignore_check_constraints=ON;
|
||||
UPDATE t4 SET x=0, y=1;
|
||||
SELECT * FROM t4;
|
||||
}
|
||||
} {0 1}
|
||||
do_test check-4.8 {
|
||||
do_test check-4.9 {
|
||||
catchsql {
|
||||
PRAGMA ignore_check_constraints=OFF;
|
||||
UPDATE t4 SET x=0, y=2;
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
ifcapable vacuum {
|
||||
do_test check_4.9 {
|
||||
do_test check_4.10 {
|
||||
catchsql {
|
||||
VACUUM
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# 2004 August 30
|
||||
# 2004 August 30 {}
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
@ -311,4 +311,41 @@ ifcapable oversize_cell_check {
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
|
||||
db close
|
||||
file delete -force test.db test.db-journal
|
||||
do_test corrupt-8.1 {
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA secure_delete = on;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(5, randomblob(1900));
|
||||
}
|
||||
|
||||
hexio_write test.db 2044 [hexio_render_int32 2]
|
||||
hexio_write test.db 24 [hexio_render_int32 45]
|
||||
|
||||
catchsql { INSERT OR REPLACE INTO t1 VALUES(5, randomblob(1900)) }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
db close
|
||||
file delete -force test.db test.db-journal
|
||||
do_test corrupt-8.2 {
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA secure_delete = on;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(5, randomblob(900));
|
||||
INSERT INTO t1 VALUES(6, randomblob(900));
|
||||
}
|
||||
|
||||
hexio_write test.db 2047 FF
|
||||
hexio_write test.db 24 [hexio_render_int32 45]
|
||||
|
||||
catchsql { INSERT INTO t1 VALUES(4, randomblob(1900)) }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
@ -89,7 +89,7 @@ Corruption detected in cell 15 on page 2}}
|
||||
sqlite3 db test.db
|
||||
db eval {PRAGMA integrity_check(1)}
|
||||
} {{*** in database main ***
|
||||
Corruption detected in cell 15 on page 2}}
|
||||
On tree page 2 cell 15: Rowid 0 out of order (previous was 15)}}
|
||||
}
|
||||
|
||||
# The code path that was causing the buffer overrun that this test
|
||||
|
||||
171
test/corruptE.test
Normal file
171
test/corruptE.test
Normal file
@ -0,0 +1,171 @@
|
||||
# 2010 February 18
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This file implements tests to make sure SQLite does not crash or
|
||||
# segfault if it sees a corrupt database file. It specifcally
|
||||
# focuses on rowid order corruption.
|
||||
#
|
||||
# $Id: corruptE.test,v 1.14 2009/07/11 06:55:34 danielk1977 Exp $
|
||||
|
||||
catch {file delete -force test.db test.db-journal test.bu}
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Construct a compact, dense database for testing.
|
||||
#
|
||||
do_test corruptE-1.1 {
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA legacy_file_format=1;
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x,y);
|
||||
INSERT INTO t1 VALUES(1,1);
|
||||
INSERT OR IGNORE INTO t1 SELECT x*2,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*3,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*5,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*7,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*11,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*13,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*17,y FROM t1;
|
||||
INSERT OR IGNORE INTO t1 SELECT x*19,y FROM t1;
|
||||
CREATE INDEX t1i1 ON t1(x);
|
||||
CREATE TABLE t2 AS SELECT x,2 as y FROM t1 WHERE rowid%5!=0;
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
ifcapable {integrityck} {
|
||||
integrity_check corruptE-1.2
|
||||
}
|
||||
|
||||
# Copy file $from into $to
|
||||
#
|
||||
proc copy_file {from to} {
|
||||
file copy -force $from $to
|
||||
}
|
||||
|
||||
# Setup for the tests. Make a backup copy of the good database in test.bu.
|
||||
#
|
||||
db close
|
||||
copy_file test.db test.bu
|
||||
sqlite3 db test.db
|
||||
set fsize [file size test.db]
|
||||
|
||||
|
||||
do_test corruptE-2.1 {
|
||||
db close
|
||||
copy_file test.bu test.db
|
||||
|
||||
# insert corrupt byte(s)
|
||||
hexio_write test.db 2041 [format %02x 0x2e]
|
||||
|
||||
sqlite3 db test.db
|
||||
|
||||
set res [ catchsql {PRAGMA integrity_check} ]
|
||||
set ans [lindex $res 1]
|
||||
|
||||
list [regexp {out of order.*previous was} $ans] \
|
||||
[regexp {out of order.*max larger than parent max} $ans]
|
||||
} {1 1}
|
||||
|
||||
do_test corruptE-2.2 {
|
||||
db close
|
||||
copy_file test.bu test.db
|
||||
|
||||
# insert corrupt byte(s)
|
||||
hexio_write test.db 2047 [format %02x 0x84]
|
||||
|
||||
sqlite3 db test.db
|
||||
|
||||
set res [ catchsql {PRAGMA integrity_check} ]
|
||||
set ans [lindex $res 1]
|
||||
|
||||
list [regexp {out of order.*previous was} $ans] \
|
||||
[regexp {out of order.*min less than parent min} $ans]
|
||||
} {1 1}
|
||||
|
||||
do_test corruptE-2.3 {
|
||||
db close
|
||||
copy_file test.bu test.db
|
||||
|
||||
# insert corrupt byte(s)
|
||||
hexio_write test.db 7420 [format %02x 0xa8]
|
||||
hexio_write test.db 10459 [format %02x 0x8d]
|
||||
|
||||
sqlite3 db test.db
|
||||
|
||||
set res [ catchsql {PRAGMA integrity_check} ]
|
||||
set ans [lindex $res 1]
|
||||
|
||||
list [regexp {out of order.*max larger than parent min} $ans]
|
||||
} {1}
|
||||
|
||||
do_test corruptE-2.4 {
|
||||
db close
|
||||
copy_file test.bu test.db
|
||||
|
||||
# insert corrupt byte(s)
|
||||
hexio_write test.db 10233 [format %02x 0xd0]
|
||||
|
||||
sqlite3 db test.db
|
||||
|
||||
set res [ catchsql {PRAGMA integrity_check} ]
|
||||
set ans [lindex $res 1]
|
||||
|
||||
list [regexp {out of order.*min less than parent max} $ans]
|
||||
} {1}
|
||||
|
||||
|
||||
set tests [list {10233 0xd0} \
|
||||
{941 0x42} \
|
||||
{1028 0x53} \
|
||||
{2041 0xd0} \
|
||||
{2042 0x1f} \
|
||||
{2047 0xaa} \
|
||||
{2263 0x29} \
|
||||
{2274 0x75} \
|
||||
{3267 0xf2} \
|
||||
{4104 0x2c} \
|
||||
{5113 0x36} \
|
||||
{10233 0x84} \
|
||||
{10234 0x74} \
|
||||
{10239 0x41} \
|
||||
{10453 0x11} \
|
||||
{11273 0x28} \
|
||||
{11455 0x11} \
|
||||
{11461 0xe6} \
|
||||
{12281 0x99} \
|
||||
{12296 0x9e} \
|
||||
{12297 0xd7} \
|
||||
{13303 0x53} ]
|
||||
|
||||
set tc 1
|
||||
foreach test $tests {
|
||||
do_test corruptE-3.$tc {
|
||||
db close
|
||||
copy_file test.bu test.db
|
||||
|
||||
# insert corrupt byte(s)
|
||||
hexio_write test.db [lindex $test 0] [format %02x [lindex $test 1]]
|
||||
|
||||
sqlite3 db test.db
|
||||
|
||||
set res [ catchsql {PRAGMA integrity_check} ]
|
||||
set ans [lindex $res 1]
|
||||
|
||||
list [regexp {out of order} $ans]
|
||||
} {1}
|
||||
incr tc 1
|
||||
}
|
||||
|
||||
finish_test
|
||||
@ -340,4 +340,62 @@ ifcapable pragma {
|
||||
} {jkl}
|
||||
}
|
||||
|
||||
for {set i 1} {$i < 10} {incr i} {
|
||||
catch { db close }
|
||||
file delete -force test.db test.db-journal
|
||||
sqlite3 db test.db
|
||||
do_test crash8-5.$i.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(x PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */
|
||||
}
|
||||
crashsql -file test.db -delay [expr ($::i%2) + 1] {
|
||||
PRAGMA cache_size = 10;
|
||||
BEGIN;
|
||||
UPDATE t1 SET x = randomblob(900);
|
||||
ROLLBACK;
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
}
|
||||
execsql { PRAGMA integrity_check }
|
||||
} {ok}
|
||||
|
||||
catch { db close }
|
||||
file delete -force test.db test.db-journal
|
||||
sqlite3 db test.db
|
||||
do_test crash8-5.$i.2 {
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
CREATE TABLE t1(x PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 rows */
|
||||
BEGIN;
|
||||
UPDATE t1 SET x = randomblob(900);
|
||||
}
|
||||
file delete -force testX.db testX.db-journal
|
||||
copy_file test.db testX.db
|
||||
copy_file test.db-journal testX.db-journal
|
||||
db close
|
||||
|
||||
crashsql -file test.db -delay [expr ($::i%2) + 1] {
|
||||
SELECT * FROM sqlite_master;
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
}
|
||||
|
||||
sqlite3 db2 testX.db
|
||||
execsql { PRAGMA integrity_check } db2
|
||||
} {ok}
|
||||
}
|
||||
catch {db2 close}
|
||||
|
||||
finish_test
|
||||
|
||||
224
test/ctime.test
Normal file
224
test/ctime.test
Normal file
@ -0,0 +1,224 @@
|
||||
# 2009 February 24
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This file implements tests for the compile time diagnostic
|
||||
# functions.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Test organization:
|
||||
#
|
||||
# ctime-1.*: Test pragma support.
|
||||
# ctime-2.*: Test function support.
|
||||
#
|
||||
|
||||
ifcapable !pragma||!compileoption_diags {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#####################
|
||||
# ctime-1.*: Test pragma support.
|
||||
|
||||
do_test ctime-1.1.1 {
|
||||
catchsql {
|
||||
PRAGMA compile_options();
|
||||
}
|
||||
} {1 {near ")": syntax error}}
|
||||
do_test ctime-1.1.2 {
|
||||
catchsql {
|
||||
PRAGMA compile_options(NULL);
|
||||
}
|
||||
} {1 {near "NULL": syntax error}}
|
||||
do_test ctime-1.1.3 {
|
||||
catchsql {
|
||||
PRAGMA compile_options *;
|
||||
}
|
||||
} {1 {near "*": syntax error}}
|
||||
|
||||
do_test ctime-1.2.1 {
|
||||
set ans [ catchsql {
|
||||
PRAGMA compile_options;
|
||||
} ]
|
||||
list [ lindex $ans 0 ]
|
||||
} {0}
|
||||
# the results should be in sorted order already
|
||||
do_test ctime-1.2.2 {
|
||||
set ans [ catchsql {
|
||||
PRAGMA compile_options;
|
||||
} ]
|
||||
list [ lindex $ans 0 ] [ expr { [lsort [lindex $ans 1]]==[lindex $ans 1] } ]
|
||||
} {0 1}
|
||||
|
||||
# SQLITE_THREADSAFE should pretty much always be defined
|
||||
# one way or the other, and it must have a value of 0 or 1.
|
||||
do_test ctime-1.4.1 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used('SQLITE_THREADSAFE');
|
||||
}
|
||||
} {0 1}
|
||||
do_test ctime-1.4.2 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used('THREADSAFE');
|
||||
}
|
||||
} {0 1}
|
||||
do_test ctime-1.4.3 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used("THREADSAFE");
|
||||
}
|
||||
} {0 1}
|
||||
|
||||
do_test ctime-1.5 {
|
||||
set ans1 [ catchsql {
|
||||
SELECT sqlite_compileoption_used('THREADSAFE=0');
|
||||
} ]
|
||||
set ans2 [ catchsql {
|
||||
SELECT sqlite_compileoption_used('THREADSAFE=1');
|
||||
} ]
|
||||
lsort [ list $ans1 $ans2 ]
|
||||
} {{0 0} {0 1}}
|
||||
|
||||
do_test ctime-1.6 {
|
||||
execsql {
|
||||
SELECT sqlite_compileoption_used('THREADSAFE=');
|
||||
}
|
||||
} {0}
|
||||
|
||||
do_test ctime-1.7.1 {
|
||||
execsql {
|
||||
SELECT sqlite_compileoption_used('SQLITE_OMIT_COMPILEOPTION_DIAGS');
|
||||
}
|
||||
} {0}
|
||||
do_test ctime-1.7.2 {
|
||||
execsql {
|
||||
SELECT sqlite_compileoption_used('OMIT_COMPILEOPTION_DIAGS');
|
||||
}
|
||||
} {0}
|
||||
|
||||
#####################
|
||||
# ctime-2.*: Test function support.
|
||||
|
||||
do_test ctime-2.1.1 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used();
|
||||
}
|
||||
} {1 {wrong number of arguments to function sqlite_compileoption_used()}}
|
||||
do_test ctime-2.1.2 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used(NULL);
|
||||
}
|
||||
} {0 {{}}}
|
||||
do_test ctime-2.1.3 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used("");
|
||||
}
|
||||
} {0 0}
|
||||
do_test ctime-2.1.4 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used('');
|
||||
}
|
||||
} {0 0}
|
||||
do_test ctime-2.1.5 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used(foo);
|
||||
}
|
||||
} {1 {no such column: foo}}
|
||||
do_test ctime-2.1.6 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used('THREADSAFE', 0);
|
||||
}
|
||||
} {1 {wrong number of arguments to function sqlite_compileoption_used()}}
|
||||
do_test ctime-2.1.7 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used(0);
|
||||
}
|
||||
} {0 0}
|
||||
do_test ctime-2.1.8 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used('0');
|
||||
}
|
||||
} {0 0}
|
||||
do_test ctime-2.1.9 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used(1.0);
|
||||
}
|
||||
} {0 0}
|
||||
|
||||
do_test ctime-2.2.1 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_get();
|
||||
}
|
||||
} {1 {wrong number of arguments to function sqlite_compileoption_get()}}
|
||||
do_test ctime-2.2.2 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_get(0, 0);
|
||||
}
|
||||
} {1 {wrong number of arguments to function sqlite_compileoption_get()}}
|
||||
|
||||
# This assumes there is at least 1 compile time option
|
||||
# (see SQLITE_THREADSAFE above).
|
||||
do_test ctime-2.3 {
|
||||
catchsql {
|
||||
SELECT sqlite_compileoption_used(sqlite_compileoption_get(0));
|
||||
}
|
||||
} {0 1}
|
||||
|
||||
# This assumes there is at least 1 compile time option
|
||||
# (see SQLITE_THREADSAFE above).
|
||||
do_test ctime-2.4 {
|
||||
set ans [ catchsql {
|
||||
SELECT sqlite_compileoption_get(0);
|
||||
} ]
|
||||
list [lindex $ans 0]
|
||||
} {0}
|
||||
|
||||
# Get the list of defines using the pragma,
|
||||
# then try querying each one with the functions.
|
||||
set ans [ catchsql {
|
||||
PRAGMA compile_options;
|
||||
} ]
|
||||
set opts [ lindex $ans 1 ]
|
||||
set tc 1
|
||||
foreach opt $opts {
|
||||
do_test ctime-2.5.$tc {
|
||||
set N [ expr {$tc-1} ]
|
||||
set ans1 [ catchsql {
|
||||
SELECT sqlite_compileoption_get($N);
|
||||
} ]
|
||||
set ans2 [ catchsql {
|
||||
SELECT sqlite_compileoption_used($opt);
|
||||
} ]
|
||||
list [ lindex $ans1 0 ] [ expr { [lindex $ans1 1]==$opt } ] \
|
||||
[ expr { $ans2 } ]
|
||||
} {0 1 {0 1}}
|
||||
incr tc 1
|
||||
}
|
||||
# test 1 past array bounds
|
||||
do_test ctime-2.5.$tc {
|
||||
set N [ expr {$tc-1} ]
|
||||
set ans [ catchsql {
|
||||
SELECT sqlite_compileoption_get($N);
|
||||
} ]
|
||||
} {0 {{}}}
|
||||
incr tc 1
|
||||
# test 1 before array bounds (N=-1)
|
||||
do_test ctime-2.5.$tc {
|
||||
set N -1
|
||||
set ans [ catchsql {
|
||||
SELECT sqlite_compileoption_get($N);
|
||||
} ]
|
||||
} {0 {{}}}
|
||||
|
||||
|
||||
finish_test
|
||||
531
test/e_fkey.test
531
test/e_fkey.test
File diff suppressed because it is too large
Load Diff
248
test/e_fts3.test
248
test/e_fts3.test
@ -20,6 +20,7 @@ source $testdir/tester.tcl
|
||||
#
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
source $testdir/fts3_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
# Procs used to make the tests in this file easier to read.
|
||||
#
|
||||
@ -46,7 +47,14 @@ proc error_test {tn sql result} {
|
||||
# DO_MALLOC_TEST=1: Run tests with transient OOM errors.
|
||||
# DO_MALLOC_TEST=2: Run tests with persistent OOM errors.
|
||||
#
|
||||
foreach DO_MALLOC_TEST [lrange {0 1 2} 0 end] {
|
||||
foreach {DO_MALLOC_TEST enc} {
|
||||
0 utf-8
|
||||
1 utf-8
|
||||
2 utf-8
|
||||
1 utf-16
|
||||
} {
|
||||
|
||||
#if {$DO_MALLOC_TEST} break
|
||||
|
||||
# Reset the database and database connection. If this iteration of the
|
||||
# [foreach] loop is testing with OOM errors, disable the lookaside buffer.
|
||||
@ -55,6 +63,15 @@ db close
|
||||
file delete -force test.db test.db-journal
|
||||
sqlite3 db test.db
|
||||
if {$DO_MALLOC_TEST} { sqlite3_db_config_lookaside db 0 0 0 }
|
||||
db eval "PRAGMA encoding = '$enc'"
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
set scan(bigEndian) I*
|
||||
binary scan $blob $scan($::tcl_platform(byteOrder)) r
|
||||
return $r
|
||||
}
|
||||
db func mit mit
|
||||
|
||||
##########################################################################
|
||||
# Test the example CREATE VIRTUAL TABLE statements in section 1.1
|
||||
@ -175,7 +192,7 @@ write_test 1.2.2.4 docs_content {
|
||||
}
|
||||
read_test 1.2.2.5 { SELECT count(*) FROM docs_segdir } {3}
|
||||
write_test 1.2.2.6 docs_segdir {
|
||||
SELECT * FROM (SELECT optimize(docs) FROM docs LIMIT 1) WHERE 0;
|
||||
INSERT INTO docs(docs) VALUES('optimize');
|
||||
}
|
||||
read_test 1.2.2.7 { SELECT count(*) FROM docs_segdir } {1}
|
||||
ddl_test 1.2.2.8 { DROP TABLE docs }
|
||||
@ -402,7 +419,7 @@ read_test 1.7.1.6 {
|
||||
|
||||
ddl_test 1.7.2.1 { CREATE VIRTUAL TABLE text USING fts3() }
|
||||
|
||||
write_test 3.2.2 text_content {
|
||||
write_test 1.7.2.2 text_content {
|
||||
INSERT INTO text VALUES('
|
||||
During 30 Nov-1 Dec, 2-3oC drops. Cool in the upper portion, minimum temperature 14-16oC and cool elsewhere, minimum temperature 17-20oC. Cold to very cold on mountaintops, minimum temperature 6-12oC. Northeasterly winds 15-30 km/hr. After that, temperature increases. Northeasterly winds 15-30 km/hr.
|
||||
');
|
||||
@ -410,11 +427,28 @@ write_test 3.2.2 text_content {
|
||||
|
||||
read_test 1.7.2.3 {
|
||||
SELECT snippet(text) FROM text WHERE text MATCH 'cold'
|
||||
} {{<b>...</b> elsewhere, minimum temperature 17-20oC. <b>Cold</b> to very <b>cold</b> on mountaintops, minimum <b>...</b>}}
|
||||
} {{<b>...</b>cool elsewhere, minimum temperature 17-20oC. <b>Cold</b> to very <b>cold</b> on mountaintops, minimum temperature 6<b>...</b>}}
|
||||
|
||||
read_test 1.7.2.4 {
|
||||
SELECT snippet(text, '[', ']', '...') FROM text WHERE text MATCH '"min* tem*"'
|
||||
} {{... 2-3oC drops. Cool in the upper portion, [minimum] [temperature] 14-16oC and cool elsewhere, [minimum] ...}}
|
||||
} {{...the upper portion, [minimum] [temperature] 14-16oC and cool elsewhere, [minimum] [temperature] 17-20oC. Cold...}}
|
||||
|
||||
ddl_test 1.7.3.1 { DROP TABLE IF EXISTS t1 }
|
||||
ddl_test 1.7.3.2 { CREATE VIRTUAL TABLE t1 USING fts3(a, b) }
|
||||
write_test 1.7.3.3 t1_content {
|
||||
INSERT INTO t1 VALUES(
|
||||
'transaction default models default', 'Non transaction reads');
|
||||
}
|
||||
write_test 1.7.3.4 t1_content {
|
||||
INSERT INTO t1 VALUES('the default transaction', 'these semantics present');
|
||||
}
|
||||
write_test 1.7.3.5 t1_content {
|
||||
INSERT INTO t1 VALUES('single request', 'default data');
|
||||
}
|
||||
read_test 1.7.3.6 {
|
||||
SELECT mit(matchinfo(t1)) FROM t1
|
||||
WHERE t1 MATCH 'default transaction "these semantics"';
|
||||
} {{3 2 1 3 2 0 1 1 1 2 2 0 1 1 0 0 0 1 1 1}}
|
||||
|
||||
##########################################################################
|
||||
# Test the example in section 5 (custom tokenizers).
|
||||
@ -443,6 +477,7 @@ read_test 1.8.2.4 {
|
||||
# functions are handled correctly.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 2.1.0 { DROP TABLE IF EXISTS t1 }
|
||||
ddl_test 2.1.1 { CREATE VIRTUAL TABLE t1 USING fts3(a, b) }
|
||||
write_test 2.1.2 t1_content {
|
||||
INSERT INTO t1 VALUES('one two three', x'A1B2C3D4E5F6');
|
||||
@ -463,7 +498,208 @@ error_test 2.1.7 {
|
||||
SELECT snippet() FROM t1 WHERE a MATCH 'one'
|
||||
} {unable to use function snippet in the requested context}
|
||||
error_test 2.1.8 {
|
||||
SELECT snippet(a, b, 'A', 'B', 'C') FROM t1 WHERE a MATCH 'one'
|
||||
SELECT snippet(a, b, 'A', 'B', 'C', 'D', 'E') FROM t1 WHERE a MATCH 'one'
|
||||
} {wrong number of arguments to function snippet()}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the effect of an OOM error while installing the FTS3 module (i.e.
|
||||
# opening a database handle). This case was not tested by the OOM testing
|
||||
# of the document examples above.
|
||||
#
|
||||
do_malloc_test e_fts3-3 -tclbody {
|
||||
if {[catch {sqlite3 db test.db}]} { error "out of memory" }
|
||||
}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify the return values of the optimize() function. If no error occurs,
|
||||
# the returned value should be "Index optimized" if the data structure
|
||||
# was modified, or "Index already optimal" if it were not.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 4.1 { CREATE VIRTUAL TABLE t4 USING fts3(a, b) }
|
||||
write_test 4.2 t4_content {
|
||||
INSERT INTO t4 VALUES('In Xanadu', 'did Kubla Khan');
|
||||
}
|
||||
write_test 4.3 t4_content {
|
||||
INSERT INTO t4 VALUES('a stately pleasure', 'dome decree');
|
||||
}
|
||||
do_test e_fts3-4.4 {
|
||||
execsql { SELECT optimize(t4) FROM t4 LIMIT 1 }
|
||||
} {{Index optimized}}
|
||||
do_test e_fts3-4.5 {
|
||||
execsql { SELECT optimize(t4) FROM t4 LIMIT 1 }
|
||||
} {{Index already optimal}}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the snippet function appears to work correctly with 1, 2, 3
|
||||
# or 4 arguments passed to it.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 5.1 { CREATE VIRTUAL TABLE t5 USING fts3(x) }
|
||||
write_test 5.2 t5_content {
|
||||
INSERT INTO t5 VALUES('In Xanadu did Kubla Khan A stately pleasure-dome decree Where Alph, the sacred river, ran Through caverns measureless to man Down to a sunless sea. So twice five miles of fertile ground With walls and towers were girdled round : And there were gardens bright with sinuous rills, Where blossomed many an incense-bearing tree ; And here were forests ancient as the hills, Enfolding sunny spots of greenery.');
|
||||
}
|
||||
read_test 5.3 {
|
||||
SELECT snippet(t5) FROM t5 WHERE t5 MATCH 'miles'
|
||||
} {{<b>...</b>to a sunless sea. So twice five <b>miles</b> of fertile ground With walls and towers<b>...</b>}}
|
||||
read_test 5.4 {
|
||||
SELECT snippet(t5, '<i>') FROM t5 WHERE t5 MATCH 'miles'
|
||||
} {{<b>...</b>to a sunless sea. So twice five <i>miles</b> of fertile ground With walls and towers<b>...</b>}}
|
||||
read_test 5.5 {
|
||||
SELECT snippet(t5, '<i>', '</i>') FROM t5 WHERE t5 MATCH 'miles'
|
||||
} {{<b>...</b>to a sunless sea. So twice five <i>miles</i> of fertile ground With walls and towers<b>...</b>}}
|
||||
read_test 5.6 {
|
||||
SELECT snippet(t5, '<i>', '</i>', 'XXX') FROM t5 WHERE t5 MATCH 'miles'
|
||||
} {{XXXto a sunless sea. So twice five <i>miles</i> of fertile ground With walls and towersXXX}}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that an empty MATCH expression returns an empty result set. As
|
||||
# does passing a NULL value as a MATCH expression.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 6.1 { CREATE VIRTUAL TABLE t6 USING fts3(x) }
|
||||
write_test 6.2 t5_content { INSERT INTO t6 VALUES('a'); }
|
||||
write_test 6.3 t5_content { INSERT INTO t6 VALUES('b'); }
|
||||
write_test 6.4 t5_content { INSERT INTO t6 VALUES('c'); }
|
||||
read_test 6.5 { SELECT * FROM t6 WHERE t6 MATCH '' } {}
|
||||
read_test 6.6 { SELECT * FROM t6 WHERE x MATCH '' } {}
|
||||
read_test 6.7 { SELECT * FROM t6 WHERE t6 MATCH NULL } {}
|
||||
read_test 6.8 { SELECT * FROM t6 WHERE x MATCH NULL } {}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a few facets of the FTS3 xFilter() callback implementation:
|
||||
#
|
||||
# 1. That the sqlite3_index_constraint.usable flag is respected.
|
||||
#
|
||||
# 2. That it is an error to use the "docid" or "rowid" column of
|
||||
# an FTS3 table as the LHS of a MATCH operator.
|
||||
#
|
||||
# 3. That it is an error to AND together two MATCH expressions in
|
||||
# that refer to a single FTS3 table in a WHERE clause.
|
||||
#
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 7.1.1 { CREATE VIRTUAL TABLE t7 USING fts3(a) }
|
||||
ddl_test 7.1.2 { CREATE VIRTUAL TABLE t8 USING fts3(b) }
|
||||
write_test 7.1.3 t7_content { INSERT INTO t7(docid, a) VALUES(4,'number four') }
|
||||
write_test 7.1.4 t7_content { INSERT INTO t7(docid, a) VALUES(5,'number five') }
|
||||
write_test 7.1.5 t8_content { INSERT INTO t8(docid, b) VALUES(4,'letter D') }
|
||||
write_test 7.1.6 t8_content { INSERT INTO t8(docid, b) VALUES(5,'letter E') }
|
||||
read_test 7.1.7 {
|
||||
SELECT a || ':' || b FROM t7 JOIN t8 USING(docid)
|
||||
} {{number four:letter D} {number five:letter E}}
|
||||
|
||||
error_test 7.2.1 {
|
||||
SELECT * FROM t7 WHERE docid MATCH 'number'
|
||||
} {unable to use function MATCH in the requested context}
|
||||
error_test 7.2.2 {
|
||||
SELECT * FROM t7 WHERE rowid MATCH 'number'
|
||||
} {unable to use function MATCH in the requested context}
|
||||
|
||||
error_test 7.3.1 {
|
||||
SELECT * FROM t7 WHERE a MATCH 'number' AND a MATCH 'four'
|
||||
} {unable to use function MATCH in the requested context}
|
||||
error_test 7.3.2 {
|
||||
SELECT * FROM t7, t8 WHERE a MATCH 'number' AND a MATCH 'four'
|
||||
} {unable to use function MATCH in the requested context}
|
||||
error_test 7.3.3 {
|
||||
SELECT * FROM t7, t8 WHERE b MATCH 'letter' AND b MATCH 'd'
|
||||
} {unable to use function MATCH in the requested context}
|
||||
read_test 7.3.4 {
|
||||
SELECT * FROM t7, t8 WHERE a MATCH 'number' AND b MATCH 'letter'
|
||||
} {{number four} {letter D} {number four} {letter E} {number five} {letter D} {number five} {letter E}}
|
||||
read_test 7.3.5 {
|
||||
SELECT * FROM t7 WHERE a MATCH 'number' AND docid = 4
|
||||
} {{number four}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the quoting of FTS3 table column names. Names may be quoted using
|
||||
# any of "", '', ``` or [].
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 8.1.1 { CREATE VIRTUAL TABLE t9a USING fts3("c1", [c2]) }
|
||||
ddl_test 8.1.2 { CREATE VIRTUAL TABLE t9b USING fts3('c1', `c2`) }
|
||||
read_test 8.1.3 { PRAGMA table_info(t9a) } {0 c1 {} 0 {} 0 1 c2 {} 0 {} 0}
|
||||
read_test 8.1.4 { PRAGMA table_info(t9b) } {0 c1 {} 0 {} 0 1 c2 {} 0 {} 0}
|
||||
ddl_test 8.2.1 { CREATE VIRTUAL TABLE t9c USING fts3("c""1", 'c''2') }
|
||||
read_test 8.2.2 { PRAGMA table_info(t9c) } {0 c\"1 {} 0 {} 0 1 c'2 {} 0 {} 0}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that FTS3 tables can be renamed using the ALTER RENAME command.
|
||||
# OOM errors are tested during ALTER RENAME commands also.
|
||||
#
|
||||
foreach DO_MALLOC_TEST {0 1 2} {
|
||||
db close
|
||||
file delete -force test.db test.db-journal
|
||||
sqlite3 db test.db
|
||||
if {$DO_MALLOC_TEST} { sqlite3_db_config_lookaside db 0 0 0 }
|
||||
|
||||
ddl_test 9.1.1 { CREATE VIRTUAL TABLE t10 USING fts3(x) }
|
||||
write_test 9.1.2 t10_content { INSERT INTO t10 VALUES('fts3 tables') }
|
||||
write_test 9.1.3 t10_content { INSERT INTO t10 VALUES('are renameable') }
|
||||
|
||||
read_test 9.1.4 {
|
||||
SELECT * FROM t10 WHERE t10 MATCH 'table*'
|
||||
} {{fts3 tables}}
|
||||
read_test 9.1.5 {
|
||||
SELECT * FROM t10 WHERE x MATCH 'rename*'
|
||||
} {{are renameable}}
|
||||
|
||||
ddl_test 9.1.6 { ALTER TABLE t10 RENAME TO t11 }
|
||||
|
||||
read_test 9.1.7 {
|
||||
SELECT * FROM t11 WHERE t11 MATCH 'table*'
|
||||
} {{fts3 tables}}
|
||||
read_test 9.1.8 {
|
||||
SELECT * FROM t11 WHERE x MATCH 'rename*'
|
||||
} {{are renameable}}
|
||||
}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a couple of cases involving corrupt data structures:
|
||||
#
|
||||
# 1) A case where a document referenced by the full-text index is
|
||||
# not present in the %_content table.
|
||||
#
|
||||
# 2) A badly formatted b-tree segment node.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
ddl_test 10.1.1 { CREATE VIRTUAL TABLE ta USING fts3 }
|
||||
write_test 10.1.2 ta_content {
|
||||
INSERT INTO ta VALUES('During a summer vacation in 1790') }
|
||||
write_test 10.1.3 ta_content {
|
||||
INSERT INTO ta VALUES('Wordsworth went on a walking tour') }
|
||||
write_test 10.1.4 ta_content { DELETE FROM ta_content WHERE rowid = 2 }
|
||||
read_test 10.1.5 {
|
||||
SELECT * FROM ta WHERE ta MATCH 'summer'
|
||||
} {{During a summer vacation in 1790}}
|
||||
error_test 10.1.6 {
|
||||
SELECT * FROM ta WHERE ta MATCH 'walking'
|
||||
} {database disk image is malformed}
|
||||
|
||||
write_test 10.2.1 ta_content { DELETE FROM ta }
|
||||
write_test 10.2.2 ta_content {
|
||||
INSERT INTO ta VALUES('debate demonstrated the rising difficulty') }
|
||||
write_test 10.2.3 ta_content {
|
||||
INSERT INTO ta VALUES('Google released its browser beta') }
|
||||
|
||||
set blob [db one {SELECT root FROM ta_segdir WHERE rowid = 2}]
|
||||
binary scan $blob "a6 a3 a*" start middle end
|
||||
set middle "\x0E\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x06\x06"
|
||||
set blob [binary format "a6 a* a*" $start $middle $end]
|
||||
write_test 10.2.4 ta_segdir {
|
||||
UPDATE ta_segdir SET root = $blob WHERE rowid = 2
|
||||
}
|
||||
error_test 10.2.5 {
|
||||
SELECT * FROM ta WHERE ta MATCH 'beta'
|
||||
} {database disk image is malformed}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
163
test/fkey2.test
163
test/fkey2.test
@ -1003,6 +1003,169 @@ ifcapable altertable {
|
||||
do_test fkey2-14.2.2.7 {
|
||||
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
|
||||
} {}
|
||||
|
||||
# Repeat for TEMP tables
|
||||
#
|
||||
drop_all_tables
|
||||
do_test fkey2-14.1tmp.1 {
|
||||
# Adding a column with a REFERENCES clause is not supported.
|
||||
execsql {
|
||||
CREATE TEMP TABLE t1(a PRIMARY KEY);
|
||||
CREATE TEMP TABLE t2(a, b);
|
||||
}
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1tmp.2 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1tmp.3 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1tmp.4 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
do_test fkey2-14.1tmp.5 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
do_test fkey2-14.1tmp.6 {
|
||||
execsql {
|
||||
PRAGMA foreign_keys = off;
|
||||
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
|
||||
PRAGMA foreign_keys = on;
|
||||
SELECT sql FROM sqlite_temp_master WHERE name='t2';
|
||||
}
|
||||
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
|
||||
|
||||
do_test fkey2-14.2tmp.1.1 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||
do_test fkey2-14.2tmp.1.2 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES t2)}}
|
||||
do_test fkey2-14.2tmp.1.3 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||
|
||||
# Test ALTER TABLE RENAME TABLE a bit.
|
||||
#
|
||||
do_test fkey2-14.2tmp.2.1 {
|
||||
drop_all_tables
|
||||
execsql {
|
||||
CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1);
|
||||
CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
|
||||
CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
|
||||
}
|
||||
execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
|
||||
} [list \
|
||||
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)} \
|
||||
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)} \
|
||||
{CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \
|
||||
]
|
||||
do_test fkey2-14.2tmp.2.2 {
|
||||
execsql { ALTER TABLE t1 RENAME TO t4 }
|
||||
execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
|
||||
} [list \
|
||||
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")} \
|
||||
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)} \
|
||||
{CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
|
||||
]
|
||||
do_test fkey2-14.2tmp.2.3 {
|
||||
catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-14.2tmp.2.4 {
|
||||
execsql { INSERT INTO t4 VALUES(1, NULL) }
|
||||
} {}
|
||||
do_test fkey2-14.2tmp.2.5 {
|
||||
catchsql { UPDATE t4 SET b = 5 }
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-14.2tmp.2.6 {
|
||||
catchsql { UPDATE t4 SET b = 1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.2tmp.2.7 {
|
||||
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
|
||||
} {}
|
||||
|
||||
# Repeat for ATTACH-ed tables
|
||||
#
|
||||
drop_all_tables
|
||||
do_test fkey2-14.1aux.1 {
|
||||
# Adding a column with a REFERENCES clause is not supported.
|
||||
execsql {
|
||||
ATTACH ':memory:' AS aux;
|
||||
CREATE TABLE aux.t1(a PRIMARY KEY);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
}
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1aux.2 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1aux.3 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
|
||||
} {0 {}}
|
||||
do_test fkey2-14.1aux.4 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
do_test fkey2-14.1aux.5 {
|
||||
catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
do_test fkey2-14.1aux.6 {
|
||||
execsql {
|
||||
PRAGMA foreign_keys = off;
|
||||
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
|
||||
PRAGMA foreign_keys = on;
|
||||
SELECT sql FROM aux.sqlite_master WHERE name='t2';
|
||||
}
|
||||
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
|
||||
|
||||
do_test fkey2-14.2aux.1.1 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||
do_test fkey2-14.2aux.1.2 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES t2)}}
|
||||
do_test fkey2-14.2aux.1.3 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
|
||||
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||
|
||||
# Test ALTER TABLE RENAME TABLE a bit.
|
||||
#
|
||||
do_test fkey2-14.2aux.2.1 {
|
||||
drop_all_tables
|
||||
execsql {
|
||||
CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1);
|
||||
CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
|
||||
CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
|
||||
}
|
||||
execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
|
||||
} [list \
|
||||
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)} \
|
||||
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)} \
|
||||
{CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \
|
||||
]
|
||||
do_test fkey2-14.2aux.2.2 {
|
||||
execsql { ALTER TABLE t1 RENAME TO t4 }
|
||||
execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
|
||||
} [list \
|
||||
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")} \
|
||||
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)} \
|
||||
{CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
|
||||
]
|
||||
do_test fkey2-14.2aux.2.3 {
|
||||
catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-14.2aux.2.4 {
|
||||
execsql { INSERT INTO t4 VALUES(1, NULL) }
|
||||
} {}
|
||||
do_test fkey2-14.2aux.2.5 {
|
||||
catchsql { UPDATE t4 SET b = 5 }
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-14.2aux.2.6 {
|
||||
catchsql { UPDATE t4 SET b = 1 }
|
||||
} {0 {}}
|
||||
do_test fkey2-14.2aux.2.7 {
|
||||
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
|
||||
} {}
|
||||
}
|
||||
|
||||
do_test fkey-2.14.3.1 {
|
||||
|
||||
@ -208,7 +208,7 @@ proc fts3_doclist {tbl term where} {
|
||||
|
||||
proc gobble_varint {varname} {
|
||||
upvar $varname blob
|
||||
set n [read_varint $blob ret]
|
||||
set n [read_fts3varint $blob ret]
|
||||
set blob [string range $blob $n end]
|
||||
return $ret
|
||||
}
|
||||
@ -310,36 +310,65 @@ proc fts3_read {tbl where varname} {
|
||||
# match the expected results passed via parameter $result.
|
||||
#
|
||||
proc do_select_test {name sql result} {
|
||||
doPassiveTest $name $sql [list 0 $result]
|
||||
uplevel [list doPassiveTest 0 $name $sql [list 0 $result]]
|
||||
}
|
||||
|
||||
proc do_restart_select_test {name sql result} {
|
||||
uplevel [list doPassiveTest 1 $name $sql [list 0 $result]]
|
||||
}
|
||||
|
||||
proc do_error_test {name sql error} {
|
||||
doPassiveTest $name $sql [list 1 $error]
|
||||
uplevel [list doPassiveTest 0 $name $sql [list 1 $error]]
|
||||
}
|
||||
|
||||
proc doPassiveTest {name sql catchres} {
|
||||
proc doPassiveTest {isRestart name sql catchres} {
|
||||
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
|
||||
|
||||
if {$::DO_MALLOC_TEST} {
|
||||
set answers [list {1 {out of memory}} $catchres]
|
||||
set modes [list 100000 transient 1 persistent]
|
||||
} else {
|
||||
set answers [list $catchres]
|
||||
set modes [list 0 nofail]
|
||||
switch $::DO_MALLOC_TEST {
|
||||
0 { # No malloc failures.
|
||||
do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
|
||||
return
|
||||
}
|
||||
1 { # Simulate transient failures.
|
||||
set nRepeat 1
|
||||
set zName "transient"
|
||||
set nStartLimit 100000
|
||||
set nBackup 1
|
||||
}
|
||||
2 { # Simulate persistent failures.
|
||||
set nRepeat 1
|
||||
set zName "persistent"
|
||||
set nStartLimit 100000
|
||||
set nBackup 1
|
||||
}
|
||||
3 { # Simulate transient failures with extra brute force.
|
||||
set nRepeat 100000
|
||||
set zName "ridiculous"
|
||||
set nStartLimit 1
|
||||
set nBackup 10
|
||||
}
|
||||
}
|
||||
|
||||
# The set of acceptable results from running [catchsql $sql].
|
||||
#
|
||||
set answers [list {1 {out of memory}} $catchres]
|
||||
set str [join $answers " OR "]
|
||||
|
||||
foreach {nRepeat zName} $modes {
|
||||
for {set iFail 1} 1 {incr iFail} {
|
||||
if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
|
||||
set nFail 1
|
||||
for {set iLimit $nStartLimit} {$nFail} {incr iLimit} {
|
||||
for {set iFail 1} {$nFail && $iFail<=$iLimit} {incr iFail} {
|
||||
for {set iTest 0} {$iTest<$nBackup && ($iFail-$iTest)>0} {incr iTest} {
|
||||
|
||||
set res [catchsql $sql]
|
||||
if {[lsearch -exact $answers $res]>=0} {
|
||||
set res $str
|
||||
if {$isRestart} { sqlite3 db test.db }
|
||||
|
||||
sqlite3_memdebug_fail [expr $iFail-$iTest] -repeat $nRepeat
|
||||
set res [uplevel [list catchsql $sql]]
|
||||
if {[lsearch -exact $answers $res]>=0} { set res $str }
|
||||
set testname "$name.$zName.$iFail"
|
||||
do_test "$name.$zName.$iLimit.$iFail" [list set {} $res] $str
|
||||
|
||||
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
|
||||
}
|
||||
do_test $name.$zName.$iFail [list set {} $res] $str
|
||||
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
|
||||
if {$nFail==0} break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1131,39 +1131,36 @@ do_test fts3ac-4.2 {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'christmas candlelight'
|
||||
}
|
||||
} {{<b>...</b> place.? What do you think about going here <b>Christmas</b>
|
||||
eve?? They have an 11:00 a.m. service and a <b>candlelight</b> service at 5:00 p.m.,
|
||||
among others. <b>...</b>}}
|
||||
} {{<b>...</b>here <b>Christmas</b>
|
||||
eve?? They have an 11:00 a.m. service and a <b>candlelight</b> service<b>...</b>}}
|
||||
|
||||
do_test fts3ac-4.3 {
|
||||
execsql {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'deal sheet potential reuse'
|
||||
}
|
||||
} {{EOL-Accenture <b>Deal</b> <b>Sheet</b> <b>...</b> intent
|
||||
Review Enron asset base for <b>potential</b> <b>reuse</b>/ licensing
|
||||
Contract negotiations <b>...</b>}}
|
||||
} {{EOL-Accenture <b>Deal</b> <b>Sheet</b><b>...</b>asset base for <b>potential</b> <b>reuse</b>/ licensing
|
||||
Contract negotiations<b>...</b>}}
|
||||
do_test fts3ac-4.4 {
|
||||
execsql {
|
||||
SELECT snippet(email,'<<<','>>>',' ') FROM email
|
||||
WHERE email MATCH 'deal sheet potential reuse'
|
||||
}
|
||||
} {{EOL-Accenture <<<Deal>>> <<<Sheet>>> intent
|
||||
Review Enron asset base for <<<potential>>> <<<reuse>>>/ licensing
|
||||
Contract negotiations }}
|
||||
} {{EOL-Accenture <<<Deal>>> <<<Sheet>>> asset base for <<<potential>>> <<<reuse>>>/ licensing
|
||||
Contract negotiations }}
|
||||
do_test fts3ac-4.5 {
|
||||
execsql {
|
||||
SELECT snippet(email,'<<<','>>>',' ') FROM email
|
||||
WHERE email MATCH 'first things'
|
||||
}
|
||||
} {{Re: <<<First>>> Polish Deal! Congrats! <<<Things>>> seem to be building rapidly now on the }}
|
||||
} {{Re: <<<First>>> Polish Deal! Congrats! <<<Things>>> seem to be building rapidly now }}
|
||||
do_test fts3ac-4.6 {
|
||||
execsql {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'chris is here'
|
||||
}
|
||||
} {{<b>chris</b>.germany@enron.com <b>...</b> Sounds good to me. I bet this <b>is</b> next to the Warick?? Hotel. <b>...</b> place.? What do you think about going <b>here</b> Christmas
|
||||
eve?? They have an 11:00 a.m. <b>...</b>}}
|
||||
} {{<b>...</b><b>chris</b>.germany@enron.com'" <<b>chris</b><b>...</b>bet this <b>is</b> next to<b>...</b>about going <b>here</b> Christmas
|
||||
eve<b>...</b>}}
|
||||
do_test fts3ac-4.7 {
|
||||
execsql {
|
||||
SELECT snippet(email) FROM email
|
||||
@ -1171,19 +1168,15 @@ do_test fts3ac-4.7 {
|
||||
}
|
||||
} {{Erin:
|
||||
|
||||
<b>Pursuant</b> <b>to</b> your request, attached are the Schedule to <b>...</b>}}
|
||||
<b>Pursuant</b> <b>to</b> your request, attached are the Schedule to the ISDA Master Agreement, together<b>...</b>}}
|
||||
do_test fts3ac-4.8 {
|
||||
execsql {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'ancillary load davis'
|
||||
}
|
||||
} {{pete.<b>davis</b>@enron.com <b>...</b> Start Date: 4/22/01; HourAhead hour: 3; No <b>ancillary</b> schedules awarded.
|
||||
Variances detected.
|
||||
Variances detected in <b>Load</b> schedule.
|
||||
} {{pete.<b>davis</b>@enron.com<b>...</b>3; No <b>ancillary</b> schedules awarded<b>...</b>detected in <b>Load</b> schedule.
|
||||
|
||||
LOG MESSAGES:
|
||||
|
||||
PARSING <b>...</b>}}
|
||||
LOG<b>...</b>}}
|
||||
|
||||
# Combinations of AND and OR operators:
|
||||
#
|
||||
@ -1192,22 +1185,35 @@ do_test fts3ac-5.1 {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'questar enron OR com'
|
||||
}
|
||||
} {{matt.smith@<b>enron</b>.<b>com</b> <b>...</b> six reports:
|
||||
|
||||
31 Keystone Receipts
|
||||
} {{matt.smith@<b>enron</b>.<b>com</b><b>...</b>31 Keystone Receipts
|
||||
15 <b>Questar</b> Pipeline
|
||||
40 Rockies Production
|
||||
22 West_2 <b>...</b>}}
|
||||
40 Rockies<b>...</b>}}
|
||||
|
||||
do_test fts3ac-5.2 {
|
||||
execsql {
|
||||
SELECT snippet(email) FROM email
|
||||
WHERE email MATCH 'enron OR com questar'
|
||||
}
|
||||
} {{matt.smith@<b>enron</b>.<b>com</b> <b>...</b> six reports:
|
||||
|
||||
31 Keystone Receipts
|
||||
} {{matt.smith@<b>enron</b>.<b>com</b><b>...</b>31 Keystone Receipts
|
||||
15 <b>Questar</b> Pipeline
|
||||
40 Rockies Production
|
||||
22 West_2 <b>...</b>}}
|
||||
40 Rockies<b>...</b>}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a problem reported on the mailing list.
|
||||
#
|
||||
do_test fts3ac-6.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE ft USING fts3(one, two);
|
||||
INSERT INTO ft VALUES('', 'foo');
|
||||
INSERT INTO ft VALUES('foo', 'foo');
|
||||
SELECT offsets(ft) FROM ft WHERE ft MATCH 'foo';
|
||||
}
|
||||
} {{1 0 0 3} {0 0 0 3 1 0 0 3}}
|
||||
do_test fts3ac-6.2 {
|
||||
execsql {
|
||||
DELETE FROM ft WHERE one = 'foo';
|
||||
SELECT offsets(ft) FROM ft WHERE ft MATCH 'foo';
|
||||
}
|
||||
} {{1 0 0 3}}
|
||||
|
||||
finish_test
|
||||
|
||||
@ -73,7 +73,7 @@ do_test fts3ag-1.9 {
|
||||
# No support for all-except queries.
|
||||
do_test fts3ag-1.10 {
|
||||
catchsql {SELECT rowid FROM t1 WHERE t1 MATCH '-this -something'}
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [-this -something]}}
|
||||
|
||||
# Test that docListOrMerge() correctly handles reaching the end of one
|
||||
# doclist before it reaches the end of the other.
|
||||
|
||||
@ -53,6 +53,10 @@ do_test fts3al-1.3 {
|
||||
#
|
||||
# The trailing and leading hi-bit chars help with code which tests for
|
||||
# isspace() to coalesce multiple spaces.
|
||||
#
|
||||
# UPDATE: The above is no longer true; there is no such code in fts3.
|
||||
# But leave the test in just the same.
|
||||
#
|
||||
|
||||
set word "\x80xxxxx\x80xxxxx\x80xxxxx\x80xxxxx\x80xxxxx\x80xxxxx\x80"
|
||||
set phrase1 "$word $word $word target $word $word $word"
|
||||
@ -64,6 +68,6 @@ db eval "INSERT INTO t4 (content) VALUES ('$phrase2')"
|
||||
|
||||
do_test fts3al-1.4 {
|
||||
execsql {SELECT rowid, length(snippet(t4)) FROM t4 WHERE t4 MATCH 'target'}
|
||||
} {1 111 2 117}
|
||||
} {1 241 2 247}
|
||||
|
||||
finish_test
|
||||
|
||||
373
test/fts3cov.test
Normal file
373
test/fts3cov.test
Normal file
@ -0,0 +1,373 @@
|
||||
# 2009 December 03
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The tests in this file are structural coverage tests. They are designed
|
||||
# to complement the tests in fts3rnd.test and fts3doc.test. Between them,
|
||||
# the three files should provide full coverage of the fts3 extension code.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If this build does not include FTS3, skip the tests in this file.
|
||||
#
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
source $testdir/fts3_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
set DO_MALLOC_TEST 0
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# When it first needs to read a block from the %_segments table, the FTS3
|
||||
# module compiles an SQL statement for that purpose. The statement is
|
||||
# stored and reused each subsequent time a block is read. This test case
|
||||
# tests the effects of an OOM error occuring while compiling the statement.
|
||||
#
|
||||
# Similarly, when FTS3 first needs to scan through a set of segment leaves
|
||||
# to find a set of documents that matches a term, it allocates a string
|
||||
# containing the text of the required SQL, and compiles one or more
|
||||
# statements to traverse the leaves. This test case tests that OOM errors
|
||||
# that occur while allocating this string and statement are handled correctly
|
||||
# also.
|
||||
#
|
||||
do_test fts3cov-1.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts3(x);
|
||||
INSERT INTO t1(t1) VALUES('nodesize=24');
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('Is the night chilly and dark?');
|
||||
INSERT INTO t1 VALUES('The night is chilly, but not dark.');
|
||||
INSERT INTO t1 VALUES('The thin gray cloud is spread on high,');
|
||||
INSERT INTO t1 VALUES('It covers but not hides the sky.');
|
||||
COMMIT;
|
||||
SELECT count(*)>0 FROM t1_segments;
|
||||
}
|
||||
} {1}
|
||||
|
||||
set DO_MALLOC_TEST 1
|
||||
do_restart_select_test fts3cov-1.2 {
|
||||
SELECT docid FROM t1 WHERE t1 MATCH 'chilly';
|
||||
} {1 2}
|
||||
set DO_MALLOC_TEST 0
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# When querying the full-text index, if an expected internal node block is
|
||||
# missing from the %_segments table, or if a NULL value is stored in the
|
||||
# %_segments table instead of a binary blob, database corruption should be
|
||||
# reported.
|
||||
#
|
||||
# Even with tiny 24 byte nodes, it takes a fair bit of data to produce a
|
||||
# segment b-tree that uses the %_segments table to store internal nodes.
|
||||
#
|
||||
do_test fts3cov-2.1 {
|
||||
execsql {
|
||||
INSERT INTO t1(t1) VALUES('nodesize=24');
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('The moon is behind, and at the full;');
|
||||
INSERT INTO t1 VALUES('And yet she looks both small and dull.');
|
||||
INSERT INTO t1 VALUES('The night is chill, the cloud is gray:');
|
||||
INSERT INTO t1 VALUES('''T is a month before the month of May,');
|
||||
INSERT INTO t1 VALUES('And the Spring comes slowly up this way.');
|
||||
INSERT INTO t1 VALUES('The lovely lady, Christabel,');
|
||||
INSERT INTO t1 VALUES('Whom her father loves so well,');
|
||||
INSERT INTO t1 VALUES('What makes her in the wood so late,');
|
||||
INSERT INTO t1 VALUES('A furlong from the castle gate?');
|
||||
INSERT INTO t1 VALUES('She had dreams all yesternight');
|
||||
INSERT INTO t1 VALUES('Of her own betrothed knight;');
|
||||
INSERT INTO t1 VALUES('And she in the midnight wood will pray');
|
||||
INSERT INTO t1 VALUES('For the weal of her lover that''s far away.');
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO t1(t1) VALUES('optimize');
|
||||
SELECT substr(hex(root), 1, 2) FROM t1_segdir;
|
||||
}
|
||||
} {03}
|
||||
|
||||
# Test the "missing entry" case:
|
||||
do_test fts3cov-2.1 {
|
||||
set root [db one {SELECT root FROM t1_segdir}]
|
||||
read_fts3varint [string range $root 1 end] left_child
|
||||
execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
|
||||
} {}
|
||||
do_error_test fts3cov-2.2 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'c*'
|
||||
} {database disk image is malformed}
|
||||
|
||||
# Test the "replaced with NULL" case:
|
||||
do_test fts3cov-2.3 {
|
||||
execsql { INSERT INTO t1_segments VALUES($left_child, NULL) }
|
||||
} {}
|
||||
do_error_test fts3cov-2.4 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'cloud'
|
||||
} {database disk image is malformed}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# The following tests are to test the effects of OOM errors while storing
|
||||
# terms in the pending-hash table. Specifically, while creating doclist
|
||||
# blobs to store in the table. More specifically, to test OOM errors while
|
||||
# appending column numbers to doclists. For example, if a doclist consists
|
||||
# of:
|
||||
#
|
||||
# <docid> <column 0 offset-list> 0x01 <column N> <column N offset-list>
|
||||
#
|
||||
# The following tests check that malloc errors encountered while appending
|
||||
# the "0x01 <column N>" data to the dynamically growable blob used to
|
||||
# accumulate the doclist in memory are handled correctly.
|
||||
#
|
||||
do_test fts3cov-3.1 {
|
||||
set cols [list]
|
||||
set vals [list]
|
||||
for {set i 0} {$i < 120} {incr i} {
|
||||
lappend cols "col$i"
|
||||
lappend vals "'word'"
|
||||
}
|
||||
execsql "CREATE VIRTUAL TABLE t2 USING fts3([join $cols ,])"
|
||||
} {}
|
||||
set DO_MALLOC_TEST 1
|
||||
do_write_test fts3cov-3.2 t2_content "
|
||||
INSERT INTO t2(docid, [join $cols ,]) VALUES(1, [join $vals ,])
|
||||
"
|
||||
do_write_test fts3cov-3.3 t2_content "
|
||||
INSERT INTO t2(docid, [join $cols ,]) VALUES(200, [join $vals ,])
|
||||
"
|
||||
do_write_test fts3cov-3.4 t2_content "
|
||||
INSERT INTO t2(docid, [join $cols ,]) VALUES(60000, [join $vals ,])
|
||||
"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# If too much data accumulates in the pending-terms hash table, it is
|
||||
# flushed to the database automatically, even if the transaction has not
|
||||
# finished. The following tests check the effects of encountering an OOM
|
||||
# while doing this.
|
||||
#
|
||||
do_test fts3cov-4.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t3 USING fts3(x);
|
||||
INSERT INTO t3(t3) VALUES('nodesize=24');
|
||||
INSERT INTO t3(t3) VALUES('maxpending=100');
|
||||
}
|
||||
} {}
|
||||
set DO_MALLOC_TEST 1
|
||||
do_write_test fts3cov-4.2 t3_content {
|
||||
INSERT INTO t3(docid, x)
|
||||
SELECT 1, 'Then Christabel stretched forth her hand,' UNION ALL
|
||||
SELECT 3, 'And comforted fair Geraldine:' UNION ALL
|
||||
SELECT 4, '''O well, bright dame, may you command' UNION ALL
|
||||
SELECT 5, 'The service of Sir Leoline;' UNION ALL
|
||||
SELECT 2, 'And gladly our stout chivalry' UNION ALL
|
||||
SELECT 7, 'Will he send forth, and friends withal,' UNION ALL
|
||||
SELECT 8, 'To guide and guard you safe and free' UNION ALL
|
||||
SELECT 6, 'Home to your noble father''s hall.'''
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When building the internal tree structure for each segment b-tree, FTS3
|
||||
# assumes that the content of each internal node will be less than
|
||||
# $nodesize bytes, where $nodesize is the advisory node size. If this turns
|
||||
# out to be untrue, then an extra buffer must be malloc'd for each term.
|
||||
# This test case tests these paths and the effects of said mallocs failing
|
||||
# by inserting insert a document with some fairly large terms into a
|
||||
# full-text table with a very small node-size.
|
||||
#
|
||||
# Test this handling of large terms in three contexts:
|
||||
#
|
||||
# 1. When flushing the pending-terms table.
|
||||
# 2. When optimizing the data structures using the INSERT syntax.
|
||||
# 2. When optimizing the data structures using the deprecated SELECT syntax.
|
||||
#
|
||||
do_test fts3cov-5.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t4 USING fts3(x);
|
||||
INSERT INTO t4(t4) VALUES('nodesize=24');
|
||||
}
|
||||
} {}
|
||||
set DO_MALLOC_TEST 1
|
||||
|
||||
# Test when flushing pending-terms table.
|
||||
do_write_test fts3cov-5.2 t4_content {
|
||||
INSERT INTO t4
|
||||
SELECT 'ItisanancientMarinerAndhestoppethoneofthreeAA' UNION ALL
|
||||
SELECT 'ItisanancientMarinerAndhestoppethoneofthreeBB' UNION ALL
|
||||
SELECT 'ItisanancientMarinerAndhestoppethoneofthreeCC' UNION ALL
|
||||
SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstAA' UNION ALL
|
||||
SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstBB' UNION ALL
|
||||
SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstCC'
|
||||
}
|
||||
|
||||
# Test when optimizing via INSERT.
|
||||
do_test fts3cov-5.3 { execsql { INSERT INTO t4 VALUES('extra!') } } {}
|
||||
do_write_test fts3cov-5.2 t4_segments { INSERT INTO t4(t4) VALUES('optimize') }
|
||||
|
||||
# Test when optimizing via SELECT.
|
||||
do_test fts3cov-5.5 { execsql { INSERT INTO t4 VALUES('more extra!') } } {}
|
||||
do_write_test fts3cov-5.6 t4_segments {
|
||||
SELECT * FROM (SELECT optimize(t4) FROM t4 LIMIT 1)
|
||||
EXCEPT SELECT 'Index optimized'
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When merging all segments at a given level to create a single segment
|
||||
# at level+1, FTS3 runs a query of the form:
|
||||
#
|
||||
# SELECT count(*) FROM %_segdir WHERE level = ?
|
||||
#
|
||||
# The query is compiled the first time this operation is required and
|
||||
# reused thereafter. This test aims to test the effects of an OOM while
|
||||
# preparing and executing this query for the first time.
|
||||
#
|
||||
# Then, keep inserting rows into the table so that the effects of an OOM
|
||||
# while re-executing the same query can also be tested.
|
||||
#
|
||||
do_test fts3cov-6.1 {
|
||||
execsql { CREATE VIRTUAL TABLE t5 USING fts3(x) }
|
||||
for {set i 0} {$i<16} {incr i} { execsql "INSERT INTO t5 VALUES('term$i')" }
|
||||
execsql { SELECT count(*) FROM t5_segdir }
|
||||
} {16}
|
||||
|
||||
# First time.
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_write_test fts3cov-6.2 t5_content {
|
||||
INSERT INTO t5 VALUES('segment number 16!');
|
||||
}
|
||||
|
||||
# Second time.
|
||||
do_test fts3cov-6.3 {
|
||||
for {set i 1} {$i<16} {incr i} { execsql "INSERT INTO t5 VALUES('term$i')" }
|
||||
execsql { SELECT count(*) FROM t5_segdir }
|
||||
} {17}
|
||||
do_write_test fts3cov-6.4 t5_content {
|
||||
INSERT INTO t5 VALUES('segment number 16!');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Update the docid of a row. Test this in two scenarios:
|
||||
#
|
||||
# 1. When the row being updated is the only row in the table.
|
||||
# 2. When it is not.
|
||||
#
|
||||
# The two cases above take different paths because in case 1 all data
|
||||
# structures can simply be emptied before inserting the new row record.
|
||||
# In case 2, the data structures actually have to be updated.
|
||||
#
|
||||
do_test fts3cov-7.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t7 USING fts3(a, b, c);
|
||||
INSERT INTO t7 VALUES('A', 'B', 'C');
|
||||
UPDATE t7 SET docid = 5;
|
||||
SELECT docid, * FROM t7;
|
||||
}
|
||||
} {5 A B C}
|
||||
do_test fts3cov-7.2 {
|
||||
execsql {
|
||||
INSERT INTO t7 VALUES('D', 'E', 'F');
|
||||
UPDATE t7 SET docid = 1 WHERE docid = 6;
|
||||
SELECT docid, * FROM t7;
|
||||
}
|
||||
} {1 D E F 5 A B C}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# If a set of documents are modified within a transaction, the
|
||||
# pending-terms table must be flushed each time a document with a docid
|
||||
# less than or equal to the previous docid is modified.
|
||||
#
|
||||
# This test checks the effects of an OOM error occuring when the
|
||||
# pending-terms table is flushed for this reason as part of a DELETE
|
||||
# statement.
|
||||
#
|
||||
do_malloc_test fts3cov-8 -sqlprep {
|
||||
BEGIN;
|
||||
CREATE VIRTUAL TABLE t8 USING fts3;
|
||||
INSERT INTO t8 VALUES('the output of each batch run');
|
||||
INSERT INTO t8 VALUES('(possibly a day''s work)');
|
||||
INSERT INTO t8 VALUES('was written to two separate disks');
|
||||
COMMIT;
|
||||
} -sqlbody {
|
||||
BEGIN;
|
||||
DELETE FROM t8 WHERE rowid = 3;
|
||||
DELETE FROM t8 WHERE rowid = 2;
|
||||
DELETE FROM t8 WHERE rowid = 1;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test some branches in the code that handles "special" inserts like:
|
||||
#
|
||||
# INSERT INTO t1(t1) VALUES('optimize');
|
||||
#
|
||||
# Also test that an optimize (INSERT method) works on an empty table.
|
||||
#
|
||||
set DO_MALLOC_TEST 0
|
||||
do_test fts3cov-9.1 {
|
||||
execsql { CREATE VIRTUAL TABLE xx USING fts3 }
|
||||
} {}
|
||||
do_error_test fts3cov-9.2 {
|
||||
INSERT INTO xx(xx) VALUES('optimise'); -- British spelling
|
||||
} {SQL logic error or missing database}
|
||||
do_error_test fts3cov-9.3 {
|
||||
INSERT INTO xx(xx) VALUES('short');
|
||||
} {SQL logic error or missing database}
|
||||
do_error_test fts3cov-9.4 {
|
||||
INSERT INTO xx(xx) VALUES('waytoolongtobecorrect');
|
||||
} {SQL logic error or missing database}
|
||||
do_test fts3cov-9.5 {
|
||||
execsql { INSERT INTO xx(xx) VALUES('optimize') }
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a table can be optimized in the middle of a transaction when
|
||||
# the pending-terms table is non-empty. This case involves some extra
|
||||
# branches because data must be read not only from the database, but
|
||||
# also from the pending-terms table.
|
||||
#
|
||||
do_malloc_test fts3cov-10 -sqlprep {
|
||||
CREATE VIRTUAL TABLE t10 USING fts3;
|
||||
INSERT INTO t10 VALUES('Optimising images for the web is a tricky business');
|
||||
BEGIN;
|
||||
INSERT INTO t10 VALUES('You have to get the right balance between');
|
||||
} -sqlbody {
|
||||
INSERT INTO t10(t10) VALUES('optimize');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a full-text query for a term that was once in the index, but is
|
||||
# no longer.
|
||||
#
|
||||
do_test fts3cov-11.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE xx USING fts3;
|
||||
INSERT INTO xx VALUES('one two three');
|
||||
INSERT INTO xx VALUES('four five six');
|
||||
DELETE FROM xx WHERE docid = 1;
|
||||
}
|
||||
execsql { SELECT * FROM xx WHERE xx MATCH 'two' }
|
||||
} {}
|
||||
|
||||
|
||||
do_malloc_test fts3cov-12 -sqlprep {
|
||||
CREATE VIRTUAL TABLE t12 USING fts3;
|
||||
INSERT INTO t12 VALUES('is one of the two togther');
|
||||
BEGIN;
|
||||
INSERT INTO t12 VALUES('one which was appropriate at the time');
|
||||
} -sqlbody {
|
||||
SELECT * FROM t12 WHERE t12 MATCH 'one'
|
||||
}
|
||||
|
||||
do_malloc_test fts3cov-13 -sqlprep {
|
||||
PRAGMA encoding = 'UTF-16';
|
||||
CREATE VIRTUAL TABLE t13 USING fts3;
|
||||
INSERT INTO t13 VALUES('two scalar functions');
|
||||
INSERT INTO t13 VALUES('scalar two functions');
|
||||
INSERT INTO t13 VALUES('functions scalar two');
|
||||
} -sqlbody {
|
||||
SELECT snippet(t13, '%%', '%%', '#') FROM t13 WHERE t13 MATCH 'two';
|
||||
SELECT snippet(t13, '%%', '%%') FROM t13 WHERE t13 MATCH 'two';
|
||||
SELECT snippet(t13, '%%') FROM t13 WHERE t13 MATCH 'two';
|
||||
}
|
||||
|
||||
finish_test
|
||||
@ -336,53 +336,53 @@ do_test fts3expr-4.1 {
|
||||
# Mismatched parenthesis:
|
||||
do_test fts3expr-4.2.1 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world))' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [example AND (hello OR world))]}}
|
||||
do_test fts3expr-4.2.2 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [example AND (hello OR world]}}
|
||||
do_test fts3expr-4.2.3 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH '(hello' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [(hello]}}
|
||||
do_test fts3expr-4.2.4 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH '(' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [(]}}
|
||||
do_test fts3expr-4.2.5 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH ')' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [)]}}
|
||||
|
||||
do_test fts3expr-4.2.6 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example (hello world' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [example (hello world]}}
|
||||
|
||||
# Unterminated quotation marks:
|
||||
do_test fts3expr-4.3.1 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR "hello world' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [example OR "hello world]}}
|
||||
do_test fts3expr-4.3.2 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR hello world"' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [example OR hello world"]}}
|
||||
|
||||
# Binary operators without the required operands.
|
||||
do_test fts3expr-4.4.1 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'OR hello world' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [OR hello world]}}
|
||||
do_test fts3expr-4.4.2 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'hello world OR' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [hello world OR]}}
|
||||
do_test fts3expr-4.4.3 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'one (hello world OR) two' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [one (hello world OR) two]}}
|
||||
do_test fts3expr-4.4.4 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'one (OR hello world) two' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [one (OR hello world) two]}}
|
||||
|
||||
# NEAR operators with something other than phrases as arguments.
|
||||
do_test fts3expr-4.5.1 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH '(hello OR world) NEAR one' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [(hello OR world) NEAR one]}}
|
||||
do_test fts3expr-4.5.2 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'one NEAR (hello OR world)' }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
} {1 {malformed MATCH expression: [one NEAR (hello OR world)]}}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# The following OOM tests are designed to cover cases in fts3_expr.c.
|
||||
|
||||
@ -33,7 +33,8 @@ set DO_MALLOC_TEST 1
|
||||
# fts3_malloc-2.*: Test OOM during SELECT operations.
|
||||
# fts3_malloc-3.*: Test OOM during SELECT operations with a larger database.
|
||||
# fts3_malloc-4.*: Test OOM during database write operations.
|
||||
#
|
||||
# fts3_malloc-5.*: Test that a couple of memory leaks that could follow
|
||||
# OOM in tokenizer code have been fixed.
|
||||
#
|
||||
|
||||
|
||||
@ -288,6 +289,16 @@ do_test fts3_malloc-4.2 {
|
||||
execsql { SELECT a FROM ft }
|
||||
} {two four {two four}}
|
||||
|
||||
do_write_test fts3_malloc-5.1 ft_content {
|
||||
INSERT INTO ft VALUES('short alongertoken reallyquitealotlongerimeanit andthistokenisjustsolongthatonemightbeforgivenforimaginingthatitwasmerelyacontrivedexampleandnotarealtoken', 'cynics!')
|
||||
}
|
||||
do_test fts3_malloc-5.2 {
|
||||
execsql { CREATE VIRTUAL TABLE ft8 USING fts3(x, tokenize porter) }
|
||||
} {}
|
||||
do_write_test fts3_malloc-5.3 ft_content {
|
||||
INSERT INTO ft8 VALUES('short alongertoken reallyquitealotlongerimeanit andthistokenisjustsolongthatonemightbeforgivenforimaginingthatitwasmerelyacontrivedexampleandnotarealtoken')
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@ -76,6 +76,17 @@ do_test fts3near-1.15 {
|
||||
execsql {SELECT docid FROM t1 WHERE content MATCH 'one NEAR two NEAR one'}
|
||||
} {3}
|
||||
|
||||
do_test fts3near-1.16 {
|
||||
execsql {
|
||||
SELECT docid FROM t1 WHERE content MATCH '"one three" NEAR/0 "four five"'
|
||||
}
|
||||
} {1}
|
||||
do_test fts3near-1.17 {
|
||||
execsql {
|
||||
SELECT docid FROM t1 WHERE content MATCH '"four five" NEAR/0 "one three"'
|
||||
}
|
||||
} {1}
|
||||
|
||||
|
||||
# Output format of the offsets() function:
|
||||
#
|
||||
@ -154,6 +165,7 @@ do_test fts3near-3.6 {
|
||||
SELECT offsets(t1) FROM t1 WHERE content MATCH 'three NEAR/0 "two four"'
|
||||
}
|
||||
} {{0 0 8 5 0 1 14 3 0 2 18 4}}
|
||||
breakpoint
|
||||
do_test fts3near-3.7 {
|
||||
execsql {
|
||||
SELECT offsets(t1) FROM t1 WHERE content MATCH '"two four" NEAR/0 three'}
|
||||
@ -170,7 +182,7 @@ do_test fts3near-4.1 {
|
||||
execsql {
|
||||
SELECT snippet(t1) FROM t1 WHERE content MATCH 'specification NEAR supports'
|
||||
}
|
||||
} {{<b>...</b> devices, handheld devices, etc. This <b>specification</b> also <b>supports</b> content positioning, downloadable fonts, <b>...</b>}}
|
||||
} {{<b>...</b>braille devices, handheld devices, etc. This <b>specification</b> also <b>supports</b> content positioning, downloadable fonts, table layout<b>...</b>}}
|
||||
|
||||
do_test fts3near-5.1 {
|
||||
execsql {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user