Merge updates from trunk.
FossilOrigin-Name: a88b5be01e68b26267ff6eb05e931ef2e7fc9f99
This commit is contained in:
commit
d5570119b7
@ -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" \
|
||||
|
28
Makefile.msc
28
Makefile.msc
@ -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
|
||||
|
525
ext/fts3/fts3.c
525
ext/fts3/fts3.c
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
706
ext/misc/vfslog.c
Normal 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
10
main.mk
@ -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
147
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
435ce3b3fc0cffb4d7e6f2694c3100066e19f9ed
|
||||
a88b5be01e68b26267ff6eb05e931ef2e7fc9f99
|
@ -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;
|
||||
|
46
src/attach.c
46
src/attach.c
@ -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;
|
||||
|
@ -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 ){
|
||||
|
@ -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).
|
||||
**
|
||||
|
99
src/build.c
99
src/build.c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
|
19
src/fkey.c
19
src/fkey.c
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 },
|
||||
|
559
src/pragma.c
559
src/pragma.c
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
117
src/select.c
117
src/select.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
*/
|
||||
|
@ -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*);
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
77
src/util.c
77
src/util.c
@ -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);
|
||||
}
|
||||
|
32
src/vacuum.c
32
src/vacuum.c
@ -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);
|
||||
|
@ -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);
|
||||
|
281
src/where.c
281
src/where.c
@ -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
117
test/amatch1.test
Normal 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
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
84
test/fts3defer3.test
Normal 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
|
@ -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
|
||||
|
1552
test/fts4aa.test
1552
test/fts4aa.test
File diff suppressed because it is too large
Load Diff
116
test/fts4docid.test
Normal file
116
test/fts4docid.test
Normal 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
53
test/fts4incr.test
Normal 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
|
@ -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}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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
1560
test/genesis.tcl
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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;
|
||||
|
@ -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
112
test/triggerE.test
Normal 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
234
tool/fast_vacuum.c
Normal 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;
|
||||
}
|
40
tool/lemon.c
40
tool/lemon.c
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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;"
|
||||
|
@ -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
|
||||
|
@ -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
92
tool/pagesig.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user