Merge updates from trunk.

FossilOrigin-Name: a88b5be01e68b26267ff6eb05e931ef2e7fc9f99
This commit is contained in:
mistachkin 2013-10-12 23:39:49 +00:00
commit d5570119b7
76 changed files with 5219 additions and 2429 deletions

View File

@ -500,11 +500,11 @@ sqlite3.pc: $(TOP)/sqlite3.pc.in
./config.status
libsqlite3.la: $(LIBOBJ)
$(LTLINK) -o $@ $(LIBOBJ) $(TLIBS) \
$(LTLINK) -no-undefined -o $@ $(LIBOBJ) $(TLIBS) \
${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(LTLINK) -o $@ tclsqlite.lo \
$(LTLINK) -no-undefined -o $@ tclsqlite.lo \
libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
-rpath "$(TCLLIBDIR)" \
-version-info "8:6:8" \

View File

@ -13,6 +13,13 @@ TOP = .
USE_AMALGAMATION = 1
!ENDIF
# Set this non-0 to split the SQLite amalgamation file into chunks to
# be used for debugging with Visual Studio.
#
!IFNDEF SPLIT_AMALGAMATION
SPLIT_AMALGAMATION = 0
!ENDIF
# Set this non-0 to use the International Components for Unicode (ICU).
#
!IFNDEF USE_ICU
@ -913,10 +920,19 @@ sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
# Set the source code file to be used by executables and libraries when
# they need the amalgamation.
#
!IF $(SPLIT_AMALGAMATION)!=0
SQLITE3C = sqlite3-all.c
!ELSE
SQLITE3C = sqlite3.c
!ENDIF
# Rule to build the amalgamation
#
sqlite3.lo: sqlite3.c
$(LTCOMPILE) -c sqlite3.c
sqlite3.lo: $(SQLITE3C)
$(LTCOMPILE) -c $(SQLITE3C)
# Rules to build the LEMON compiler generator
#
@ -1276,7 +1292,7 @@ TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib
TESTFIXTURE_SRC1 = $(TESTEXT) sqlite3.c
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
!IF $(USE_AMALGAMATION)==0
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
!ELSE
@ -1304,8 +1320,8 @@ queryplantest: testfixture.exe sqlite3.exe
test: testfixture.exe sqlite3.exe
.\testfixture.exe $(TOP)\test\veryquick.test
sqlite3_analyzer.c: sqlite3.c $(TOP)\src\test_stat.c $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
copy sqlite3.c + $(TOP)\src\test_stat.c + $(TOP)\src\tclsqlite.c $@
sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\test_stat.c $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
copy $(SQLITE3C) + $(TOP)\src\test_stat.c + $(TOP)\src\tclsqlite.c $@
echo static const char *tclsh_main_loop(void){ >> $@
echo static const char *zMainloop = >> $@
$(NAWK) -f $(TOP)\tool\tostr.awk $(TOP)\tool\spaceanal.tcl >> $@
@ -1331,7 +1347,7 @@ clean:
del /Q tclsqlite3.exe tclsqlite3.exp
del /Q testfixture.exe testfixture.exp test.db
del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
del /Q sqlite3.c
del /Q sqlite3.c sqlite3-*.c
del /Q sqlite3rc.h
del /Q shell.c sqlite3ext.h
del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c

View File

@ -1457,7 +1457,11 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts3Table *p = (Fts3Table *)pVTab;
int i; /* Iterator variable */
int iCons = -1; /* Index of constraint to use */
int iLangidCons = -1; /* Index of langid=x constraint, if present */
int iDocidGe = -1; /* Index of docid>=x constraint, if present */
int iDocidLe = -1; /* Index of docid<=x constraint, if present */
int iIdx;
/* By default use a full table scan. This is an expensive option,
** so search through the constraints to see if a more efficient
@ -1466,14 +1470,14 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
pInfo->estimatedCost = 5000000;
for(i=0; i<pInfo->nConstraint; i++){
int bDocid; /* True if this constraint is on docid */
struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
if( pCons->usable==0 ) continue;
bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1);
/* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
if( iCons<0
&& pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
&& (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1 )
){
if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){
pInfo->idxNum = FTS3_DOCID_SEARCH;
pInfo->estimatedCost = 1.0;
iCons = i;
@ -1502,14 +1506,38 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
){
iLangidCons = i;
}
if( bDocid ){
switch( pCons->op ){
case SQLITE_INDEX_CONSTRAINT_GE:
case SQLITE_INDEX_CONSTRAINT_GT:
iDocidGe = i;
break;
case SQLITE_INDEX_CONSTRAINT_LE:
case SQLITE_INDEX_CONSTRAINT_LT:
iDocidLe = i;
break;
}
}
}
iIdx = 1;
if( iCons>=0 ){
pInfo->aConstraintUsage[iCons].argvIndex = 1;
pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
pInfo->aConstraintUsage[iCons].omit = 1;
}
if( iLangidCons>=0 ){
pInfo->aConstraintUsage[iLangidCons].argvIndex = 2;
pInfo->idxNum |= FTS3_HAVE_LANGID;
pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++;
}
if( iDocidGe>=0 ){
pInfo->idxNum |= FTS3_HAVE_DOCID_GE;
pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++;
}
if( iDocidLe>=0 ){
pInfo->idxNum |= FTS3_HAVE_DOCID_LE;
pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++;
}
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
@ -2956,6 +2984,33 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
return rc;
}
/*
** The following are copied from sqliteInt.h.
**
** Constants for the largest and smallest possible 64-bit signed integers.
** These macros are designed to work correctly on both 32-bit and 64-bit
** compilers.
*/
#ifndef SQLITE_AMALGAMATION
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
/*
** If the numeric type of argument pVal is "integer", then return it
** converted to a 64-bit signed integer. Otherwise, return a copy of
** the second parameter, iDefault.
*/
static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){
if( pVal ){
int eType = sqlite3_value_numeric_type(pVal);
if( eType==SQLITE_INTEGER ){
return sqlite3_value_int64(pVal);
}
}
return iDefault;
}
/*
** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional
@ -2981,40 +3036,58 @@ static int fts3FilterMethod(
){
int rc;
char *zSql; /* SQL statement used to access %_content */
int eSearch;
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */
sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */
sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */
sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */
int iIdx;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(nVal);
assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
assert( nVal==0 || nVal==1 || nVal==2 );
assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
eSearch = (idxNum & 0x0000FFFF);
assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
assert( p->pSegments==0 );
/* Collect arguments into local variables */
iIdx = 0;
if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++];
if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++];
if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++];
if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++];
assert( iIdx==nVal );
/* In case the cursor has been used before, clear it now. */
sqlite3_finalize(pCsr->pStmt);
sqlite3_free(pCsr->aDoclist);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
/* Set the lower and upper bounds on docids to return */
pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64);
if( idxStr ){
pCsr->bDesc = (idxStr[0]=='D');
}else{
pCsr->bDesc = p->bDescIdx;
}
pCsr->eSearch = (i16)idxNum;
pCsr->eSearch = (i16)eSearch;
if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){
int iCol = eSearch-FTS3_FULLTEXT_SEARCH;
const char *zQuery = (const char *)sqlite3_value_text(pCons);
if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){
return SQLITE_NOMEM;
}
pCsr->iLangid = 0;
if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid);
assert( p->base.zErrMsg==0 );
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
@ -3037,7 +3110,7 @@ static int fts3FilterMethod(
** full-text query or docid lookup, the statement retrieves a single
** row by docid.
*/
if( idxNum==FTS3_FULLSCAN_SEARCH ){
if( eSearch==FTS3_FULLSCAN_SEARCH ){
zSql = sqlite3_mprintf(
"SELECT %s ORDER BY rowid %s",
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
@ -3048,10 +3121,10 @@ static int fts3FilterMethod(
}else{
rc = SQLITE_NOMEM;
}
}else if( idxNum==FTS3_DOCID_SEARCH ){
}else if( eSearch==FTS3_DOCID_SEARCH ){
rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
}
}
if( rc!=SQLITE_OK ) return rc;
@ -3942,6 +4015,12 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
return SQLITE_OK;
}
/*
** Maximum number of tokens a phrase may have to be considered for the
** incremental doclists strategy.
*/
#define MAX_INCR_PHRASE_TOKENS 4
/*
** This function is called for each Fts3Phrase in a full-text query
** expression to initialize the mechanism for returning rows. Once this
@ -3955,23 +4034,43 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
*/
static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
int rc; /* Error code */
Fts3PhraseToken *pFirst = &p->aToken[0];
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
int rc = SQLITE_OK; /* Error code */
int i;
if( pCsr->bDesc==pTab->bDescIdx
&& bOptOk==1
&& p->nToken==1
&& pFirst->pSegcsr
&& pFirst->pSegcsr->bLookup
&& pFirst->bFirst==0
){
/* Determine if doclists may be loaded from disk incrementally. This is
** possible if the bOptOk argument is true, the FTS doclists will be
** scanned in forward order, and the phrase consists of
** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first"
** tokens or prefix tokens that cannot use a prefix-index. */
int bHaveIncr = 0;
int bIncrOk = (bOptOk
&& pCsr->bDesc==pTab->bDescIdx
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
#ifdef SQLITE_TEST
&& pTab->bNoIncrDoclist==0
#endif
);
for(i=0; bIncrOk==1 && i<p->nToken; i++){
Fts3PhraseToken *pToken = &p->aToken[i];
if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){
bIncrOk = 0;
}
if( pToken->pSegcsr ) bHaveIncr = 1;
}
if( bIncrOk && bHaveIncr ){
/* Use the incremental approach. */
int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
rc = sqlite3Fts3MsrIncrStart(
pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
Fts3PhraseToken *pToken = &p->aToken[i];
Fts3MultiSegReader *pSegcsr = pToken->pSegcsr;
if( pSegcsr ){
rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n);
}
}
p->bIncr = 1;
}else{
/* Load the full doclist for the phrase into memory. */
rc = fts3EvalPhraseLoad(pCsr, p);
@ -4080,6 +4179,216 @@ void sqlite3Fts3DoclistNext(
*ppIter = p;
}
/*
** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof
** to true if EOF is reached.
*/
static void fts3EvalDlPhraseNext(
Fts3Table *pTab,
Fts3Doclist *pDL,
u8 *pbEof
){
char *pIter; /* Used to iterate through aAll */
char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
if( pDL->pNextDocid ){
pIter = pDL->pNextDocid;
}else{
pIter = pDL->aAll;
}
if( pIter>=pEnd ){
/* We have already reached the end of this doclist. EOF. */
*pbEof = 1;
}else{
sqlite3_int64 iDelta;
pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
pDL->iDocid += iDelta;
}else{
pDL->iDocid -= iDelta;
}
pDL->pList = pIter;
fts3PoslistCopy(0, &pIter);
pDL->nList = (int)(pIter - pDL->pList);
/* pIter now points just past the 0x00 that terminates the position-
** list for document pDL->iDocid. However, if this position-list was
** edited in place by fts3EvalNearTrim(), then pIter may not actually
** point to the start of the next docid value. The following line deals
** with this case by advancing pIter past the zero-padding added by
** fts3EvalNearTrim(). */
while( pIter<pEnd && *pIter==0 ) pIter++;
pDL->pNextDocid = pIter;
assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
*pbEof = 0;
}
}
/*
** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext().
*/
typedef struct TokenDoclist TokenDoclist;
struct TokenDoclist {
int bIgnore;
sqlite3_int64 iDocid;
char *pList;
int nList;
};
/*
** Token pToken is an incrementally loaded token that is part of a
** multi-token phrase. Advance it to the next matching document in the
** database and populate output variable *p with the details of the new
** entry. Or, if the iterator has reached EOF, set *pbEof to true.
**
** If an error occurs, return an SQLite error code. Otherwise, return
** SQLITE_OK.
*/
static int incrPhraseTokenNext(
Fts3Table *pTab, /* Virtual table handle */
Fts3Phrase *pPhrase, /* Phrase to advance token of */
int iToken, /* Specific token to advance */
TokenDoclist *p, /* OUT: Docid and doclist for new entry */
u8 *pbEof /* OUT: True if iterator is at EOF */
){
int rc = SQLITE_OK;
if( pPhrase->iDoclistToken==iToken ){
assert( p->bIgnore==0 );
assert( pPhrase->aToken[iToken].pSegcsr==0 );
fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof);
p->pList = pPhrase->doclist.pList;
p->nList = pPhrase->doclist.nList;
p->iDocid = pPhrase->doclist.iDocid;
}else{
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
assert( pToken->pDeferred==0 );
assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 );
if( pToken->pSegcsr ){
assert( p->bIgnore==0 );
rc = sqlite3Fts3MsrIncrNext(
pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList
);
if( p->pList==0 ) *pbEof = 1;
}else{
p->bIgnore = 1;
}
}
return rc;
}
/*
** The phrase iterator passed as the second argument:
**
** * features at least one token that uses an incremental doclist, and
**
** * does not contain any deferred tokens.
**
** Advance it to the next matching documnent in the database and populate
** the Fts3Doclist.pList and nList fields.
**
** If there is no "next" entry and no error occurs, then *pbEof is set to
** 1 before returning. Otherwise, if no error occurs and the iterator is
** successfully advanced, *pbEof is set to 0.
**
** If an error occurs, return an SQLite error code. Otherwise, return
** SQLITE_OK.
*/
static int fts3EvalIncrPhraseNext(
Fts3Cursor *pCsr, /* FTS Cursor handle */
Fts3Phrase *p, /* Phrase object to advance to next docid */
u8 *pbEof /* OUT: Set to 1 if EOF */
){
int rc = SQLITE_OK;
Fts3Doclist *pDL = &p->doclist;
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
u8 bEof = 0;
/* This is only called if it is guaranteed that the phrase has at least
** one incremental token. In which case the bIncr flag is set. */
assert( p->bIncr==1 );
if( p->nToken==1 && p->bIncr ){
rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
&pDL->iDocid, &pDL->pList, &pDL->nList
);
if( pDL->pList==0 ) bEof = 1;
}else{
int bDescDoclist = pCsr->bDesc;
struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS];
memset(a, 0, sizeof(a));
assert( p->nToken<=MAX_INCR_PHRASE_TOKENS );
assert( p->iDoclistToken<MAX_INCR_PHRASE_TOKENS );
while( bEof==0 ){
int bMaxSet = 0;
sqlite3_int64 iMax = 0; /* Largest docid for all iterators */
int i; /* Used to iterate through tokens */
/* Advance the iterator for each token in the phrase once. */
for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){
iMax = a[i].iDocid;
bMaxSet = 1;
}
}
assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
assert( rc!=SQLITE_OK || bMaxSet );
/* Keep advancing iterators until they all point to the same document */
for(i=0; i<p->nToken; i++){
while( rc==SQLITE_OK && bEof==0
&& a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
){
rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
if( DOCID_CMP(a[i].iDocid, iMax)>0 ){
iMax = a[i].iDocid;
i = 0;
}
}
}
/* Check if the current entries really are a phrase match */
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
char *aDoclist = sqlite3_malloc(nByte+1);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
for(i=0; i<(p->nToken-1); i++){
if( a[i].bIgnore==0 ){
char *pL = a[i].pList;
char *pR = aDoclist;
char *pOut = aDoclist;
int nDist = p->nToken-1-i;
int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR);
if( res==0 ) break;
nList = (int)(pOut - aDoclist);
}
}
if( i==(p->nToken-1) ){
pDL->iDocid = iMax;
pDL->pList = aDoclist;
pDL->nList = nList;
pDL->bFreeList = 1;
break;
}
sqlite3_free(aDoclist);
}
}
}
*pbEof = bEof;
return rc;
}
/*
** Attempt to move the phrase iterator to point to the next matching docid.
** If an error occurs, return an SQLite error code. Otherwise, return
@ -4099,55 +4408,14 @@ static int fts3EvalPhraseNext(
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
if( p->bIncr ){
assert( p->nToken==1 );
assert( pDL->pNextDocid==0 );
rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
&pDL->iDocid, &pDL->pList, &pDL->nList
);
if( rc==SQLITE_OK && !pDL->pList ){
*pbEof = 1;
}
rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof);
}else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
&pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
);
pDL->pList = pDL->pNextDocid;
}else{
char *pIter; /* Used to iterate through aAll */
char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
if( pDL->pNextDocid ){
pIter = pDL->pNextDocid;
}else{
pIter = pDL->aAll;
}
if( pIter>=pEnd ){
/* We have already reached the end of this doclist. EOF. */
*pbEof = 1;
}else{
sqlite3_int64 iDelta;
pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
pDL->iDocid += iDelta;
}else{
pDL->iDocid -= iDelta;
}
pDL->pList = pIter;
fts3PoslistCopy(0, &pIter);
pDL->nList = (int)(pIter - pDL->pList);
/* pIter now points just past the 0x00 that terminates the position-
** list for document pDL->iDocid. However, if this position-list was
** edited in place by fts3EvalNearTrim(), then pIter may not actually
** point to the start of the next docid value. The following line deals
** with this case by advancing pIter past the zero-padding added by
** fts3EvalNearTrim(). */
while( pIter<pEnd && *pIter==0 ) pIter++;
pDL->pNextDocid = pIter;
assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
*pbEof = 0;
}
fts3EvalDlPhraseNext(pTab, pDL, pbEof);
}
return rc;
@ -4172,7 +4440,6 @@ static int fts3EvalPhraseNext(
static void fts3EvalStartReaders(
Fts3Cursor *pCsr, /* FTS Cursor handle */
Fts3Expr *pExpr, /* Expression to initialize phrases in */
int bOptOk, /* True to enable incremental loading */
int *pRc /* IN/OUT: Error code */
){
if( pExpr && SQLITE_OK==*pRc ){
@ -4183,10 +4450,10 @@ static void fts3EvalStartReaders(
if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
}
pExpr->bDeferred = (i==nToken);
*pRc = fts3EvalPhraseStart(pCsr, bOptOk, pExpr->pPhrase);
*pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase);
}else{
fts3EvalStartReaders(pCsr, pExpr->pLeft, bOptOk, pRc);
fts3EvalStartReaders(pCsr, pExpr->pRight, bOptOk, pRc);
fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc);
fts3EvalStartReaders(pCsr, pExpr->pRight, pRc);
pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
}
}
@ -4428,7 +4695,7 @@ static int fts3EvalSelectDeferred(
** overflowing the 32-bit integer it is stored in. */
if( ii<12 ) nLoad4 = nLoad4*4;
if( ii==0 || pTC->pPhrase->nToken>1 ){
if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){
/* Either this is the cheapest token in the entire query, or it is
** part of a multi-token phrase. Either way, the entire doclist will
** (eventually) be loaded into memory. It may as well be now. */
@ -4508,7 +4775,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
}
#endif
fts3EvalStartReaders(pCsr, pCsr->pExpr, 1, &rc);
fts3EvalStartReaders(pCsr, pCsr->pExpr, &rc);
return rc;
}
@ -4991,6 +5258,16 @@ static int fts3EvalNext(Fts3Cursor *pCsr){
pCsr->iPrevId = pExpr->iDocid;
}while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) );
}
/* Check if the cursor is past the end of the docid range specified
** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */
if( rc==SQLITE_OK && (
(pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid)
|| (pCsr->bDesc!=0 && pCsr->iPrevId<pCsr->iMinDocid)
)){
pCsr->isEof = 1;
}
return rc;
}
@ -5014,12 +5291,16 @@ static void fts3EvalRestart(
if( pPhrase ){
fts3EvalInvalidatePoslist(pPhrase);
if( pPhrase->bIncr ){
assert( pPhrase->nToken==1 );
assert( pPhrase->aToken[0].pSegcsr );
sqlite3Fts3MsrIncrRestart(pPhrase->aToken[0].pSegcsr);
int i;
for(i=0; i<pPhrase->nToken; i++){
Fts3PhraseToken *pToken = &pPhrase->aToken[i];
assert( pToken->pDeferred==0 );
if( pToken->pSegcsr ){
sqlite3Fts3MsrIncrRestart(pToken->pSegcsr);
}
}
*pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase);
}
pPhrase->doclist.pNextDocid = 0;
pPhrase->doclist.iDocid = 0;
}
@ -5268,15 +5549,23 @@ int sqlite3Fts3EvalPhrasePoslist(
pIter = pPhrase->doclist.pList;
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
int iMul; /* +1 if csr dir matches index dir, else -1 */
int bOr = 0;
u8 bEof = 0;
Fts3Expr *p;
u8 bTreeEof = 0;
Fts3Expr *p; /* Used to iterate from pExpr to root */
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
/* Check if this phrase descends from an OR expression node. If not,
** return NULL. Otherwise, the entry that corresponds to docid
** pCsr->iPrevId may lie earlier in the doclist buffer. */
** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the
** tree that the node is part of has been marked as EOF, but the node
** itself is not EOF, then it may point to an earlier entry. */
pNear = pExpr;
for(p=pExpr->pParent; p; p=p->pParent){
if( p->eType==FTSQUERY_OR ) bOr = 1;
if( p->eType==FTSQUERY_NEAR ) pNear = p;
if( p->bEof ) bTreeEof = 1;
}
if( bOr==0 ) return SQLITE_OK;
@ -5295,29 +5584,59 @@ int sqlite3Fts3EvalPhrasePoslist(
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
if( rc!=SQLITE_OK ) return rc;
}
if( pExpr->bEof ){
pIter = 0;
iDocid = 0;
iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
while( bTreeEof==1
&& pNear->bEof==0
&& (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
){
int rc = SQLITE_OK;
fts3EvalNextRow(pCsr, pExpr, &rc);
if( rc!=SQLITE_OK ) return rc;
iDocid = pExpr->iDocid;
pIter = pPhrase->doclist.pList;
}
bEof = (pPhrase->doclist.nAll==0);
assert( bDescDoclist==0 || bDescDoclist==1 );
assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
if( pCsr->bDesc==bDescDoclist ){
int dummy;
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
sqlite3Fts3DoclistPrev(
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
&pIter, &iDocid, &dummy, &bEof
);
}
}else{
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
sqlite3Fts3DoclistNext(
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
&pIter, &iDocid, &bEof
);
if( bEof==0 ){
if( pCsr->bDesc==bDescDoclist ){
int dummy;
if( pNear->bEof ){
/* This expression is already at EOF. So position it to point to the
** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
** iDocid is already set for this entry, so all that is required is
** to set pIter to point to the first byte of the last position-list
** in the doclist.
**
** It would also be correct to set pIter and iDocid to zero. In
** this case, the first call to sqltie3Fts4DoclistPrev() below
** would also move the iterator to point to the last entry in the
** doclist. However, this is expensive, as to do so it has to
** iterate through the entire doclist from start to finish (since
** it does not know the docid for the last entry). */
pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
}
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
sqlite3Fts3DoclistPrev(
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
&pIter, &iDocid, &dummy, &bEof
);
}
}else{
if( pNear->bEof ){
pIter = 0;
iDocid = 0;
}
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
sqlite3Fts3DoclistNext(
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
&pIter, &iDocid, &bEof
);
}
}
}

View File

@ -267,6 +267,12 @@ struct Fts3Table {
int inTransaction; /* True after xBegin but before xCommit/xRollback */
int mxSavepoint; /* Largest valid xSavepoint integer */
#endif
#ifdef SQLITE_TEST
/* True to disable the incremental doclist optimization. This is controled
** by special insert command 'test-no-incr-doclist'. */
int bNoIncrDoclist;
#endif
};
/*
@ -292,7 +298,8 @@ struct Fts3Cursor {
int eEvalmode; /* An FTS3_EVAL_XX constant */
int nRowAvg; /* Average size of database rows, in pages */
sqlite3_int64 nDoc; /* Documents in table */
i64 iMinDocid; /* Minimum docid to return */
i64 iMaxDocid; /* Maximum docid to return */
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
u32 *aMatchinfo; /* Information about most recent match */
int nMatchinfo; /* Number of elements in aMatchinfo[] */
@ -322,6 +329,15 @@ struct Fts3Cursor {
#define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */
#define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */
/*
** The lower 16-bits of the sqlite3_index_info.idxNum value set by
** the xBestIndex() method contains the Fts3Cursor.eSearch value described
** above. The upper 16-bits contain a combination of the following
** bits, used to describe extra constraints on full-text searches.
*/
#define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */
#define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */
#define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */
struct Fts3Doclist {
char *aAll; /* Array containing doclist (or NULL) */

View File

@ -4780,7 +4780,7 @@ static int fts3DoAutoincrmerge(
if( rc ) return rc;
}
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
if( rc ) return rc;;
if( rc ) return rc;
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
sqlite3_step(pStmt);
@ -5050,6 +5050,9 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
p->nMaxPendingData = atoi(&zVal[11]);
rc = SQLITE_OK;
}else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
p->bNoIncrDoclist = atoi(&zVal[21]);
rc = SQLITE_OK;
#endif
}else{
rc = SQLITE_ERROR;

View File

@ -786,6 +786,7 @@ static void amatchFree(amatch_vtab *p){
sqlite3_free(p->zVocabTab);
sqlite3_free(p->zVocabWord);
sqlite3_free(p->zVocabLang);
sqlite3_free(p->zSelf);
memset(p, 0, sizeof(*p));
sqlite3_free(p);
}
@ -948,6 +949,9 @@ static void amatchClearCursor(amatch_cursor *pCur){
pCur->pAllWords = 0;
sqlite3_free(pCur->zInput);
pCur->zInput = 0;
sqlite3_free(pCur->zBuf);
pCur->zBuf = 0;
pCur->nBuf = 0;
pCur->pCost = 0;
pCur->pWord = 0;
pCur->pCurrent = 0;
@ -1103,7 +1107,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
char *zSql;
if( p->zVocabLang && p->zVocabLang[0] ){
zSql = sqlite3_mprintf(
"SELECT \"%s\" FROM \"%s\"",
"SELECT \"%w\" FROM \"%w\"",
" WHERE \"%w\">=?1 AND \"%w\"=?2"
" ORDER BY 1",
p->zVocabWord, p->zVocabTab,
@ -1111,7 +1115,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){
);
}else{
zSql = sqlite3_mprintf(
"SELECT \"%s\" FROM \"%s\""
"SELECT \"%w\" FROM \"%w\""
" WHERE \"%w\">=?1"
" ORDER BY 1",
p->zVocabWord, p->zVocabTab,

View File

@ -38,6 +38,19 @@
** out) run the following query:
**
** SELECT next_char('cha','dictionary','word');
**
** IMPLEMENTATION NOTES:
**
** The next_char function is implemented using recursive SQL that makes
** use of the table name and column name as part of a query. If either
** the table name or column name are keywords or contain special characters,
** then they should be escaped. For example:
**
** SELECT next_char('cha','[dictionary]','[word]');
**
** This also means that the table name can be a subquery:
**
** SELECT next_char('cha','(SELECT word AS w FROM dictionary)','w');
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@ -231,9 +244,9 @@ static void nextCharFunc(
zColl = "";
}
zSql = sqlite3_mprintf(
"SELECT \"%w\" FROM \"%w\""
" WHERE \"%w\">=(?1 || ?2) %s"
" AND \"%w\"<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */
"SELECT %s FROM %s"
" WHERE %s>=(?1 || ?2) %s"
" AND %s<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */
" %s"
" ORDER BY 1 %s ASC LIMIT 1",
zField, zTable, zField, zColl, zField, zColl, zWhereClause, zColl

706
ext/misc/vfslog.c Normal file
View File

@ -0,0 +1,706 @@
/*
** 2013-10-09
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains the implementation of an SQLite vfs wrapper for
** unix that generates per-database log files of all disk activity.
*/
/*
** This module contains code for a wrapper VFS that causes a log of
** most VFS calls to be written into a file on disk. The log
** is stored as comma-separated variables.
**
** All calls on sqlite3_file objects are logged.
** Additionally, calls to the xAccess(), xOpen(), and xDelete()
** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64)
** are not logged.
*/
#include "sqlite3.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#if SQLITE_OS_UNIX
# include <unistd.h>
#endif
/*
** Forward declaration of objects used by this utility
*/
typedef struct VLogLog VLogLog;
typedef struct VLogVfs VLogVfs;
typedef struct VLogFile VLogFile;
/* There is a pair (an array of size 2) of the following objects for
** each database file being logged. The first contains the filename
** and is used to log I/O with the main database. The second has
** a NULL filename and is used to log I/O for the journal. Both
** out pointers are the same.
*/
struct VLogLog {
VLogLog *pNext; /* Next in a list of all active logs */
VLogLog **ppPrev; /* Pointer to this in the list */
int nRef; /* Number of references to this object */
int nFilename; /* Length of zFilename in bytes */
char *zFilename; /* Name of database file. NULL for journal */
FILE *out; /* Write information here */
};
struct VLogVfs {
sqlite3_vfs base; /* VFS methods */
sqlite3_vfs *pVfs; /* Parent VFS */
};
struct VLogFile {
sqlite3_file base; /* IO methods */
sqlite3_file *pReal; /* Underlying file handle */
VLogLog *pLog; /* The log file for this file */
};
#define REALVFS(p) (((VLogVfs*)(p))->pVfs)
/*
** Methods for VLogFile
*/
static int vlogClose(sqlite3_file*);
static int vlogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int vlogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int vlogTruncate(sqlite3_file*, sqlite3_int64 size);
static int vlogSync(sqlite3_file*, int flags);
static int vlogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int vlogLock(sqlite3_file*, int);
static int vlogUnlock(sqlite3_file*, int);
static int vlogCheckReservedLock(sqlite3_file*, int *pResOut);
static int vlogFileControl(sqlite3_file*, int op, void *pArg);
static int vlogSectorSize(sqlite3_file*);
static int vlogDeviceCharacteristics(sqlite3_file*);
/*
** Methods for VLogVfs
*/
static int vlogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int vlogDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int vlogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int vlogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *vlogDlOpen(sqlite3_vfs*, const char *zFilename);
static void vlogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*vlogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
static void vlogDlClose(sqlite3_vfs*, void*);
static int vlogRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int vlogSleep(sqlite3_vfs*, int microseconds);
static int vlogCurrentTime(sqlite3_vfs*, double*);
static int vlogGetLastError(sqlite3_vfs*, int, char *);
static int vlogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static VLogVfs vlog_vfs = {
{
1, /* iVersion */
0, /* szOsFile (set by register_vlog()) */
1024, /* mxPathname */
0, /* pNext */
"vfslog", /* zName */
0, /* pAppData */
vlogOpen, /* xOpen */
vlogDelete, /* xDelete */
vlogAccess, /* xAccess */
vlogFullPathname, /* xFullPathname */
vlogDlOpen, /* xDlOpen */
vlogDlError, /* xDlError */
vlogDlSym, /* xDlSym */
vlogDlClose, /* xDlClose */
vlogRandomness, /* xRandomness */
vlogSleep, /* xSleep */
vlogCurrentTime, /* xCurrentTime */
vlogGetLastError, /* xGetLastError */
vlogCurrentTimeInt64 /* xCurrentTimeInt64 */
},
0
};
static sqlite3_io_methods vlog_io_methods = {
1, /* iVersion */
vlogClose, /* xClose */
vlogRead, /* xRead */
vlogWrite, /* xWrite */
vlogTruncate, /* xTruncate */
vlogSync, /* xSync */
vlogFileSize, /* xFileSize */
vlogLock, /* xLock */
vlogUnlock, /* xUnlock */
vlogCheckReservedLock, /* xCheckReservedLock */
vlogFileControl, /* xFileControl */
vlogSectorSize, /* xSectorSize */
vlogDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0 /* xShmUnmap */
};
#if SQLITE_OS_UNIX && !defined(NO_GETTOD)
#include <sys/time.h>
static sqlite3_uint64 vlog_time(){
struct timeval sTime;
gettimeofday(&sTime, 0);
return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
}
#elif SQLITE_OS_WIN
#include <windows.h>
#include <time.h>
static sqlite3_uint64 vlog_time(){
FILETIME ft;
sqlite3_uint64 u64time = 0;
GetSystemTimeAsFileTime(&ft);
u64time |= ft.dwHighDateTime;
u64time <<= 32;
u64time |= ft.dwLowDateTime;
/* ft is 100-nanosecond intervals, we want microseconds */
return u64time /(sqlite3_uint64)10;
}
#else
static sqlite3_uint64 vlog_time(){
return 0;
}
#endif
/*
** Write a message to the log file
*/
static void vlogLogPrint(
VLogLog *pLog, /* The log file to write into */
sqlite3_int64 tStart, /* Start time of system call */
sqlite3_int64 tElapse, /* Elapse time of system call */
const char *zOp, /* Type of system call */
sqlite3_int64 iArg1, /* First argument */
sqlite3_int64 iArg2, /* Second argument */
const char *zArg3, /* Third argument */
int iRes /* Result */
){
char z1[40], z2[40], z3[70];
if( pLog==0 ) return;
if( iArg1>=0 ){
sqlite3_snprintf(sizeof(z1), z1, "%lld", iArg1);
}else{
z1[0] = 0;
}
if( iArg2>=0 ){
sqlite3_snprintf(sizeof(z2), z2, "%lld", iArg2);
}else{
z2[0] = 0;
}
if( zArg3 ){
sqlite3_snprintf(sizeof(z3), z3, "\"%s\"", zArg3);
}else{
z3[0] = 0;
}
fprintf(pLog->out,"%lld,%lld,%s,%d,%s,%s,%s,%d\n",
tStart, tElapse, zOp, pLog->zFilename==0, z1, z2, z3, iRes);
}
/*
** List of all active log connections. Protected by the master mutex.
*/
static VLogLog *allLogs = 0;
/*
** Close a VLogLog object
*/
static void vlogLogClose(VLogLog *p){
if( p ){
sqlite3_mutex *pMutex;
p->nRef--;
if( p->nRef>0 || p->zFilename==0 ) return;
pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
sqlite3_mutex_enter(pMutex);
*p->ppPrev = p->pNext;
if( p->pNext ) p->pNext->ppPrev = p->ppPrev;
sqlite3_mutex_leave(pMutex);
fclose(p->out);
sqlite3_free(p);
}
}
/*
** Open a VLogLog object on the given file
*/
static VLogLog *vlogLogOpen(const char *zFilename){
int nName = (int)strlen(zFilename);
int isJournal = 0;
sqlite3_mutex *pMutex;
VLogLog *pLog, *pTemp;
sqlite3_int64 tNow = 0;
if( nName>4 && strcmp(zFilename+nName-4,"-wal")==0 ){
return 0; /* Do not log wal files */
}else
if( nName>8 && strcmp(zFilename+nName-8,"-journal")==0 ){
nName -= 8;
isJournal = 1;
}else if( nName>12
&& sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){
return 0; /* Do not log master journal files */
}
pTemp = sqlite3_malloc( sizeof(*pLog)*2 + nName + 60 );
if( pTemp==0 ) return 0;
pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
sqlite3_mutex_enter(pMutex);
for(pLog=allLogs; pLog; pLog=pLog->pNext){
if( pLog->nFilename==nName && !memcmp(pLog->zFilename, zFilename, nName) ){
break;
}
}
if( pLog==0 ){
pLog = pTemp;
pTemp = 0;
memset(pLog, 0, sizeof(*pLog)*2);
pLog->zFilename = (char*)&pLog[2];
tNow = vlog_time();
sqlite3_snprintf(nName+60, pLog->zFilename, "%.*s-debuglog-%lld",
nName, zFilename, tNow);
pLog->out = fopen(pLog->zFilename, "a");
if( pLog->out==0 ){
sqlite3_mutex_leave(pMutex);
sqlite3_free(pLog);
return 0;
}
pLog->nFilename = nName;
pLog[1].out = pLog[0].out;
pLog->ppPrev = &allLogs;
if( allLogs ) allLogs->ppPrev = &pLog->pNext;
pLog->pNext = allLogs;
allLogs = pLog;
}
sqlite3_mutex_leave(pMutex);
if( pTemp ){
sqlite3_free(pTemp);
}else{
#if SQLITE_OS_UNIX
char zHost[200];
zHost[0] = 0;
gethostname(zHost, sizeof(zHost)-1);
zHost[sizeof(zHost)-1] = 0;
vlogLogPrint(pLog, tNow, 0, "IDENT", getpid(), -1, zHost, 0);
#endif
}
if( pLog && isJournal ) pLog++;
pLog->nRef++;
return pLog;
}
/*
** Close an vlog-file.
*/
static int vlogClose(sqlite3_file *pFile){
sqlite3_uint64 tStart, tElapse;
int rc = SQLITE_OK;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
if( p->pReal->pMethods ){
rc = p->pReal->pMethods->xClose(p->pReal);
}
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "CLOSE", -1, -1, 0, rc);
vlogLogClose(p->pLog);
return rc;
}
/*
** Compute signature for a block of content.
**
** For blocks of 16 or fewer bytes, the signature is just a hex dump of
** the entire block.
**
** For blocks of more than 16 bytes, the signature is a hex dump of the
** first 8 bytes followed by a 64-bit has of the entire block.
*/
static void vlogSignature(unsigned char *p, int n, char *zCksum){
unsigned int s0 = 0, s1 = 0;
unsigned int *pI;
int i;
if( n<=16 ){
for(i=0; i<n; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
}else{
pI = (unsigned int*)p;
for(i=0; i<n-7; i+=8){
s0 += pI[0] + s1;
s1 += pI[1] + s0;
pI += 2;
}
for(i=0; i<8; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
sqlite3_snprintf(18, zCksum+i*2, "-%08x%08x", s0, s1);
}
}
/*
** Read data from an vlog-file.
*/
static int vlogRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
char zSig[40];
tStart = vlog_time();
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
tElapse = vlog_time() - tStart;
if( rc==SQLITE_OK ){
vlogSignature(zBuf, iAmt, zSig);
}else{
zSig[0] = 0;
}
vlogLogPrint(p->pLog, tStart, tElapse, "READ", iAmt, iOfst, zSig, rc);
if( rc==SQLITE_OK
&& p->pLog
&& p->pLog->zFilename
&& iOfst<=24
&& iOfst+iAmt>=28
){
unsigned char *x = ((unsigned char*)zBuf)+(24-iOfst);
unsigned iCtr;
iCtr = (x[0]<<24) + (x[1]<<16) + (x[2]<<8) + x[3];
vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-READ", iCtr, -1, 0, 0);
}
return rc;
}
/*
** Write data to an vlog-file.
*/
static int vlogWrite(
sqlite3_file *pFile,
const void *z,
int iAmt,
sqlite_int64 iOfst
){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
char zSig[40];
tStart = vlog_time();
vlogSignature((unsigned char*)z, iAmt, zSig);
rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "WRITE", iAmt, iOfst, zSig, rc);
if( rc==SQLITE_OK
&& p->pLog
&& p->pLog->zFilename
&& iOfst<=24
&& iOfst+iAmt>=28
){
unsigned char *x = ((unsigned char*)z)+(24-iOfst);
unsigned iCtr;
iCtr = (x[0]<<24) + (x[1]<<16) + (x[2]<<8) + x[3];
vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-WRITE", iCtr, -1, 0, 0);
}
return rc;
}
/*
** Truncate an vlog-file.
*/
static int vlogTruncate(sqlite3_file *pFile, sqlite_int64 size){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xTruncate(p->pReal, size);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "TRUNCATE", size, -1, 0, rc);
return rc;
}
/*
** Sync an vlog-file.
*/
static int vlogSync(sqlite3_file *pFile, int flags){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xSync(p->pReal, flags);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "SYNC", flags, -1, 0, rc);
return rc;
}
/*
** Return the current file-size of an vlog-file.
*/
static int vlogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "FILESIZE", *pSize, -1, 0, rc);
return rc;
}
/*
** Lock an vlog-file.
*/
static int vlogLock(sqlite3_file *pFile, int eLock){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xLock(p->pReal, eLock);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "LOCK", eLock, -1, 0, rc);
return rc;
}
/*
** Unlock an vlog-file.
*/
static int vlogUnlock(sqlite3_file *pFile, int eLock){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "UNLOCK", eLock, -1, 0, rc);
return rc;
}
/*
** Check if another file-handle holds a RESERVED lock on an vlog-file.
*/
static int vlogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "CHECKRESERVEDLOCK",
*pResOut, -1, "", rc);
return rc;
}
/*
** File control method. For custom operations on an vlog-file.
*/
static int vlogFileControl(sqlite3_file *pFile, int op, void *pArg){
VLogFile *p = (VLogFile *)pFile;
sqlite3_uint64 tStart, tElapse;
int rc;
tStart = vlog_time();
rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
*(char**)pArg = sqlite3_mprintf("vlog/%z", *(char**)pArg);
}
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, -1, 0, rc);
return rc;
}
/*
** Return the sector-size in bytes for an vlog-file.
*/
static int vlogSectorSize(sqlite3_file *pFile){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xSectorSize(p->pReal);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "SECTORSIZE", -1, -1, 0, rc);
return rc;
}
/*
** Return the device characteristic flags supported by an vlog-file.
*/
static int vlogDeviceCharacteristics(sqlite3_file *pFile){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogFile *p = (VLogFile *)pFile;
tStart = vlog_time();
rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
tElapse = vlog_time() - tStart;
vlogLogPrint(p->pLog, tStart, tElapse, "DEVCHAR", -1, -1, 0, rc);
return rc;
}
/*
** Open an vlog file handle.
*/
static int vlogOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
int rc;
sqlite3_uint64 tStart, tElapse;
sqlite3_int64 iArg2;
VLogFile *p = (VLogFile*)pFile;
p->pReal = (sqlite3_file*)&p[1];
if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){
p->pLog = vlogLogOpen(zName);
}else{
p->pLog = 0;
}
tStart = vlog_time();
rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
tElapse = vlog_time() - tStart;
iArg2 = pOutFlags ? *pOutFlags : -1;
vlogLogPrint(p->pLog, tStart, tElapse, "OPEN", flags, iArg2, 0, rc);
if( rc==SQLITE_OK ){
pFile->pMethods = &vlog_io_methods;
}else{
if( p->pLog ) vlogLogClose(p->pLog);
p->pLog = 0;
}
return rc;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int vlogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogLog *pLog;
tStart = vlog_time();
rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
tElapse = vlog_time() - tStart;
pLog = vlogLogOpen(zPath);
vlogLogPrint(pLog, tStart, tElapse, "DELETE", dirSync, -1, 0, rc);
vlogLogClose(pLog);
return rc;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int vlogAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
int rc;
sqlite3_uint64 tStart, tElapse;
VLogLog *pLog;
tStart = vlog_time();
rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
tElapse = vlog_time() - tStart;
pLog = vlogLogOpen(zPath);
vlogLogPrint(pLog, tStart, tElapse, "ACCESS", flags, *pResOut, 0, rc);
vlogLogClose(pLog);
return rc;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (INST_MAX_PATHNAME+1) bytes.
*/
static int vlogFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *vlogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
}
/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
** utf-8 string describing the most recent error encountered associated
** with dynamic libraries.
*/
static void vlogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*vlogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
}
/*
** Close the dynamic library handle pHandle.
*/
static void vlogDlClose(sqlite3_vfs *pVfs, void *pHandle){
REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int vlogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int vlogSleep(sqlite3_vfs *pVfs, int nMicro){
return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int vlogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
}
static int vlogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
}
static int vlogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
}
/*
** Register debugvfs as the default VFS for this process.
*/
int sqlite3_register_vfslog(const char *zArg){
vlog_vfs.pVfs = sqlite3_vfs_find(0);
vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile;
return sqlite3_vfs_register(&vlog_vfs.base, 1);
}

10
main.mk
View File

@ -279,7 +279,8 @@ TESTSRC += \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/spellfix.c \
$(TOP)/ext/misc/wholenumber.c
$(TOP)/ext/misc/wholenumber.c \
$(TOP)/ext/misc/vfslog.c
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
@ -618,6 +619,10 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c
extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
./testfixture$(EXE) $(TOP)/test/loadext.test
showdb: $(TOP)/tool/showdb.c sqlite3.c
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showdb \
$(TOP)/tool/showdb.c sqlite3.c
# This target will fail if the SQLite amalgamation contains any exported
# symbols that do not begin with "sqlite3_". It is run as part of the
# releasetest.tcl script.
@ -651,9 +656,10 @@ clean:
rm -f fts3-testfixture fts3-testfixture.exe
rm -f testfixture testfixture.exe
rm -f threadtest3 threadtest3.exe
rm -f sqlite3.c fts?amal.c tclsqlite3.c
rm -f sqlite3.c sqlite3-*.c fts?amal.c tclsqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe
rm -f showdb

147
manifest
View File

@ -1,9 +1,9 @@
C Merge\supdates\sfrom\strunk.
D 2013-09-24T19:07:48.655
D 2013-10-12T23:39:49.890
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
F Makefile.in e2d28ec95bd17ab4f3b6ee40b7102e9d7a0857b9
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc ef17891ca710b1e7bc9cbab2061381884362aeb3
F Makefile.msc d72be28ba13ec3986ac5791a6549036a84dc5903
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION a8d1f6839521130dc73c5408cdd24bcfd791df34
@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 0d6311cd433ea30c9e941b93bfeac2f9e6937980
F ext/fts3/fts3.c dcb90d12ff4a0ccfceaefb3bae2199b6536e0dfc
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h c7a451661c2d9b2440b2008c3f63ce06f13181d6
F ext/fts3/fts3Int.h 8689f7cf85020e7f88d1e761eeac480c3b0ea7ad
F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd
F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
F ext/fts3/fts3_write.c ce45c3ea578464f26b0293ea8e54a39694f18b64
F ext/fts3/fts3_write.c 17817f0cb6c8555e1be5e073fbddf676c60f4ea9
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
@ -106,15 +106,16 @@ F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06
F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012
F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
F ext/misc/nextchar.c 80ba262d23238efcfcb3d72d71aa4513098e26a6
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
F ext/misc/spellfix.c 5e1d547e9a2aed13897fa91bac924333f62fd2d9
F ext/misc/vfslog.c 1abb192d8d4bd323adbddec0c024580496b51b7a
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
@ -139,7 +140,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d
F main.mk a10f1925ae3bb545a045d1f1867506f49bee972f
F main.mk 2e01504061f618db804812143a9e9ec45a66ae70
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
@ -157,30 +158,30 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
F src/analyze.c d322972af09e3f8debb45f420dfe3ded142b108b
F src/attach.c 4a2b6a6d9b5f9fd55a8b59488ff7929fef73a195
F src/analyze.c f9e4eec962f2d81d775d8d5c2efb27b84acb0be0
F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c b9b57df546df2636294bfb21a986f5707b417df2
F src/btree.c d5720cbb21ae56e7e5b07847e05e5b203818acac
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
F src/btreeInt.h 51cf220a9b9223354770883e93a859dc377aa27f
F src/build.c f63e8929c7f89c0074fbc74929bc946ea117b2f8
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
F src/build.c 8ae900bf021a66ac110f5eb2dcf994d24d1c2061
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
F src/date.c 65196e95e69f36993659bd7781abe7c2f1994739
F src/delete.c 2dc64ca360b7d7da481183ea920a813a0c203c97
F src/expr.c 1017f482217e093ecdaca91e8666681e83733252
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c 45788c5e48734f2af4acd75a876466e5b9838e34
F src/expr.c e7338ccffdc391c53ba2d51c5eb6a2f5299e040e
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c be866cd8c4fa6cae98ba33109578fd1a3311ee5b
F src/fkey.c 5dc10cbaa355753903cd2a64da040f948997ebf8
F src/func.c 5fb4103cc5fd2920696e0a263e6a56a2844ab35d
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c a271771db927873c850da8928d6ee9fc058fb9fe
F src/insert.c 9a3f578ffe37f18ef695a06764320db5dc1f0011
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@ -203,29 +204,29 @@ F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 243fb37f47dc072fc59839ea241ff0a17c8d76e6
F src/os_win.c b8f54f42d9c232c48cb694b7dbe94e601c816b5c
F src/os_win.c 0fea05bc7b75eccb01d8a8a10aaeaf4147b8e0cd
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
F src/parse.y a97566d6da75075589a7c716d1bda14b586cf8da
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
F src/pragma.c 0c7a67a75cb4f9849190f33f62534d37f38ff8ed
F src/pragma.c 1c00ed0dea8bc119d248e26e648d438e16e92010
F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
F src/resolve.c 7459801d02997b07e8b8da85ef255392ba1d022b
F src/resolve.c 5f15b00644c36a1610b87857abf42db38c07519c
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c fc60e8e539cb9a895cac197de95048759b0f3ab0
F src/shell.c d920a891ca09b8bd262cced7fb0ab9d723f7a747
F src/sqlite.h.in ec40aa958a270416fb04b4f72210357bf163d2c5
F src/select.c 15127b54cc11defb2cddef6914e1f384501a61c4
F src/shell.c 6f11f0e9ded63d48e306f2c6858c521e568a47bb
F src/sqlite.h.in 4c6eb96fded1d56a27cec04b6b6803789eb28f54
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 18c7f80e7e23098942436f7286e9c93adc6908be
F src/sqliteInt.h eeebd2522bbd5ac7e3024be64113e8366caa66c8
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 659dad8ef30b54831306a244b43e37af4725a444
F src/tclsqlite.c 3b5f3716e320480659239abe887164521c575d83
F src/test1.c 26226cfd2b6dc3f77d2eb27f07ffcf236b4e728b
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
@ -233,7 +234,7 @@ F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220
F src/test7.c 126b886b53f0358b92aba9b81d3fcbfbe9a93cd6
F src/test8.c 7ee77ea522ae34aa691dfe407139dec80d4fc039
F src/test8.c c7aab1d9fbbf54fc33d43b73aa24aa55f9eaf534
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
@ -245,7 +246,7 @@ F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
F src/test_func.c f8235719dff4bf9ffee04c55a190af8782ce9ab5
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
@ -272,25 +273,25 @@ F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e
F src/trigger.c ba0a883cd536b7dfdd4df3733001f5372a4299da
F src/update.c f5182157f5d0d0a97bc5f5e3c9bdba0dfbe08f08
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/util.c 7f3e35432d6888d1e770c488c35bd98970c44eec
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
F src/vacuum.c f313bc97123a4dd4bfd3f50a00c4d44c08a5b1b7
F src/vdbe.c 56e648f5ba9a91810caf216857adfed9039cd174
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
F src/vdbeInt.h ff57f67aee1ba26a3a47e786533dab155ab6dad6
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
F src/vdbeaux.c 55f4858fe6abd84bd7311acbf30a75a28903ec25
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
F src/vdbemem.c 817ce21ab4ca57f902619bb8fef3f8a51bbd0ed8
F src/vdbemem.c 28730af78c730cf230b64d62757a009668e76444
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
F src/where.c d2f58a441ba8709a99df6654b26a50b7ca7dada4
F src/where.c dd2d0d69280d6653d8ef8cf3b6b4b848b9058197
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@ -301,11 +302,12 @@ F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
F test/analyze9.test 1b9b7e9a096d1536f03d9ad7b72f638ef5669347
@ -318,7 +320,7 @@ F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test 9bf1d25180a2e05fc12ce3940cc8003033642f68
F test/attach.test 0d112b7713611fdf0340260192749737135fda5f
F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
@ -413,7 +415,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/date.test 502ddcbaaac9ce103bcd76d8e9d9bc8aa04e61b0
F test/date.test 42973251b9429f2c41b77eb98a7b0b0ba2d3b2c0
F test/dbstatus.test aee30c3f337e6c217ff06df59fb8fe6e6448dce2
F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
@ -436,7 +438,7 @@ F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test 291e056e1a442a5e5166a989a8a03a46e38225ca
F test/e_reindex.test e175794fc41f8e8aef34772e87a7d7b7a9251dd3
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
F test/e_select.test f2358d074bd82240bc79a8348f284a2a8909dc1f
F test/e_select.test d3226cb94fae4af3f198e68e71f655e106d0be47
F test/e_select2.test 22c660a7becf0712c95e1ca1b2d9e716a1261460
F test/e_update.test bea00499e43ee1da77b03cdb0b20c7c864c1ec5a
F test/e_uri.test a2c92d80093a7efdcfbb11093651cbea87097b6b
@ -445,7 +447,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test d9e7ad4e7bd36d976f1b631f76e6e6ea090c41a0
F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac
F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75
@ -460,8 +462,8 @@ F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b
F test/fkey2.test 06e0b4cc9e1b3271ae2ae6feeb19755468432111
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
F test/fkey6.test c555f7fc45d842cc84b0d3ff93951ce2b8c25fc8
F test/fkey5.test 2b8c761ad23bb6a95b9cf8366c9a982a80a439c2
F test/fkey6.test 18e8c024d39f68f8d4bb1177c992bcffdc273464
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
@ -530,6 +532,7 @@ F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
@ -546,24 +549,26 @@ F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
F test/fts3query.test 4fefd43ff24993bc2c9b2778f2bec0cc7629e7ed
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
F test/fts3snippet.test 24d6ff1920a70fd970c401a8525834b4ad12cece
F test/fts3snippet.test d524af6bcef4714e059ef559113dbdc924cd33d1
F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
F test/fts3tok1.test b10d0a12a0ab5f905cea1200b745de233f37443f
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae
F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca
F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8
F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
F test/fts4incr.test 2fae04582c2329a038b2b1f985e702478fb94888
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
F test/fts4unicode.test ebd937061e1ce096240d2352feb424587f2187b9
F test/fts4unicode.test e28ba1a14181e709dcdf47455f207adf14c7cfe0
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test cd25cf605c5a345d038dc7b84232204c6a901c84
F test/func.test c7e80a44eebac8604397eb2ad83d0d5d9d541237
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
F test/func4.test 142490571f2e7ee6c3c5a65f24cad3f8342c02a2
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
@ -573,6 +578,7 @@ F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
F test/hook.test 45cb22b940c3cc0af616ba7430f666e245711a48
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
@ -595,7 +601,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
F test/index6.test e96324d8c1ade4b30a4c6cee14b1fc2e5a367cda
F test/index6.test 9996f064672c03e768e256e4bf7cff4b63e8b109
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
@ -604,7 +610,7 @@ F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
F test/insert4.test 87f6798f31d60c4e177622fcc3663367e6ecbd90
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0
F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
F test/intpkey.test a9674fc6195e0952e4e6105a9981ce1e48e7f215
@ -719,9 +725,9 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
F test/permutations.test 72f4f8881d388163ddbbeec0a6ed812e863ea2e6
F test/permutations.test e154f5ed66d4d4913a99a110e870c9407f75b055
F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178
F test/pragma2.test 224f0381f9411a78ae685cac24c13656a62021b7
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@ -757,7 +763,7 @@ F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5
F test/schema5.test 0103e4c0313b3725b5ae5600bdca53006ab53db3
F test/securedel.test 87a2561151af1f1e349071a89fdd77059f50113c
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test deba017eed9daa5af33de868676c997e7eebb931
F test/select1.test fc2a61f226a649393664ad54bc5376631801517c
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 00179be44e531fe04c1c3f15df216439dff2519d
@ -774,15 +780,15 @@ F test/selectE.test fc02a1eb04c8eb537091482644b7d778ae8759b7
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257
F test/shared3.test fcd65cb11d189eff5f5c85cc4fad246fb0933108
F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956
F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538
F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
F test/sharedlock.test 927a4b6da11978c82b857dbdb20a932aad732123
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test e7c0b9ebda25d5e78f0a3ea0dc4e31bb6d8098c0
F test/shell2.test e1d3790f064e50b2f973502f45750012667486df
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
@ -802,11 +808,11 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/spellfix.test 38246facf7d9d7eeb8a57d7497cf7ce73ce5785d
F test/spellfix.test 8c40b169b104086d8795781f670ba3c786d6d8be
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
F test/subquery.test 3b97763ada8b3a4092d2c80db3ebc0e7870e7eaf
F test/subquery.test 666fdecceac258f5fd84bed09a64e49d9f37edd9
F test/subquery2.test 91e1e364072aeff431d1f9689b15147e421d88c7
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
@ -852,7 +858,7 @@ F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f
F test/tkt-6bfb98dfc0.test 24780633627b5cfc0635a5500c2389ebfb563336
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
F test/tkt-78e04e52ea.test 787b70cfb0488c356266bb8d5ad8a657f9efceb8
F test/tkt-78e04e52ea.test b0190d3375cf88b97d32188149cc99ccf22f556b
F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844
F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
@ -985,6 +991,7 @@ F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test a7b4367392c755bc5fd5fff88011753e6b6afe90
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52
F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
@ -1045,8 +1052,8 @@ F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
F test/where.test 8d66dfbfd4d12816f74f854dbf67dee492c06267
F test/where2.test 76d5346f7edb2a6a0442dcf3e9d088ac6903e0b5
F test/where.test 701a633ed16c661cd597b9d504b485197a0f49d7
F test/where2.test ed6baa9420a109d8be683dbef5d153d186f3690b
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
@ -1073,25 +1080,28 @@ F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/lemon.c 680980c7935bfa1edec20c804c9e5ba4b1dd96f5
F tool/lemon.c 796930d5fc2036c7636f3f1ee12f9ae03719a2eb
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
F tool/logest.c 7ad625cac3d54012b27d468b7af6612f78b9ba75
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl e24da1496b4af6de448e9673cf6adbef53e6e830
F tool/mkpragmatab.tcl 3fc52e00a234750675e8a569d2919ff48558e9eb
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
F tool/mksqlite3c.tcl d344cc3144a0271cd853c5e3df36e9f31d78d619
F tool/mksqlite3c.tcl d8dc444d403019167260e5578f5c362741f03696
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
F tool/mkvsix.tcl f3312df26fd9938a27fa0a845ec96bea84b0c16b
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
F tool/omittest.tcl 4665982e95a6e5c1bd806cf7bc3dea95be422d77
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
F tool/showdb.c 525ecc443578647703051308ad50a93de6ba2c4b
@ -1099,7 +1109,7 @@ F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
F tool/spaceanal.tcl f87fc8e459e3e42255b52987fe0dda3f8a8c513d
F tool/spaceanal.tcl d8c11da184b1a13d0456d786e70b3867e141b74a
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
@ -1112,10 +1122,9 @@ F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 8922be1a3e0269552e12b87fe1e5141c38a8d3f8 ed24051462c09220ebfb82a347b4a2b5c820ef63
R 4d2894e447b5c39e0b9e2bc56076987a
P 435ce3b3fc0cffb4d7e6f2694c3100066e19f9ed f0cf8c85dcbcc7778aed2816792c368d777f79cb
R 891b0b68c6f6fe8752068d950723fcad
U mistachkin
Z 7dee757dc233dca1626329d37ad8fbdb
Z f69b0089d66b59d2f7fc2c4b7bcb9bb1

View File

@ -1 +1 @@
435ce3b3fc0cffb4d7e6f2694c3100066e19f9ed
a88b5be01e68b26267ff6eb05e931ef2e7fc9f99

View File

@ -589,6 +589,11 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
}
}
#endif
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
UNUSED_PARAMETER( p );
UNUSED_PARAMETER( iChng );
#endif
}
/*
@ -614,6 +619,8 @@ static void statPush(
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
int iChng = sqlite3_value_int(argv[1]);
UNUSED_PARAMETER( argc );
UNUSED_PARAMETER( context );
assert( p->nCol>1 ); /* Includes rowid field */
assert( iChng<p->nCol );
@ -743,12 +750,12 @@ static void statGet(
return;
}
sqlite3_snprintf(24, zRet, "%lld", p->nRow);
sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<(p->nCol-1); i++){
i64 nDistinct = p->current.anDLt[i] + 1;
i64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
sqlite3_snprintf(24, z, " %lld", iVal);
u64 nDistinct = p->current.anDLt[i] + 1;
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
sqlite3_snprintf(24, z, " %llu", iVal);
z += sqlite3Strlen30(z);
assert( p->current.anEq[i] );
}
@ -789,7 +796,7 @@ static void statGet(
int i;
char *z = zRet;
for(i=0; i<p->nCol; i++){
sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
z += sqlite3Strlen30(z);
}
assert( z[0]=='\0' && z>zRet );
@ -799,6 +806,9 @@ static void statGet(
}
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {
1+IsStat34, /* nArg */
@ -817,8 +827,10 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
assert( regOut!=regStat4 && regOut!=regStat4+1 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
#else
#elif SQLITE_DEBUG
assert( iParam==STAT_GET_STAT1 );
#else
UNUSED_PARAMETER( iParam );
#endif
sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regOut);
sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
@ -1250,18 +1262,16 @@ struct analysisInfo {
** the array aOut[].
*/
static void decodeIntArray(
char *zIntArray,
int nOut,
tRowcnt *aOut,
int *pbUnordered
char *zIntArray, /* String containing int array to decode */
int nOut, /* Number of slots in aOut[] */
tRowcnt *aOut, /* Store integers here */
Index *pIndex /* Handle extra flags for this index, if not NULL */
){
char *z = zIntArray;
int c;
int i;
tRowcnt v;
assert( pbUnordered==0 || *pbUnordered==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( z==0 ) z = "";
#else
@ -1276,8 +1286,19 @@ static void decodeIntArray(
aOut[i] = v;
if( *z==' ' ) z++;
}
if( pbUnordered && strcmp(z, "unordered")==0 ){
*pbUnordered = 1;
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
assert( pIndex!=0 );
#else
if( pIndex )
#endif
{
if( strcmp(z, "unordered")==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
int v32 = 0;
sqlite3GetInt32(z+3, &v32);
pIndex->szIdxRow = sqlite3LogEst(v32);
}
}
}
@ -1316,12 +1337,13 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
z = argv[2];
if( pIndex ){
int bUnordered = 0;
decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst,&bUnordered);
decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
pIndex->bUnordered = bUnordered;
}else{
decodeIntArray((char*)z, 1, &pTable->nRowEst, 0);
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
}
return 0;

View File

@ -417,11 +417,8 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
/*
** Initialize a DbFixer structure. This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below.
**
** The return value indicates whether or not fixation is required. TRUE
** means we do need to fix the database references, FALSE means we do not.
*/
int sqlite3FixInit(
void sqlite3FixInit(
DbFixer *pFix, /* The fixer to be initialized */
Parse *pParse, /* Error messages will be written here */
int iDb, /* This is the database that must be used */
@ -430,7 +427,6 @@ int sqlite3FixInit(
){
sqlite3 *db;
if( NEVER(iDb<0) || iDb==1 ) return 0;
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
@ -438,7 +434,7 @@ int sqlite3FixInit(
pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
return 1;
pFix->bVarOnly = (iDb==1);
}
/*
@ -466,15 +462,17 @@ int sqlite3FixSrcList(
if( NEVER(pList==0) ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
if( pFix->bVarOnly==0 ){
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
}
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
@ -497,9 +495,21 @@ int sqlite3FixSelect(
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
return 1;
}
if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
return 1;
}
if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
return 1;
}
pSelect = pSelect->pPrior;
}
return 0;
@ -509,6 +519,14 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
}else{
sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
return 1;
}
}
if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;

View File

@ -2508,7 +2508,6 @@ static int lockBtree(BtShared *pBt){
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
pBt->nPage = nPage;
assert( pPage1->leaf==0 || pPage1->leaf==1 );
return SQLITE_OK;
page1_init_failed:
@ -2668,7 +2667,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
goto trans_begun;
}
assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
/* Write transactions are not possible on a read-only database */
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){

View File

@ -56,13 +56,13 @@
**
** OFFSET SIZE DESCRIPTION
** 0 16 Header string: "SQLite format 3\000"
** 16 2 Page size in bytes.
** 16 2 Page size in bytes. (1 means 65536)
** 18 1 File format write version
** 19 1 File format read version
** 20 1 Bytes of unused space at the end of each page
** 21 1 Max embedded payload fraction
** 22 1 Min embedded payload fraction
** 23 1 Min leaf payload fraction
** 21 1 Max embedded payload fraction (must be 64)
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
** 28 4 Reserved for future use
** 32 4 First freelist page
@ -76,9 +76,10 @@
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
** 60 4 User version
** 64 4 Incremental vacuum mode
** 68 4 unused
** 72 4 unused
** 76 4 unused
** 68 4 Application-ID
** 72 20 unused
** 92 4 The version-valid-for number
** 96 4 SQLITE_VERSION_NUMBER
**
** All of the integer values are big-endian (most significant byte first).
**

View File

@ -879,7 +879,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
pTable->nRowEst = 1000000;
pTable->nRowEst = 1048576;
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
@ -1026,6 +1026,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
** be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_NONE;
pCol->szEst = 1;
p->nCol++;
}
@ -1067,15 +1068,18 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.
*/
char sqlite3AffinityType(const char *zIn){
char sqlite3AffinityType(const char *zIn, u8 *pszEst){
u32 h = 0;
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
if( zIn ) while( zIn[0] ){
if( zIn==0 ) return aff;
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
aff = SQLITE_AFF_TEXT;
aff = SQLITE_AFF_TEXT;
zChar = zIn;
}else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
aff = SQLITE_AFF_TEXT;
}else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
@ -1083,6 +1087,7 @@ char sqlite3AffinityType(const char *zIn){
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
&& (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
aff = SQLITE_AFF_NONE;
if( zIn[0]=='(' ) zChar = zIn;
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
&& aff==SQLITE_AFF_NUMERIC ){
@ -1100,6 +1105,28 @@ char sqlite3AffinityType(const char *zIn){
}
}
/* If pszEst is not NULL, store an estimate of the field size. The
** estimate is scaled so that the size of an integer is 1. */
if( pszEst ){
*pszEst = 1; /* default size is approx 4 bytes */
if( aff<=SQLITE_AFF_NONE ){
if( zChar ){
while( zChar[0] ){
if( sqlite3Isdigit(zChar[0]) ){
int v = 0;
sqlite3GetInt32(zChar, &v);
v = v/4 + 1;
if( v>255 ) v = 255;
*pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
break;
}
zChar++;
}
}else{
*pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
}
}
}
return aff;
}
@ -1121,7 +1148,7 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
pCol = &p->aCol[p->nCol-1];
assert( pCol->zType==0 );
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
pCol->affinity = sqlite3AffinityType(pCol->zType);
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
}
/*
@ -1469,7 +1496,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
len = sqlite3Strlen30(zType);
assert( pCol->affinity==SQLITE_AFF_NONE
|| pCol->affinity==sqlite3AffinityType(zType) );
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
memcpy(&zStmt[k], zType, len);
k += len;
assert( k<=n );
@ -1478,6 +1505,34 @@ static char *createTableStmt(sqlite3 *db, Table *p){
return zStmt;
}
/*
** Estimate the total row width for a table.
*/
static void estimateTableWidth(Table *pTab){
unsigned wTable = 0;
const Column *pTabCol;
int i;
for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){
wTable += pTabCol->szEst;
}
if( pTab->iPKey<0 ) wTable++;
pTab->szTabRow = sqlite3LogEst(wTable*4);
}
/*
** Estimate the average size of a row for an index.
*/
static void estimateIndexWidth(Index *pIdx){
unsigned wIndex = 1;
int i;
const Column *aCol = pIdx->pTable->aCol;
for(i=0; i<pIdx->nColumn; i++){
assert( pIdx->aiColumn[i]>=0 && pIdx->aiColumn[i]<pIdx->pTable->nCol );
wIndex += aCol[pIdx->aiColumn[i]].szEst;
}
pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
}
/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
@ -1504,9 +1559,10 @@ void sqlite3EndTable(
Token *pEnd, /* The final ')' token in the CREATE TABLE */
Select *pSelect /* Select from a "CREATE ... AS SELECT" */
){
Table *p;
sqlite3 *db = pParse->db;
int iDb;
Table *p; /* The new table */
sqlite3 *db = pParse->db; /* The database connection */
int iDb; /* Database in which the table lives */
Index *pIdx; /* An implied index of the table */
if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
return;
@ -1526,6 +1582,12 @@ void sqlite3EndTable(
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* Estimate the average row size for the table and for all implied indices */
estimateTableWidth(p);
for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
estimateIndexWidth(pIdx);
}
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number
@ -1722,9 +1784,8 @@ void sqlite3CreateView(
}
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
iDb = sqlite3SchemaToIndex(db, p->pSchema);
if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
&& sqlite3FixSelect(&sFix, pSelect)
){
sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
if( sqlite3FixSelect(&sFix, pSelect) ){
sqlite3SelectDelete(db, pSelect);
return;
}
@ -2485,9 +2546,10 @@ Index *sqlite3CreateIndex(
int iDb; /* Index of the database that is being written */
Token *pName = 0; /* Unqualified name of the index to create */
struct ExprList_item *pListItem; /* For looping over pList */
int nCol;
int nExtra = 0;
char *zExtra;
const Column *pTabCol; /* A column in the table */
int nCol; /* Number of columns */
int nExtra = 0; /* Space allocated for zExtra[] */
char *zExtra; /* Extra space after the Index object */
assert( pParse->nErr==0 ); /* Never called with prior errors */
if( db->mallocFailed || IN_DECLARE_VTAB ){
@ -2524,9 +2586,8 @@ Index *sqlite3CreateIndex(
}
#endif
if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
sqlite3FixSrcList(&sFix, pTblName)
){
sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
if( sqlite3FixSrcList(&sFix, pTblName) ){
/* Because the parser constructs pTblName from a single identifier,
** sqlite3FixSrcList can never fail. */
assert(0);
@ -2715,7 +2776,6 @@ Index *sqlite3CreateIndex(
*/
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
const char *zColName = pListItem->zName;
Column *pTabCol;
int requestedSortOrder;
char *zColl; /* Collation sequence name */
@ -2752,6 +2812,7 @@ Index *sqlite3CreateIndex(
if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
}
sqlite3DefaultRowEst(pIndex);
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a

View File

@ -426,6 +426,10 @@ static void clearYMD_HMS_TZ(DateTime *p){
**
** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
** routine will always fail.
**
** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
** library function localtime_r() is used to assist in the calculation of
** local time.
*/
static int osLocaltime(time_t *t, struct tm *pTm){
int rc;
@ -482,6 +486,11 @@ static sqlite3_int64 localtimeOffset(
x = *p;
computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){
/* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only
** works for years between 1970 and 2037. For dates outside this range,
** SQLite attempts to map the year into an equivalent year within this
** range, do the calculation, then map the year back.
*/
x.Y = 2000;
x.M = 1;
x.D = 1;

View File

@ -350,6 +350,7 @@ void sqlite3DeleteFrom(
&& 0==sqlite3FkRequired(pParse, pTab, 0, 0)
){
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
pTab->zName, P4_STATIC);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){

View File

@ -41,7 +41,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
return sqlite3AffinityType(pExpr->u.zToken);
return sqlite3AffinityType(pExpr->u.zToken, 0);
}
#endif
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
@ -2461,7 +2461,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int aff, to_op;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
assert( !ExprHasProperty(pExpr, EP_IntValue) );
aff = sqlite3AffinityType(pExpr->u.zToken);
aff = sqlite3AffinityType(pExpr->u.zToken, 0);
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
@ -3128,7 +3128,7 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
const char *zAff = "unk";
switch( sqlite3AffinityType(pExpr->u.zToken) ){
switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){
case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
case SQLITE_AFF_NONE: zAff = "NONE"; break;
case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;

View File

@ -656,7 +656,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** when this statement is run. */
FKey *p;
for(p=pTab->pFKey; p; p=p->pNextFrom){
if( p->isDeferred ) break;
if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
}
if( !p ) return;
iSkip = sqlite3VdbeMakeLabel(v);
@ -670,11 +670,18 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
/* If the DELETE has generated immediate foreign key constraint
** violations, halt the VDBE and return an error at this point, before
** any modifications to the schema are made. This is because statement
** transactions are not able to rollback schema changes. */
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
OE_Abort, "foreign key constraint failed", P4_STATIC
);
** transactions are not able to rollback schema changes.
**
** If the SQLITE_DeferFKs flag is set, then this is not required, as
** the statement transaction will not be rolled back even if FK
** constraints are violated.
*/
if( (db->flags & SQLITE_DeferFKs)==0 ){
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
OE_Abort, "foreign key constraint failed", P4_STATIC
);
}
if( iSkip ){
sqlite3VdbeResolveLabel(v, iSkip);

View File

@ -1900,6 +1900,7 @@ static int xferOptimization(
pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest,
(char*)pKey, P4_KEYINFO_HANDOFF);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);

View File

@ -682,7 +682,7 @@ static struct win_syscall {
#define osGetVersionExA ((BOOL(WINAPI*)( \
LPOSVERSIONINFOA))aSyscall[34].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
#else
{ "GetVersionExW", (SYSCALL)0, 0 },

View File

@ -56,189 +56,378 @@
#define PragTyp_SECURE_DELETE 25
#define PragTyp_SHRINK_MEMORY 26
#define PragTyp_SOFT_HEAP_LIMIT 27
#define PragTyp_SYNCHRONOUS 28
#define PragTyp_TABLE_INFO 29
#define PragTyp_TEMP_STORE 30
#define PragTyp_TEMP_STORE_DIRECTORY 31
#define PragTyp_WAL_AUTOCHECKPOINT 32
#define PragTyp_WAL_CHECKPOINT 33
#define PragTyp_ACTIVATE_EXTENSIONS 34
#define PragTyp_HEXKEY 35
#define PragTyp_KEY 36
#define PragTyp_REKEY 37
#define PragTyp_LOCK_STATUS 38
#define PragTyp_PARSER_TRACE 39
#define PragTyp_STATS 28
#define PragTyp_SYNCHRONOUS 29
#define PragTyp_TABLE_INFO 30
#define PragTyp_TEMP_STORE 31
#define PragTyp_TEMP_STORE_DIRECTORY 32
#define PragTyp_WAL_AUTOCHECKPOINT 33
#define PragTyp_WAL_CHECKPOINT 34
#define PragTyp_ACTIVATE_EXTENSIONS 35
#define PragTyp_HEXKEY 36
#define PragTyp_KEY 37
#define PragTyp_REKEY 38
#define PragTyp_LOCK_STATUS 39
#define PragTyp_PARSER_TRACE 40
#define PragFlag_NeedSchema 0x01
static const struct sPragmaNames {
const char *const zName; /* Name of pragma */
u8 ePragTyp; /* PragTyp_XXX value */
u8 mPragFlag; /* Zero or more PragFlag_XXX values */
u32 iArg; /* Extra argument */
} aPragmaNames[] = {
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
{ "activate_extensions", PragTyp_ACTIVATE_EXTENSIONS, 0 },
{ /* zName: */ "activate_extensions",
/* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ "application_id", PragTyp_HEADER_VALUE, 0 },
{ /* zName: */ "application_id",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
{ "auto_vacuum", PragTyp_AUTO_VACUUM, 0 },
{ /* zName: */ "auto_vacuum",
/* ePragTyp: */ PragTyp_AUTO_VACUUM,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
{ "automatic_index", PragTyp_FLAG,
SQLITE_AutoIndex },
{ /* zName: */ "automatic_index",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_AutoIndex },
#endif
{ "busy_timeout", PragTyp_BUSY_TIMEOUT, 0 },
{ /* zName: */ "busy_timeout",
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "cache_size", PragTyp_CACHE_SIZE, 0 },
{ /* zName: */ "cache_size",
/* ePragTyp: */ PragTyp_CACHE_SIZE,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
{ "cache_spill", PragTyp_FLAG,
SQLITE_CacheSpill },
{ "case_sensitive_like", PragTyp_CASE_SENSITIVE_LIKE, 0 },
{ "checkpoint_fullfsync", PragTyp_FLAG,
SQLITE_CkptFullFSync },
{ /* zName: */ "cache_spill",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_CacheSpill },
{ /* zName: */ "case_sensitive_like",
/* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "checkpoint_fullfsync",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_CkptFullFSync },
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ "collation_list", PragTyp_COLLATION_LIST, 0 },
{ /* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
{ "compile_options", PragTyp_COMPILE_OPTIONS, 0 },
{ /* zName: */ "compile_options",
/* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "count_changes", PragTyp_FLAG,
SQLITE_CountRows },
{ /* zName: */ "count_changes",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_CountRows },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
{ "data_store_directory", PragTyp_DATA_STORE_DIRECTORY, 0 },
{ /* zName: */ "data_store_directory",
/* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ "database_list", PragTyp_DATABASE_LIST, 0 },
{ /* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
{ "default_cache_size", PragTyp_DEFAULT_CACHE_SIZE, 0 },
{ /* zName: */ "default_cache_size",
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{ "defer_foreign_keys", PragTyp_FLAG,
SQLITE_DeferFKs },
{ /* zName: */ "defer_foreign_keys",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_DeferFKs },
#endif
{ "empty_result_callbacks", PragTyp_FLAG,
SQLITE_NullCallback },
{ /* zName: */ "empty_result_callbacks",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_NullCallback },
#if !defined(SQLITE_OMIT_UTF16)
{ "encoding", PragTyp_ENCODING, 0 },
{ /* zName: */ "encoding",
/* ePragTyp: */ PragTyp_ENCODING,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{ "foreign_key_check", PragTyp_FOREIGN_KEY_CHECK, 0 },
{ /* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
{ "foreign_key_list", PragTyp_FOREIGN_KEY_LIST, 0 },
{ /* zName: */ "foreign_key_list",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{ "foreign_keys", PragTyp_FLAG,
SQLITE_ForeignKeys },
{ /* zName: */ "foreign_keys",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_ForeignKeys },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ "freelist_count", PragTyp_HEADER_VALUE, 0 },
{ /* zName: */ "freelist_count",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "full_column_names", PragTyp_FLAG,
SQLITE_FullColNames },
{ "fullfsync", PragTyp_FLAG,
SQLITE_FullFSync },
{ /* zName: */ "full_column_names",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_FullColNames },
{ /* zName: */ "fullfsync",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_FullFSync },
#if defined(SQLITE_HAS_CODEC)
{ "hexkey", PragTyp_HEXKEY, 0 },
{ /* zName: */ "hexkey",
/* ePragTyp: */ PragTyp_HEXKEY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "hexrekey",
/* ePragTyp: */ PragTyp_HEXKEY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_CHECK)
{ "ignore_check_constraints", PragTyp_FLAG,
SQLITE_IgnoreChecks },
{ /* zName: */ "ignore_check_constraints",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_IgnoreChecks },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
{ "incremental_vacuum", PragTyp_INCREMENTAL_VACUUM, 0 },
{ /* zName: */ "incremental_vacuum",
/* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ "index_info", PragTyp_INDEX_INFO, 0 },
{ "index_list", PragTyp_INDEX_LIST, 0 },
{ /* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
{ /* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{ "integrity_check", PragTyp_INTEGRITY_CHECK, 0 },
{ /* zName: */ "integrity_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "journal_mode", PragTyp_JOURNAL_MODE, 0 },
{ "journal_size_limit", PragTyp_JOURNAL_SIZE_LIMIT, 0 },
{ /* zName: */ "journal_mode",
/* ePragTyp: */ PragTyp_JOURNAL_MODE,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
{ /* zName: */ "journal_size_limit",
/* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if defined(SQLITE_HAS_CODEC)
{ "key", PragTyp_KEY, 0 },
{ /* zName: */ "key",
/* ePragTyp: */ PragTyp_KEY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "legacy_file_format", PragTyp_FLAG,
SQLITE_LegacyFileFmt },
{ /* zName: */ "legacy_file_format",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_LegacyFileFmt },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
{ "lock_proxy_file", PragTyp_LOCK_PROXY_FILE, 0 },
{ /* zName: */ "lock_proxy_file",
/* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
{ "lock_status", PragTyp_LOCK_STATUS, 0 },
{ /* zName: */ "lock_status",
/* ePragTyp: */ PragTyp_LOCK_STATUS,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "locking_mode", PragTyp_LOCKING_MODE, 0 },
{ "max_page_count", PragTyp_PAGE_COUNT, 0 },
{ "mmap_size", PragTyp_MMAP_SIZE, 0 },
{ "page_count", PragTyp_PAGE_COUNT, 0 },
{ "page_size", PragTyp_PAGE_SIZE, 0 },
{ /* zName: */ "locking_mode",
/* ePragTyp: */ PragTyp_LOCKING_MODE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "max_page_count",
/* ePragTyp: */ PragTyp_PAGE_COUNT,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
{ /* zName: */ "mmap_size",
/* ePragTyp: */ PragTyp_MMAP_SIZE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "page_count",
/* ePragTyp: */ PragTyp_PAGE_COUNT,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
{ /* zName: */ "page_size",
/* ePragTyp: */ PragTyp_PAGE_SIZE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG)
{ "parser_trace", PragTyp_PARSER_TRACE, 0 },
{ /* zName: */ "parser_trace",
/* ePragTyp: */ PragTyp_PARSER_TRACE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "query_only", PragTyp_FLAG,
SQLITE_QueryOnly },
{ /* zName: */ "query_only",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_QueryOnly },
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{ "quick_check", PragTyp_INTEGRITY_CHECK, 0 },
{ /* zName: */ "quick_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
{ "read_uncommitted", PragTyp_FLAG,
SQLITE_ReadUncommitted },
{ "recursive_triggers", PragTyp_FLAG,
SQLITE_RecTriggers },
{ /* zName: */ "read_uncommitted",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_ReadUncommitted },
{ /* zName: */ "recursive_triggers",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_RecTriggers },
#if defined(SQLITE_HAS_CODEC)
{ "rekey", PragTyp_REKEY, 0 },
{ /* zName: */ "rekey",
/* ePragTyp: */ PragTyp_REKEY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "reverse_unordered_selects", PragTyp_FLAG,
SQLITE_ReverseOrder },
{ /* zName: */ "reverse_unordered_selects",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_ReverseOrder },
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ "schema_version", PragTyp_HEADER_VALUE, 0 },
{ /* zName: */ "schema_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "secure_delete", PragTyp_SECURE_DELETE, 0 },
{ /* zName: */ "secure_delete",
/* ePragTyp: */ PragTyp_SECURE_DELETE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
{ "short_column_names", PragTyp_FLAG,
SQLITE_ShortColNames },
{ "shrink_memory", PragTyp_SHRINK_MEMORY, 0 },
{ "soft_heap_limit", PragTyp_SOFT_HEAP_LIMIT, 0 },
{ /* zName: */ "short_column_names",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_ShortColNames },
{ /* zName: */ "shrink_memory",
/* ePragTyp: */ PragTyp_SHRINK_MEMORY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "soft_heap_limit",
/* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#if defined(SQLITE_DEBUG)
{ "sql_trace", PragTyp_FLAG,
SQLITE_SqlTrace },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "synchronous", PragTyp_SYNCHRONOUS, 0 },
{ /* zName: */ "sql_trace",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_SqlTrace },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ "table_info", PragTyp_TABLE_INFO, 0 },
{ /* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ "temp_store", PragTyp_TEMP_STORE, 0 },
{ "temp_store_directory", PragTyp_TEMP_STORE_DIRECTORY, 0 },
{ /* zName: */ "synchronous",
/* ePragTyp: */ PragTyp_SYNCHRONOUS,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ /* zName: */ "table_info",
/* ePragTyp: */ PragTyp_TABLE_INFO,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ /* zName: */ "temp_store",
/* ePragTyp: */ PragTyp_TEMP_STORE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "temp_store_directory",
/* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ "user_version", PragTyp_HEADER_VALUE, 0 },
{ /* zName: */ "user_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG)
{ "vdbe_addoptrace", PragTyp_FLAG,
SQLITE_VdbeAddopTrace },
{ "vdbe_debug", PragTyp_FLAG,
SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
{ "vdbe_listing", PragTyp_FLAG,
SQLITE_VdbeListing },
{ "vdbe_trace", PragTyp_FLAG,
SQLITE_VdbeTrace },
{ /* zName: */ "vdbe_addoptrace",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_VdbeAddopTrace },
{ /* zName: */ "vdbe_debug",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
{ /* zName: */ "vdbe_listing",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_VdbeListing },
{ /* zName: */ "vdbe_trace",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_VdbeTrace },
#endif
#if !defined(SQLITE_OMIT_WAL)
{ "wal_autocheckpoint", PragTyp_WAL_AUTOCHECKPOINT, 0 },
{ "wal_checkpoint", PragTyp_WAL_CHECKPOINT, 0 },
{ /* zName: */ "wal_autocheckpoint",
/* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
{ /* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
#endif
{ "writable_schema", PragTyp_FLAG,
SQLITE_WriteSchema|SQLITE_RecoveryMode },
{ /* zName: */ "writable_schema",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
};
/* Number of pragmas: 55 on by default, 66 total. */
/* Number of pragmas: 56 on by default, 68 total. */
/* End of the automatically generated pragma table.
***************************************************************************/
@ -571,6 +760,11 @@ void sqlite3Pragma(
}
if( lwr>upr ) goto pragma_out;
/* Make sure the database schema is loaded if the pragma requires that */
if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
/* Jump to the appropriate pragma handler */
switch( aPragmaNames[mid].ePragTyp ){
@ -604,7 +798,6 @@ void sqlite3Pragma(
{ OP_ResultRow, 1, 1, 0},
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
@ -700,7 +893,6 @@ void sqlite3Pragma(
*/
case PragTyp_PAGE_COUNT: {
int iReg;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3CodeVerifySchema(pParse, iDb);
iReg = ++pParse->nMem;
if( sqlite3Tolower(zLeft[0])=='p' ){
@ -773,14 +965,6 @@ void sqlite3Pragma(
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
int ii; /* Loop counter */
/* Force the schema to be loaded on all databases. This causes all
** database files to be opened and the journal_modes set. This is
** necessary because subsequent processing must know if the databases
** are in WAL mode. */
if( sqlite3ReadSchema(pParse) ){
goto pragma_out;
}
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
@ -846,51 +1030,40 @@ void sqlite3Pragma(
case PragTyp_AUTO_VACUUM: {
Btree *pBt = pDb->pBt;
assert( pBt!=0 );
if( sqlite3ReadSchema(pParse) ){
goto pragma_out;
}
if( !zRight ){
int auto_vacuum;
if( ALWAYS(pBt) ){
auto_vacuum = sqlite3BtreeGetAutoVacuum(pBt);
}else{
auto_vacuum = SQLITE_DEFAULT_AUTOVACUUM;
}
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
returnSingleInt(pParse, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
}else{
int eAuto = getAutoVacuum(zRight);
assert( eAuto>=0 && eAuto<=2 );
db->nextAutovac = (u8)eAuto;
if( ALWAYS(eAuto>=0) ){
/* Call SetAutoVacuum() to set initialize the internal auto and
** incr-vacuum flags. This is required in case this connection
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
/* Call SetAutoVacuum() to set initialize the internal auto and
** incr-vacuum flags. This is required in case this connection
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
*/
rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
/* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
*/
rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
/* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
*/
static const VdbeOpList setMeta6[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
{ OP_Integer, 0, 1, 0}, /* 4 */
{ OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
};
int iAddr;
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
sqlite3VdbeChangeP1(v, iAddr, iDb);
sqlite3VdbeChangeP1(v, iAddr+1, iDb);
sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
sqlite3VdbeChangeP1(v, iAddr+5, iDb);
sqlite3VdbeUsesBtree(v, iDb);
}
static const VdbeOpList setMeta6[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
{ OP_Integer, 0, 1, 0}, /* 4 */
{ OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
};
int iAddr;
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
sqlite3VdbeChangeP1(v, iAddr, iDb);
sqlite3VdbeChangeP1(v, iAddr+1, iDb);
sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
sqlite3VdbeChangeP1(v, iAddr+5, iDb);
sqlite3VdbeUsesBtree(v, iDb);
}
}
break;
@ -905,9 +1078,6 @@ void sqlite3Pragma(
#ifndef SQLITE_OMIT_AUTOVACUUM
case PragTyp_INCREMENTAL_VACUUM: {
int iLimit, addr;
if( sqlite3ReadSchema(pParse) ){
goto pragma_out;
}
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
iLimit = 0x7fffffff;
}
@ -935,7 +1105,6 @@ void sqlite3Pragma(
** of memory.
*/
case PragTyp_CACHE_SIZE: {
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
@ -1156,7 +1325,6 @@ void sqlite3Pragma(
** opened.
*/
case PragTyp_SYNCHRONOUS: {
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
@ -1218,7 +1386,6 @@ void sqlite3Pragma(
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i, k;
@ -1265,10 +1432,39 @@ void sqlite3Pragma(
}
break;
case PragTyp_STATS: {
Index *pIdx;
HashElem *i;
v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 4);
pParse->nMem = 4;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "index", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "width", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "height", SQLITE_STATIC);
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pTab->zName, 0);
sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pTab->szTabRow), 3);
sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
}
}
}
break;
case PragTyp_INDEX_INFO: if( zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
@ -1294,27 +1490,21 @@ void sqlite3Pragma(
case PragTyp_INDEX_LIST: if( zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
int i;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
pIdx = pTab->pIndex;
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
while(pIdx){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
++i;
pIdx = pIdx->pNext;
}
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
}
@ -1322,7 +1512,6 @@ void sqlite3Pragma(
case PragTyp_DATABASE_LIST: {
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
@ -1361,7 +1550,6 @@ void sqlite3Pragma(
case PragTyp_FOREIGN_KEY_LIST: if( zRight ){
FKey *pFK;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
@ -1423,7 +1611,6 @@ void sqlite3Pragma(
int addrOk; /* Jump here if the key is OK */
int *aiCols; /* child to parent column mapping */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
@ -1584,7 +1771,6 @@ void sqlite3Pragma(
if( pId2->z==0 ) iDb = -1;
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pParse->nMem = 6;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
@ -1908,7 +2094,6 @@ void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_RESTART;
}
}
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
@ -2028,12 +2213,12 @@ void sqlite3Pragma(
}
case PragTyp_HEXKEY: {
if( zRight ){
int i, h1, h2;
u8 iByte;
int i;
char zKey[40];
for(i=0; (h1 = zRight[i])!=0 && (h2 = zRight[i+1])!=0; i+=2){
h1 += 9*(1&(h1>>6));
h2 += 9*(1&(h2>>6));
zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4);
for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){
iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
if( (i&1)!=0 ) zKey[i/2] = iByte;
}
if( (zLeft[3] & 0xf)==0xb ){
sqlite3_key_v2(db, zDb, zKey, i/2);

View File

@ -707,6 +707,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pNC->nErr++;
}
}else{
/* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
** likelihood(X, 0.0625).
** EVIDENCE-OF: R-35738-39582 The unlikely(X) fucntion is short-hand for
** likelihood(X,0.0625). */
pExpr->iTable = 62; /* TUNING: Default 2nd arg to unlikely() is 0.0625 */
}
}

View File

@ -1061,6 +1061,9 @@ static void generateSortTail(
** Return a pointer to a string containing the 'declaration type' of the
** expression pExpr. The string may be treated as static by the caller.
**
** Also try to estimate the size of the returned value and return that
** result in *pEstWidth.
**
** The declaration type is the exact datatype definition extracted from the
** original CREATE TABLE statement if the expression is a column. The
** declaration type for a ROWID field is INTEGER. Exactly when an expression
@ -1074,21 +1077,36 @@ static void generateSortTail(
** SELECT abc FROM (SELECT col AS abc FROM tbl);
**
** The declaration type for any expression other than a column is NULL.
**
** This routine has either 3 or 6 parameters depending on whether or not
** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
*/
static const char *columnType(
#ifdef SQLITE_ENABLE_COLUMN_METADATA
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
static const char *columnTypeImpl(
NameContext *pNC,
Expr *pExpr,
const char **pzOriginDb,
const char **pzOriginTab,
const char **pzOriginCol
const char **pzOrigDb,
const char **pzOrigTab,
const char **pzOrigCol,
u8 *pEstWidth
){
char const *zOrigDb = 0;
char const *zOrigTab = 0;
char const *zOrigCol = 0;
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
static const char *columnTypeImpl(
NameContext *pNC,
Expr *pExpr,
u8 *pEstWidth
){
#endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */
char const *zType = 0;
char const *zOriginDb = 0;
char const *zOriginTab = 0;
char const *zOriginCol = 0;
int j;
if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
u8 estWidth = 1;
if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: {
@ -1149,25 +1167,35 @@ static const char *columnType(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
}
}else if( ALWAYS(pTab->pSchema) ){
/* A real table */
assert( !pS );
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
#ifdef SQLITE_ENABLE_COLUMN_METADATA
if( iCol<0 ){
zType = "INTEGER";
zOriginCol = "rowid";
zOrigCol = "rowid";
}else{
zType = pTab->aCol[iCol].zType;
zOriginCol = pTab->aCol[iCol].zName;
zOrigCol = pTab->aCol[iCol].zName;
estWidth = pTab->aCol[iCol].szEst;
}
zOriginTab = pTab->zName;
zOrigTab = pTab->zName;
if( pNC->pParse ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
zOriginDb = pNC->pParse->db->aDb[iDb].zName;
zOrigDb = pNC->pParse->db->aDb[iDb].zName;
}
#else
if( iCol<0 ){
zType = "INTEGER";
}else{
zType = pTab->aCol[iCol].zType;
estWidth = pTab->aCol[iCol].szEst;
}
#endif
}
break;
}
@ -1184,18 +1212,21 @@ static const char *columnType(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
break;
}
#endif
}
if( pzOriginDb ){
assert( pzOriginTab && pzOriginCol );
*pzOriginDb = zOriginDb;
*pzOriginTab = zOriginTab;
*pzOriginCol = zOriginCol;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
if( pzOrigDb ){
assert( pzOrigTab && pzOrigCol );
*pzOrigDb = zOrigDb;
*pzOrigTab = zOrigTab;
*pzOrigCol = zOrigCol;
}
#endif
if( pEstWidth ) *pEstWidth = estWidth;
return zType;
}
@ -1221,7 +1252,7 @@ static void generateColumnTypes(
const char *zOrigDb = 0;
const char *zOrigTab = 0;
const char *zOrigCol = 0;
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
/* The vdbe must make its own copy of the column-type and other
** column specific strings, in case the schema is reset before this
@ -1231,11 +1262,11 @@ static void generateColumnTypes(
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
#else
zType = columnType(&sNC, p, 0, 0, 0);
zType = columnType(&sNC, p, 0, 0, 0, 0);
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
#endif /* SQLITE_OMIT_DECLTYPE */
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
/*
@ -1424,8 +1455,7 @@ static int selectColumnsFromExprList(
*/
static void selectAddColumnTypeAndCollation(
Parse *pParse, /* Parsing contexts */
int nCol, /* Number of columns */
Column *aCol, /* List of columns */
Table *pTab, /* Add column type information to this table */
Select *pSelect /* SELECT used to determine types and collations */
){
sqlite3 *db = pParse->db;
@ -1435,17 +1465,19 @@ static void selectAddColumnTypeAndCollation(
int i;
Expr *p;
struct ExprList_item *a;
u64 szAll = 0;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
assert( nCol==pSelect->pEList->nExpr || db->mallocFailed );
assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
if( db->mallocFailed ) return;
memset(&sNC, 0, sizeof(sNC));
sNC.pSrcList = pSelect->pSrc;
a = pSelect->pEList->a;
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
p = a[i].pExpr;
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0));
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p);
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
pColl = sqlite3ExprCollSeq(pParse, p);
@ -1453,6 +1485,7 @@ static void selectAddColumnTypeAndCollation(
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
pTab->szTabRow = sqlite3LogEst(szAll*4);
}
/*
@ -1480,9 +1513,9 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
assert( db->lookaside.bEnabled==0 );
pTab->nRef = 1;
pTab->zName = 0;
pTab->nRowEst = 1000000;
pTab->nRowEst = 1048576;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@ -3394,11 +3427,11 @@ static int selectExpander(Walker *pWalker, Select *p){
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nRef = 1;
pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
pTab->iPKey = -1;
pTab->nRowEst = 1000000;
pTab->nRowEst = 1048576;
pTab->tabFlags |= TF_Ephemeral;
#endif
}else{
@ -3682,7 +3715,7 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Select *pSel = pFrom->pSelect;
assert( pSel );
while( pSel->pPrior ) pSel = pSel->pPrior;
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
selectAddColumnTypeAndCollation(pParse, pTab, pSel);
}
}
}
@ -4597,25 +4630,25 @@ int sqlite3Select(
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
/* Search for the index that has the least amount of columns. If
** there is such an index, and it has less columns than the table
** does, then we can assume that it consumes less space on disk and
** will therefore be cheaper to scan to determine the query result.
** In this case set iRoot to the root page number of the index b-tree
** and pKeyInfo to the KeyInfo structure required to navigate the
** index.
/* Search for the index that has the lowest scan cost.
**
** (2011-04-15) Do not do a full scan of an unordered index.
**
** (2013-10-03) Do not count the entires in a partial index.
**
** In practice the KeyInfo structure will not be used. It is only
** passed to keep OP_OpenRead happy.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
if( pIdx->bUnordered==0
&& pIdx->szIdxRow<pTab->szTabRow
&& pIdx->pPartIdxWhere==0
&& (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
){
pBest = pIdx;
}
}
if( pBest && pBest->nColumn<pTab->nCol ){
if( pBest ){
iRoot = pBest->tnum;
pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
}

View File

@ -974,7 +974,7 @@ static int run_table_dump_query(
rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
p->nErr++;
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
return rc;
}
rc = sqlite3_step(pSelect);
@ -1001,7 +1001,7 @@ static int run_table_dump_query(
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
p->nErr++;
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
}
return rc;
}
@ -1204,7 +1204,7 @@ static int shell_exec(
/* extract the data and data types */
for(i=0; i<nCol; i++){
aiTypes[i] = x = sqlite3_column_type(pStmt, i);
if( x==SQLITE_BLOB && pArg->mode==MODE_Insert ){
if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
azVals[i] = "";
}else{
azVals[i] = (char*)sqlite3_column_text(pStmt, i);

View File

@ -1612,27 +1612,27 @@ struct sqlite3_mem_methods {
** function must be threadsafe. </dd>
**
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
** <dd> This option takes a single argument of type int. If non-zero, then
** <dd>^(This option takes a single argument of type int. If non-zero, then
** URI handling is globally enabled. If the parameter is zero, then URI handling
** is globally disabled. If URI handling is globally enabled, all filenames
** is globally disabled.)^ ^If URI handling is globally enabled, all filenames
** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
** connection is opened. If it is globally disabled, filenames are
** connection is opened. ^If it is globally disabled, filenames are
** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
** database connection is opened. By default, URI handling is globally
** database connection is opened. ^(By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** [SQLITE_USE_URI] symbol defined.
** [SQLITE_USE_URI] symbol defined.)^
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
** <dd> This option takes a single integer argument which is interpreted as
** <dd>^This option takes a single integer argument which is interpreted as
** a boolean in order to enable or disable the use of covering indices for
** full table scans in the query optimizer. The default setting is determined
** full table scans in the query optimizer. ^The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
** is because some incorrectly coded legacy applications might malfunction
** malfunction when the optimization is enabled. Providing the ability to
** when the optimization is enabled. Providing the ability to
** disable the optimization allows the older, buggy application code to work
** without change even with newer versions of SQLite.
**
@ -1661,16 +1661,16 @@ struct sqlite3_mem_methods {
**
** [[SQLITE_CONFIG_MMAP_SIZE]]
** <dt>SQLITE_CONFIG_MMAP_SIZE
** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
** <dd>^SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
** that are the default mmap size limit (the default setting for
** [PRAGMA mmap_size]) and the maximum allowed mmap size limit.
** The default setting can be overridden by each database connection using
** ^The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
** cannot be changed at run-time. Nor may the maximum allowed mmap size
** exceed the compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.
** If either argument to this option is negative, then that argument is
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
** </dl>
*/

View File

@ -12,6 +12,7 @@
** Internal interface definitions for SQLite.
**
*/
#include "sqlite3.h"
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -305,7 +306,6 @@
#define likely(X) (X)
#define unlikely(X) (X)
#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
@ -470,6 +470,31 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
typedef u32 tRowcnt; /* 32-bit is the default */
#endif
/*
** Estimated quantities used for query planning are stored as 16-bit
** logarithms. For quantity X, the value stored is 10*log2(X). This
** gives a possible range of values of approximately 1.0e986 to 1e-986.
** But the allowed values are "grainy". Not every value is representable.
** For example, quantities 16 and 17 are both represented by a LogEst
** of 40. However, since LogEst quantatites are suppose to be estimates,
** not exact values, this imprecision is not a problem.
**
** "LogEst" is short for "Logarithimic Estimate".
**
** Examples:
** 1 -> 0 20 -> 43 10000 -> 132
** 2 -> 10 25 -> 46 25000 -> 146
** 3 -> 16 100 -> 66 1000000 -> 199
** 4 -> 20 1000 -> 99 1048576 -> 200
** 10 -> 33 1024 -> 100 4294967296 -> 320
**
** The LogEst can be negative to indicate fractional values.
** Examples:
**
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
*/
typedef INT16_TYPE LogEst;
/*
** Macros to determine whether the machine is big or little endian,
** evaluated at runtime.
@ -1197,7 +1222,8 @@ struct Column {
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
u8 szEst; /* Estimated size of this column. INT==1 */
u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
/* Allowed values for Column.colFlags:
@ -1361,6 +1387,7 @@ struct Table {
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
i16 nCol; /* Number of columns in this table */
u16 nRef; /* Number of pointers to this Table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
u8 tabFlags; /* Mask of TF_* values */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
#ifndef SQLITE_OMIT_ALTERTABLE
@ -1472,7 +1499,7 @@ struct FKey {
#define OE_SetDflt 8 /* Set the foreign key value to its default */
#define OE_Cascade 9 /* Cascade the changes */
#define OE_Default 99 /* Do whatever the default action is */
#define OE_Default 10 /* Do whatever the default action is */
/*
@ -1559,6 +1586,7 @@ struct Index {
char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nColumn; /* Number of columns in table used by this index */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
@ -2414,6 +2442,7 @@ typedef struct DbFixer DbFixer;
struct DbFixer {
Parse *pParse; /* The parsing context. Error messages written here */
Schema *pSchema; /* Fix items to this schema */
int bVarOnly; /* Check for variable references only */
const char *zDb; /* Make sure all objects are contained in this database */
const char *zType; /* Type of the container - used for error messages */
const Token *pName; /* Name of the container - used for error messages */
@ -2952,7 +2981,7 @@ void sqlite3DeferForeignKey(Parse*, int);
#endif
void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
void sqlite3Detach(Parse*, Expr*);
int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
int sqlite3FixSrcList(DbFixer*, SrcList*);
int sqlite3FixSelect(DbFixer*, Select*);
int sqlite3FixExpr(DbFixer*, Expr*);
@ -2964,6 +2993,12 @@ int sqlite3Atoi(const char*);
int sqlite3Utf16ByteLen(const void *pData, int nChar);
int sqlite3Utf8CharLen(const char *pData, int nByte);
u32 sqlite3Utf8Read(const u8**);
LogEst sqlite3LogEst(u64);
LogEst sqlite3LogEstAdd(LogEst,LogEst);
#ifndef SQLITE_OMIT_VIRTUALTABLE
LogEst sqlite3LogEstFromDouble(double);
#endif
u64 sqlite3LogEstToInt(LogEst);
/*
** Routines to read and write variable-length integers. These used to
@ -3080,7 +3115,7 @@ void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
char sqlite3AffinityType(const char*);
char sqlite3AffinityType(const char*, u8*);
void sqlite3Analyze(Parse*, Token*, Token*);
int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);

View File

@ -3377,7 +3377,6 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){
MD5Transform(ctx->buf, (uint32 *)ctx->in);
byteReverse((unsigned char *)ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
}
/*

View File

@ -265,6 +265,7 @@ static int getIndexArray(
while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zIdx = (const char *)sqlite3_column_text(pStmt, 1);
sqlite3_stmt *pStmt2 = 0;
if( zIdx==0 ) continue;
zSql = sqlite3_mprintf("PRAGMA index_info(%s)", zIdx);
if( !zSql ){
rc = SQLITE_NOMEM;

View File

@ -219,7 +219,6 @@ static int init_wrapper_uninstall(
return TCL_ERROR;
}
memset(&wrapped, 0, sizeof(&wrapped));
sqlite3_shutdown();
sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex);
sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem);

View File

@ -148,8 +148,8 @@ void sqlite3BeginTrigger(
/* Ensure the table name matches database name and that the table exists */
if( db->mallocFailed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){
sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName);
if( sqlite3FixSrcList(&sFix, pTableName) ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
@ -291,8 +291,10 @@ void sqlite3FinishTrigger(
}
nameToken.z = pTrig->zName;
nameToken.n = sqlite3Strlen30(nameToken.z);
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken)
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
|| sqlite3FixExpr(&sFix, pTrig->pWhen)
){
goto triggerfinish_cleanup;
}

View File

@ -1208,3 +1208,80 @@ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
}
}
#endif
/*
** Find (an approximate) sum of two LogEst values. This computation is
** not a simple "+" operator because LogEst is stored as a logarithmic
** value.
**
*/
LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
static const unsigned char x[] = {
10, 10, /* 0,1 */
9, 9, /* 2,3 */
8, 8, /* 4,5 */
7, 7, 7, /* 6,7,8 */
6, 6, 6, /* 9,10,11 */
5, 5, 5, /* 12-14 */
4, 4, 4, 4, /* 15-18 */
3, 3, 3, 3, 3, 3, /* 19-24 */
2, 2, 2, 2, 2, 2, 2, /* 25-31 */
};
if( a>=b ){
if( a>b+49 ) return a;
if( a>b+31 ) return a+1;
return a+x[a-b];
}else{
if( b>a+49 ) return b;
if( b>a+31 ) return b+1;
return b+x[b-a];
}
}
/*
** Convert an integer into a LogEst. In other words, compute a
** good approximatation for 10*log2(x).
*/
LogEst sqlite3LogEst(u64 x){
static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
LogEst y = 40;
if( x<8 ){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
while( x>255 ){ y += 40; x >>= 4; }
while( x>15 ){ y += 10; x >>= 1; }
}
return a[x&7] + y - 10;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Convert a double into a LogEst
** In other words, compute an approximation for 10*log2(x).
*/
LogEst sqlite3LogEstFromDouble(double x){
u64 a;
LogEst e;
assert( sizeof(x)==8 && sizeof(a)==8 );
if( x<=1 ) return 0;
if( x<=2000000000 ) return sqlite3LogEst((u64)x);
memcpy(&a, &x, 8);
e = (a>>52) - 1022;
return e*10;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/*
** Convert a LogEst into an integer.
*/
u64 sqlite3LogEstToInt(LogEst x){
u64 n;
if( x<10 ) return 1;
n = x%10;
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
if( x>=3 ) return (n+8)<<(x-3);
return (n+8)>>(3-x);
}

View File

@ -72,14 +72,34 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
}
/*
** The non-standard VACUUM command is used to clean up the database,
** The VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
** in PostgreSQL.
** in PostgreSQL. The VACUUM command works as follows:
**
** In version 1.0.x of SQLite, the VACUUM command would call
** gdbm_reorganize() on all the database tables. But beginning
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
** (1) Create a new transient database file
** (2) Copy all content from the database being vacuumed into
** the new transient database file
** (3) Copy content from the transient database back into the
** original database.
**
** The transient database requires temporary disk space approximately
** equal to the size of the original database. The copy operation of
** step (3) requires additional temporary disk space approximately equal
** to the size of the original database for the rollback journal.
** Hence, temporary disk space that is approximately 2x the size of the
** orginal database is required. Every page of the database is written
** approximately 3 times: Once for step (2) and twice for step (3).
** Two writes per page are required in step (3) because the original
** database content must be written into the rollback journal prior to
** overwriting the database with the vacuumed content.
**
** Only 1x temporary space and only 1x writes would be required if
** the copy of step (3) were replace by deleting the original database
** and renaming the transient database as the original. But that will
** not work if other processes are attached to the original database.
** And a power loss in between deleting the original and renaming the
** transient would cause the database file to appear to be deleted
** following reboot.
*/
void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse);

View File

@ -1059,7 +1059,9 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
pRec->nField = p->iVal+1;
return &pRec->aMem[p->iVal];
}
#endif
#else
UNUSED_PARAMETER(p);
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
return sqlite3ValueNew(db);
}
@ -1230,6 +1232,7 @@ static void recordFunc(
sqlite3 *db;
u8 *aRet;
UNUSED_PARAMETER( argc );
iSerial = sqlite3VdbeSerialType(argv[0], file_format);
nSerial = sqlite3VarintLen(iSerial);
nVal = sqlite3VdbeSerialTypeLen(iSerial);

View File

@ -48,26 +48,6 @@ typedef struct WhereScan WhereScan;
typedef struct WhereOrCost WhereOrCost;
typedef struct WhereOrSet WhereOrSet;
/*
** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
** (Virtual tables can return a larger cost, but let's assume they do not.)
** So all costs can be stored in a 16-bit integer without risk
** of overflow.
**
** Costs are estimates, so no effort is made to compute 10*log2(X) exactly.
** Instead, a close estimate is used. Any value of X=1 is stored as 0.
** X=2 is 10. X=3 is 16. X=1000 is 99. etc. Negative values are allowed.
** A WhereCost of -10 means 0.5. WhereCost of -20 means 0.25. And so forth.
**
** The tool/wherecosttest.c source file implements a command-line program
** that will convert WhereCosts to integers, convert integers to WhereCosts
** and do addition and multiplication on WhereCost values. The wherecosttest
** command-line program is a useful utility to have around when working with
** this module.
*/
typedef short int WhereCost;
/*
** This object contains information needed to implement a single nested
** loop in WHERE clause.
@ -132,9 +112,9 @@ struct WhereLoop {
#endif
u8 iTab; /* Position in FROM clause of table for this loop */
u8 iSortIdx; /* Sorting index number. 0==None */
WhereCost rSetup; /* One-time setup cost (ex: create transient index) */
WhereCost rRun; /* Cost of running each loop */
WhereCost nOut; /* Estimated number of output rows */
LogEst rSetup; /* One-time setup cost (ex: create transient index) */
LogEst rRun; /* Cost of running each loop */
LogEst nOut; /* Estimated number of output rows */
union {
struct { /* Information for internal btree tables */
int nEq; /* Number of equality constraints */
@ -164,8 +144,8 @@ struct WhereLoop {
*/
struct WhereOrCost {
Bitmask prereq; /* Prerequisites */
WhereCost rRun; /* Cost of running this subquery */
WhereCost nOut; /* Number of outputs for this subquery */
LogEst rRun; /* Cost of running this subquery */
LogEst nOut; /* Number of outputs for this subquery */
};
/* The WhereOrSet object holds a set of possible WhereOrCosts that
@ -203,8 +183,8 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
WhereCost nRow; /* Estimated number of rows generated by this path */
WhereCost rCost; /* Total cost of this path */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
u8 isOrdered; /* True if this path satisfies ORDER BY */
u8 isOrderedValid; /* True if the isOrdered field is valid */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
@ -270,7 +250,7 @@ struct WhereTerm {
WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
} u;
WhereCost truthProb; /* Probability of truth for this expression */
LogEst truthProb; /* Probability of truth for this expression */
u16 eOperator; /* A WO_xx value describing <op> */
u8 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
@ -418,7 +398,7 @@ struct WhereInfo {
ExprList *pResultSet; /* Result set. DISTINCT operates on these */
WhereLoop *pLoops; /* List of all WhereLoop objects */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereCost nRowOut; /* Estimated number of output rows */
LogEst nRowOut; /* Estimated number of output rows */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
u8 bOBSat; /* ORDER BY satisfied by indices */
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
@ -478,26 +458,11 @@ struct WhereInfo {
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
/* Convert a WhereCost value (10 times log2(X)) into its integer value X.
** A rough approximation is used. The value returned is not exact.
*/
static u64 whereCostToInt(WhereCost x){
u64 n;
if( x<10 ) return 1;
n = x%10;
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
if( x>=3 ) return (n+8)<<(x-3);
return (n+8)>>(3-x);
}
/*
** Return the estimated number of output rows from a WHERE clause
*/
u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
return whereCostToInt(pWInfo->nRowOut);
return sqlite3LogEstToInt(pWInfo->nRowOut);
}
/*
@ -559,8 +524,8 @@ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
static int whereOrInsert(
WhereOrSet *pSet, /* The WhereOrSet to be updated */
Bitmask prereq, /* Prerequisites of the new entry */
WhereCost rRun, /* Run-cost of the new entry */
WhereCost nOut /* Number of outputs for the new entry */
LogEst rRun, /* Run-cost of the new entry */
LogEst nOut /* Number of outputs for the new entry */
){
u16 i;
WhereOrCost *p;
@ -645,9 +610,6 @@ static void whereClauseClear(WhereClause *pWC){
}
}
/* Forward declaration */
static WhereCost whereCost(tRowcnt x);
/*
** Add a single new WhereTerm entry to the WhereClause object pWC.
** The new WhereTerm object is constructed from Expr p and with wtFlags.
@ -690,7 +652,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( p && ExprHasProperty(p, EP_Unlikely) ){
pTerm->truthProb = whereCost(p->iTable) - 99;
pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
}else{
pTerm->truthProb = -1;
}
@ -1954,75 +1916,12 @@ static int isDistinctRedundant(
return 0;
}
/*
** Find (an approximate) sum of two WhereCosts. This computation is
** not a simple "+" operator because WhereCost is stored as a logarithmic
** value.
**
*/
static WhereCost whereCostAdd(WhereCost a, WhereCost b){
static const unsigned char x[] = {
10, 10, /* 0,1 */
9, 9, /* 2,3 */
8, 8, /* 4,5 */
7, 7, 7, /* 6,7,8 */
6, 6, 6, /* 9,10,11 */
5, 5, 5, /* 12-14 */
4, 4, 4, 4, /* 15-18 */
3, 3, 3, 3, 3, 3, /* 19-24 */
2, 2, 2, 2, 2, 2, 2, /* 25-31 */
};
if( a>=b ){
if( a>b+49 ) return a;
if( a>b+31 ) return a+1;
return a+x[a-b];
}else{
if( b>a+49 ) return b;
if( b>a+31 ) return b+1;
return b+x[b-a];
}
}
/*
** Convert an integer into a WhereCost. In other words, compute a
** good approximatation for 10*log2(x).
*/
static WhereCost whereCost(tRowcnt x){
static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
WhereCost y = 40;
if( x<8 ){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
while( x>255 ){ y += 40; x >>= 4; }
while( x>15 ){ y += 10; x >>= 1; }
}
return a[x&7] + y - 10;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Convert a double (as received from xBestIndex of a virtual table)
** into a WhereCost. In other words, compute an approximation for
** 10*log2(x).
*/
static WhereCost whereCostFromDouble(double x){
u64 a;
WhereCost e;
assert( sizeof(x)==8 && sizeof(a)==8 );
if( x<=1 ) return 0;
if( x<=2000000000 ) return whereCost((tRowcnt)x);
memcpy(&a, &x, 8);
e = (a>>52) - 1022;
return e*10;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/*
** Estimate the logarithm of the input value to base 2.
*/
static WhereCost estLog(WhereCost N){
WhereCost x = whereCost(N);
static LogEst estLog(LogEst N){
LogEst x = sqlite3LogEst(N);
return x>33 ? x - 33 : 0;
}
@ -2438,6 +2337,9 @@ static void whereKeyStats(
int iTest; /* Next sample to test */
int res; /* Result of comparison operation */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( pParse );
#endif
assert( pRec!=0 || pParse->db->mallocFailed );
if( pRec==0 ) return;
iCol = pRec->nField - 1;
@ -2535,7 +2437,7 @@ static void whereKeyStats(
**
** then nEq is set to 0.
**
** When this function is called, *pnOut is set to the whereCost() of the
** When this function is called, *pnOut is set to the sqlite3LogEst() of the
** number of rows that the index scan is expected to visit without
** considering the range constraints. If nEq is 0, this is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
@ -2551,15 +2453,15 @@ static int whereRangeScanEst(
WhereLoopBuilder *pBuilder,
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
WhereCost *pnOut /* IN/OUT: Number of rows visited */
WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */
){
int rc = SQLITE_OK;
int nOut = (int)*pnOut;
WhereCost nNew;
int nOut = pLoop->nOut;
LogEst nNew;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
Index *p = pBuilder->pNew->u.btree.pIndex;
int nEq = pBuilder->pNew->u.btree.nEq;
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
if( p->nSample>0
&& nEq==pBuilder->nRecValid
@ -2640,14 +2542,14 @@ static int whereRangeScanEst(
pBuilder->pRec = pRec;
if( rc==SQLITE_OK ){
if( iUpper>iLower ){
nNew = whereCost(iUpper - iLower);
nNew = sqlite3LogEst(iUpper - iLower);
}else{
nNew = 10; assert( 10==whereCost(2) );
nNew = 10; assert( 10==sqlite3LogEst(2) );
}
if( nNew<nOut ){
nOut = nNew;
}
*pnOut = (WhereCost)nOut;
pLoop->nOut = (LogEst)nOut;
WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
return SQLITE_OK;
@ -2662,16 +2564,16 @@ static int whereRangeScanEst(
** A BETWEEN operator, therefore, reduces the search space 16-fold */
nNew = nOut;
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
nNew -= 20; assert( 20==whereCost(4) );
nNew -= 20; assert( 20==sqlite3LogEst(4) );
nOut--;
}
if( pUpper ){
nNew -= 20; assert( 20==whereCost(4) );
nNew -= 20; assert( 20==sqlite3LogEst(4) );
nOut--;
}
if( nNew<10 ) nNew = 10;
if( nNew<nOut ) nOut = nNew;
*pnOut = (WhereCost)nOut;
pLoop->nOut = (LogEst)nOut;
return rc;
}
@ -4283,7 +4185,7 @@ whereLoopInsert_noop:
** the number of output rows by a factor of 10 and each additional term
** reduces the number of output rows by sqrt(2).
*/
static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop, int iCur){
static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
WhereTerm *pTerm, *pX;
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
int i, j;
@ -4315,7 +4217,7 @@ static int whereLoopAddBtreeIndex(
WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
struct SrcList_item *pSrc, /* FROM clause term being analyzed */
Index *pProbe, /* An index on pSrc */
WhereCost nInMul /* log(Number of iterations due to IN) */
LogEst nInMul /* log(Number of iterations due to IN) */
){
WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
Parse *pParse = pWInfo->pParse; /* Parsing context */
@ -4328,11 +4230,11 @@ static int whereLoopAddBtreeIndex(
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
int saved_nEq; /* Original value of pNew->u.btree.nEq */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
WhereCost saved_nOut; /* Original value of pNew->nOut */
LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */
WhereCost nRowEst; /* Estimated index selectivity */
WhereCost rLogSize; /* Logarithm of table size */
LogEst nRowEst; /* Estimated index selectivity */
LogEst rLogSize; /* Logarithm of table size */
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
pNew = pBuilder->pNew;
@ -4352,7 +4254,7 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nEq<=pProbe->nColumn );
if( pNew->u.btree.nEq < pProbe->nColumn ){
iCol = pProbe->aiColumn[pNew->u.btree.nEq];
nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
}else{
iCol = -1;
@ -4366,7 +4268,7 @@ static int whereLoopAddBtreeIndex(
saved_prereq = pNew->prereq;
saved_nOut = pNew->nOut;
pNew->rSetup = 0;
rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
int nIn = 0;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@ -4393,10 +4295,10 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
nIn = 46; assert( 46==whereCost(25) );
nIn = 46; assert( 46==sqlite3LogEst(25) );
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
/* "x IN (value, value, ...)" */
nIn = whereCost(pExpr->x.pList->nExpr);
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
}
pNew->rRun += nIn;
pNew->u.btree.nEq++;
@ -4418,7 +4320,7 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_NULL;
pNew->u.btree.nEq++;
/* TUNING: IS NULL selects 2 rows */
nIn = 10; assert( 10==whereCost(2) );
nIn = 10; assert( 10==sqlite3LogEst(2) );
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_GT|WO_GE) ){
testcase( pTerm->eOperator & WO_GT );
@ -4438,7 +4340,7 @@ static int whereLoopAddBtreeIndex(
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
/* Adjust nOut and rRun for STAT3 range values */
assert( pNew->nOut==saved_nOut );
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
}
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( nInMul==0
@ -4458,19 +4360,19 @@ static int whereLoopAddBtreeIndex(
}
assert( nOut==0 || rc==SQLITE_OK );
if( nOut ){
nOut = whereCost(nOut);
pNew->nOut = MIN(nOut, saved_nOut);
pNew->nOut = sqlite3LogEst(nOut);
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
}
}
#endif
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
/* Each row involves a step of the index, then a binary search of
** the main table */
pNew->rRun = whereCostAdd(pNew->rRun, rLogSize>27 ? rLogSize-17 : 10);
pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10);
}
/* Step cost for each output row */
pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut);
whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor);
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut);
whereLoopOutputAdjust(pBuilder->pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
&& pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0))
@ -4569,14 +4471,16 @@ static int whereLoopAddBtree(
int rc = SQLITE_OK; /* Return code */
int iSortIdx = 1; /* Index number */
int b; /* A boolean value */
WhereCost rSize; /* number of rows in the table */
WhereCost rLogSize; /* Logarithm of the number of rows in the table */
LogEst rSize; /* number of rows in the table */
LogEst rLogSize; /* Logarithm of the number of rows in the table */
WhereClause *pWC; /* The parsed WHERE clause */
Table *pTab; /* Table being queried */
pNew = pBuilder->pNew;
pWInfo = pBuilder->pWInfo;
pTabList = pWInfo->pTabList;
pSrc = pTabList->a + pNew->iTab;
pTab = pSrc->pTab;
pWC = pBuilder->pWC;
assert( !IsVirtual(pSrc->pTab) );
@ -4594,8 +4498,8 @@ static int whereLoopAddBtree(
sPk.aiColumn = &aiColumnPk;
sPk.aiRowEst = aiRowEstPk;
sPk.onError = OE_Replace;
sPk.pTable = pSrc->pTab;
aiRowEstPk[0] = pSrc->pTab->nRowEst;
sPk.pTable = pTab;
aiRowEstPk[0] = pTab->nRowEst;
aiRowEstPk[1] = 1;
pFirst = pSrc->pTab->pIndex;
if( pSrc->notIndexed==0 ){
@ -4605,7 +4509,7 @@ static int whereLoopAddBtree(
}
pProbe = &sPk;
}
rSize = whereCost(pSrc->pTab->nRowEst);
rSize = sqlite3LogEst(pTab->nRowEst);
rLogSize = estLog(rSize);
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@ -4630,13 +4534,13 @@ static int whereLoopAddBtree(
/* TUNING: One-time cost for computing the automatic index is
** approximately 7*N*log2(N) where N is the number of rows in
** the table being indexed. */
pNew->rSetup = rLogSize + rSize + 28; assert( 28==whereCost(7) );
pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowning how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
pNew->nOut = 43; assert( 43==whereCost(20) );
pNew->rRun = whereCostAdd(rLogSize,pNew->nOut);
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
pNew->wsFlags = WHERE_AUTO_INDEX;
pNew->prereq = mExtra | pTerm->prereqRight;
rc = whereLoopInsert(pBuilder, pNew);
@ -4670,11 +4574,9 @@ static int whereLoopAddBtree(
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: Cost of full table scan is 3*(N + log2(N)).
** + The extra 3 factor is to encourage the use of indexed lookups
** over full scans. A smaller constant 2 is used for covering
** index scans so that a covering index scan will be favored over
** a table scan. */
pNew->rRun = whereCostAdd(rSize,rLogSize) + 16;
whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
** over full scans. FIXME */
pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16;
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@ -4686,6 +4588,7 @@ static int whereLoopAddBtree(
if( b
|| ( m==0
&& pProbe->bUnordered==0
&& pProbe->szIdxRow<pTab->szTabRow
&& (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
&& sqlite3GlobalConfig.bUseCis
&& OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
@ -4693,22 +4596,20 @@ static int whereLoopAddBtree(
){
pNew->iSortIdx = b ? iSortIdx : 0;
if( m==0 ){
/* TUNING: Cost of a covering index scan is 2*(N + log2(N)).
** + The extra 2 factor is to encourage the use of indexed lookups
** over index scans. A table scan uses a factor of 3 so that
** index scans are favored over table scans.
** + If this covering index might also help satisfy the ORDER BY
** clause, then the cost is fudged down slightly so that this
** index is favored above other indices that have no hope of
** helping with the ORDER BY. */
pNew->rRun = 10 + whereCostAdd(rSize,rLogSize) - b;
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
** + The extra factor K of between 1.1 and 3.0 that depends
** on the relative sizes of the table and the index. K
** is smaller for smaller indices, thus favoring them.
*/
pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
(15*pProbe->szIdxRow)/pTab->szTabRow;
}else{
assert( b!=0 );
/* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
** which we will simplify to just N*log2(N) */
pNew->rRun = rSize + rLogSize;
}
whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@ -4879,9 +4780,9 @@ static int whereLoopAddVirtual(
pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
&& pIdxInfo->orderByConsumed);
pNew->rSetup = 0;
pNew->rRun = whereCostFromDouble(pIdxInfo->estimatedCost);
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
/* TUNING: Every virtual table query returns 25 rows */
pNew->nOut = 46; assert( 46==whereCost(25) );
pNew->nOut = 46; assert( 46==sqlite3LogEst(25) );
whereLoopInsert(pBuilder, pNew);
if( pNew->u.vtab.needFree ){
sqlite3_free(pNew->u.vtab.idxStr);
@ -4918,6 +4819,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
pWCEnd = pWC->a + pWC->nTerm;
pNew = pBuilder->pNew;
memset(&sSum, 0, sizeof(sSum));
pItem = pWInfo->pTabList->a + pNew->iTab;
iCur = pItem->iCursor;
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
if( (pTerm->eOperator & WO_OR)!=0
@ -4929,8 +4832,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
int once = 1;
int i, j;
pItem = pWInfo->pTabList->a + pNew->iTab;
iCur = pItem->iCursor;
sSubBuild = *pBuilder;
sSubBuild.pOrderBy = 0;
sSubBuild.pOrSet = &sCur;
@ -4971,8 +4872,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
for(i=0; i<sPrev.n; i++){
for(j=0; j<sCur.n; j++){
whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
sqlite3LogEstAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
sqlite3LogEstAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
}
}
}
@ -5310,7 +5211,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
** error occurs.
*/
static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
@ -5318,11 +5219,11 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
WhereCost rCost; /* Cost of a path */
WhereCost nOut; /* Number of outputs */
WhereCost mxCost = 0; /* Maximum cost of a set of paths */
WhereCost mxOut = 0; /* Maximum nOut value on the set of paths */
WhereCost rSortCost; /* Cost to do a sort */
LogEst rCost; /* Cost of a path */
LogEst nOut; /* Number of outputs */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
LogEst rSortCost; /* Cost to do a sort */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
@ -5359,7 +5260,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
** TUNING: Do not let the number of iterations go above 25. If the cost
** of computing an automatic index is not paid back within the first 25
** rows, then do not use the automatic index. */
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==whereCost(25) );
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
nFrom = 1;
/* Precompute the cost of sorting the final result set, if the caller
@ -5368,8 +5269,10 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
aFrom[0].isOrderedValid = 1;
}else{
/* TUNING: Estimated cost of sorting is N*log2(N) where N is the
** number of output rows. */
/* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
** number of output rows. The 48 is the expected size of a row to sort.
** FIXME: compute a better estimate of the 48 multiplier based on the
** result set expressions. */
rSortCost = nRowEst + estLog(nRowEst);
WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
}
@ -5389,8 +5292,8 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rCost = whereCostAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rCost = whereCostAdd(rCost, pFrom->rCost);
rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
if( !isOrderedValid ){
@ -5404,7 +5307,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
case 0: /* No. pFrom+pWLoop will require a separate sort */
isOrdered = 0;
isOrderedValid = 1;
rCost = whereCostAdd(rCost, rSortCost);
rCost = sqlite3LogEstAdd(rCost, rSortCost);
break;
default: /* Cannot tell yet. Try again on the next iteration */
break;
@ -5611,7 +5514,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->nLTerm = 1;
pLoop->u.btree.nEq = 1;
/* TUNING: Cost of a rowid lookup is 10 */
pLoop->rRun = 33; /* 33==whereCost(10) */
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
@ -5634,12 +5537,12 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->u.btree.nEq = j;
pLoop->u.btree.pIndex = pIdx;
/* TUNING: Cost of a unique index lookup is 15 */
pLoop->rRun = 39; /* 39==whereCost(15) */
pLoop->rRun = 39; /* 39==sqlite3LogEst(15) */
break;
}
}
if( pLoop->wsFlags ){
pLoop->nOut = (WhereCost)1;
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
pWInfo->a[0].iTabCur = iCur;
@ -6007,7 +5910,7 @@ WhereInfo *sqlite3WhereBegin(
/* If the caller is an UPDATE or DELETE statement that is requesting
** to use a one-pass algorithm, determine if this is appropriate.
** The one-pass algorithm only works if the WHERE clause constraints
** The one-pass algorithm only works if the WHERE clause constrains
** the statement to update a single row.
*/
assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );

117
test/amatch1.test Normal file
View File

@ -0,0 +1,117 @@
# 2013-09-30
#
# 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 "approximate_match" virtual
# table that is in the "amatch.c" extension.
#
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS4 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
# Create the fts_kjv_genesis procedure which fills and FTS3/4 table with
# the complete text of the Book of Genesis.
#
source $testdir/genesis.tcl
do_test amatch1-1.0 {
db eval {
CREATE VIRTUAL TABLE t1 USING fts4(words); --, tokenize porter);
}
fts_kjv_genesis
db eval {
INSERT INTO t1(t1) VALUES('optimize');
CREATE VIRTUAL TABLE temp.t1aux USING fts4aux(main, t1);
SELECT term FROM t1aux WHERE col=0 ORDER BY 1 LIMIT 5
}
} {a abated abel abelmizraim abidah}
do_test amatch1-1.1 {
db eval {
SELECT term FROM t1aux WHERE term>'b' AND col=0 ORDER BY 1 LIMIT 5
}
} {baalhanan babel back backward bad}
do_test amatch1-1.2 {
db eval {
SELECT term FROM t1aux WHERE term>'b' AND col=0 LIMIT 5
}
} {baalhanan babel back backward bad}
# Load the amatch extension
load_static_extension db amatch
do_execsql_test amatch1-2.0 {
CREATE TABLE costs(iLang, cFrom, cTo, Cost);
INSERT INTO costs VALUES(0, '', '?', 100);
INSERT INTO costs VALUES(0, '?', '', 100);
INSERT INTO costs VALUES(0, '?', '?', 150);
CREATE TABLE vocab(w TEXT UNIQUE);
INSERT OR IGNORE INTO vocab SELECT term FROM t1aux;
CREATE VIRTUAL TABLE t2 USING approximate_match(
vocabulary_table=t1aux,
vocabulary_word=term,
edit_distances=costs
);
CREATE VIRTUAL TABLE t3 USING approximate_match(
vocabulary_table=vocab,
vocabulary_word=w,
edit_distances=costs
);
CREATE VIRTUAL TABLE t4 USING approximate_match(
vocabulary_table=vtemp,
vocabulary_word=w,
edit_distances=costs
);
} {}
puts "Query against fts4aux: [time {
do_execsql_test amatch1-2.1 {
SELECT word, distance FROM t2
WHERE word MATCH 'josxph' AND distance<300;
} {joseph 150}} 1]"
puts "Query against ordinary table: [time {
do_execsql_test amatch1-2.2 {
SELECT word, distance FROM t3
WHERE word MATCH 'josxph' AND distance<300;
} {joseph 150}} 1]"
puts "Temp table initialized from fts4aux: [time {
do_execsql_test amatch1-2.3a {
CREATE TEMP TABLE vtemp(w TEXT UNIQUE);
INSERT OR IGNORE INTO vtemp SELECT term FROM t1aux;
} {}} 1]"
puts "Query against temp table: [time {
do_execsql_test amatch1-2.3b {
SELECT word, distance FROM t4
WHERE word MATCH 'josxph' AND distance<300;
} {joseph 150}} 1]"
do_execsql_test amatch1-2.11 {
SELECT word, distance FROM t2
WHERE word MATCH 'joxxph' AND distance<=300;
} {joseph 300}
do_execsql_test amatch1-2.12 {
SELECT word, distance FROM t3
WHERE word MATCH 'joxxph' AND distance<=300;
} {joseph 300}
do_execsql_test amatch1-2.21 {
SELECT word, distance FROM t2
WHERE word MATCH 'joxxph' AND distance<300;
} {}
do_execsql_test amatch1-2.22 {
SELECT word, distance FROM t3
WHERE word MATCH 'joxxph' AND distance<300;
} {}
finish_test

View File

@ -30,14 +30,14 @@ proc eqp {sql {db db}} {
do_test analyze6-1.0 {
db eval {
CREATE TABLE cat(x INT);
CREATE TABLE cat(x INT, yz TEXT);
CREATE UNIQUE INDEX catx ON cat(x);
/* Give cat 16 unique integers */
INSERT INTO cat VALUES(1);
INSERT INTO cat VALUES(2);
INSERT INTO cat SELECT x+2 FROM cat;
INSERT INTO cat SELECT x+4 FROM cat;
INSERT INTO cat SELECT x+8 FROM cat;
INSERT INTO cat(x) VALUES(1);
INSERT INTO cat(x) VALUES(2);
INSERT INTO cat(x) SELECT x+2 FROM cat;
INSERT INTO cat(x) SELECT x+4 FROM cat;
INSERT INTO cat(x) SELECT x+8 FROM cat;
CREATE TABLE ev(y INT);
CREATE INDEX evy ON ev(y);

View File

@ -377,6 +377,9 @@ do_test attach2-6.2 {
}
} {1 {cannot ATTACH database within transaction}}
# EVIDENCE-OF: R-59740-55581 This statement will fail if SQLite is in
# the middle of a transaction.
#
do_test attach2-6.3 {
catchsql {
DETACH aux;

View File

@ -532,6 +532,10 @@ if {0==[sqlite3 -has-codec]} {
# Verify that multiple calls to date functions with 'now' return the
# same answer.
#
# EVIDENCE-OF: R-34818-13664 The 'now' argument to date and time
# functions always returns exactly the same value for multiple
# invocations within the same sqlite3_step() call.
#
proc sleeper {} {after 100}
do_test date-15.1 {
db func sleeper sleeper

View File

@ -450,17 +450,17 @@ do_join_test e_select-1.4.1.4 {
# left-hand and right-hand datasets.
#
do_join_test e_select-1.4.2.1 {
SELECT * FROM x2 %JOIN% x3
SELECT * FROM x2 %JOIN% x3 ORDER BY +c, +f
} [list -60.06 {} {} -39.24 {} encompass -1 \
-60.06 {} {} presenting 51 reformation dignified \
-60.06 {} {} conducting -87.24 37.56 {} \
-60.06 {} {} coldest -96 dramatists 82.3 \
-60.06 {} {} alerting {} -93.79 {} \
-60.06 {} {} coldest -96 dramatists 82.3 \
-60.06 {} {} conducting -87.24 37.56 {} \
-60.06 {} {} presenting 51 reformation dignified \
-58 {} 1.21 -39.24 {} encompass -1 \
-58 {} 1.21 presenting 51 reformation dignified \
-58 {} 1.21 conducting -87.24 37.56 {} \
-58 {} 1.21 coldest -96 dramatists 82.3 \
-58 {} 1.21 alerting {} -93.79 {} \
-58 {} 1.21 coldest -96 dramatists 82.3 \
-58 {} 1.21 conducting -87.24 37.56 {} \
-58 {} 1.21 presenting 51 reformation dignified \
]
# TODO: Come back and add a few more like the above.

View File

@ -33,11 +33,11 @@ set testprefix eqp
proc det {args} { uplevel do_eqp_test $args }
do_execsql_test 1.1 {
CREATE TABLE t1(a, b);
CREATE TABLE t1(a INT, b INT, ex TEXT);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
CREATE TABLE t2(a, b);
CREATE TABLE t3(a, b);
CREATE TABLE t2(a INT, b INT, ex TEXT);
CREATE TABLE t3(a INT, b INT, ex TEXT);
}
do_eqp_test 1.2 {
@ -122,9 +122,9 @@ do_eqp_test 1.11 {
#
drop_all_tables
do_execsql_test 2.1 {
CREATE TABLE t1(x, y);
CREATE TABLE t1(x INT, y INT, ex TEXT);
CREATE TABLE t2(x, y);
CREATE TABLE t2(x INT, y INT, ex TEXT);
CREATE INDEX t2i1 ON t2(x);
}
@ -374,7 +374,7 @@ drop_all_tables
# FROM t1 WHERE a=1;
# 0|0|0|SCAN TABLE t1
#
do_execsql_test 5.1.0 { CREATE TABLE t1(a, b) }
do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) }
det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" {
0 0 0 {SCAN TABLE t1}
}
@ -402,8 +402,8 @@ det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" {
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
# 0|1|1|SCAN TABLE t2
#
do_execsql_test 5.4.0 {CREATE TABLE t2(c, d)}
det 5.4.1 "SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)}
det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)}
0 1 1 {SCAN TABLE t2}
}
@ -413,7 +413,7 @@ det 5.4.1 "SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
# 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
# 0|1|0|SCAN TABLE t2
#
det 5.5 "SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)}
0 1 0 {SCAN TABLE t2}
}
@ -424,7 +424,7 @@ det 5.5 "SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?)
#
do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)}
det 5.6.1 "SELECT * FROM t1 WHERE a=1 OR b=2" {
det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" {
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)}
0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)}
}
@ -485,7 +485,7 @@ det 5.10 {
# 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?)
# 0|1|1|SCAN TABLE t1
#
det 5.11 "SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1" {
det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" {
0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)}
0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2}
}
@ -496,7 +496,7 @@ det 5.11 "SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1" {
# 2|0|0|SCAN TABLE t2
# 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)
#
det 5.12 "SELECT a FROM t1 UNION SELECT c FROM t2" {
det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" {
1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2}
2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
@ -509,7 +509,7 @@ det 5.12 "SELECT a FROM t1 UNION SELECT c FROM t2" {
# 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
#
det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" {
1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2}
1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
@ -548,7 +548,7 @@ proc do_peqp_test {tn sql res} {
}
do_peqp_test 6.1 {
SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1
SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1
} [string trimleft {
1 0 0 SCAN TABLE t1 USING COVERING INDEX i2
2 0 0 SCAN TABLE t2
@ -563,8 +563,8 @@ do_peqp_test 6.1 {
drop_all_tables
do_execsql_test 7.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(a, b);
CREATE TABLE t1(a INT, b INT, ex CHAR(100));
CREATE TABLE t2(a INT, b INT, ex CHAR(100));
CREATE INDEX i1 ON t2(a);
}
@ -577,12 +577,12 @@ det 7.2 "SELECT count(*) FROM t2" {
}
do_execsql_test 7.3 {
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1(a,b) VALUES(1, 2);
INSERT INTO t1(a,b) VALUES(3, 4);
INSERT INTO t2 VALUES(1, 2);
INSERT INTO t2 VALUES(3, 4);
INSERT INTO t2 VALUES(5, 6);
INSERT INTO t2(a,b) VALUES(1, 2);
INSERT INTO t2(a,b) VALUES(3, 4);
INSERT INTO t2(a,b) VALUES(5, 6);
ANALYZE;
}

View File

@ -12,6 +12,8 @@
#
# This file tests the PRAGMA foreign_key_check command.
#
# EVIDENCE-OF: R-05426-18119 PRAGMA foreign_key_check; PRAGMA
# foreign_key_check(table-name);
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -82,6 +84,20 @@ do_test fkey5-1.4 {
}
} {}
# EVIDENCE-OF: R-45728-08709 There are four columns in each result row.
#
# EVIDENCE-OF: R-55672-01620 The first column is the name of the table
# that contains the REFERENCES clause.
#
# EVIDENCE-OF: R-25219-25618 The second column is the rowid of the row
# that contains the invalid REFERENCES clause.
#
# EVIDENCE-OF: R-40482-20265 The third column is the name of the table
# that is referred to.
#
# EVIDENCE-OF: R-62839-07969 The fourth column is the index of the
# specific foreign key constraint that failed.
#
do_test fkey5-2.0 {
db eval {
INSERT INTO c5 SELECT x FROM c1;
@ -99,6 +115,9 @@ do_test fkey5-2.2 {
PRAGMA foreign_key_check(c1);
}
} {}
do_execsql_test fkey5-2.3 {
PRAGMA foreign_key_list(c5);
} {0 0 p1 x {} {NO ACTION} {NO ACTION} NONE}
do_test fkey5-3.0 {
db eval {

View File

@ -13,6 +13,13 @@
# This file tests the PRAGMA defer_foreign_keys and
# SQLITE_DBSTATUS_DEFERRED_FKS
#
# EVIDENCE-OF: R-18981-16292 When the defer_foreign_keys PRAGMA is on,
# enforcement of all foreign key constraints is delayed until the
# outermost transaction is committed.
#
# EVIDENCE-OF: R-28911-57501 The defer_foreign_keys pragma defaults to
# OFF so that foreign key constraints are only deferred if they are
# created as "DEFERRABLE INITIALLY DEFERRED".
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -22,6 +29,10 @@ ifcapable {!foreignkey} {
return
}
do_execsql_test fkey6-1.0 {
PRAGMA defer_foreign_keys;
} {0}
do_execsql_test fkey6-1.1 {
PRAGMA foreign_keys=ON;
CREATE TABLE t1(x INTEGER PRIMARY KEY);
@ -70,12 +81,23 @@ do_test fkey6-1.8 {
do_test fkey6-1.9 {
sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
} {0 1 0}
do_test fkey6-1.10 {
execsql {
ROLLBACK;
PRAGMA defer_foreign_keys=OFF;
BEGIN;
}
# EVIDENCE-OF: R-21752-26913 The defer_foreign_keys pragma is
# automatically switched off at each COMMIT or ROLLBACK. Hence, the
# defer_foreign_keys pragma must be separately enabled for each
# transaction.
do_execsql_test fkey6-1.10.1 {
PRAGMA defer_foreign_keys;
ROLLBACK;
PRAGMA defer_foreign_keys;
BEGIN;
PRAGMA defer_foreign_keys=ON;
PRAGMA defer_foreign_keys;
COMMIT;
PRAGMA defer_foreign_keys;
BEGIN;
} {1 0 1 0}
do_test fkey6-1.10.2 {
catchsql {DELETE FROM t1 WHERE x=3}
} {1 {foreign key constraint failed}}
db eval {ROLLBACK}
@ -99,5 +121,56 @@ do_test fkey6-1.22 {
}
} {}
do_execsql_test fkey6-2.1 {
CREATE TABLE p1(a PRIMARY KEY);
INSERT INTO p1 VALUES('one'), ('two');
CREATE TABLE c1(x REFERENCES p1);
INSERT INTO c1 VALUES('two'), ('one');
}
do_execsql_test fkey6-2.2 {
BEGIN;
PRAGMA defer_foreign_keys = 1;
DELETE FROM p1;
ROLLBACK;
PRAGMA defer_foreign_keys;
} {0}
do_execsql_test fkey6-2.3 {
BEGIN;
PRAGMA defer_foreign_keys = 1;
DROP TABLE p1;
PRAGMA vdbe_trace = 0;
ROLLBACK;
PRAGMA defer_foreign_keys;
} {0}
do_execsql_test fkey6-2.4 {
BEGIN;
PRAGMA defer_foreign_keys = 1;
DELETE FROM p1;
DROP TABLE c1;
COMMIT;
PRAGMA defer_foreign_keys;
} {0}
do_execsql_test fkey6-2.5 {
DROP TABLE p1;
CREATE TABLE p1(a PRIMARY KEY);
INSERT INTO p1 VALUES('one'), ('two');
CREATE TABLE c1(x REFERENCES p1);
INSERT INTO c1 VALUES('two'), ('one');
}
do_execsql_test fkey6-2.6 {
BEGIN;
PRAGMA defer_foreign_keys = 1;
INSERT INTO c1 VALUES('three');
DROP TABLE c1;
COMMIT;
PRAGMA defer_foreign_keys;
} {0}
finish_test

84
test/fts3defer3.test Normal file
View File

@ -0,0 +1,84 @@
# 2010 October 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 contains a very simple test to show that the deferred tokens
# optimization is doing something.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
ifcapable !fts3||!fts4_deferred {
finish_test
return
}
set testprefix fts3defer3
set nDoclist 3204
set nDoc 800
# Set up a database that contains 800 rows. Each row contains the document
# "b b", except for the row with docid=200, which contains "a b". Hence
# token "b" is extremely common and token "a" is not.
#
do_test 1.1 {
execsql {
CREATE VIRTUAL TABLE t1 USING fts4;
BEGIN;
}
for {set i 1} {$i <= $nDoc} {incr i} {
set document "b b"
if {$i==200} { set document "a b" }
execsql { INSERT INTO t1 (docid, content) VALUES($i, $document) }
}
execsql COMMIT
} {}
# Check that the db contains two doclists. A small one for "a" and a
# larger one for "b".
#
do_execsql_test 1.2 {
SELECT blockid, length(block) FROM t1_segments;
} [list 1 8 2 $nDoclist]
# Query for 'a b'. Although this test doesn't prove so, token "b" will
# be deferred because of the very large associated doclist.
#
do_execsql_test 1.3 {
SELECT docid, content FROM t1 WHERE t1 MATCH 'a b';
} {200 {a b}}
# Zero out the doclist for token "b" within the database file. Now the
# only queries that use token "b" that will work are those that defer
# it. Any query that tries to use the doclist belonging to token "b"
# will fail.
#
do_test 1.4 {
set fd [db incrblob t1_segments block 2]
puts -nonewline $fd [string repeat "\00" $nDoclist]
close $fd
} {}
# The first two queries succeed, as they defer token "b". The last one
# fails, as it tries to load the corrupt doclist.
#
do_execsql_test 1.5 {
SELECT docid, content FROM t1 WHERE t1 MATCH 'a b';
} {200 {a b}}
do_execsql_test 1.6 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'a b';
} {1}
do_catchsql_test 1.7 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'b';
} {1 {database disk image is malformed}}
finish_test

View File

@ -16,6 +16,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3snippet
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }
@ -138,7 +139,7 @@ foreach {DO_MALLOC_TEST enc} {
# Set variable $T to the test name prefix for this iteration of the loop.
#
set T "fts3snippet-$enc"
set T "fts3snippet-1.$enc"
##########################################################################
# Test the offset function.
@ -459,5 +460,65 @@ foreach {DO_MALLOC_TEST enc} {
} {0 blob}
}
#-------------------------------------------------------------------------
# Test an interaction between the snippet() function and OR clauses.
#
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t2 USING fts4;
INSERT INTO t2 VALUES('one two three four five');
INSERT INTO t2 VALUES('two three four five one');
INSERT INTO t2 VALUES('three four five one two');
INSERT INTO t2 VALUES('four five one two three');
INSERT INTO t2 VALUES('five one two three four');
}
do_execsql_test 2.2 {
SELECT snippet(t2, '[', ']') FROM t2 WHERE t2 MATCH 'one OR (four AND six)'
} {
{[one] two three [four] five}
{two three [four] five [one]}
{three [four] five [one] two}
{[four] five [one] two three}
{five [one] two three [four]}
}
do_execsql_test 2.3 {
SELECT snippet(t2, '[', ']') FROM t2
WHERE t2 MATCH 'one OR (four AND six)'
ORDER BY docid DESC
} {
{five [one] two three [four]}
{[four] five [one] two three}
{three [four] five [one] two}
{two three [four] five [one]}
{[one] two three [four] five}
}
do_execsql_test 2.4 {
INSERT INTO t2 VALUES('six');
}
do_execsql_test 2.5 {
SELECT snippet(t2, '[', ']') FROM t2 WHERE t2 MATCH 'one OR (four AND six)'
} {
{[one] two three [four] five}
{two three [four] five [one]}
{three [four] five [one] two}
{[four] five [one] two three}
{five [one] two three [four]}
}
do_execsql_test 2.6 {
SELECT snippet(t2, '[', ']') FROM t2
WHERE t2 MATCH 'one OR (four AND six)'
ORDER BY docid DESC
} {
{five [one] two three [four]}
{[four] five [one] two three}
{three [four] five [one] two}
{two three [four] five [one]}
{[one] two three [four] five}
}
set sqlite_fts3_enable_parentheses 0
finish_test

File diff suppressed because it is too large Load Diff

116
test/fts4docid.test Normal file
View File

@ -0,0 +1,116 @@
# 2012 March 26
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/fts3_common.tcl
set ::testprefix fts4docid
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
# Initialize a table with pseudo-randomly generated data.
#
do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts4; }
do_test 1.1 {
foreach {docid content} {
0 {F N K B T I K V B A} 1 {D M J E S P H E L O}
2 {W U T Q T Q T L H G} 3 {D W H M B R S Z B K}
4 {F Q I N P Q J L Z D} 5 {J O Q E Y A O E L B}
6 {O V R A C R K C Y H} 7 {Z J H T Q Q O R A G}
8 {L K J W G D Y W B M} 9 {K E Y I A Q R Q T S}
10 {N P H Y Z M R T I C} 11 {E X H O I S E S Z F}
12 {B Y Q T J X C L L J} 13 {Q D C U U A Q E Z U}
14 {S I T C J R X S J M} 15 {M X M K E X L H Q Y}
16 {O W E I C H U Y S Y} 17 {P V V E M T H C C S}
18 {L Y A M I E N M X O} 19 {S Y R U L S Q Y F P}
20 {U J S T T J J S V X} 21 {T E I W P O V A A P}
22 {W D K H D H F G O J} 23 {T X Y P G M J U I L}
24 {F V X E B C N B K W} 25 {E B A Y N N T Z I C}
26 {G E E B C P U D H G} 27 {J D J K N S B Q T M}
28 {Q T G M D O D Y V G} 29 {P X W I W V P W Z G}
} {
execsql { INSERT INTO t1(docid, content) VALUES($docid, $content) }
}
} {}
# Quick test regarding affinites and the docid/rowid column.
do_execsql_test 2.1.1 { SELECT docid FROM t1 WHERE docid = 5 } {5}
do_execsql_test 2.1.2 { SELECT docid FROM t1 WHERE docid = '5' } {5}
do_execsql_test 2.1.3 { SELECT docid FROM t1 WHERE docid = +5 } {5}
do_execsql_test 2.1.4 { SELECT docid FROM t1 WHERE docid = +'5' } {5}
do_execsql_test 2.1.5 { SELECT docid FROM t1 WHERE docid < 5 } {0 1 2 3 4}
do_execsql_test 2.1.6 { SELECT docid FROM t1 WHERE docid < '5' } {0 1 2 3 4}
do_execsql_test 2.2.1 { SELECT rowid FROM t1 WHERE rowid = 5 } {5}
do_execsql_test 2.2.2 { SELECT rowid FROM t1 WHERE rowid = '5' } {5}
do_execsql_test 2.2.3 { SELECT rowid FROM t1 WHERE rowid = +5 } {5}
do_execsql_test 2.2.4 { SELECT rowid FROM t1 WHERE rowid = +'5' } {5}
do_execsql_test 2.2.5 { SELECT rowid FROM t1 WHERE rowid < 5 } {0 1 2 3 4}
do_execsql_test 2.2.6 { SELECT rowid FROM t1 WHERE rowid < '5' } {0 1 2 3 4}
#-------------------------------------------------------------------------
# Now test a bunch of full-text queries featuring range constraints on
# the docid field. Each query is run so that the range constraint:
#
# * is on the docid field,
# * is on the docid field with a unary +,
# * is on the rowid field,
# * is on the rowid field with a unary +.
#
# Queries are run with both "ORDER BY docid DESC" and "ORDER BY docid ASC"
# clauses.
#
foreach {tn where result} {
1 {WHERE t1 MATCH 'O' AND xxx < 17} {1 5 6 7 11 16}
2 {WHERE t1 MATCH 'O' AND xxx < 4123456789123456} {1 5 6 7 11 16 18 21 22 28}
3 {WHERE t1 MATCH 'O' AND xxx < 1} {}
4 {WHERE t1 MATCH 'O' AND xxx < -4123456789123456} {}
5 {WHERE t1 MATCH 'O' AND xxx > 17} {18 21 22 28}
6 {WHERE t1 MATCH 'O' AND xxx > 4123456789123456} {}
7 {WHERE t1 MATCH 'O' AND xxx > 1} {5 6 7 11 16 18 21 22 28}
8 {WHERE t1 MATCH 'O' AND xxx > -4123456789123456} {1 5 6 7 11 16 18 21 22 28}
9 {WHERE t1 MATCH '"Q T"' AND xxx < 27} {2 9 12}
10 {WHERE t1 MATCH '"Q T"' AND xxx <= 27} {2 9 12 27}
11 {WHERE t1 MATCH '"Q T"' AND xxx > 27} {28}
12 {WHERE t1 MATCH '"Q T"' AND xxx >= 27} {27 28}
} {
foreach {tn2 ref order} {
1 docid "ORDER BY docid ASC"
2 +docid "ORDER BY docid ASC"
3 rowid "ORDER BY docid ASC"
4 +rowid "ORDER BY docid ASC"
5 docid "ORDER BY docid DESC"
6 +docid "ORDER BY docid DESC"
7 rowid "ORDER BY docid DESC"
8 +rowid "ORDER BY docid DESC"
} {
set w [string map "xxx $ref" $where]
set q "SELECT docid FROM t1 $w $order"
if {$tn2<5} {
set r [lsort -integer -increasing $result]
} else {
set r [lsort -integer -decreasing $result]
}
do_execsql_test 3.$tn.$tn2 $q $r
}
}
finish_test

53
test/fts4incr.test Normal file
View File

@ -0,0 +1,53 @@
# 2012 March 26
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/fts3_common.tcl
set ::testprefix fts4incr
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
# Create the fts_kjv_genesis procedure which fills and FTS3/4 table
# with the complete text of the Book of Genesis.
#
source $testdir/genesis.tcl
do_test 1.0 {
execsql { CREATE VIRTUAL TABLE t1 USING fts4(words) }
fts_kjv_genesis
} {}
do_execsql_test 1.1 {
SELECT min(docid), max(docid) FROM t1;
} {1001001 1050026}
foreach {tn q res} {
1 { SELECT count(*) FROM t1 WHERE t1 MATCH 'and' AND docid < 1010000} 224
2 { SELECT count(*) FROM t1 WHERE t1 MATCH '"in the"' AND docid < 1010000} 47
3 { SELECT count(*) FROM t1 WHERE t1 MATCH '"And God"' AND docid < 1010000} 33
4 { SELECT count(*) FROM t1 WHERE t1
MATCH '"land of canaan"' AND docid < 1030000 } 7
} {
foreach s {0 1} {
execsql "INSERT INTO t1(t1) VALUES('test-no-incr-doclist=$s')"
do_execsql_test 2.$tn.$s $q $res
set t($s) [lindex [time [list execsql $q] 100] 0]
}
puts "with optimization: $t(0) without: $t(1)"
}
finish_test

View File

@ -44,31 +44,36 @@ proc do_unicode_token_test3 {tn args} {
}
do_unicode_token_test 1.0 {a B c D} {0 a a 1 b B 2 c c 3 d D}
do_unicode_token_test 1.1 {Ä Ö Ü} {0 ä Ä 1 ö Ö 2 ü Ü}
do_unicode_token_test 1.2 {xÄx xÖx xÜx} {0 xäx xÄx 1 xöx xÖx 2 xüx xÜx}
do_unicode_token_test 1.1 "\uC4 \uD6 \uDC" \
"0 \uE4 \uC4 1 \uF6 \uD6 2 \uFC \uDC"
do_unicode_token_test 1.2 "x\uC4x x\uD6x x\uDCx" \
"0 x\uE4x x\uC4x 1 x\uF6x x\uD6x 2 x\uFCx x\uDCx"
# 0x00DF is a small "sharp s". 0x1E9E is a capital sharp s.
do_unicode_token_test 1.3 "\uDF" "0 \uDF \uDF"
do_unicode_token_test 1.4 "\u1E9E" "0 ß \u1E9E"
do_unicode_token_test 1.5 "\u1E9E" "0 \uDF \u1E9E"
do_unicode_token_test 1.4 "\u1E9E" "0 \uDF \u1E9E"
do_unicode_token_test 1.6 "The quick brown fox" {
do_unicode_token_test 1.5 "The quick brown fox" {
0 the The 1 quick quick 2 brown brown 3 fox fox
}
do_unicode_token_test 1.7 "The\u00bfquick\u224ebrown\u2263fox" {
do_unicode_token_test 1.6 "The\u00bfquick\u224ebrown\u2263fox" {
0 the The 1 quick quick 2 brown brown 3 fox fox
}
do_unicode_token_test2 1.8 {a B c D} {0 a a 1 b B 2 c c 3 d D}
do_unicode_token_test2 1.9 {Ä Ö Ü} {0 a Ä 1 o Ö 2 u Ü}
do_unicode_token_test2 1.10 {xÄx xÖx xÜx} {0 xax xÄx 1 xox xÖx 2 xux xÜx}
do_unicode_token_test2 1.7 {a B c D} {0 a a 1 b B 2 c c 3 d D}
do_unicode_token_test2 1.8 "\uC4 \uD6 \uDC" "0 a \uC4 1 o \uD6 2 u \uDC"
do_unicode_token_test2 1.9 "x\uC4x x\uD6x x\uDCx" \
"0 xax x\uC4x 1 xox x\uD6x 2 xux x\uDCx"
# Check that diacritics are removed if remove_diacritics=1 is specified.
# And that they do not break tokens.
do_unicode_token_test2 1.11 "xx\u0301xx" "0 xxxx xx\u301xx"
do_unicode_token_test2 1.10 "xx\u0301xx" "0 xxxx xx\u301xx"
# Title-case mappings work
do_unicode_token_test 1.12 "\u01c5" "0 \u01c6 \u01c5"
do_unicode_token_test 1.11 "\u01c5" "0 \u01c6 \u01c5"
#-------------------------------------------------------------------------
#
@ -378,10 +383,10 @@ foreach T $tokenizers {
do_isspace_test 6.$T.18 $T 12288
do_isspace_test 6.$T.19 $T {32 160 5760 6158}
do_isspace_test 6.$T.19 $T {8192 8193 8194 8195}
do_isspace_test 6.$T.19 $T {8196 8197 8198 8199}
do_isspace_test 6.$T.19 $T {8200 8201 8202 8239}
do_isspace_test 6.$T.19 $T {8287 12288}
do_isspace_test 6.$T.20 $T {8192 8193 8194 8195}
do_isspace_test 6.$T.21 $T {8196 8197 8198 8199}
do_isspace_test 6.$T.22 $T {8200 8201 8202 8239}
do_isspace_test 6.$T.23 $T {8287 12288}
}
#-------------------------------------------------------------------------

View File

@ -1319,6 +1319,14 @@ do_test func-29.6 {
set x
} {1}
# EVIDENCE-OF: R-29701-50711 The unicode(X) function returns the numeric
# unicode code point corresponding to the first character of the string
# X.
#
# EVIDENCE-OF: R-55469-62130 The char(X1,X2,...,XN) function returns a
# string composed of characters having the unicode code point values of
# integers X1 through XN, respectively.
#
do_execsql_test func-30.1 {SELECT unicode('$');} 36
do_execsql_test func-30.2 [subst {SELECT unicode('\u00A2');}] 162
do_execsql_test func-30.3 [subst {SELECT unicode('\u20AC');}] 8364

View File

@ -70,4 +70,87 @@ do_test func3-4.1 {
} {1 SQLITE_MISUSE}
do_test func3-4.2 { set destroyed } 1
# EVIDENCE-OF: R-41921-05214 The likelihood(X,Y) function returns
# argument X unchanged.
#
do_execsql_test func3-5.1 {
SELECT likelihood(9223372036854775807, 0.5);
} {9223372036854775807}
do_execsql_test func3-5.2 {
SELECT likelihood(-9223372036854775808, 0.5);
} {-9223372036854775808}
do_execsql_test func3-5.3 {
SELECT likelihood(14.125, 0.5);
} {14.125}
do_execsql_test func3-5.4 {
SELECT likelihood(NULL, 0.5);
} {{}}
do_execsql_test func3-5.5 {
SELECT likelihood('test-string', 0.5);
} {test-string}
do_execsql_test func3-5.6 {
SELECT quote(likelihood(x'010203000405', 0.5));
} {X'010203000405'}
# EVIDENCE-OF: R-44133-61651 The value Y in likelihood(X,Y) must be a
# floating point constant between 0.0 and 1.0, inclusive.
#
do_execsql_test func3-5.7 {
SELECT likelihood(123, 1.0), likelihood(456, 0.0);
} {123 456}
do_test func3-5.8 {
catchsql {
SELECT likelihood(123, 1.000001);
}
} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}}
do_test func3-5.9 {
catchsql {
SELECT likelihood(123, -0.000001);
}
} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}}
do_test func3-5.10 {
catchsql {
SELECT likelihood(123, 0.5+0.3);
}
} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}}
# EVIDENCE-OF: R-28535-44631 The likelihood(X) function is a no-op that
# the code generator optimizes away so that it consumes no CPU cycles
# during run-time (that is, during calls to sqlite3_step()).
#
do_test func3-5.20 {
db eval {EXPLAIN SELECT likelihood(min(1.0+'2.0',4*11), 0.5)}
} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}]
# EVIDENCE-OF: R-11152-23456 The unlikely(X) function returns the
# argument X unchanged.
#
do_execsql_test func3-5.30 {
SELECT unlikely(9223372036854775807);
} {9223372036854775807}
do_execsql_test func3-5.31 {
SELECT unlikely(-9223372036854775808);
} {-9223372036854775808}
do_execsql_test func3-5.32 {
SELECT unlikely(14.125);
} {14.125}
do_execsql_test func3-5.33 {
SELECT unlikely(NULL);
} {{}}
do_execsql_test func3-5.34 {
SELECT unlikely('test-string');
} {test-string}
do_execsql_test func3-5.35 {
SELECT quote(unlikely(x'010203000405'));
} {X'010203000405'}
# EVIDENCE-OF: R-22887-63324 The unlikely(X) function is a no-op that
# the code generator optimizes away so that it consumes no CPU cycles at
# run-time (that is, during calls to sqlite3_step()).
#
do_test func3-5.40 {
db eval {EXPLAIN SELECT unlikely(min(1.0+'2.0',4*11))}
} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}]
finish_test

1560
test/genesis.tcl Normal file

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,13 @@ do_test index6-1.1 {
}
} {14 20 ok}
# Make sure the count(*) optimization works correctly with
# partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03.
#
do_execsql_test index6-1.1.1 {
SELECT count(*) FROM t1;
} {20}
# Error conditions during parsing...
#
do_test index6-1.2 {

View File

@ -11,6 +11,11 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the built-in INSTR() functions.
#
# EVIDENCE-OF: R-27549-59611 The instr(X,Y) function finds the first
# occurrence of string Y within string X and returns the number of prior
# characters plus 1, or 0 if Y is nowhere found within X.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -199,12 +204,48 @@ do_test instr-1.54 {
do_test instr-1.55 {
db eval {SELECT instr(x'78c3a4e282ac79','y');}
} {4}
do_test instr-1.56 {
# EVIDENCE-OF: R-46421-32541 Or, if X and Y are both BLOBs, then
# instr(X,Y) returns one more than the number bytes prior to the first
# occurrence of Y, or 0 if Y does not occur anywhere within X.
#
do_test instr-1.56.1 {
db eval {SELECT instr(x'78c3a4e282ac79',x'79');}
} {7}
do_test instr-1.57 {
do_test instr-1.56.2 {
db eval {SELECT instr(x'78c3a4e282ac79',x'7a');}
} {0}
do_test instr-1.56.3 {
db eval {SELECT instr(x'78c3a4e282ac79',x'78');}
} {1}
do_test instr-1.56.3 {
db eval {SELECT instr(x'78c3a4e282ac79',x'a4');}
} {3}
# EVIDENCE-OF: R-17329-35644 If both arguments X and Y to instr(X,Y) are
# non-NULL and are not BLOBs then both are interpreted as strings.
#
do_test instr-1.57.1 {
db eval {SELECT instr('xä€y',x'79');}
} {4}
do_test instr-1.57.2 {
db eval {SELECT instr('xä€y',x'a4');}
} {0}
do_test instr-1.57.3 {
db eval {SELECT instr(x'78c3a4e282ac79','y');}
} {4}
# EVIDENCE-OF: R-14708-27487 If either X or Y are NULL in instr(X,Y)
# then the result is NULL.
#
do_execsql_test instr-1.60 {
SELECT coalesce(instr(NULL,'abc'), 999);
} {999}
do_execsql_test instr-1.61 {
SELECT coalesce(instr('abc',NULL), 999);
} {999}
do_execsql_test instr-1.62 {
SELECT coalesce(instr(NULL,NULL), 999);
} {999}
finish_test

View File

@ -289,6 +289,17 @@ test_suite "queryplanner" -prefix "" -description {
where.test
}
test_suite "vfslog" -prefix "" -description {
"Vfslog" quick test suite. Like "veryquick" except does not omits
a few tests that do not work with a version 1 VFS. And the quota* tests,
which do not work with a VFS that uses the pVfs argument passed to
sqlite3_vfs methods.
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* oserror.test \
pager1.test syscall.test sysfault.test tkt3457.test quota* superlock* \
wal* mmap*
]
lappend ::testsuitelist xxx
#-------------------------------------------------------------------------
# Define the coverage related test suites:

View File

@ -119,6 +119,11 @@ ifcapable attach {
# Default setting of PRAGMA cache_spill is always ON
#
# EVIDENCE-OF: R-51036-62828 PRAGMA cache_spill; PRAGMA
# cache_spill=boolean;
#
# EVIDENCE-OF: R-23955-02765 Cache_spill is enabled by default
#
db close
delete_file test.db test.db-journal
delete_file test2.db test2.db-journal
@ -155,6 +160,11 @@ do_execsql_test pragma2-4.3 {
PRAGMA cache_spill=ON;
} {}
sqlite3_release_memory
#
# EVIDENCE-OF: R-07634-40532 The cache_spill pragma enables or disables
# the ability of the pager to spill dirty cache pages to the database
# file in the middle of a transaction.
#
do_test pragma2-4.4 {
db eval {
BEGIN;

View File

@ -542,7 +542,7 @@ do_test select1-6.9.7 {
set x [execsql2 {
SELECT * FROM test1 a, (select 5, 6) LIMIT 1
}]
regsub -all {subquery_[0-9a-fA-F]+_} $x {subquery} x
regsub -all {sq_[0-9a-fA-F_]+} $x {subquery} x
set x
} {a.f1 11 a.f2 22 sqlite_subquery.5 5 sqlite_subquery.6 6}
do_test select1-6.9.8 {

View File

@ -13,6 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shared3
db close
ifcapable !shared_cache {
@ -103,5 +104,39 @@ db1 close
db2 close
db3 close
#-------------------------------------------------------------------------
# At one point this was causing a faulty assert to fail.
#
forcedelete test.db
sqlite3 db test.db
sqlite3 db2 test.db
do_execsql_test 3.1 {
PRAGMA auto_vacuum = 2;
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(randomblob(500), randomblob(500));
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1;
}
do_test 3.2 {
execsql { SELECT count(*) FROM sqlite_master } db2
} {1}
do_execsql_test 3.3 {
BEGIN;
DELETE FROM t1 WHERE 1;
PRAGMA incremental_vacuum;
} {}
do_test 3.4 {
execsql { SELECT count(*) FROM sqlite_master } db2
} {1}
do_test 3.5 {
execsql { COMMIT }
} {}
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test

View File

@ -23,6 +23,9 @@ do_test shared7-1.1 {
sqlite3_enable_shared_cache
} {1}
# EVIDENCE-OF: R-05098-06501 In shared cache mode, attempting to attach
# the same database file more than once results in an error.
#
do_test shared7-1.2 {
db close
sqlite3 db test.db

View File

@ -13,6 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sharedlock
db close
ifcapable !shared_cache {
@ -47,8 +48,35 @@ do_test sharedlock-1.2 {
set res
} {1 one 2 two 3 three}
#-------------------------------------------------------------------------
# Test that a write-lock is taken on a table when its entire contents
# are deleted using the OP_Clear optimization.
#
foreach {tn delete_sql} {
1 { DELETE FROM t2 WHERE 1 }
2 { DELETE FROM t2 }
} {
do_execsql_test 2.1 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(x, y);
INSERT INTO t2 VALUES(1, 2);
INSERT INTO t2 VALUES(3, 4);
}
do_test 2.2 { execsql { SELECT * FROM t2 } db2 } {1 2 3 4}
do_execsql_test 2.3 " BEGIN; $delete_sql; "
do_test 2.4 {
catchsql { SELECT * FROM t2 } db2
} {1 {database table is locked: t2}}
do_execsql_test 2.5 COMMIT
}
db close
db2 close
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test

View File

@ -95,6 +95,9 @@ do_test 1.10 {
do_execsql_test 1.11 {
SELECT next_char('re','vocab','w');
} {a}
do_execsql_test 1.11sub {
SELECT next_char('re','(SELECT w AS x FROM vocab)','x');
} {a}
do_execsql_test 1.12 {
SELECT next_char('r','vocab','w');
} {ae}

View File

@ -245,7 +245,7 @@ do_test subquery-2.5.3.2 {
EXPLAIN QUERY PLAN
SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
}
} {/SCAN TABLE t4 /}
} {~/t4i/}
do_test subquery-2.5.4 {
execsql {
DROP TABLE t3;

View File

@ -18,23 +18,23 @@ source $testdir/tester.tcl
do_test tkt-78e04-1.0 {
execsql {
CREATE TABLE ""("" UNIQUE);
CREATE TABLE ""("" UNIQUE, x CHAR(100));
CREATE TABLE t2(x);
INSERT INTO "" VALUES(1);
INSERT INTO ""("") VALUES(1);
INSERT INTO t2 VALUES(2);
SELECT * FROM "", t2;
}
} {1 2}
} {1 {} 2}
do_test tkt-78e04-1.1 {
catchsql {
INSERT INTO "" VALUES(1);
INSERT INTO ""("") VALUES(1);
}
} {1 {column is not unique}}
do_test tkt-78e04-1.2 {
execsql {
PRAGMA table_info("");
}
} {0 {} {} 0 {} 0}
} {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0}
do_test tkt-78e04-1.3 {
execsql {
CREATE INDEX i1 ON ""("" COLLATE nocase);
@ -42,7 +42,7 @@ do_test tkt-78e04-1.3 {
} {}
do_test tkt-78e04-1.4 {
execsql {
EXPLAIN QUERY PLAN SELECT * FROM "" WHERE "" LIKE 'abc%';
EXPLAIN QUERY PLAN SELECT "" FROM "" WHERE "" LIKE 'abc%';
}
} {0 0 0 {SCAN TABLE USING COVERING INDEX i1}}
do_test tkt-78e04-1.5 {

112
test/triggerE.test Normal file
View File

@ -0,0 +1,112 @@
# 2009 December 29
#
# The author disclaims copyright to this source code. In place of
# a legal notice', here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file tests the effects of SQL variable references embedded in
# triggers. If the user attempts to create such a trigger, it is an
# error. However, if an existing trigger definition is read from
# the sqlite_master table, the variable reference always evaluates
# to NULL.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
finish_test
return
}
set testprefix triggerE
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
CREATE TABLE t3(e, f);
}
# forcedelete test.db2
# do_execsql_test 1.1 {
# ATTACH 'test.db2' AS aux;
# CREATE TABLE aux.t4(x);
# INSERT INTO aux.t4 VALUES(5);
#
# CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.a IN (SELECT x FROM aux.t4)
# BEGIN
# SELECT 1;
# END;
# }
# do_execsql_test 1.2 { INSERT INTO t1 VALUES(1,1); }
# do_execsql_test 1.3 { INSERT INTO t1 VALUES(5,5); }
#-------------------------------------------------------------------------
# Attempt to create various triggers that use bound variables.
#
set errmsg "trigger cannot use variables"
foreach {tn defn} {
1 { AFTER INSERT ON t1 WHEN new.a = ? BEGIN SELECT 1; END; }
2 { BEFORE DELETE ON t1 BEGIN SELECT ?; END; }
3 { BEFORE DELETE ON t1 BEGIN SELECT * FROM (SELECT * FROM (SELECT ?)); END; }
5 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 GROUP BY ?; END; }
6 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 LIMIT ?; END; }
7 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 ORDER BY ?; END; }
8 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = ?; END; }
9 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = 1 WHERE d = ?; END; }
} {
catchsql {drop trigger tr1}
do_catchsql_test 1.1.$tn "CREATE TRIGGER tr1 $defn" [list 1 $errmsg]
do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg]
}
#-------------------------------------------------------------------------
# Test that variable references within trigger definitions loaded from
# the sqlite_master table are automatically converted to NULL.
#
do_execsql_test 2.1 {
PRAGMA writable_schema = 1;
INSERT INTO sqlite_master VALUES('trigger', 'tr1', 't1', 0,
'CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(?1, ?2);
END'
);
INSERT INTO sqlite_master VALUES('trigger', 'tr2', 't3', 0,
'CREATE TRIGGER tr2 AFTER INSERT ON t3 WHEN ?1 IS NULL BEGIN
UPDATE t2 SET c=d WHERE c IS ?2;
END'
);
}
db close
sqlite3 db test.db
do_execsql_test 2.2.1 {
INSERT INTO t1 VALUES(1, 2);
SELECT * FROM t2;
} {{} {}}
do_test 2.2.2 {
set one 3
execsql {
DELETE FROM t2;
INSERT INTO t1 VALUES($one, ?1);
SELECT * FROM t2;
}
} {{} {}}
do_execsql_test 2.2.3 { SELECT * FROM t1 } {1 2 3 3}
do_execsql_test 2.3 {
DELETE FROM t2;
INSERT INTO t2 VALUES('x', 'y');
INSERT INTO t2 VALUES(NULL, 'z');
INSERT INTO t3 VALUES(1, 2);
SELECT * FROM t3;
SELECT * FROM t2;
} {1 2 x y z z}
finish_test

View File

@ -1125,9 +1125,9 @@ do_test where-13.12 {
if {[permutation] != "no_optimization"} {
do_test where-14.1 {
execsql {
CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT UNIQUE);
INSERT INTO t8 VALUES(1,'one');
INSERT INTO t8 VALUES(4,'four');
CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT UNIQUE, c CHAR(100));
INSERT INTO t8(a,b) VALUES(1,'one');
INSERT INTO t8(a,b) VALUES(4,'four');
}
cksort {
SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.a, y.b

View File

@ -314,9 +314,9 @@ if {[permutation] != "no_optimization"} {
#
do_test where2-6.7 {
execsql {
CREATE TABLE t2249a(a TEXT UNIQUE);
CREATE TABLE t2249a(a TEXT UNIQUE, x CHAR(100));
CREATE TABLE t2249b(b INTEGER);
INSERT INTO t2249a VALUES('0123');
INSERT INTO t2249a(a) VALUES('0123');
INSERT INTO t2249b VALUES(123);
}
queryplan {
@ -324,7 +324,7 @@ do_test where2-6.7 {
-- will attempt to convert to NUMERIC before the comparison.
-- They will thus compare equal.
--
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
}
} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.9 {
@ -332,13 +332,13 @@ do_test where2-6.9 {
-- The + operator removes affinity from the rhs. No conversions
-- occur and the comparison is false. The result is an empty set.
--
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.9.2 {
# The same thing but with the expression flipped around.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.10 {
@ -346,32 +346,32 @@ do_test where2-6.10 {
-- Use + on both sides of the comparison to disable indices
-- completely. Make sure we get the same result.
--
SELECT * FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.11 {
# This will not attempt the OR optimization because of the a=b
# comparison.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
}
} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.11.2 {
# Permutations of the expression terms.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
}
} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.11.3 {
# Permutations of the expression terms.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
}
} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.11.4 {
# Permutations of the expression terms.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
}
} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
ifcapable explain&&subquery {
@ -385,7 +385,7 @@ ifcapable explain&&subquery {
# the OR optimization to be used again. The result is now an empty
# set, the same as in where2-6.9.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.12.2 {
@ -393,7 +393,7 @@ ifcapable explain&&subquery {
# the OR optimization to be used again. The result is now an empty
# set, the same as in where2-6.9.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.12.3 {
@ -401,14 +401,14 @@ ifcapable explain&&subquery {
# the OR optimization to be used again. The result is now an empty
# set, the same as in where2-6.9.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
do_test where2-6.13 {
# The addition of +a on the second term disabled the OR optimization.
# But we should still get the same empty-set result as in where2-6.9.
queryplan {
SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
}
} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
}
@ -417,7 +417,7 @@ ifcapable explain&&subquery {
# to make sure the OR optimizer can recognize them all.
do_test where2-6.20 {
queryplan {
SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a
SELECT x.a, y.a FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a
}
} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1}
ifcapable explain&&subquery {
@ -428,17 +428,20 @@ ifcapable explain&&subquery {
#
do_test where2-6.21 {
queryplan {
SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a OR y.a='hello'
SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y
WHERE x.a=y.a OR y.a='hello'
}
} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1}
do_test where2-6.22 {
queryplan {
SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a=x.a OR y.a='hello'
SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y
WHERE y.a=x.a OR y.a='hello'
}
} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1}
do_test where2-6.23 {
queryplan {
SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a='hello' OR x.a=y.a
SELECT x.a,y.a FROM t2249a x CROSS JOIN t2249a y
WHERE y.a='hello' OR x.a=y.a
}
} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1}
}
@ -703,7 +706,7 @@ do_test where2-11.4 {
# the OR clause scores slightly better on an inner loop.
if {[permutation] != "no_optimization"} {
do_execsql_test where2-12.1 {
CREATE TABLE t12(x INTEGER PRIMARY KEY, y);
CREATE TABLE t12(x INTEGER PRIMARY KEY, y INT, z CHAR(100));
CREATE INDEX t12y ON t12(y);
EXPLAIN QUERY PLAN
SELECT a.x, b.x

234
tool/fast_vacuum.c Normal file
View File

@ -0,0 +1,234 @@
/*
** 2013-10-01
**
** 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 program implements a high-speed version of the VACUUM command.
** It repacks an SQLite database to remove as much unused space as
** possible and to relocate content sequentially in the file.
**
** This program runs faster and uses less temporary disk space than the
** built-in VACUUM command. On the other hand, this program has a number
** of important restrictions relative to the built-in VACUUM command.
**
** (1) The caller must ensure that no other processes are accessing the
** database file while the vacuum is taking place. The usual SQLite
** file locking is insufficient for this. The caller must use
** external means to make sure only this one routine is reading and
** writing the database.
**
** (2) Database reconfiguration such as page size or auto_vacuum changes
** are not supported by this utility.
**
** (3) The database file might be renamed if a power loss or crash
** occurs at just the wrong moment. Recovery must be prepared to
** to deal with the possibly changed filename.
**
** This program is intended as a *Demonstration Only*. The intent of this
** program is to provide example code that application developers can use
** when creating similar functionality in their applications.
**
** To compile this program:
**
** cc fast_vacuum.c sqlite3.c
**
** Add whatever linker options are required. (Example: "-ldl -lpthread").
** Then to run the program:
**
** ./a.out file-to-vacuum
**
*/
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
/*
** Finalize a prepared statement. If an error has occurred, print the
** error message and exit.
*/
static void vacuumFinalize(sqlite3_stmt *pStmt){
sqlite3 *db = sqlite3_db_handle(pStmt);
int rc = sqlite3_finalize(pStmt);
if( rc ){
fprintf(stderr, "finalize error: %s\n", sqlite3_errmsg(db));
exit(1);
}
}
/*
** Execute zSql on database db. The SQL text is printed to standard
** output. If an error occurs, print an error message and exit the
** process.
*/
static void execSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt;
if( !zSql ){
fprintf(stderr, "out of memory!\n");
exit(1);
}
printf("%s;\n", zSql);
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
exit(1);
}
sqlite3_step(pStmt);
vacuumFinalize(pStmt);
}
/*
** Execute zSql on database db. The zSql statement returns exactly
** one column. Execute this return value as SQL on the same database.
**
** The zSql statement is printed on standard output prior to being
** run. If any errors occur, an error is printed and the process
** exits.
*/
static void execExecSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt;
int rc;
printf("%s;\n", zSql);
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
exit(1);
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
execSql(db, (char*)sqlite3_column_text(pStmt, 0));
}
vacuumFinalize(pStmt);
}
int main(int argc, char **argv){
sqlite3 *db; /* Connection to the database file */
int rc; /* Return code from SQLite interface calls */
sqlite3_uint64 r; /* A random number */
const char *zDbToVacuum; /* Database to be vacuumed */
char *zBackupDb; /* Backup copy of the original database */
char *zTempDb; /* Temporary database */
char *zSql; /* An SQL statement */
if( argc!=2 ){
fprintf(stderr, "Usage: %s DATABASE\n", argv[0]);
return 1;
}
/* Identify the database file to be vacuumed and open it.
*/
zDbToVacuum = argv[1];
printf("-- open database file \"%s\"\n", zDbToVacuum);
rc = sqlite3_open(zDbToVacuum, &db);
if( rc ){
fprintf(stderr, "%s: %s\n", zDbToVacuum, sqlite3_errstr(rc));
return 1;
}
/* Create names for two other files. zTempDb will be a new database
** into which we construct a vacuumed copy of zDbToVacuum. zBackupDb
** will be a new name for zDbToVacuum after it is vacuumed.
*/
sqlite3_randomness(sizeof(r), &r);
zTempDb = sqlite3_mprintf("%s-vacuum-%016llx", zDbToVacuum, r);
zBackupDb = sqlite3_mprintf("%s-backup-%016llx", zDbToVacuum, r);
/* Attach the zTempDb database to the database connection.
*/
zSql = sqlite3_mprintf("ATTACH '%q' AS vacuum_db;", zTempDb);
execSql(db, zSql);
sqlite3_free(zSql);
/* TODO:
** Set the page_size and auto_vacuum mode for zTempDb here, if desired.
*/
/* The vacuum will occur inside of a transaction. Set writable_schema
** to ON so that we can directly update the sqlite_master table in the
** zTempDb database.
*/
execSql(db, "PRAGMA writable_schema=ON");
execSql(db, "BEGIN");
/* Query the schema of the main database. Create a mirror schema
** in the temporary database.
*/
execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0"
);
execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %'"
);
execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
);
/* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
** the contents to the temporary database.
*/
execExecSql(db,
"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"
);
/* Copy over the sequence table
*/
execExecSql(db,
"SELECT 'DELETE FROM vacuum_db.' || quote(name) "
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence'"
);
execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) "
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence'"
);
/* Copy the triggers, views, and virtual tables from the main database
** over to the temporary database. None of these objects has any
** associated storage, so all we have to do is copy their entries
** from the SQLITE_MASTER table.
*/
execSql(db,
"INSERT INTO vacuum_db.sqlite_master "
" SELECT type, name, tbl_name, rootpage, sql"
" FROM main.sqlite_master"
" WHERE type='view' OR type='trigger'"
" OR (type='table' AND rootpage=0)"
);
/* Commit the transaction and close the database
*/
execSql(db, "COMMIT");
printf("-- close database\n");
sqlite3_close(db);
/* At this point, zDbToVacuum is unchanged. zTempDb contains a
** vacuumed copy of zDbToVacuum. Rearrange filenames so that
** zTempDb becomes thenew zDbToVacuum.
*/
printf("-- rename \"%s\" to \"%s\"\n", zDbToVacuum, zBackupDb);
rename(zDbToVacuum, zBackupDb);
printf("-- rename \"%s\" to \"%s\"\n", zTempDb, zDbToVacuum);
rename(zTempDb, zDbToVacuum);
/* Release allocated memory */
sqlite3_free(zTempDb);
sqlite3_free(zBackupDb);
return 0;
}

View File

@ -3391,7 +3391,7 @@ void print_stack_union(
int maxdtlength; /* Maximum length of any ".datatype" field. */
char *stddt; /* Standardized name for a datatype */
int i,j; /* Loop counters */
int hash; /* For hashing the name of a type */
unsigned hash; /* For hashing the name of a type */
const char *name; /* Name of the parser */
/* Allocate and initialize types[] and allocate stddt[] */
@ -3458,7 +3458,7 @@ void print_stack_union(
break;
}
hash++;
if( hash>=arraysize ) hash = 0;
if( hash>=(unsigned)arraysize ) hash = 0;
}
if( types[hash]==0 ){
sp->dtnum = hash + 1;
@ -4234,10 +4234,10 @@ int SetUnion(char *s1, char *s2)
** Code for processing tables in the LEMON parser generator.
*/
PRIVATE int strhash(const char *x)
PRIVATE unsigned strhash(const char *x)
{
int h = 0;
while( *x) h = h*13 + *(x++);
unsigned h = 0;
while( *x ) h = h*13 + *(x++);
return h;
}
@ -4309,8 +4309,8 @@ void Strsafe_init(){
int Strsafe_insert(const char *data)
{
x1node *np;
int h;
int ph;
unsigned h;
unsigned ph;
if( x1a==0 ) return 0;
ph = strhash(data);
@ -4364,7 +4364,7 @@ int Strsafe_insert(const char *data)
** if no such key. */
const char *Strsafe_find(const char *key)
{
int h;
unsigned h;
x1node *np;
if( x1a==0 ) return 0;
@ -4475,8 +4475,8 @@ void Symbol_init(){
int Symbol_insert(struct symbol *data, const char *key)
{
x2node *np;
int h;
int ph;
unsigned h;
unsigned ph;
if( x2a==0 ) return 0;
ph = strhash(key);
@ -4532,7 +4532,7 @@ int Symbol_insert(struct symbol *data, const char *key)
** if no such key. */
struct symbol *Symbol_find(const char *key)
{
int h;
unsigned h;
x2node *np;
if( x2a==0 ) return 0;
@ -4606,9 +4606,9 @@ PRIVATE int statecmp(struct config *a, struct config *b)
}
/* Hash a state */
PRIVATE int statehash(struct config *a)
PRIVATE unsigned statehash(struct config *a)
{
int h=0;
unsigned h=0;
while( a ){
h = h*571 + a->rp->index*37 + a->dot;
a = a->bp;
@ -4674,8 +4674,8 @@ void State_init(){
int State_insert(struct state *data, struct config *key)
{
x3node *np;
int h;
int ph;
unsigned h;
unsigned ph;
if( x3a==0 ) return 0;
ph = statehash(key);
@ -4731,7 +4731,7 @@ int State_insert(struct state *data, struct config *key)
** if no such key. */
struct state *State_find(struct config *key)
{
int h;
unsigned h;
x3node *np;
if( x3a==0 ) return 0;
@ -4761,9 +4761,9 @@ struct state **State_arrayof()
}
/* Hash a configuration */
PRIVATE int confighash(struct config *a)
PRIVATE unsigned confighash(struct config *a)
{
int h=0;
unsigned h=0;
h = h*571 + a->rp->index*37 + a->dot;
return h;
}
@ -4816,8 +4816,8 @@ void Configtable_init(){
int Configtable_insert(struct config *data)
{
x4node *np;
int h;
int ph;
unsigned h;
unsigned ph;
if( x4a==0 ) return 0;
ph = confighash(data);

View File

@ -10,39 +10,42 @@
**
*************************************************************************
** This file contains a simple command-line utility for converting from
** integers and WhereCost values and back again and for doing simple
** arithmetic operations (multiple and add) on WhereCost values.
** integers and LogEst values and back again and for doing simple
** arithmetic operations (multiple and add) on LogEst values.
**
** Usage:
**
** ./wherecosttest ARGS
** ./LogEst ARGS
**
** Arguments:
**
** 'x' Multiple the top two elements of the stack
** '+' Add the top two elements of the stack
** NUM Convert NUM from integer to WhereCost and push onto the stack
** ^NUM Interpret NUM as a WhereCost and push onto stack.
** NUM Convert NUM from integer to LogEst and push onto the stack
** ^NUM Interpret NUM as a LogEst and push onto stack.
**
** Examples:
**
** To convert 123 from WhereCost to integer:
** To convert 123 from LogEst to integer:
**
** ./wherecosttest ^123
** ./LogEst ^123
**
** To convert 123456 from integer to WhereCost:
** To convert 123456 from integer to LogEst:
**
** ./wherecosttest 123456
** ./LogEst 123456
**
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include "sqlite3.h"
typedef unsigned short int WhereCost; /* 10 times log2() */
typedef short int LogEst; /* 10 times log2() */
WhereCost whereCostMultiply(WhereCost a, WhereCost b){ return a+b; }
WhereCost whereCostAdd(WhereCost a, WhereCost b){
LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; }
LogEst logEstAdd(LogEst a, LogEst b){
static const unsigned char x[] = {
10, 10, /* 0,1 */
9, 9, /* 2,3 */
@ -54,14 +57,14 @@ WhereCost whereCostAdd(WhereCost a, WhereCost b){
3, 3, 3, 3, 3, 3, /* 19-24 */
2, 2, 2, 2, 2, 2, 2, /* 25-31 */
};
if( a<b ){ WhereCost t = a; a = b; b = t; }
if( a<b ){ LogEst t = a; a = b; b = t; }
if( a>b+49 ) return a;
if( a>b+31 ) return a+1;
return a+x[a-b];
}
WhereCost whereCostFromInteger(int x){
static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
WhereCost y = 40;
LogEst logEstFromInteger(sqlite3_uint64 x){
static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
LogEst y = 40;
if( x<8 ){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
@ -71,8 +74,8 @@ WhereCost whereCostFromInteger(int x){
}
return a[x&7] + y - 10;
}
static unsigned long int whereCostToInt(WhereCost x){
unsigned long int n;
static sqlite3_uint64 logEstToInt(LogEst x){
sqlite3_uint64 n;
if( x<10 ) return 1;
n = x%10;
x /= 10;
@ -81,31 +84,58 @@ static unsigned long int whereCostToInt(WhereCost x){
if( x>=3 ) return (n+8)<<(x-3);
return (n+8)>>(3-x);
}
static LogEst logEstFromDouble(double x){
sqlite3_uint64 a;
LogEst e;
assert( sizeof(x)==8 && sizeof(a)==8 );
if( x<=0.0 ) return -32768;
if( x<1.0 ) return -logEstFromDouble(1/x);
if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
memcpy(&a, &x, 8);
e = (a>>52) - 1022;
return e*10;
}
int isFloat(const char *z){
while( z[0] ){
if( z[0]=='.' || z[0]=='E' || z[0]=='e' ) return 1;
z++;
}
return 0;
}
int main(int argc, char **argv){
int i;
int n = 0;
WhereCost a[100];
LogEst a[100];
for(i=1; i<argc; i++){
const char *z = argv[i];
if( z[0]=='+' ){
if( n>=2 ){
a[n-2] = whereCostAdd(a[n-2],a[n-1]);
a[n-2] = logEstAdd(a[n-2],a[n-1]);
n--;
}
}else if( z[0]=='x' ){
if( n>=2 ){
a[n-2] = whereCostMultiply(a[n-2],a[n-1]);
a[n-2] = logEstMultiply(a[n-2],a[n-1]);
n--;
}
}else if( z[0]=='^' ){
a[n++] = atoi(z+1);
}else if( isFloat(z) ){
a[n++] = logEstFromDouble(atof(z));
}else{
a[n++] = whereCostFromInteger(atoi(z));
a[n++] = logEstFromInteger(atoi(z));
}
}
for(i=n-1; i>=0; i--){
printf("%d (%lu)\n", a[i], whereCostToInt(a[i]));
if( a[i]<0 ){
printf("%d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
}else{
sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
printf("%d (%lld.%02lld)\n", a[i], x/100, x%100);
}
}
return 0;
}

View File

@ -109,6 +109,7 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
NAME: default_cache_size
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
NAME: page_size
@ -118,31 +119,37 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: page_count
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: max_page_count
TYPE: PAGE_COUNT
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: locking_mode
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: journal_mode
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: journal_size_limit
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: cache_size
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: mmap_size
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: auto_vacuum
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
NAME: incremental_vacuum
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
NAME: temp_store
@ -158,27 +165,38 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
NAME: synchronous
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
NAME: table_info
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: stats
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: index_info
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: index_list
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: database_list
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: collation_list
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: foreign_key_list
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
NAME: foreign_key_check
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
NAME: parser_trace
@ -187,10 +205,12 @@ set pragma_def {
NAME: case_sensitive_like
NAME: integrity_check
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK)
NAME: quick_check
TYPE: INTEGRITY_CHECK
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK)
NAME: encoding
@ -216,6 +236,7 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
NAME: wal_checkpoint
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_WAL)
NAME: wal_autocheckpoint
@ -237,6 +258,10 @@ set pragma_def {
NAME: hexkey
IF: defined(SQLITE_HAS_CODEC)
NAME: hexrekey
TYPE: HEXKEY
IF: defined(SQLITE_HAS_CODEC)
NAME: activate_extensions
IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
@ -245,14 +270,16 @@ set pragma_def {
set name {}
set type {}
set if {}
set flags {}
set arg 0
proc record_one {} {
global name type if arg allbyname typebyif
global name type if arg allbyname typebyif flags
if {$name==""} return
set allbyname($name) [list $type $arg $if]
set allbyname($name) [list $type $arg $if $flags]
set name {}
set type {}
set if {}
set flags {}
set arg 0
}
foreach line [split $pragma_def \n] {
@ -270,6 +297,11 @@ foreach line [split $pragma_def \n] {
set arg $val
} elseif {$id=="IF"} {
set if $val
} elseif {$id=="FLAG"} {
foreach term [split $val] {
lappend flags $term
set allflags($term) 1
}
} else {
error "bad pragma_def line: $line"
}
@ -308,30 +340,42 @@ foreach name $allnames {
incr pnum
}
# Generate #defines for flags
#
set fv 1
foreach f [lsort [array names allflags]] {
puts [format {#define PragFlag_%-20s 0x%02x} $f $fv]
set fv [expr {$fv*2}]
}
# Generate the lookup table
#
puts "static const struct sPragmaNames \173"
puts " const char *const zName; /* Name of pragma */"
puts " u8 ePragTyp; /* PragTyp_XXX value */"
puts " u8 mPragFlag; /* Zero or more PragFlag_XXX values */"
puts " u32 iArg; /* Extra argument */"
puts "\175 aPragmaNames\[\] = \173"
set current_if {}
set spacer [format { %26s } {}]
foreach name $allnames {
foreach {type arg if} $allbyname($name) break
foreach {type arg if flag} $allbyname($name) break
if {$if!=$current_if} {
if {$current_if!=""} {puts "#endif"}
set current_if $if
if {$current_if!=""} {puts "#if $current_if"}
}
set namex [format %-26s \"$name\",]
set typex [format PragTyp_%-23s $type,]
if {[string length $arg]>10} {
puts " \173 $namex $typex\n$spacer$arg \175,"
if {$flag==""} {
set flagx "0"
} else {
puts " \173 $namex $typex $arg \175,"
set flagx PragFlag_[join $flag {|PragFlag_}]
}
puts " \173 /* zName: */ \"$name\","
puts " /* ePragTyp: */ PragTyp_$type,"
puts " /* ePragFlag: */ $flagx,"
puts " /* iArg: */ $arg \175,"
}
if {$current_if!=""} {puts "#endif"}
puts "\175;"

View File

@ -120,6 +120,7 @@ foreach hdr {
set available_hdr($hdr) 1
}
set available_hdr(sqliteInt.h) 0
set available_hdr(sqlite3.h) 0
# 78 stars used for comment formatting.
set s78 \
@ -227,6 +228,7 @@ proc copy_file {filename} {
# inlining opportunities.
#
foreach file {
sqlite3.h
sqliteInt.h
global.c

View File

@ -279,8 +279,18 @@ if {[string equal -nocase $packageFlavor WinRT]} then {
set minVsVersion 11.0
set extraSdkPath "\\..\\$targetPlatformIdentifier"
set extraFileListAttributes ""
} elseif {[string equal -nocase $packageFlavor Win32]} then {
set shortName SQLite.Win32
set displayName "SQLite for Windows"
set targetPlatformIdentifier Windows
set targetPlatformVersion v8.0
set minVsVersion 11.0
set extraSdkPath ""
set extraFileListAttributes [appendArgs \
"\r\n " {AppliesTo="VisualC"} \
"\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}]
} else {
fail "unsupported package flavor, must be \"WinRT\", \"WinRT81\", or \"WP80\""
fail "unsupported package flavor, must be one of: WinRT WinRT81 WP80 Win32"
}
if {$argc >= 4} then {

92
tool/pagesig.c Normal file
View File

@ -0,0 +1,92 @@
/*
** 2013-10-01
**
** 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.
**
******************************************************************************
**
** Compute hash signatures for every page of a database file. This utility
** program is useful for analyzing the output logs generated by the
** ext/misc/vfslog.c extension.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
/*
** Compute signature for a block of content.
**
** For blocks of 16 or fewer bytes, the signature is just a hex dump of
** the entire block.
**
** For blocks of more than 16 bytes, the signature is a hex dump of the
** first 8 bytes followed by a 64-bit has of the entire block.
*/
static void vlogSignature(unsigned char *p, int n, char *zCksum){
unsigned int s0 = 0, s1 = 0;
unsigned int *pI;
int i;
if( n<=16 ){
for(i=0; i<n; i++) sprintf(zCksum+i*2, "%02x", p[i]);
}else{
pI = (unsigned int*)p;
for(i=0; i<n-7; i+=8){
s0 += pI[0] + s1;
s1 += pI[1] + s0;
pI += 2;
}
for(i=0; i<8; i++) sprintf(zCksum+i*2, "%02x", p[i]);
sprintf(zCksum+i*2, "-%08x%08x", s0, s1);
}
}
/*
** Open a file. Find its page size. Read each page, and compute and
** display the page signature.
*/
static void computeSigs(const char *zFilename){
FILE *in = fopen(zFilename, "rb");
unsigned pgsz;
size_t got;
unsigned n;
unsigned char aBuf[50];
unsigned char aPage[65536];
if( in==0 ){
fprintf(stderr, "cannot open \"%s\"\n", zFilename);
return;
}
got = fread(aBuf, 1, sizeof(aBuf), in);
if( got!=sizeof(aBuf) ){
goto endComputeSigs;
}
pgsz = aBuf[16]*256 + aBuf[17];
if( pgsz==1 ) pgsz = 65536;
if( (pgsz & (pgsz-1))!=0 ){
fprintf(stderr, "invalid page size: %02x%02x\n", aBuf[16], aBuf[17]);
goto endComputeSigs;
}
rewind(in);
for(n=1; (got=fread(aPage, 1, pgsz, in))==pgsz; n++){
vlogSignature(aPage, pgsz, aBuf);
printf("%4d: %s\n", n, aBuf);
}
endComputeSigs:
fclose(in);
}
/*
** Find page signatures for all named files.
*/
int main(int argc, char **argv){
int i;
for(i=1; i<argc; i++) computeSigs(argv[i]);
return 0;
}

View File

@ -199,15 +199,17 @@ foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
# is.
#
set gap_cnt 0
set pglist [db eval {
SELECT pageno FROM temp.dbstat WHERE name = $name ORDER BY rowid
}]
set prev [lindex $pglist 0]
foreach pgno [lrange $pglist 1 end] {
if {$pgno != $prev+1} {incr gap_cnt}
set prev $pgno
set prev 0
db eval {
SELECT pageno, pagetype FROM temp.dbstat
WHERE name=$name
ORDER BY pageno
} {
if {$prev>0 && $pagetype=="leaf" && $pageno!=$prev+1} {
incr gap_cnt
}
set prev $pageno
}
mem eval {
INSERT INTO space_used VALUES(
$name,
@ -298,7 +300,7 @@ proc divide {num denom} {
# Generate a subreport that covers some subset of the database.
# the $where clause determines which subset to analyze.
#
proc subreport {title where} {
proc subreport {title where showFrag} {
global pageSize file_pgcnt compressOverhead
# Query the in-memory database for the sum of various statistics
@ -384,9 +386,9 @@ proc subreport {title where} {
if {[info exists avg_fanout]} {
statline {Average fanout} $avg_fanout
}
if {$total_pages>1} {
set fragmentation [percent $gap_cnt [expr {$total_pages-1}] {fragmentation}]
statline {Fragmentation} $fragmentation
if {$showFrag && $total_pages>1} {
set fragmentation [percent $gap_cnt [expr {$total_pages-1}]]
statline {Non-sequential pages} $gap_cnt $fragmentation
}
statline {Maximum payload per entry} $mx_payload
statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent
@ -509,8 +511,8 @@ statline {Pages on the freelist (calculated)} $free_pgcnt $free_percent
statline {Pages of auto-vacuum overhead} $av_pgcnt $av_percent
statline {Number of tables in the database} $ntable
statline {Number of indices} $nindex
statline {Number of named indices} $nmanindex
statline {Automatically generated indices} $nautoindex
statline {Number of defined indices} $nmanindex
statline {Number of implied indices} $nautoindex
if {$isCompressed} {
statline {Size of uncompressed content in bytes} $file_bytes
set efficiency [percent $true_file_size $file_bytes]
@ -563,11 +565,11 @@ if {$isCompressed} {
# Output subreports
#
if {$nindex>0} {
subreport {All tables and indices} 1
subreport {All tables and indices} 1 0
}
subreport {All tables} {NOT is_index}
subreport {All tables} {NOT is_index} 0
if {$nindex>0} {
subreport {All indices} {is_index}
subreport {All indices} {is_index} 0
}
foreach tbl [mem eval {SELECT name FROM space_used WHERE NOT is_index
ORDER BY name}] {
@ -578,17 +580,17 @@ foreach tbl [mem eval {SELECT name FROM space_used WHERE NOT is_index
set idxlist [mem eval "SELECT name FROM space_used
WHERE tblname='$qn' AND is_index
ORDER BY 1"]
subreport "Table $name and all its indices" "tblname='$qn'"
subreport "Table $name w/o any indices" "name='$qn'"
subreport "Table $name and all its indices" "tblname='$qn'" 0
subreport "Table $name w/o any indices" "name='$qn'" 1
if {[llength $idxlist]>1} {
subreport "Indices of table $name" "tblname='$qn' AND is_index"
subreport "Indices of table $name" "tblname='$qn' AND is_index" 0
}
foreach idx $idxlist {
set qidx [quote $idx]
subreport "Index [string toupper $idx] of table $name" "name='$qidx'"
subreport "Index [string toupper $idx] of table $name" "name='$qidx'" 1
}
} else {
subreport "Table $name" "name='$qn'"
subreport "Table $name" "name='$qn'" 1
}
}
@ -633,11 +635,11 @@ Number of indices
The total number of indices in the database.
Number of named indices
Number of defined indices
The number of indices created using an explicit CREATE INDEX statement.
Automatically generated indices
Number of implied indices
The number of indices used to implement PRIMARY KEY or UNIQUE constraints
on tables.
@ -686,13 +688,16 @@ Average unused bytes per entry
category on a per-entry basis. This is the number of unused bytes on
all pages divided by the number of entries.
Fragmentation
Non-sequential pages
The percentage of pages in the table or index that are not
consecutive in the disk file. Many filesystems are optimized
for sequential file access so smaller fragmentation numbers
sometimes result in faster queries, especially for larger
database files that do not fit in the disk cache.
The number of pages in the table or index that are out of sequence.
Many filesystems are optimized for sequential file access so a small
number of non-sequential pages might result in faster queries,
especially for larger database files that do not fit in the disk cache.
Note that after running VACUUM, the root page of each table or index is
at the beginning of the database file and all other pages are in a
separate part of the database file, resulting in a single non-
sequential page.
Maximum payload per entry

View File

@ -9,9 +9,9 @@ echo '********** No optimizations. Includes FTS4 and RTREE *********'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
sqlite3.c
echo '********** No optimizations. ENABLE_STAT3. THREADSAFE=0 *******'
echo '********** No optimizations. ENABLE_STAT4. THREADSAFE=0 *******'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
-ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \
sqlite3.c
echo '********** Optimized -O3. Includes FTS4 and RTREE ************'
gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \