Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c216566ba5 | |||
| a4bbc8b119 | |||
| cfe111b1f7 | |||
| a703f50d7e | |||
| a2617433a9 | |||
| bc863b50ba | |||
| 0593516fcc | |||
| 5f8cdac620 | |||
| 362d21614e | |||
| 4398c9524f | |||
| 67896cef89 | |||
| 71d5338c5d | |||
| 0ae4f14e45 | |||
| a7f4bf3f88 | |||
| c0f1d0c697 | |||
| d5570119b7 | |||
| 3ef261567a | |||
| 5e87830fa3 | |||
| a8dbadacee | |||
| 5dbb7cc24f | |||
| b084582299 | |||
| 0ed02a6dcb | |||
| 549bc3db1f | |||
| cf9fca4629 | |||
| 0aedc6be45 | |||
| 7651091de5 | |||
| 2b51f2153b | |||
| 691d4c9936 | |||
| cbc53fec75 | |||
| e4bf4f08c0 | |||
| 3432daa8b2 | |||
| 4f99189051 | |||
| 80e0b72e8d | |||
| e71e0603c5 | |||
| 7e65c94bdc | |||
| a0cbd3fd17 | |||
| 919e3b3908 | |||
| 7cd84ffc60 | |||
| 30e2f0ae08 | |||
| 3d8b2395b3 | |||
| 26586e77d9 | |||
| 1f1fc0c24d | |||
| 833d198fb1 | |||
| b50596d64d | |||
| 5f3e5e747d | |||
| 186ad8cc32 | |||
| 86f72f0721 | |||
| 3495d20dbe | |||
| bbff218016 | |||
| 9a5cbbc4a5 | |||
| 0157e01cc8 | |||
| 9a5b271908 | |||
| aeddf19e60 | |||
| 1c215c9fd4 | |||
| 05b1ba1e3f | |||
| a17713ff8d | |||
| 09dee52885 | |||
| 5db4f78ef5 | |||
| 60883e5401 | |||
| 312404ef76 | |||
| 98ab33a82f | |||
| db1c12b79f | |||
| 36df58e45f | |||
| 5805eedb87 | |||
| 749ced9923 | |||
| cf02d7cf0b | |||
| 626c25846c | |||
| 0057a74675 | |||
| f5fe3ae9e6 | |||
| 1654256ac8 | |||
| f13394c0ad | |||
| 46d269bc14 | |||
| bc3ec28b88 | |||
| ee1c64ed25 | |||
| 32be00a55b | |||
| 69f3d04810 |
+3
-2
@@ -396,6 +396,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/spellfix.c \
|
||||
$(TOP)/ext/misc/totype.c \
|
||||
$(TOP)/ext/misc/wholenumber.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
@@ -500,11 +501,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" \
|
||||
|
||||
+45
-7
@@ -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
|
||||
@@ -25,6 +32,13 @@ USE_ICU = 0
|
||||
USE_CRT_DLL = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to generate assembly code listings for the source code
|
||||
# files.
|
||||
#
|
||||
!IFNDEF USE_LISTINGS
|
||||
USE_LISTINGS = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to attempt setting the native compiler automatically
|
||||
# for cross-compiling the command line tools needed during the compilation
|
||||
# process.
|
||||
@@ -181,6 +195,13 @@ NSDKLIBPATH = $(NSDKLIBPATH:\\=\)
|
||||
#
|
||||
BCC = $(NCC) -W3
|
||||
|
||||
# Check if assembly code listings should be generated for the source
|
||||
# code files to be compiled.
|
||||
#
|
||||
!IF $(USE_LISTINGS)!=0
|
||||
BCC = $(BCC) -FAcs
|
||||
!ENDIF
|
||||
|
||||
# Check if the native library paths should be used when compiling
|
||||
# the command line tools used during the compilation process. If
|
||||
# so, set the necessary macro now.
|
||||
@@ -196,6 +217,13 @@ NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)"
|
||||
TCC = $(CC) -W3 -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src -fp:precise
|
||||
RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src
|
||||
|
||||
# Check if assembly code listings should be generated for the source
|
||||
# code files to be compiled.
|
||||
#
|
||||
!IF $(USE_LISTINGS)!=0
|
||||
TCC = $(TCC) -FAcs
|
||||
!ENDIF
|
||||
|
||||
# When compiling the library for use in the WinRT environment,
|
||||
# the following compile-time options must be used as well to
|
||||
# disable use of Win32 APIs that are not available and to enable
|
||||
@@ -754,6 +782,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\spellfix.c \
|
||||
$(TOP)\ext\misc\totype.c \
|
||||
$(TOP)\ext\misc\wholenumber.c
|
||||
|
||||
|
||||
@@ -892,10 +921,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
|
||||
#
|
||||
@@ -1255,7 +1293,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
|
||||
@@ -1283,8 +1321,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 >> $@
|
||||
@@ -1296,7 +1334,7 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
|
||||
clean:
|
||||
del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib
|
||||
del /Q *.da *.bb *.bbg gmon.out
|
||||
del /Q *.cod *.da *.bb *.bbg gmon.out
|
||||
del /Q sqlite3.h opcodes.c opcodes.h
|
||||
del /Q lemon.exe lempar.c parse.*
|
||||
del /Q mkkeywordhash.exe keywordhash.h
|
||||
@@ -1310,7 +1348,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
|
||||
|
||||
+4
-4
@@ -3036,7 +3036,7 @@ static int fts3FilterMethod(
|
||||
){
|
||||
int rc;
|
||||
char *zSql; /* SQL statement used to access %_content */
|
||||
int eSearch;;
|
||||
int eSearch;
|
||||
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
|
||||
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
|
||||
|
||||
@@ -4327,11 +4327,11 @@ static int fts3EvalIncrPhraseNext(
|
||||
|
||||
while( bEof==0 ){
|
||||
int bMaxSet = 0;
|
||||
sqlite3_int64 iMax; /* Largest docid for all iterators */
|
||||
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++){
|
||||
for(i=0; rc==SQLITE_OK && i<p->nToken && bEof==0; 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;
|
||||
@@ -4370,7 +4370,7 @@ static int fts3EvalIncrPhraseNext(
|
||||
int nDist = p->nToken-1-i;
|
||||
int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR);
|
||||
if( res==0 ) break;
|
||||
nList = (pOut - aDoclist);
|
||||
nList = (int)(pOut - aDoclist);
|
||||
}
|
||||
}
|
||||
if( i==(p->nToken-1) ){
|
||||
|
||||
+96
-33
@@ -31,6 +31,7 @@ struct Fts3auxCursor {
|
||||
Fts3SegFilter filter;
|
||||
char *zStop;
|
||||
int nStop; /* Byte-length of string zStop */
|
||||
int iLangid; /* Language id to query */
|
||||
int isEof; /* True if cursor is at EOF */
|
||||
sqlite3_int64 iRowid; /* Current rowid */
|
||||
|
||||
@@ -45,7 +46,8 @@ struct Fts3auxCursor {
|
||||
/*
|
||||
** Schema of the terms table.
|
||||
*/
|
||||
#define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, col, documents, occurrences)"
|
||||
#define FTS3_AUX_SCHEMA \
|
||||
"CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)"
|
||||
|
||||
/*
|
||||
** This function does all the work for both the xConnect and xCreate methods.
|
||||
@@ -92,7 +94,7 @@ static int fts3auxConnectMethod(
|
||||
}
|
||||
nFts3 = (int)strlen(zFts3);
|
||||
|
||||
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
|
||||
rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
|
||||
@@ -152,6 +154,8 @@ static int fts3auxBestIndexMethod(
|
||||
int iEq = -1;
|
||||
int iGe = -1;
|
||||
int iLe = -1;
|
||||
int iLangid = -1;
|
||||
int iNext = 1; /* Next free argvIndex value */
|
||||
|
||||
UNUSED_PARAMETER(pVTab);
|
||||
|
||||
@@ -163,36 +167,48 @@ static int fts3auxBestIndexMethod(
|
||||
pInfo->orderByConsumed = 1;
|
||||
}
|
||||
|
||||
/* Search for equality and range constraints on the "term" column. */
|
||||
/* Search for equality and range constraints on the "term" column.
|
||||
** And equality constraints on the hidden "languageid" column. */
|
||||
for(i=0; i<pInfo->nConstraint; i++){
|
||||
if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 ){
|
||||
if( pInfo->aConstraint[i].usable ){
|
||||
int op = pInfo->aConstraint[i].op;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i;
|
||||
int iCol = pInfo->aConstraint[i].iColumn;
|
||||
|
||||
if( iCol==0 ){
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i;
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i;
|
||||
}
|
||||
if( iCol==4 ){
|
||||
if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( iEq>=0 ){
|
||||
pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT;
|
||||
pInfo->aConstraintUsage[iEq].argvIndex = 1;
|
||||
pInfo->aConstraintUsage[iEq].argvIndex = iNext++;
|
||||
pInfo->estimatedCost = 5;
|
||||
}else{
|
||||
pInfo->idxNum = 0;
|
||||
pInfo->estimatedCost = 20000;
|
||||
if( iGe>=0 ){
|
||||
pInfo->idxNum += FTS4AUX_GE_CONSTRAINT;
|
||||
pInfo->aConstraintUsage[iGe].argvIndex = 1;
|
||||
pInfo->aConstraintUsage[iGe].argvIndex = iNext++;
|
||||
pInfo->estimatedCost /= 2;
|
||||
}
|
||||
if( iLe>=0 ){
|
||||
pInfo->idxNum += FTS4AUX_LE_CONSTRAINT;
|
||||
pInfo->aConstraintUsage[iLe].argvIndex = 1 + (iGe>=0);
|
||||
pInfo->aConstraintUsage[iLe].argvIndex = iNext++;
|
||||
pInfo->estimatedCost /= 2;
|
||||
}
|
||||
}
|
||||
if( iLangid>=0 ){
|
||||
pInfo->aConstraintUsage[iLangid].argvIndex = iNext++;
|
||||
pInfo->estimatedCost--;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -352,7 +368,14 @@ static int fts3auxFilterMethod(
|
||||
Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
|
||||
Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab;
|
||||
int rc;
|
||||
int isScan;
|
||||
int isScan = 0;
|
||||
int iLangVal = 0; /* Language id to query */
|
||||
|
||||
int iEq = -1; /* Index of term=? value in apVal */
|
||||
int iGe = -1; /* Index of term>=? value in apVal */
|
||||
int iLe = -1; /* Index of term<=? value in apVal */
|
||||
int iLangid = -1; /* Index of languageid=? value in apVal */
|
||||
int iNext = 0;
|
||||
|
||||
UNUSED_PARAMETER(nVal);
|
||||
UNUSED_PARAMETER(idxStr);
|
||||
@@ -362,7 +385,21 @@ static int fts3auxFilterMethod(
|
||||
|| idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT
|
||||
|| idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT)
|
||||
);
|
||||
isScan = (idxNum!=FTS4AUX_EQ_CONSTRAINT);
|
||||
|
||||
if( idxNum==FTS4AUX_EQ_CONSTRAINT ){
|
||||
iEq = iNext++;
|
||||
}else{
|
||||
isScan = 1;
|
||||
if( idxNum & FTS4AUX_GE_CONSTRAINT ){
|
||||
iGe = iNext++;
|
||||
}
|
||||
if( idxNum & FTS4AUX_LE_CONSTRAINT ){
|
||||
iLe = iNext++;
|
||||
}
|
||||
}
|
||||
if( iNext<nVal ){
|
||||
iLangid = iNext++;
|
||||
}
|
||||
|
||||
/* In case this cursor is being reused, close and zero it. */
|
||||
testcase(pCsr->filter.zTerm);
|
||||
@@ -374,22 +411,35 @@ static int fts3auxFilterMethod(
|
||||
pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
|
||||
if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN;
|
||||
|
||||
if( idxNum&(FTS4AUX_EQ_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) ){
|
||||
if( iEq>=0 || iGe>=0 ){
|
||||
const unsigned char *zStr = sqlite3_value_text(apVal[0]);
|
||||
assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) );
|
||||
if( zStr ){
|
||||
pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
|
||||
pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
|
||||
if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
if( idxNum&FTS4AUX_LE_CONSTRAINT ){
|
||||
int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0;
|
||||
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx]));
|
||||
pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]);
|
||||
|
||||
if( iLe>=0 ){
|
||||
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe]));
|
||||
pCsr->nStop = sqlite3_value_bytes(apVal[iLe]);
|
||||
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
if( iLangid>=0 ){
|
||||
iLangVal = sqlite3_value_int(apVal[iLangid]);
|
||||
|
||||
rc = sqlite3Fts3SegReaderCursor(pFts3, 0, 0, FTS3_SEGCURSOR_ALL,
|
||||
/* If the user specified a negative value for the languageid, use zero
|
||||
** instead. This works, as the "languageid=?" constraint will also
|
||||
** be tested by the VDBE layer. The test will always be false (since
|
||||
** this module will not return a row with a negative languageid), and
|
||||
** so the overall query will return zero rows. */
|
||||
if( iLangVal<0 ) iLangVal = 0;
|
||||
}
|
||||
pCsr->iLangid = iLangVal;
|
||||
|
||||
rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL,
|
||||
pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -413,24 +463,37 @@ static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){
|
||||
*/
|
||||
static int fts3auxColumnMethod(
|
||||
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
|
||||
sqlite3_context *pContext, /* Context for sqlite3_result_xxx() calls */
|
||||
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
|
||||
int iCol /* Index of column to read value from */
|
||||
){
|
||||
Fts3auxCursor *p = (Fts3auxCursor *)pCursor;
|
||||
|
||||
assert( p->isEof==0 );
|
||||
if( iCol==0 ){ /* Column "term" */
|
||||
sqlite3_result_text(pContext, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
|
||||
}else if( iCol==1 ){ /* Column "col" */
|
||||
if( p->iCol ){
|
||||
sqlite3_result_int(pContext, p->iCol-1);
|
||||
}else{
|
||||
sqlite3_result_text(pContext, "*", -1, SQLITE_STATIC);
|
||||
}
|
||||
}else if( iCol==2 ){ /* Column "documents" */
|
||||
sqlite3_result_int64(pContext, p->aStat[p->iCol].nDoc);
|
||||
}else{ /* Column "occurrences" */
|
||||
sqlite3_result_int64(pContext, p->aStat[p->iCol].nOcc);
|
||||
switch( iCol ){
|
||||
case 0: /* term */
|
||||
sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
|
||||
break;
|
||||
|
||||
case 1: /* col */
|
||||
if( p->iCol ){
|
||||
sqlite3_result_int(pCtx, p->iCol-1);
|
||||
}else{
|
||||
sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* documents */
|
||||
sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc);
|
||||
break;
|
||||
|
||||
case 3: /* occurrences */
|
||||
sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc);
|
||||
break;
|
||||
|
||||
default: /* languageid */
|
||||
assert( iCol==4 );
|
||||
sqlite3_result_int(pCtx, p->iLangid);
|
||||
break;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
** 2013-10-14
|
||||
**
|
||||
** 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 SQLite extension implements functions tointeger(X) and toreal(X).
|
||||
**
|
||||
** If X is an integer, real, or string value that can be
|
||||
** losslessly represented as an integer, then tointeger(X)
|
||||
** returns the corresponding integer value.
|
||||
** If X is an 8-byte BLOB then that blob is interpreted as
|
||||
** a signed two-compliment little-endian encoding of an integer
|
||||
** and tointeger(X) returns the corresponding integer value.
|
||||
** Otherwise tointeger(X) return NULL.
|
||||
**
|
||||
** If X is an integer, real, or string value that can be
|
||||
** convert into a real number, preserving at least 15 digits
|
||||
** of precision, then toreal(X) returns the corresponding real value.
|
||||
** If X is an 8-byte BLOB then that blob is interpreted as
|
||||
** a 64-bit IEEE754 big-endian floating point value
|
||||
** and toreal(X) returns the corresponding real value.
|
||||
** Otherwise toreal(X) return NULL.
|
||||
**
|
||||
** Note that tointeger(X) of an 8-byte BLOB assumes a little-endian
|
||||
** encoding whereas toreal(X) of an 8-byte BLOB assumes a big-endian
|
||||
** encoding.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Determine if this is running on a big-endian or little-endian
|
||||
** processor
|
||||
*/
|
||||
#if defined(i386) || defined(__i386__) || defined(_M_IX86)\
|
||||
|| defined(__x86_64) || defined(__x86_64__)
|
||||
# define TOTYPE_BIGENDIAN 0
|
||||
# define TOTYPE_LITTLEENDIAN 1
|
||||
#else
|
||||
const int totype_one = 1;
|
||||
# define TOTYPE_BIGENDIAN (*(char *)(&totype_one)==0)
|
||||
# define TOTYPE_LITTLEENDIAN (*(char *)(&totype_one)==1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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 LARGEST_INT64
|
||||
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
||||
#endif
|
||||
|
||||
#ifndef SMALLEST_INT64
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return TRUE if character c is a whitespace character
|
||||
*/
|
||||
static int totypeIsspace(unsigned char c){
|
||||
return c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r';
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if character c is a digit
|
||||
*/
|
||||
static int totypeIsdigit(unsigned char c){
|
||||
return c>='0' && c<='9';
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the 19-character string zNum against the text representation
|
||||
** value 2^63: 9223372036854775808. Return negative, zero, or positive
|
||||
** if zNum is less than, equal to, or greater than the string.
|
||||
** Note that zNum must contain exactly 19 characters.
|
||||
**
|
||||
** Unlike memcmp() this routine is guaranteed to return the difference
|
||||
** in the values of the last digit if the only difference is in the
|
||||
** last digit. So, for example,
|
||||
**
|
||||
** totypeCompare2pow63("9223372036854775800")
|
||||
**
|
||||
** will return -8.
|
||||
*/
|
||||
static int totypeCompare2pow63(const char *zNum){
|
||||
int c = 0;
|
||||
int i;
|
||||
/* 012345678901234567 */
|
||||
const char *pow63 = "922337203685477580";
|
||||
for(i=0; c==0 && i<18; i++){
|
||||
c = (zNum[i]-pow63[i])*10;
|
||||
}
|
||||
if( c==0 ){
|
||||
c = zNum[18] - '8';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert zNum to a 64-bit signed integer.
|
||||
**
|
||||
** If the zNum value is representable as a 64-bit twos-complement
|
||||
** integer, then write that value into *pNum and return 0.
|
||||
**
|
||||
** If zNum is exactly 9223372036854665808, return 2. This special
|
||||
** case is broken out because while 9223372036854665808 cannot be a
|
||||
** signed 64-bit integer, its negative -9223372036854665808 can be.
|
||||
**
|
||||
** If zNum is too big for a 64-bit integer and is not
|
||||
** 9223372036854665808 or if zNum contains any non-numeric text,
|
||||
** then return 1.
|
||||
**
|
||||
** The string is not necessarily zero-terminated.
|
||||
*/
|
||||
static int totypeAtoi64(const char *zNum, sqlite3_int64 *pNum, int length){
|
||||
sqlite3_uint64 u = 0;
|
||||
int neg = 0; /* assume positive */
|
||||
int i;
|
||||
int c = 0;
|
||||
int nonNum = 0;
|
||||
const char *zStart;
|
||||
const char *zEnd = zNum + length;
|
||||
|
||||
while( zNum<zEnd && totypeIsspace(*zNum) ) zNum++;
|
||||
if( zNum<zEnd ){
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
}else if( *zNum=='+' ){
|
||||
zNum++;
|
||||
}
|
||||
}
|
||||
zStart = zNum;
|
||||
while( zNum<zEnd && zNum[0]=='0' ){ zNum++; } /* Skip leading zeros. */
|
||||
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i++){
|
||||
u = u*10 + c - '0';
|
||||
}
|
||||
if( u>LARGEST_INT64 ){
|
||||
*pNum = SMALLEST_INT64;
|
||||
}else if( neg ){
|
||||
*pNum = -(sqlite3_int64)u;
|
||||
}else{
|
||||
*pNum = (sqlite3_int64)u;
|
||||
}
|
||||
if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19 || nonNum ){
|
||||
/* zNum is empty or contains non-numeric text or is longer
|
||||
** than 19 digits (thus guaranteeing that it is too large) */
|
||||
return 1;
|
||||
}else if( i<19 ){
|
||||
/* Less than 19 digits, so we know that it fits in 64 bits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return 0;
|
||||
}else{
|
||||
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
|
||||
c = totypeCompare2pow63(zNum);
|
||||
if( c<0 ){
|
||||
/* zNum is less than 9223372036854775808 so it fits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return 0;
|
||||
}else if( c>0 ){
|
||||
/* zNum is greater than 9223372036854775808 so it overflows */
|
||||
return 1;
|
||||
}else{
|
||||
/* zNum is exactly 9223372036854775808. Fits if negative. The
|
||||
** special case 2 overflow if positive */
|
||||
assert( u-1==LARGEST_INT64 );
|
||||
assert( (*pNum)==SMALLEST_INT64 );
|
||||
return neg ? 0 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The string z[] is an text representation of a real number.
|
||||
** Convert this string to a double and write it into *pResult.
|
||||
**
|
||||
** The string is not necessarily zero-terminated.
|
||||
**
|
||||
** Return TRUE if the result is a valid real number (or integer) and FALSE
|
||||
** if the string is empty or contains extraneous text. Valid numbers
|
||||
** are in one of these formats:
|
||||
**
|
||||
** [+-]digits[E[+-]digits]
|
||||
** [+-]digits.[digits][E[+-]digits]
|
||||
** [+-].digits[E[+-]digits]
|
||||
**
|
||||
** Leading and trailing whitespace is ignored for the purpose of determining
|
||||
** validity.
|
||||
**
|
||||
** If some prefix of the input string is a valid number, this routine
|
||||
** returns FALSE but it still converts the prefix and writes the result
|
||||
** into *pResult.
|
||||
*/
|
||||
static int totypeAtoF(const char *z, double *pResult, int length){
|
||||
const char *zEnd = z + length;
|
||||
/* sign * significand * (10 ^ (esign * exponent)) */
|
||||
int sign = 1; /* sign of significand */
|
||||
sqlite3_int64 s = 0; /* significand */
|
||||
int d = 0; /* adjust exponent for shifting decimal point */
|
||||
int esign = 1; /* sign of exponent */
|
||||
int e = 0; /* exponent */
|
||||
int eValid = 1; /* True exponent is either not used or is well-formed */
|
||||
double result;
|
||||
int nDigits = 0;
|
||||
int nonNum = 0;
|
||||
|
||||
*pResult = 0.0; /* Default return value, in case of an error */
|
||||
|
||||
/* skip leading spaces */
|
||||
while( z<zEnd && totypeIsspace(*z) ) z++;
|
||||
if( z>=zEnd ) return 0;
|
||||
|
||||
/* get sign of significand */
|
||||
if( *z=='-' ){
|
||||
sign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
|
||||
/* skip leading zeroes */
|
||||
while( z<zEnd && z[0]=='0' ) z++, nDigits++;
|
||||
|
||||
/* copy max significant digits to significand */
|
||||
while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
|
||||
s = s*10 + (*z - '0');
|
||||
z++, nDigits++;
|
||||
}
|
||||
|
||||
/* skip non-significant significand digits
|
||||
** (increase exponent by d to shift decimal left) */
|
||||
while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++, d++;
|
||||
if( z>=zEnd ) goto totype_atof_calc;
|
||||
|
||||
/* if decimal point is present */
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
/* copy digits from after decimal to significand
|
||||
** (decrease exponent by d to shift decimal right) */
|
||||
while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
|
||||
s = s*10 + (*z - '0');
|
||||
z++, nDigits++, d--;
|
||||
}
|
||||
/* skip non-significant digits */
|
||||
while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++;
|
||||
}
|
||||
if( z>=zEnd ) goto totype_atof_calc;
|
||||
|
||||
/* if exponent is present */
|
||||
if( *z=='e' || *z=='E' ){
|
||||
z++;
|
||||
eValid = 0;
|
||||
if( z>=zEnd ) goto totype_atof_calc;
|
||||
/* get sign of exponent */
|
||||
if( *z=='-' ){
|
||||
esign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
/* copy digits to exponent */
|
||||
while( z<zEnd && totypeIsdigit(*z) ){
|
||||
e = e<10000 ? (e*10 + (*z - '0')) : 10000;
|
||||
z++;
|
||||
eValid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip trailing spaces */
|
||||
if( nDigits && eValid ){
|
||||
while( z<zEnd && totypeIsspace(*z) ) z++;
|
||||
}
|
||||
|
||||
totype_atof_calc:
|
||||
/* adjust exponent by d, and update sign */
|
||||
e = (e*esign) + d;
|
||||
if( e<0 ) {
|
||||
esign = -1;
|
||||
e *= -1;
|
||||
} else {
|
||||
esign = 1;
|
||||
}
|
||||
|
||||
/* if 0 significand */
|
||||
if( !s ) {
|
||||
/* In the IEEE 754 standard, zero is signed.
|
||||
** Add the sign if we've seen at least one digit */
|
||||
result = (sign<0 && nDigits) ? -(double)0 : (double)0;
|
||||
} else {
|
||||
/* attempt to reduce exponent */
|
||||
if( esign>0 ){
|
||||
while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
|
||||
}else{
|
||||
while( !(s%10) && e>0 ) e--,s/=10;
|
||||
}
|
||||
|
||||
/* adjust the sign of significand */
|
||||
s = sign<0 ? -s : s;
|
||||
|
||||
/* if exponent, scale significand as appropriate
|
||||
** and store in result. */
|
||||
if( e ){
|
||||
double scale = 1.0;
|
||||
/* attempt to handle extremely small/large numbers better */
|
||||
if( e>307 && e<342 ){
|
||||
while( e%308 ) { scale *= 1.0e+1; e -= 1; }
|
||||
if( esign<0 ){
|
||||
result = s / scale;
|
||||
result /= 1.0e+308;
|
||||
}else{
|
||||
result = s * scale;
|
||||
result *= 1.0e+308;
|
||||
}
|
||||
}else if( e>=342 ){
|
||||
if( esign<0 ){
|
||||
result = 0.0*s;
|
||||
}else{
|
||||
result = 1e308*1e308*s; /* Infinity */
|
||||
}
|
||||
}else{
|
||||
/* 1.0e+22 is the largest power of 10 than can be
|
||||
** represented exactly. */
|
||||
while( e%22 ) { scale *= 1.0e+1; e -= 1; }
|
||||
while( e>0 ) { scale *= 1.0e+22; e -= 22; }
|
||||
if( esign<0 ){
|
||||
result = s / scale;
|
||||
}else{
|
||||
result = s * scale;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = (double)s;
|
||||
}
|
||||
}
|
||||
|
||||
/* store the result */
|
||||
*pResult = result;
|
||||
|
||||
/* return true if number and no extra non-whitespace chracters after */
|
||||
return z>=zEnd && nDigits>0 && eValid && nonNum==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** tointeger(X): If X is any value (integer, double, blob, or string) that
|
||||
** can be losslessly converted into an integer, then make the conversion and
|
||||
** return the result. Otherwise, return NULL.
|
||||
*/
|
||||
static void tointegerFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
(void)argc;
|
||||
switch( sqlite3_value_type(argv[0]) ){
|
||||
case SQLITE_FLOAT: {
|
||||
double rVal = sqlite3_value_double(argv[0]);
|
||||
sqlite3_int64 iVal = (sqlite3_int64)rVal;
|
||||
if( rVal==(double)iVal ){
|
||||
sqlite3_result_int64(context, iVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
|
||||
if( zBlob ){
|
||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||
if( nBlob==sizeof(sqlite3_int64) ){
|
||||
sqlite3_int64 iVal;
|
||||
if( TOTYPE_BIGENDIAN ){
|
||||
int i;
|
||||
unsigned char zBlobRev[sizeof(sqlite3_int64)];
|
||||
for(i=0; i<sizeof(sqlite3_int64); i++){
|
||||
zBlobRev[i] = zBlob[sizeof(sqlite3_int64)-1-i];
|
||||
}
|
||||
memcpy(&iVal, zBlobRev, sizeof(sqlite3_int64));
|
||||
}else{
|
||||
memcpy(&iVal, zBlob, sizeof(sqlite3_int64));
|
||||
}
|
||||
sqlite3_result_int64(context, iVal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
const unsigned char *zStr = sqlite3_value_text(argv[0]);
|
||||
if( zStr ){
|
||||
int nStr = sqlite3_value_bytes(argv[0]);
|
||||
if( nStr && !totypeIsspace(zStr[0]) ){
|
||||
sqlite3_int64 iVal;
|
||||
if( !totypeAtoi64((const char*)zStr, &iVal, nStr) ){
|
||||
sqlite3_result_int64(context, iVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** toreal(X): If X is any value (integer, double, blob, or string) that can
|
||||
** be losslessly converted into a real number, then do so and return that
|
||||
** real number. Otherwise return NULL.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable: 4748)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
static void torealFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
(void)argc;
|
||||
switch( sqlite3_value_type(argv[0]) ){
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_result_double(context, sqlite3_value_double(argv[0]));
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_int64 iVal = sqlite3_value_int64(argv[0]);
|
||||
double rVal = (double)iVal;
|
||||
if( iVal==(sqlite3_int64)rVal ){
|
||||
sqlite3_result_double(context, rVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
|
||||
if( zBlob ){
|
||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||
if( nBlob==sizeof(double) ){
|
||||
double rVal;
|
||||
if( TOTYPE_LITTLEENDIAN ){
|
||||
int i;
|
||||
unsigned char zBlobRev[sizeof(double)];
|
||||
for(i=0; i<sizeof(double); i++){
|
||||
zBlobRev[i] = zBlob[sizeof(double)-1-i];
|
||||
}
|
||||
memcpy(&rVal, zBlobRev, sizeof(double));
|
||||
}else{
|
||||
memcpy(&rVal, zBlob, sizeof(double));
|
||||
}
|
||||
sqlite3_result_double(context, rVal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
const unsigned char *zStr = sqlite3_value_text(argv[0]);
|
||||
if( zStr ){
|
||||
int nStr = sqlite3_value_bytes(argv[0]);
|
||||
if( nStr && !totypeIsspace(zStr[0]) && !totypeIsspace(zStr[nStr-1]) ){
|
||||
double rVal;
|
||||
if( totypeAtoF((const char*)zStr, &rVal, nStr) ){
|
||||
sqlite3_result_double(context, rVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#pragma warning(default: 4748)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_totype_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "tointeger", 1, SQLITE_UTF8, 0,
|
||||
tointegerFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0,
|
||||
torealFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -26,4 +26,5 @@
|
||||
>68 belong =0x42654c6e Bentley Systems Localization File -
|
||||
>60 belong =0x5f4d544e Monotone source repository -
|
||||
>68 belong =0x47504b47 OGC GeoPackage file -
|
||||
>68 belong =0x47503130 OGC GeoPackage version 1.0 file -
|
||||
>0 string =SQLite SQLite3 database
|
||||
|
||||
@@ -279,7 +279,9 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/spellfix.c \
|
||||
$(TOP)/ext/misc/wholenumber.c
|
||||
$(TOP)/ext/misc/totype.c \
|
||||
$(TOP)/ext/misc/wholenumber.c \
|
||||
$(TOP)/ext/misc/vfslog.c
|
||||
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
@@ -618,6 +620,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 +657,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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
C Try\sto\sremember\sstatistics\sfrom\sANALYZE\susing\sLogEst\sinstead\sof\su64.
|
||||
D 2013-10-07T16:53:50.515
|
||||
C Fix\smemory/resource\sleaks\sfor\sWinCE\sand\sCygwin.
|
||||
D 2013-10-16T09:49:10.719
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 9af063716f726a73b5d5c98c69ea97eca6a9369b
|
||||
F Makefile.msc ec5d662ed5a15ff819928c0495017af13910d7b6
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION a8d1f6839521130dc73c5408cdd24bcfd791df34
|
||||
@@ -78,10 +78,10 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 6d277a3ff6b20ff815184395407c5a4bd7787f9c
|
||||
F ext/fts3/fts3.c f25ae5729d40cc4e661c0a552685038f27e72bc9
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 8689f7cf85020e7f88d1e761eeac480c3b0ea7ad
|
||||
F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7
|
||||
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
@@ -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 851e65f413576055f2e86a63d45b7d67c829db56
|
||||
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
|
||||
@@ -115,6 +115,8 @@ 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/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c 1abb192d8d4bd323adbddec0c024580496b51b7a
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
@@ -138,8 +140,8 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d
|
||||
F main.mk a10f1925ae3bb545a045d1f1867506f49bee972f
|
||||
F magic.txt 814d3de5ec227817ff2ad26cbc73159c968a2a58
|
||||
F main.mk c6a433cb334bbb019625c137ab5d5e7568b47cff
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
|
||||
@@ -157,7 +159,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/analyze.c 3994309c21b7324217cd32225b7abb5cb1bd1946
|
||||
F src/analyze.c f1c5ed1fe128c3f106dcd95e97ee9ef94db7a3fa
|
||||
F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
|
||||
@@ -166,15 +168,15 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c d5720cbb21ae56e7e5b07847e05e5b203818acac
|
||||
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 46bb89df0a204eb7154874f966f11d16a7fbced7
|
||||
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/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 2c47b65e6e00e3e9374942f28254faf8adafe398
|
||||
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
@@ -203,36 +205,36 @@ 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 c812a3c37e113423f1579aba876acc240189d5d6
|
||||
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 f4ff6e29c316d06bf7dffca0c8cee7c229cae42e
|
||||
F src/pragma.c 64d3d1f8b4ed144ba85c061d00d96d6be8aa2fea
|
||||
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 19611e6da6646a1090164b29d6b23b7c8e7364ea
|
||||
F src/shell.c 5ee50ca3e35453bbd6ccdf1bdd0f6bbe9738e9fb
|
||||
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 a5fa87b540662fb552ba81c0d4eeb368aebb5af7
|
||||
F src/sqliteInt.h 4dd81a25a919509ce94b1f8f120bbef14458d4b9
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 3b5f3716e320480659239abe887164521c575d83
|
||||
F src/test1.c 26226cfd2b6dc3f77d2eb27f07ffcf236b4e728b
|
||||
F src/test1.c 5757066e503a8ed51313cb3a5d9bcdcced2991a9
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220
|
||||
F src/test7.c 126b886b53f0358b92aba9b81d3fcbfbe9a93cd6
|
||||
F src/test6.c 00af0fe1947305222b8ed488a69c76c5a2b632e2
|
||||
F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2
|
||||
F src/test8.c c7aab1d9fbbf54fc33d43b73aa24aa55f9eaf534
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
@@ -261,7 +263,7 @@ F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47
|
||||
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
|
||||
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
@@ -275,7 +277,7 @@ F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
|
||||
F src/trigger.c ba0a883cd536b7dfdd4df3733001f5372a4299da
|
||||
F src/update.c f5182157f5d0d0a97bc5f5e3c9bdba0dfbe08f08
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c 2f0c9b1f884d038eb90f48cf17042a88dc1629d3
|
||||
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
||||
F src/vacuum.c f313bc97123a4dd4bfd3f50a00c4d44c08a5b1b7
|
||||
F src/vdbe.c 56e648f5ba9a91810caf216857adfed9039cd174
|
||||
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
|
||||
@@ -283,14 +285,14 @@ 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 649933bad3e922465b726eaf85c72a75acba2ab7
|
||||
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 7916e32a4d7f8cc891a08de09380ef519415d275
|
||||
F src/where.c dd2d0d69280d6653d8ef8cf3b6b4b848b9058197
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@@ -319,7 +321,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
|
||||
@@ -414,7 +416,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
|
||||
@@ -437,7 +439,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
|
||||
@@ -461,8 +463,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 8a1fde4e7721ae00b05b3178888833726ca2df8d
|
||||
F test/fkey6.test 18e8c024d39f68f8d4bb1177c992bcffdc273464
|
||||
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
|
||||
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@@ -521,6 +523,7 @@ F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda
|
||||
F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451
|
||||
F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9
|
||||
F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221
|
||||
F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba
|
||||
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
||||
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
||||
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
|
||||
@@ -556,18 +559,19 @@ 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/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9
|
||||
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 cb3f888a1cafad195a1f8d396875bdb11dc4faf9
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
|
||||
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
@@ -608,7 +612,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
|
||||
@@ -723,9 +727,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/pragma.test de128f0253ee42a1edf6c80f21813babfb19bd3b
|
||||
F test/pragma2.test 224f0381f9411a78ae685cac24c13656a62021b7
|
||||
F test/permutations.test e154f5ed66d4d4913a99a110e870c9407f75b055
|
||||
F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
@@ -761,7 +765,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
|
||||
@@ -781,7 +785,7 @@ F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
|
||||
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
|
||||
@@ -1083,22 +1087,23 @@ F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 323e54ac86fb2393f9950219224e304620d2fb12
|
||||
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 ceaaeebcd882864caefe4176592ca6fa4648fab1
|
||||
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
|
||||
@@ -1119,12 +1124,12 @@ 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/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 1d7b2dc0eae70c0c0e523b715acf758bb4cfa9ac
|
||||
R faf619696f929769ec0cefbeba9e27c2
|
||||
T *branch * log-stats
|
||||
T *sym-log-stats *
|
||||
T -sym-row-size-est *
|
||||
U drh
|
||||
Z 72baf94bdfc7ce8839761e1732e0e2d4
|
||||
P 891df358e51075fb937f34952ce43bf51130b0d0
|
||||
R 220c145b0b7752ec81af9a6d3dc55290
|
||||
T *branch * wince-fixes
|
||||
T *sym-wince-fixes *
|
||||
T -sym-trunk *
|
||||
U mistachkin
|
||||
Z cf86f3f77bb8f85bf54a57b7b4d91994
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8e78557a40a6b97009852f5b72e68d6483fb00fc
|
||||
2470d1bb08b2661bcfde7a605208eb6044836d5c
|
||||
+47
-30
@@ -31,7 +31,7 @@
|
||||
** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
|
||||
** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced
|
||||
** version of sqlite_stat3 and is only available when compiled with
|
||||
** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.0 and later. It is
|
||||
** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is
|
||||
** not possible to enable both STAT3 and STAT4 at the same time. If they
|
||||
** are both enabled, then STAT4 takes precedence.
|
||||
**
|
||||
@@ -107,12 +107,12 @@
|
||||
** The idx column names the index and the tbl column is the table of the
|
||||
** index. If the idx and tbl columns are the same, then the sample is
|
||||
** of the INTEGER PRIMARY KEY. The sample column is a blob which is the
|
||||
** binary encoding of a key from the index, with the trailing rowid
|
||||
** omitted. The nEq column is a list of integers. The first integer
|
||||
** is the approximate number of entries in the index whose left-most
|
||||
** column exactly matches the left-most column of the sample. The second
|
||||
** integer in nEq is the approximate number of entries in the index where
|
||||
** the first two columns match the first two columns of the sample.
|
||||
** binary encoding of a key from the index. The nEq column is a
|
||||
** list of integers. The first integer is the approximate number
|
||||
** of entries in the index whose left-most column exactly matches
|
||||
** the left-most column of the sample. The second integer in nEq
|
||||
** is the approximate number of entries in the index where the
|
||||
** first two columns match the first two columns of the sample.
|
||||
** And so forth. nLt is another list of integers that show the approximate
|
||||
** number of entries that are strictly less than the sample. The first
|
||||
** integer in nLt contains the number of entries in the index where the
|
||||
@@ -444,7 +444,7 @@ static int sampleIsBetter(
|
||||
/*
|
||||
** Copy the contents of object (*pFrom) into (*pTo).
|
||||
*/
|
||||
void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
pTo->iRowid = pFrom->iRowid;
|
||||
pTo->isPSample = pFrom->isPSample;
|
||||
pTo->iCol = pFrom->iCol;
|
||||
@@ -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);
|
||||
@@ -1252,13 +1264,13 @@ struct analysisInfo {
|
||||
static void decodeIntArray(
|
||||
char *zIntArray, /* String containing int array to decode */
|
||||
int nOut, /* Number of slots in aOut[] */
|
||||
LogEst *aOut, /* Convert values to 10*log2() and store here */
|
||||
tRowcnt *aOut, /* Store integers here */
|
||||
Index *pIndex /* Handle extra flags for this index, if not NULL */
|
||||
){
|
||||
char *z = zIntArray;
|
||||
int c;
|
||||
int i;
|
||||
u64 v;
|
||||
tRowcnt v;
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( z==0 ) z = "";
|
||||
@@ -1271,10 +1283,15 @@ static void decodeIntArray(
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
aOut[i] = sqlite3LogEst(v);
|
||||
aOut[i] = v;
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
if( pIndex ){
|
||||
#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 ){
|
||||
@@ -1368,10 +1385,10 @@ static void initAvgEq(Index *pIdx){
|
||||
int iCol;
|
||||
for(iCol=0; iCol<pIdx->nColumn; iCol++){
|
||||
int i; /* Used to iterate through samples */
|
||||
u64 sumEq = 0; /* Sum of the nEq values */
|
||||
u64 nSum = 0; /* Number of terms contributing to sumEq */
|
||||
u64 avgEq = 0;
|
||||
u64 nDLt = sqlite3LogEstToInt(pFinal->anDLt[iCol]);
|
||||
tRowcnt sumEq = 0; /* Sum of the nEq values */
|
||||
tRowcnt nSum = 0; /* Number of terms contributing to sumEq */
|
||||
tRowcnt avgEq = 0;
|
||||
tRowcnt nDLt = pFinal->anDLt[iCol];
|
||||
|
||||
/* Set nSum to the number of distinct (iCol+1) field prefixes that
|
||||
** occur in the stat4 table for this index before pFinal. Set
|
||||
@@ -1380,15 +1397,15 @@ static void initAvgEq(Index *pIdx){
|
||||
** prefixes). */
|
||||
for(i=0; i<(pIdx->nSample-1); i++){
|
||||
if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
|
||||
sumEq += sqlite3LogEstToInt(aSample[i].anEq[iCol]);
|
||||
sumEq += aSample[i].anEq[iCol];
|
||||
nSum++;
|
||||
}
|
||||
}
|
||||
if( nDLt>nSum ){
|
||||
avgEq = (sqlite3LogEstToInt(pFinal->anLt[iCol]) - sumEq)/(nDLt - nSum);
|
||||
avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
|
||||
}
|
||||
if( avgEq<=0 ) avgEq = 1;
|
||||
pIdx->aAvgEq[iCol] = sqlite3LogEst(avgEq);
|
||||
if( avgEq==0 ) avgEq = 1;
|
||||
pIdx->aAvgEq[iCol] = avgEq;
|
||||
if( pIdx->nSampleCol==1 ) break;
|
||||
}
|
||||
}
|
||||
@@ -1438,7 +1455,7 @@ static int loadStatTbl(
|
||||
int nSample; /* Number of samples */
|
||||
int nByte; /* Bytes of space required */
|
||||
int i; /* Bytes of space required */
|
||||
LogEst *pSpace;
|
||||
tRowcnt *pSpace;
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
if( zIndex==0 ) continue;
|
||||
@@ -1454,15 +1471,15 @@ static int loadStatTbl(
|
||||
}
|
||||
pIdx->nSampleCol = nIdxCol;
|
||||
nByte = sizeof(IndexSample) * nSample;
|
||||
nByte += sizeof(LogEst) * nIdxCol * 3 * nSample;
|
||||
nByte += nAvgCol * sizeof(LogEst); /* Space for Index.aAvgEq[] */
|
||||
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
|
||||
nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
|
||||
|
||||
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
|
||||
if( pIdx->aSample==0 ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pSpace = (LogEst*)&pIdx->aSample[nSample];
|
||||
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
|
||||
pIdx->aAvgEq = pSpace; pSpace += nAvgCol;
|
||||
for(i=0; i<nSample; i++){
|
||||
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
|
||||
|
||||
+11
-12
@@ -879,7 +879,7 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
pTable->nRowEst = 200;
|
||||
pTable->nRowEst = 1048576;
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
@@ -1113,7 +1113,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
||||
if( zChar ){
|
||||
while( zChar[0] ){
|
||||
if( sqlite3Isdigit(zChar[0]) ){
|
||||
int v;
|
||||
int v = 0;
|
||||
sqlite3GetInt32(zChar, &v);
|
||||
v = v/4 + 1;
|
||||
if( v>255 ) v = 255;
|
||||
@@ -2722,7 +2722,7 @@ Index *sqlite3CreateIndex(
|
||||
nCol = pList->nExpr;
|
||||
pIndex = sqlite3DbMallocZero(db,
|
||||
ROUND8(sizeof(Index)) + /* Index structure */
|
||||
ROUND8(sizeof(LogEst)*(nCol+1)) + /* Index.aiRowEst */
|
||||
ROUND8(sizeof(tRowcnt)*(nCol+1)) + /* Index.aiRowEst */
|
||||
sizeof(char *)*nCol + /* Index.azColl */
|
||||
sizeof(int)*nCol + /* Index.aiColumn */
|
||||
sizeof(u8)*nCol + /* Index.aSortOrder */
|
||||
@@ -2733,9 +2733,9 @@ Index *sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
zExtra = (char*)pIndex;
|
||||
pIndex->aiRowEst = (LogEst*)&zExtra[ROUND8(sizeof(Index))];
|
||||
pIndex->aiRowEst = (tRowcnt*)&zExtra[ROUND8(sizeof(Index))];
|
||||
pIndex->azColl = (char**)
|
||||
((char*)pIndex->aiRowEst + ROUND8(sizeof(LogEst)*nCol+1));
|
||||
((char*)pIndex->aiRowEst + ROUND8(sizeof(tRowcnt)*nCol+1));
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
||||
pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
|
||||
@@ -3014,20 +3014,19 @@ exit_create_index:
|
||||
** are based on typical values found in actual indices.
|
||||
*/
|
||||
void sqlite3DefaultRowEst(Index *pIdx){
|
||||
LogEst *a = pIdx->aiRowEst;
|
||||
tRowcnt *a = pIdx->aiRowEst;
|
||||
int i;
|
||||
LogEst n;
|
||||
tRowcnt n;
|
||||
assert( a!=0 );
|
||||
a[0] = pIdx->pTable->nRowEst;
|
||||
assert( 33==sqlite3LogEst(10) );
|
||||
if( a[0]<34 ){ a[0] = 34; }
|
||||
n = 34;
|
||||
if( a[0]<10 ) a[0] = 10;
|
||||
n = 10;
|
||||
for(i=1; i<=pIdx->nColumn; i++){
|
||||
a[i] = n;
|
||||
if( n>24 ) n -= 2;
|
||||
if( n>5 ) n--;
|
||||
}
|
||||
if( pIdx->onError!=OE_None ){
|
||||
a[pIdx->nColumn] = 0;
|
||||
a[pIdx->nColumn] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+13
-6
@@ -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);
|
||||
|
||||
+8
-6
@@ -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 },
|
||||
@@ -2196,8 +2196,7 @@ static int winClose(sqlite3_file *id){
|
||||
OSTRACE(("CLOSE file=%p\n", pFile->h));
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
rc = winUnmapfile(pFile);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
winUnmapfile(pFile);
|
||||
#endif
|
||||
|
||||
do{
|
||||
@@ -3003,7 +3002,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
|
||||
pFile->mmapSizeMax = newLimit;
|
||||
if( pFile->mmapSize>0 ){
|
||||
(void)winUnmapfile(pFile);
|
||||
winUnmapfile(pFile);
|
||||
rc = winMapfile(pFile, -1);
|
||||
}
|
||||
}
|
||||
@@ -4073,6 +4072,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
if( winIsDriveLetterAndColon(zDir) ){
|
||||
zConverted = winConvertFromUtf8Filename(zDir);
|
||||
if( !zConverted ){
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
@@ -4085,6 +4085,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
}else{
|
||||
zConverted = sqlite3MallocZero( nBuf+1 );
|
||||
if( !zConverted ){
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
@@ -4092,6 +4093,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
|
||||
zConverted, nBuf+1)<0 ){
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n"));
|
||||
return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno,
|
||||
"winGetTempname1", zDir);
|
||||
@@ -4105,6 +4107,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
char *zUtf8 = winUnicodeToUtf8(zConverted);
|
||||
if( !zUtf8 ){
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
@@ -4120,7 +4123,6 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
}
|
||||
sqlite3_free(zConverted);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
|
||||
@@ -4490,9 +4492,9 @@ static int winOpen(
|
||||
#endif
|
||||
{
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zTmpname);
|
||||
}
|
||||
|
||||
sqlite3_free(zTmpname);
|
||||
pFile->pMethod = &winIoMethod;
|
||||
pFile->pVfs = pVfs;
|
||||
pFile->h = h;
|
||||
|
||||
+70
-38
@@ -56,18 +56,19 @@
|
||||
#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 */
|
||||
@@ -359,6 +360,12 @@ static const struct sPragmaNames {
|
||||
/* ePragFlag: */ 0,
|
||||
/* iArg: */ SQLITE_SqlTrace },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
{ /* zName: */ "stats",
|
||||
/* ePragTyp: */ PragTyp_STATS,
|
||||
/* ePragFlag: */ PragFlag_NeedSchema,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{ /* zName: */ "synchronous",
|
||||
/* ePragTyp: */ PragTyp_SYNCHRONOUS,
|
||||
@@ -420,7 +427,7 @@ static const struct sPragmaNames {
|
||||
/* ePragFlag: */ 0,
|
||||
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
|
||||
};
|
||||
/* Number of pragmas: 55 on by default, 67 total. */
|
||||
/* Number of pragmas: 56 on by default, 68 total. */
|
||||
/* End of the automatically generated pragma table.
|
||||
***************************************************************************/
|
||||
|
||||
@@ -1425,6 +1432,36 @@ 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;
|
||||
@@ -1457,26 +1494,17 @@ void sqlite3Pragma(
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeSetNumCols(v, 4);
|
||||
pParse->nMem = 4;
|
||||
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);
|
||||
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "avgrowsize", SQLITE_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pTab->szTabRow), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
for(pIdx=pTab->pIndex, i=1; pIdx; pIdx=pIdx->pNext, i++){
|
||||
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_Integer,
|
||||
(int)sqlite3LogEstToInt(pIdx->szIdxRow), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1610,8 +1638,8 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName,
|
||||
P4_TRANSIENT);
|
||||
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
||||
pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
|
||||
if( pParent==0 ) break;
|
||||
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
||||
if( pParent==0 ) continue;
|
||||
pIdx = 0;
|
||||
sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
|
||||
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
|
||||
@@ -1628,18 +1656,20 @@ void sqlite3Pragma(
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert( pParse->nErr>0 || pFK==0 );
|
||||
if( pFK ) break;
|
||||
if( pParse->nTab<i ) pParse->nTab = i;
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0);
|
||||
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
||||
pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
|
||||
assert( pParent!=0 );
|
||||
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
||||
pIdx = 0;
|
||||
aiCols = 0;
|
||||
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
|
||||
assert( x==0 );
|
||||
if( pParent ){
|
||||
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
|
||||
assert( x==0 );
|
||||
}
|
||||
addrOk = sqlite3VdbeMakeLabel(v);
|
||||
if( pIdx==0 ){
|
||||
if( pParent && pIdx==0 ){
|
||||
int iKey = pFK->aCol[0].iFrom;
|
||||
assert( iKey>=0 && iKey<pTab->nCol );
|
||||
if( iKey!=pTab->iPKey ){
|
||||
@@ -1657,13 +1687,15 @@ void sqlite3Pragma(
|
||||
}else{
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
|
||||
aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j);
|
||||
aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey);
|
||||
sqlite3VdbeChangeP4(v, -1,
|
||||
sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
if( pParent ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey);
|
||||
sqlite3VdbeChangeP4(v, -1,
|
||||
sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0,
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
+66
-33
@@ -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 = 200;
|
||||
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 = 200;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+13
-13
@@ -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>
|
||||
*/
|
||||
|
||||
+10
-10
@@ -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>
|
||||
@@ -1382,11 +1382,11 @@ struct Table {
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
#endif
|
||||
tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
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 nRowEst; /* Estimated number of rows in the 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 */
|
||||
@@ -1577,7 +1577,7 @@ struct UnpackedRecord {
|
||||
struct Index {
|
||||
char *zName; /* Name of this index */
|
||||
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
|
||||
LogEst *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
Table *pTable; /* The SQL table being indexed */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
@@ -1595,7 +1595,7 @@ struct Index {
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
LogEst *aAvgEq; /* Average nEq values for keys not in aSample */
|
||||
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
|
||||
IndexSample *aSample; /* Samples of the left-most key */
|
||||
#endif
|
||||
};
|
||||
@@ -1608,9 +1608,9 @@ struct Index {
|
||||
struct IndexSample {
|
||||
void *p; /* Pointer to sampled record */
|
||||
int n; /* Size of record in bytes */
|
||||
LogEst *anEq; /* Est. number of rows where the key equals this sample */
|
||||
LogEst *anLt; /* Est. number of rows where key is less than this sample */
|
||||
LogEst *anDLt; /* Est. number of distinct keys less than this sample */
|
||||
tRowcnt *anEq; /* Est. number of rows where the key equals this sample */
|
||||
tRowcnt *anLt; /* Est. number of rows where key is less than this sample */
|
||||
tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3248,10 +3248,10 @@ const char *sqlite3JournalModename(int);
|
||||
FKey *sqlite3FkReferences(Table *);
|
||||
#else
|
||||
#define sqlite3FkActions(a,b,c,d,e,f)
|
||||
#define sqlite3FkCheck(a,b,c,d)
|
||||
#define sqlite3FkCheck(a,b,c,d,e,f)
|
||||
#define sqlite3FkDropTable(a,b,c)
|
||||
#define sqlite3FkOldmask(a,b) 0
|
||||
#define sqlite3FkRequired(a,b,c,d,e,f) 0
|
||||
#define sqlite3FkOldmask(a,b) 0
|
||||
#define sqlite3FkRequired(a,b,c,d) 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
void sqlite3FkDelete(sqlite3 *, Table*);
|
||||
|
||||
@@ -6160,6 +6160,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
static const struct {
|
||||
const char *zExtName;
|
||||
@@ -6173,6 +6174,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
{ "percentile", sqlite3_percentile_init },
|
||||
{ "regexp", sqlite3_regexp_init },
|
||||
{ "spellfix", sqlite3_spellfix_init },
|
||||
{ "totype", sqlite3_totype_init },
|
||||
{ "wholenumber", sqlite3_wholenumber_init },
|
||||
};
|
||||
sqlite3 *db;
|
||||
|
||||
+2
-2
@@ -133,9 +133,9 @@ struct CrashFile {
|
||||
** OsFileSize() calls. Although both could be done by traversing the
|
||||
** write-list, in practice this is impractically slow.
|
||||
*/
|
||||
int iSize; /* Size of file in bytes */
|
||||
int nData; /* Size of buffer allocated at zData */
|
||||
u8 *zData; /* Buffer containing file contents */
|
||||
int nData; /* Size of buffer allocated at zData */
|
||||
i64 iSize; /* Size of file in bytes */
|
||||
};
|
||||
|
||||
struct CrashGlobal {
|
||||
|
||||
+17
-1
@@ -40,6 +40,7 @@ int sqlite3_client_finalize(sqlite3_stmt*);
|
||||
int sqlite3_client_close(sqlite3*);
|
||||
int sqlite3_server_start(void);
|
||||
int sqlite3_server_stop(void);
|
||||
void sqlite3_server_start2(int *pnDecr);
|
||||
|
||||
/*
|
||||
** Each thread is controlled by an instance of the following
|
||||
@@ -68,6 +69,13 @@ struct Thread {
|
||||
int argc; /* number of columns in result */
|
||||
const char *argv[100]; /* result columns */
|
||||
const char *colv[100]; /* result column names */
|
||||
|
||||
/* Initialized to 1 by the supervisor thread when the client is
|
||||
** created, and then deemed read-only to the supervisor thread.
|
||||
** Is set to 0 by the server thread belonging to this client
|
||||
** just before it exits.
|
||||
*/
|
||||
int nServer; /* Number of server threads running */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -175,7 +183,10 @@ static int tcl_client_create(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pthread_detach(x);
|
||||
sqlite3_server_start();
|
||||
if( threadset[i].nServer==0 ){
|
||||
threadset[i].nServer = 1;
|
||||
sqlite3_server_start2(&threadset[i].nServer);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -268,6 +279,11 @@ static int tcl_client_halt(
|
||||
for(i=0; i<N_THREAD && threadset[i].busy==0; i++){}
|
||||
if( i>=N_THREAD ){
|
||||
sqlite3_server_stop();
|
||||
while( 1 ){
|
||||
for(i=0; i<N_THREAD && threadset[i].nServer==0; i++);
|
||||
if( i==N_THREAD ) break;
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -472,6 +472,32 @@ void sqlite3_server_start(void){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around sqlite3_server() that decrements the int variable
|
||||
** pointed to by the first argument after the sqlite3_server() call
|
||||
** returns.
|
||||
*/
|
||||
static void *serverWrapper(void *pnDecr){
|
||||
void *p = sqlite3_server(0);
|
||||
(*(int*)pnDecr)--;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is the similar to sqlite3_server_start(), except that
|
||||
** the integer pointed to by the first argument is decremented when
|
||||
** the server thread exits.
|
||||
*/
|
||||
void sqlite3_server_start2(int *pnDecr){
|
||||
pthread_t x;
|
||||
int rc;
|
||||
g.serverHalt = 0;
|
||||
rc = pthread_create(&x, 0, serverWrapper, (void*)pnDecr);
|
||||
if( rc==0 ){
|
||||
pthread_detach(x);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If a server thread is running, then stop it. If no server is
|
||||
** running, this routine is effectively a no-op.
|
||||
|
||||
@@ -1213,6 +1213,7 @@ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
|
||||
** 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[] = {
|
||||
|
||||
+5
-2
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1073,7 +1075,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
** NULL, it is assumed that the caller will free any allocated object
|
||||
** in all cases.
|
||||
*/
|
||||
int valueFromExpr(
|
||||
static int valueFromExpr(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Expr *pExpr, /* The expression to evaluate */
|
||||
u8 enc, /* Encoding to use */
|
||||
@@ -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);
|
||||
|
||||
+71
-62
@@ -2328,7 +2328,7 @@ static void whereKeyStats(
|
||||
Index *pIdx, /* Index to consider domain of */
|
||||
UnpackedRecord *pRec, /* Vector of values to consider */
|
||||
int roundUp, /* Round up if true. Round down if false */
|
||||
LogEst *aStat /* OUT: stats written here */
|
||||
tRowcnt *aStat /* OUT: stats written here */
|
||||
){
|
||||
IndexSample *aSample = pIdx->aSample;
|
||||
int iCol; /* Index of required stats in anEq[] etc. */
|
||||
@@ -2337,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;
|
||||
@@ -2381,16 +2384,15 @@ static void whereKeyStats(
|
||||
aStat[0] = aSample[i].anLt[iCol];
|
||||
aStat[1] = aSample[i].anEq[iCol];
|
||||
}else{
|
||||
LogEst iLower, iUpper, iGap;
|
||||
tRowcnt iLower, iUpper, iGap;
|
||||
if( i==0 ){
|
||||
iLower = 0;
|
||||
iUpper = aSample[0].anLt[iCol];
|
||||
}else{
|
||||
iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol];
|
||||
iLower = sqlite3LogEstAdd(aSample[i-1].anEq[iCol],
|
||||
aSample[i-1].anLt[iCol]);
|
||||
iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
|
||||
}
|
||||
aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 0);
|
||||
aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 1);
|
||||
if( iLower>=iUpper ){
|
||||
iGap = 0;
|
||||
}else{
|
||||
@@ -2451,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 */
|
||||
LogEst *pnOut /* IN/OUT: Number of rows visited */
|
||||
WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int nOut = (int)*pnOut;
|
||||
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
|
||||
@@ -2467,7 +2469,7 @@ static int whereRangeScanEst(
|
||||
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
|
||||
){
|
||||
UnpackedRecord *pRec = pBuilder->pRec;
|
||||
LogEst a[2];
|
||||
tRowcnt a[2];
|
||||
u8 aff;
|
||||
|
||||
/* Variable iLower will be set to the estimate of the number of rows in
|
||||
@@ -2487,8 +2489,8 @@ static int whereRangeScanEst(
|
||||
** is either ($P) or ($P:$U). Again, even if $U is available, both values
|
||||
** of iUpper are requested of whereKeyStats() and the smaller used.
|
||||
*/
|
||||
LogEst iLower;
|
||||
LogEst iUpper;
|
||||
tRowcnt iLower;
|
||||
tRowcnt iUpper;
|
||||
|
||||
if( nEq==p->nColumn ){
|
||||
aff = SQLITE_AFF_INTEGER;
|
||||
@@ -2504,7 +2506,7 @@ static int whereRangeScanEst(
|
||||
** have been requested when testing key $P in whereEqualScanEst(). */
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
iLower = a[0];
|
||||
iUpper = sqlite3LogEstAdd(a[0],a[1]);
|
||||
iUpper = a[0] + a[1];
|
||||
}
|
||||
|
||||
/* If possible, improve on the iLower estimate using ($P:$L). */
|
||||
@@ -2514,9 +2516,9 @@ static int whereRangeScanEst(
|
||||
assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
|
||||
if( rc==SQLITE_OK && bOk ){
|
||||
LogEst iNew;
|
||||
tRowcnt iNew;
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
iNew = sqlite3LogEstAdd(a[0],((pLower->eOperator & WO_GT) ? a[1] : 0));
|
||||
iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
|
||||
if( iNew>iLower ) iLower = iNew;
|
||||
nOut--;
|
||||
}
|
||||
@@ -2529,9 +2531,9 @@ static int whereRangeScanEst(
|
||||
assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
|
||||
if( rc==SQLITE_OK && bOk ){
|
||||
LogEst iNew;
|
||||
tRowcnt iNew;
|
||||
whereKeyStats(pParse, p, pRec, 1, a);
|
||||
iNew = sqlite3LogEstAdd(a[0],((pUpper->eOperator & WO_LE) ? a[1] : 0));
|
||||
iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
|
||||
if( iNew<iUpper ) iUpper = iNew;
|
||||
nOut--;
|
||||
}
|
||||
@@ -2539,17 +2541,17 @@ static int whereRangeScanEst(
|
||||
|
||||
pBuilder->pRec = pRec;
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iUpper<=iLower ) iUpper = iLower+1;
|
||||
nNew = sqlite3LogEst(sqlite3LogEstToInt(iUpper)
|
||||
- sqlite3LogEstToInt(iLower));
|
||||
if( iUpper>iLower ){
|
||||
nNew = sqlite3LogEst(iUpper - iLower);
|
||||
}else{
|
||||
nNew = 10; assert( 10==sqlite3LogEst(2) );
|
||||
}
|
||||
if( nNew<nOut ){
|
||||
nOut = nNew;
|
||||
}
|
||||
*pnOut = (LogEst)nOut;
|
||||
WHERETRACE(0x100, ("range scan regions: %llu..%llu est=%d\n",
|
||||
sqlite3LogEstToInt(iLower),
|
||||
sqlite3LogEstToInt(iUpper),
|
||||
nOut));
|
||||
pLoop->nOut = (LogEst)nOut;
|
||||
WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
|
||||
(u32)iLower, (u32)iUpper, nOut));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@@ -2571,7 +2573,7 @@ static int whereRangeScanEst(
|
||||
}
|
||||
if( nNew<10 ) nNew = 10;
|
||||
if( nNew<nOut ) nOut = nNew;
|
||||
*pnOut = (LogEst)nOut;
|
||||
pLoop->nOut = (LogEst)nOut;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2597,14 +2599,14 @@ static int whereEqualScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
WhereLoopBuilder *pBuilder,
|
||||
Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */
|
||||
LogEst *pnRow /* Write the revised row estimate here */
|
||||
tRowcnt *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
Index *p = pBuilder->pNew->u.btree.pIndex;
|
||||
int nEq = pBuilder->pNew->u.btree.nEq;
|
||||
UnpackedRecord *pRec = pBuilder->pRec;
|
||||
u8 aff; /* Column affinity */
|
||||
int rc; /* Subfunction return code */
|
||||
LogEst a[2]; /* Statistics */
|
||||
tRowcnt a[2]; /* Statistics */
|
||||
int bOk;
|
||||
|
||||
assert( nEq>=1 );
|
||||
@@ -2634,8 +2636,7 @@ static int whereEqualScanEst(
|
||||
pBuilder->nRecValid = nEq;
|
||||
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
WHERETRACE(0x100,("equality scan regions: %d (%llu)\n", a[1],
|
||||
sqlite3LogEstToInt(a[1])));
|
||||
WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
|
||||
*pnRow = a[1];
|
||||
|
||||
return rc;
|
||||
@@ -2663,28 +2664,27 @@ static int whereInScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
WhereLoopBuilder *pBuilder,
|
||||
ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
|
||||
LogEst *pnRow /* Write the revised row estimate here */
|
||||
tRowcnt *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
Index *p = pBuilder->pNew->u.btree.pIndex;
|
||||
int nRecValid = pBuilder->nRecValid;
|
||||
int rc = SQLITE_OK; /* Subfunction return code */
|
||||
LogEst nEst; /* Number of rows for a single term */
|
||||
u64 nRowEst = 0; /* New estimate of the number of rows */
|
||||
tRowcnt nEst; /* Number of rows for a single term */
|
||||
tRowcnt nRowEst = 0; /* New estimate of the number of rows */
|
||||
int i; /* Loop counter */
|
||||
|
||||
assert( p->aSample!=0 );
|
||||
for(i=0; rc==SQLITE_OK && i<pList->nExpr; i++){
|
||||
nEst = p->aiRowEst[0];
|
||||
rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst);
|
||||
nRowEst += sqlite3LogEstToInt(nEst);
|
||||
nRowEst += nEst;
|
||||
pBuilder->nRecValid = nRecValid;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
nEst = sqlite3LogEst(nRowEst);
|
||||
if( nEst > p->aiRowEst[0] ) nEst = p->aiRowEst[0];
|
||||
*pnRow = nEst;
|
||||
WHERETRACE(0x100,("IN row estimate: est=%d (%llu)\n", nEst, nRowEst));
|
||||
if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
|
||||
*pnRow = nRowEst;
|
||||
WHERETRACE(0x100,("IN row estimate: est=%g\n", nRowEst));
|
||||
}
|
||||
assert( pBuilder->nRecValid==nRecValid );
|
||||
return rc;
|
||||
@@ -4185,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;
|
||||
@@ -4254,8 +4254,8 @@ 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 = pProbe->aiRowEst[pNew->u.btree.nEq+1];
|
||||
if( nRowEst<10 && pProbe->onError==OE_None ) nRowEst = 10;
|
||||
nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
|
||||
if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
|
||||
}else{
|
||||
iCol = -1;
|
||||
nRowEst = 0;
|
||||
@@ -4268,7 +4268,7 @@ static int whereLoopAddBtreeIndex(
|
||||
saved_prereq = pNew->prereq;
|
||||
saved_nOut = pNew->nOut;
|
||||
pNew->rSetup = 0;
|
||||
rLogSize = estLog(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
|
||||
@@ -4340,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
|
||||
@@ -4349,7 +4349,7 @@ static int whereLoopAddBtreeIndex(
|
||||
&& OptimizationEnabled(db, SQLITE_Stat3)
|
||||
){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
LogEst nOut = pNew->nOut;
|
||||
tRowcnt nOut = 0;
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){
|
||||
testcase( pTerm->eOperator & WO_EQ );
|
||||
testcase( pTerm->eOperator & WO_ISNULL );
|
||||
@@ -4358,8 +4358,11 @@ static int whereLoopAddBtreeIndex(
|
||||
&& !ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
|
||||
}
|
||||
assert( nOut==pNew->nOut || rc==SQLITE_OK );
|
||||
if( nOut<pNew->nOut ) pNew->nOut = nOut;
|
||||
assert( nOut==0 || rc==SQLITE_OK );
|
||||
if( nOut ){
|
||||
pNew->nOut = sqlite3LogEst(nOut);
|
||||
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
||||
@@ -4369,7 +4372,7 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
/* Step cost for each output row */
|
||||
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut);
|
||||
whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor);
|
||||
whereLoopOutputAdjust(pBuilder->pWC, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
|
||||
&& pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0))
|
||||
@@ -4460,7 +4463,7 @@ static int whereLoopAddBtree(
|
||||
WhereInfo *pWInfo; /* WHERE analysis context */
|
||||
Index *pProbe; /* An index we are evaluating */
|
||||
Index sPk; /* A fake index object for the primary key */
|
||||
LogEst aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
|
||||
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
|
||||
int aiColumnPk = -1; /* The aColumn[] value for the sPk index */
|
||||
SrcList *pTabList; /* The FROM clause */
|
||||
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
|
||||
@@ -4471,11 +4474,13 @@ static int whereLoopAddBtree(
|
||||
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) );
|
||||
|
||||
@@ -4493,9 +4498,9 @@ static int whereLoopAddBtree(
|
||||
sPk.aiColumn = &aiColumnPk;
|
||||
sPk.aiRowEst = aiRowEstPk;
|
||||
sPk.onError = OE_Replace;
|
||||
sPk.pTable = pSrc->pTab;
|
||||
aiRowEstPk[0] = pSrc->pTab->nRowEst;
|
||||
aiRowEstPk[1] = 0;
|
||||
sPk.pTable = pTab;
|
||||
aiRowEstPk[0] = pTab->nRowEst;
|
||||
aiRowEstPk[1] = 1;
|
||||
pFirst = pSrc->pTab->pIndex;
|
||||
if( pSrc->notIndexed==0 ){
|
||||
/* The real indices of the table are only considered if the
|
||||
@@ -4504,7 +4509,7 @@ static int whereLoopAddBtree(
|
||||
}
|
||||
pProbe = &sPk;
|
||||
}
|
||||
rSize = pSrc->pTab->nRowEst;
|
||||
rSize = sqlite3LogEst(pTab->nRowEst);
|
||||
rLogSize = estLog(rSize);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
@@ -4571,7 +4576,7 @@ static int whereLoopAddBtree(
|
||||
** + The extra 3 factor is to encourage the use of indexed lookups
|
||||
** over full scans. FIXME */
|
||||
pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16;
|
||||
whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
if( rc ) break;
|
||||
@@ -4583,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)
|
||||
@@ -4591,18 +4597,19 @@ static int whereLoopAddBtree(
|
||||
pNew->iSortIdx = b ? iSortIdx : 0;
|
||||
if( m==0 ){
|
||||
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
|
||||
** + The extra factor K of between 1.1 (iScanRatio between 0
|
||||
** and 9) and 2.8 (iScanRatio between 126 and 127) is added
|
||||
** to encourage the use of indexed lookups. FIXME
|
||||
** + 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) + 10;
|
||||
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;
|
||||
@@ -4812,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
|
||||
@@ -4823,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;
|
||||
@@ -5262,8 +5269,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst 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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+7
-7
@@ -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.
|
||||
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
#
|
||||
# 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
|
||||
set testprefix fkey5
|
||||
|
||||
ifcapable {!foreignkey} {
|
||||
finish_test
|
||||
@@ -82,6 +85,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 +116,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 {
|
||||
@@ -306,5 +326,38 @@ do_test fkey5-8.7 {
|
||||
} {}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests 9.* verify that missing parent tables are handled correctly.
|
||||
#
|
||||
do_execsql_test 9.1.1 {
|
||||
CREATE TABLE k1(x REFERENCES s1);
|
||||
PRAGMA foreign_key_check(k1);
|
||||
} {}
|
||||
do_execsql_test 9.1.2 {
|
||||
INSERT INTO k1 VALUES(NULL);
|
||||
PRAGMA foreign_key_check(k1);
|
||||
} {}
|
||||
do_execsql_test 9.1.3 {
|
||||
INSERT INTO k1 VALUES(1);
|
||||
PRAGMA foreign_key_check(k1);
|
||||
} {k1 2 s1 0}
|
||||
|
||||
do_execsql_test 9.2.1 {
|
||||
CREATE TABLE k2(x, y, FOREIGN KEY(x, y) REFERENCES s1(a, b));
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {}
|
||||
do_execsql_test 9.2 {
|
||||
INSERT INTO k2 VALUES(NULL, 'five');
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {}
|
||||
do_execsql_test 9.3 {
|
||||
INSERT INTO k2 VALUES('one', NULL);
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {}
|
||||
do_execsql_test 9.4 {
|
||||
INSERT INTO k2 VALUES('six', 'seven');
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {k2 3 s1 0}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+79
-6
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
# 2011 January 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
set ::testprefix fts3aux2
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=l);
|
||||
INSERT INTO t1(a, b, l) VALUES
|
||||
('zero zero', 'zero zero', 0),
|
||||
('one two', 'three four', 1),
|
||||
('five six', 'seven eight', 2)
|
||||
;
|
||||
CREATE VIRTUAL TABLE terms USING fts4aux(t1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.1 {
|
||||
SELECT term, documents, occurrences, languageid FROM terms WHERE col = '*';
|
||||
} {zero 1 4 0}
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
SELECT * FROM terms;
|
||||
} {zero * 1 4 zero 0 1 2 zero 1 1 2}
|
||||
|
||||
do_execsql_test 1.2.3 {
|
||||
SELECT * FROM terms WHERE languageid='';
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.4 {
|
||||
SELECT * FROM terms WHERE languageid=-1;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.5 {
|
||||
SELECT * FROM terms WHERE languageid=9223372036854775807;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.6 {
|
||||
SELECT * FROM terms WHERE languageid=-9223372036854775808;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2.7 {
|
||||
SELECT * FROM terms WHERE languageid=NULL;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.3.1 {
|
||||
SELECT term, documents, occurrences, languageid
|
||||
FROM terms WHERE col = '*' AND languageid=1;
|
||||
} {
|
||||
four 1 1 1 one 1 1 1 three 1 1 1 two 1 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3.2 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid=1;
|
||||
} {
|
||||
four * 1 1 1 four 1 1 1 1
|
||||
one * 1 1 1 one 0 1 1 1
|
||||
three * 1 1 1 three 1 1 1 1
|
||||
two * 1 1 1 two 0 1 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3.3 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid=1 AND term='zero'
|
||||
} {
|
||||
}
|
||||
|
||||
do_execsql_test 1.3.4 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid='1' AND term='two'
|
||||
} {
|
||||
two * 1 1 1 two 0 1 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3.5 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid='+1' AND term>'four'
|
||||
} {
|
||||
one * 1 1 1 one 0 1 1 1
|
||||
three * 1 1 1 three 1 1 1 1
|
||||
two * 1 1 1 two 0 1 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.1 {
|
||||
SELECT term, documents, occurrences, languageid
|
||||
FROM terms WHERE col = '*' AND languageid=2;
|
||||
} {
|
||||
eight 1 1 2 five 1 1 2 seven 1 1 2 six 1 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.2 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid=2;
|
||||
} {
|
||||
eight * 1 1 2 eight 1 1 1 2
|
||||
five * 1 1 2 five 0 1 1 2
|
||||
seven * 1 1 2 seven 1 1 1 2
|
||||
six * 1 1 2 six 0 1 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.3 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE languageid=2 AND term='five';
|
||||
} {
|
||||
five * 1 1 2 five 0 1 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.4 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE term='five' AND languageid=2
|
||||
} {
|
||||
five * 1 1 2 five 0 1 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.5 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE term>='seven' AND languageid=2
|
||||
} {
|
||||
seven * 1 1 2 seven 1 1 1 2
|
||||
six * 1 1 2 six 0 1 1 2
|
||||
}
|
||||
|
||||
do_execsql_test 1.4.6 {
|
||||
SELECT term, col, documents, occurrences, languageid
|
||||
FROM terms WHERE term>='e' AND term<'seven' AND languageid=2
|
||||
} {
|
||||
eight * 1 1 2 eight 1 1 1 2
|
||||
five * 1 1 2 five 0 1 1 2
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -50,4 +50,26 @@ foreach {tn q res} {
|
||||
puts "with optimization: $t(0) without: $t(1)"
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t2 USING fts4(order=DESC);
|
||||
}
|
||||
set num [list one two three four five six seven eight nine ten]
|
||||
execsql BEGIN
|
||||
for {set i 0} {$i < 10000} {incr i} {
|
||||
set x "[lindex $num [expr $i%10]] zero"
|
||||
execsql { INSERT INTO t2(docid, content) VALUES($i, $x) }
|
||||
}
|
||||
execsql COMMIT
|
||||
execsql { INSERT INTO t2(t2) VALUES('optimize') }
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT count(*) FROM t2 WHERE t2 MATCH '"never zero"'
|
||||
} {0}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT count(*) FROM t2 WHERE t2 MATCH '"two zero"'
|
||||
} {1000}
|
||||
|
||||
finish_test
|
||||
|
||||
+20
-15
@@ -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
|
||||
|
||||
+758
@@ -0,0 +1,758 @@
|
||||
# 2013 March 10
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The focus of
|
||||
# this file is testing the tointeger() and toreal() functions.
|
||||
#
|
||||
# Several of the toreal() tests are disabled on platforms where floating
|
||||
# point precision is not high enough to represent their constant integer
|
||||
# expression arguments as double precision floating point values.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set saved_tcl_precision $tcl_precision
|
||||
set tcl_precision 0
|
||||
load_static_extension db totype
|
||||
|
||||
set highPrecision(1) [expr \
|
||||
{[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}]
|
||||
|
||||
do_execsql_test func4-1.1 {
|
||||
SELECT tointeger(NULL);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.2 {
|
||||
SELECT tointeger('');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.3 {
|
||||
SELECT tointeger(' ');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.4 {
|
||||
SELECT tointeger('1234');
|
||||
} {1234}
|
||||
do_execsql_test func4-1.5 {
|
||||
SELECT tointeger(' 1234');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.6 {
|
||||
SELECT tointeger('bad');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.7 {
|
||||
SELECT tointeger('0xBAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.8 {
|
||||
SELECT tointeger('123BAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.9 {
|
||||
SELECT tointeger('0x123BAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.10 {
|
||||
SELECT tointeger('123NO');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.11 {
|
||||
SELECT tointeger('0x123NO');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.12 {
|
||||
SELECT tointeger('-0x1');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.13 {
|
||||
SELECT tointeger('-0x0');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.14 {
|
||||
SELECT tointeger('0x0');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.15 {
|
||||
SELECT tointeger('0x1');
|
||||
} {{}}
|
||||
do_execsql_test func4-1.16 {
|
||||
SELECT tointeger(-1);
|
||||
} {-1}
|
||||
do_execsql_test func4-1.17 {
|
||||
SELECT tointeger(-0);
|
||||
} {0}
|
||||
do_execsql_test func4-1.18 {
|
||||
SELECT tointeger(0);
|
||||
} {0}
|
||||
do_execsql_test func4-1.19 {
|
||||
SELECT tointeger(1);
|
||||
} {1}
|
||||
do_execsql_test func4-1.20 {
|
||||
SELECT tointeger(-1.79769313486232e308 - 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.21 {
|
||||
SELECT tointeger(-1.79769313486232e308);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.22 {
|
||||
SELECT tointeger(-1.79769313486232e308 + 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.23 {
|
||||
SELECT tointeger(-9223372036854775808 - 1);
|
||||
} {-9223372036854775808}
|
||||
do_execsql_test func4-1.24 {
|
||||
SELECT tointeger(-9223372036854775808);
|
||||
} {-9223372036854775808}
|
||||
do_execsql_test func4-1.25 {
|
||||
SELECT tointeger(-9223372036854775808 + 1);
|
||||
} {-9223372036854775807}
|
||||
do_execsql_test func4-1.26 {
|
||||
SELECT tointeger(-9223372036854775807 - 1);
|
||||
} {-9223372036854775808}
|
||||
do_execsql_test func4-1.27 {
|
||||
SELECT tointeger(-9223372036854775807);
|
||||
} {-9223372036854775807}
|
||||
do_execsql_test func4-1.28 {
|
||||
SELECT tointeger(-9223372036854775807 + 1);
|
||||
} {-9223372036854775806}
|
||||
do_execsql_test func4-1.29 {
|
||||
SELECT tointeger(-2147483648 - 1);
|
||||
} {-2147483649}
|
||||
do_execsql_test func4-1.30 {
|
||||
SELECT tointeger(-2147483648);
|
||||
} {-2147483648}
|
||||
do_execsql_test func4-1.31 {
|
||||
SELECT tointeger(-2147483648 + 1);
|
||||
} {-2147483647}
|
||||
do_execsql_test func4-1.32 {
|
||||
SELECT tointeger(2147483647 - 1);
|
||||
} {2147483646}
|
||||
do_execsql_test func4-1.33 {
|
||||
SELECT tointeger(2147483647);
|
||||
} {2147483647}
|
||||
do_execsql_test func4-1.34 {
|
||||
SELECT tointeger(2147483647 + 1);
|
||||
} {2147483648}
|
||||
do_execsql_test func4-1.35 {
|
||||
SELECT tointeger(9223372036854775807 - 1);
|
||||
} {9223372036854775806}
|
||||
do_execsql_test func4-1.36 {
|
||||
SELECT tointeger(9223372036854775807);
|
||||
} {9223372036854775807}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-1.37 {
|
||||
SELECT tointeger(9223372036854775807 + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-1.38 {
|
||||
SELECT tointeger(1.79769313486232e308 - 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.39 {
|
||||
SELECT tointeger(1.79769313486232e308);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.40 {
|
||||
SELECT tointeger(1.79769313486232e308 + 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.41 {
|
||||
SELECT tointeger(4503599627370496 - 1);
|
||||
} {4503599627370495}
|
||||
do_execsql_test func4-1.42 {
|
||||
SELECT tointeger(4503599627370496);
|
||||
} {4503599627370496}
|
||||
do_execsql_test func4-1.43 {
|
||||
SELECT tointeger(4503599627370496 + 1);
|
||||
} {4503599627370497}
|
||||
do_execsql_test func4-1.44 {
|
||||
SELECT tointeger(9007199254740992 - 1);
|
||||
} {9007199254740991}
|
||||
do_execsql_test func4-1.45 {
|
||||
SELECT tointeger(9007199254740992);
|
||||
} {9007199254740992}
|
||||
do_execsql_test func4-1.46 {
|
||||
SELECT tointeger(9007199254740992 + 1);
|
||||
} {9007199254740993}
|
||||
do_execsql_test func4-1.47 {
|
||||
SELECT tointeger(9223372036854775807 - 1);
|
||||
} {9223372036854775806}
|
||||
do_execsql_test func4-1.48 {
|
||||
SELECT tointeger(9223372036854775807);
|
||||
} {9223372036854775807}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-1.49 {
|
||||
SELECT tointeger(9223372036854775807 + 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.50 {
|
||||
SELECT tointeger(9223372036854775808 - 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.51 {
|
||||
SELECT tointeger(9223372036854775808);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.52 {
|
||||
SELECT tointeger(9223372036854775808 + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-1.53 {
|
||||
SELECT tointeger(18446744073709551616 - 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.54 {
|
||||
SELECT tointeger(18446744073709551616);
|
||||
} {{}}
|
||||
do_execsql_test func4-1.55 {
|
||||
SELECT tointeger(18446744073709551616 + 1);
|
||||
} {{}}
|
||||
|
||||
ifcapable floatingpoint {
|
||||
set highPrecision(2) [expr \
|
||||
{[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]
|
||||
|
||||
do_execsql_test func4-2.1 {
|
||||
SELECT toreal(NULL);
|
||||
} {{}}
|
||||
do_execsql_test func4-2.2 {
|
||||
SELECT toreal('');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.3 {
|
||||
SELECT toreal(' ');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.4 {
|
||||
SELECT toreal('1234');
|
||||
} {1234.0}
|
||||
do_execsql_test func4-2.5 {
|
||||
SELECT toreal(' 1234');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.6 {
|
||||
SELECT toreal('bad');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.7 {
|
||||
SELECT toreal('0xBAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.8 {
|
||||
SELECT toreal('123BAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.9 {
|
||||
SELECT toreal('0x123BAD');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.10 {
|
||||
SELECT toreal('123NO');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.11 {
|
||||
SELECT toreal('0x123NO');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.12 {
|
||||
SELECT toreal('-0x1');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.13 {
|
||||
SELECT toreal('-0x0');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.14 {
|
||||
SELECT toreal('0x0');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.15 {
|
||||
SELECT toreal('0x1');
|
||||
} {{}}
|
||||
do_execsql_test func4-2.16 {
|
||||
SELECT toreal(-1);
|
||||
} {-1.0}
|
||||
do_execsql_test func4-2.17 {
|
||||
SELECT toreal(-0);
|
||||
} {0.0}
|
||||
do_execsql_test func4-2.18 {
|
||||
SELECT toreal(0);
|
||||
} {0.0}
|
||||
do_execsql_test func4-2.19 {
|
||||
SELECT toreal(1);
|
||||
} {1.0}
|
||||
do_execsql_test func4-2.20 {
|
||||
SELECT toreal(-1.79769313486232e308 - 1);
|
||||
} {-Inf}
|
||||
do_execsql_test func4-2.21 {
|
||||
SELECT toreal(-1.79769313486232e308);
|
||||
} {-Inf}
|
||||
do_execsql_test func4-2.22 {
|
||||
SELECT toreal(-1.79769313486232e308 + 1);
|
||||
} {-Inf}
|
||||
do_execsql_test func4-2.23 {
|
||||
SELECT toreal(-9223372036854775808 - 1);
|
||||
} {-9.223372036854776e+18}
|
||||
do_execsql_test func4-2.24 {
|
||||
SELECT toreal(-9223372036854775808);
|
||||
} {-9.223372036854776e+18}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-2.25 {
|
||||
SELECT toreal(-9223372036854775808 + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-2.26 {
|
||||
SELECT toreal(-9223372036854775807 - 1);
|
||||
} {-9.223372036854776e+18}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-2.27 {
|
||||
SELECT toreal(-9223372036854775807);
|
||||
} {{}}
|
||||
do_execsql_test func4-2.28 {
|
||||
SELECT toreal(-9223372036854775807 + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-2.29 {
|
||||
SELECT toreal(-2147483648 - 1);
|
||||
} {-2147483649.0}
|
||||
do_execsql_test func4-2.30 {
|
||||
SELECT toreal(-2147483648);
|
||||
} {-2147483648.0}
|
||||
do_execsql_test func4-2.31 {
|
||||
SELECT toreal(-2147483648 + 1);
|
||||
} {-2147483647.0}
|
||||
do_execsql_test func4-2.32 {
|
||||
SELECT toreal(2147483647 - 1);
|
||||
} {2147483646.0}
|
||||
do_execsql_test func4-2.33 {
|
||||
SELECT toreal(2147483647);
|
||||
} {2147483647.0}
|
||||
do_execsql_test func4-2.34 {
|
||||
SELECT toreal(2147483647 + 1);
|
||||
} {2147483648.0}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-2.35 {
|
||||
SELECT toreal(9223372036854775807 - 1);
|
||||
} {{}}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-2.36 {
|
||||
SELECT toreal(9223372036854775807);
|
||||
} {{}}
|
||||
}
|
||||
}
|
||||
do_execsql_test func4-2.37 {
|
||||
SELECT toreal(9223372036854775807 + 1);
|
||||
} {9.223372036854776e+18}
|
||||
do_execsql_test func4-2.38 {
|
||||
SELECT toreal(1.79769313486232e308 - 1);
|
||||
} {Inf}
|
||||
do_execsql_test func4-2.39 {
|
||||
SELECT toreal(1.79769313486232e308);
|
||||
} {Inf}
|
||||
do_execsql_test func4-2.40 {
|
||||
SELECT toreal(1.79769313486232e308 + 1);
|
||||
} {Inf}
|
||||
do_execsql_test func4-2.41 {
|
||||
SELECT toreal(4503599627370496 - 1);
|
||||
} {4503599627370495.0}
|
||||
do_execsql_test func4-2.42 {
|
||||
SELECT toreal(4503599627370496);
|
||||
} {4503599627370496.0}
|
||||
do_execsql_test func4-2.43 {
|
||||
SELECT toreal(4503599627370496 + 1);
|
||||
} {4503599627370497.0}
|
||||
do_execsql_test func4-2.44 {
|
||||
SELECT toreal(9007199254740992 - 1);
|
||||
} {9007199254740991.0}
|
||||
do_execsql_test func4-2.45 {
|
||||
SELECT toreal(9007199254740992);
|
||||
} {9007199254740992.0}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-2.46 {
|
||||
SELECT toreal(9007199254740992 + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-2.47 {
|
||||
SELECT toreal(9007199254740992 + 2);
|
||||
} {9007199254740994.0}
|
||||
do_execsql_test func4-2.48 {
|
||||
SELECT toreal(tointeger(9223372036854775808) - 1);
|
||||
} {{}}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-2.49 {
|
||||
SELECT toreal(tointeger(9223372036854775808));
|
||||
} {{}}
|
||||
do_execsql_test func4-2.50 {
|
||||
SELECT toreal(tointeger(9223372036854775808) + 1);
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-2.51 {
|
||||
SELECT toreal(tointeger(18446744073709551616) - 1);
|
||||
} {{}}
|
||||
do_execsql_test func4-2.52 {
|
||||
SELECT toreal(tointeger(18446744073709551616));
|
||||
} {{}}
|
||||
do_execsql_test func4-2.53 {
|
||||
SELECT toreal(tointeger(18446744073709551616) + 1);
|
||||
} {{}}
|
||||
}
|
||||
|
||||
ifcapable check {
|
||||
do_execsql_test func4-3.1 {
|
||||
CREATE TABLE t1(
|
||||
x INTEGER CHECK(tointeger(x) IS NOT NULL)
|
||||
);
|
||||
} {}
|
||||
do_test func4-3.2 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.3 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.4 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.5 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.6 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('1234bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.7 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('1234.56bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.8 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (1234);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-3.9 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (1234.56);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.10 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('1234');
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-3.11 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('1234.56');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.12 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (ZEROBLOB(4));
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.13 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (X'');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.14 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (X'1234');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.15 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (X'12345678');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.16 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('1234.00');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-3.17 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (1234.00);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-3.18 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES ('-9223372036854775809');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
if {$highPrecision(1)} {
|
||||
do_test func4-3.19 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES (9223372036854775808);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
}
|
||||
do_execsql_test func4-3.20 {
|
||||
SELECT x FROM t1 ORDER BY x;
|
||||
} {1234 1234 1234}
|
||||
|
||||
ifcapable floatingpoint {
|
||||
do_execsql_test func4-4.1 {
|
||||
CREATE TABLE t2(
|
||||
x REAL CHECK(toreal(x) IS NOT NULL)
|
||||
);
|
||||
} {}
|
||||
do_test func4-4.2 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.3 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.4 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.5 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.6 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('1234bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.7 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('1234.56bad');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.8 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (1234);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-4.9 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (1234.56);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-4.10 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('1234');
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-4.11 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES ('1234.56');
|
||||
}
|
||||
} {0 {}}
|
||||
do_test func4-4.12 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (ZEROBLOB(4));
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.13 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (X'');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.14 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (X'1234');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test func4-4.15 {
|
||||
catchsql {
|
||||
INSERT INTO t2 (x) VALUES (X'12345678');
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_execsql_test func4-4.16 {
|
||||
SELECT x FROM t2 ORDER BY x;
|
||||
} {1234.0 1234.0 1234.56 1234.56}
|
||||
}
|
||||
}
|
||||
|
||||
ifcapable floatingpoint {
|
||||
do_execsql_test func4-5.1 {
|
||||
SELECT tointeger(toreal('1234'));
|
||||
} {1234}
|
||||
do_execsql_test func4-5.2 {
|
||||
SELECT tointeger(toreal(-1));
|
||||
} {-1}
|
||||
do_execsql_test func4-5.3 {
|
||||
SELECT tointeger(toreal(-0));
|
||||
} {0}
|
||||
do_execsql_test func4-5.4 {
|
||||
SELECT tointeger(toreal(0));
|
||||
} {0}
|
||||
do_execsql_test func4-5.5 {
|
||||
SELECT tointeger(toreal(1));
|
||||
} {1}
|
||||
do_execsql_test func4-5.6 {
|
||||
SELECT tointeger(toreal(-9223372036854775808 - 1));
|
||||
} {-9223372036854775808}
|
||||
do_execsql_test func4-5.7 {
|
||||
SELECT tointeger(toreal(-9223372036854775808));
|
||||
} {-9223372036854775808}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-5.8 {
|
||||
SELECT tointeger(toreal(-9223372036854775808 + 1));
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-5.9 {
|
||||
SELECT tointeger(toreal(-2147483648 - 1));
|
||||
} {-2147483649}
|
||||
do_execsql_test func4-5.10 {
|
||||
SELECT tointeger(toreal(-2147483648));
|
||||
} {-2147483648}
|
||||
do_execsql_test func4-5.11 {
|
||||
SELECT tointeger(toreal(-2147483648 + 1));
|
||||
} {-2147483647}
|
||||
do_execsql_test func4-5.12 {
|
||||
SELECT tointeger(toreal(2147483647 - 1));
|
||||
} {2147483646}
|
||||
do_execsql_test func4-5.13 {
|
||||
SELECT tointeger(toreal(2147483647));
|
||||
} {2147483647}
|
||||
do_execsql_test func4-5.14 {
|
||||
SELECT tointeger(toreal(2147483647 + 1));
|
||||
} {2147483648}
|
||||
do_execsql_test func4-5.15 {
|
||||
SELECT tointeger(toreal(9223372036854775807 - 1));
|
||||
} {{}}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-5.16 {
|
||||
SELECT tointeger(toreal(9223372036854775807));
|
||||
} {{}}
|
||||
do_execsql_test func4-5.17 {
|
||||
SELECT tointeger(toreal(9223372036854775807 + 1));
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-5.18 {
|
||||
SELECT tointeger(toreal(4503599627370496 - 1));
|
||||
} {4503599627370495}
|
||||
do_execsql_test func4-5.19 {
|
||||
SELECT tointeger(toreal(4503599627370496));
|
||||
} {4503599627370496}
|
||||
do_execsql_test func4-5.20 {
|
||||
SELECT tointeger(toreal(4503599627370496 + 1));
|
||||
} {4503599627370497}
|
||||
do_execsql_test func4-5.21 {
|
||||
SELECT tointeger(toreal(9007199254740992 - 1));
|
||||
} {9007199254740991}
|
||||
do_execsql_test func4-5.22 {
|
||||
SELECT tointeger(toreal(9007199254740992));
|
||||
} {9007199254740992}
|
||||
if {$highPrecision(2)} {
|
||||
do_execsql_test func4-5.23 {
|
||||
SELECT tointeger(toreal(9007199254740992 + 1));
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-5.24 {
|
||||
SELECT tointeger(toreal(9007199254740992 + 2));
|
||||
} {9007199254740994}
|
||||
if {$highPrecision(1)} {
|
||||
do_execsql_test func4-5.25 {
|
||||
SELECT tointeger(toreal(9223372036854775808 - 1));
|
||||
} {{}}
|
||||
do_execsql_test func4-5.26 {
|
||||
SELECT tointeger(toreal(9223372036854775808));
|
||||
} {{}}
|
||||
do_execsql_test func4-5.27 {
|
||||
SELECT tointeger(toreal(9223372036854775808 + 1));
|
||||
} {{}}
|
||||
}
|
||||
do_execsql_test func4-5.28 {
|
||||
SELECT tointeger(toreal(18446744073709551616 - 1));
|
||||
} {{}}
|
||||
do_execsql_test func4-5.29 {
|
||||
SELECT tointeger(toreal(18446744073709551616));
|
||||
} {{}}
|
||||
do_execsql_test func4-5.30 {
|
||||
SELECT tointeger(toreal(18446744073709551616 + 1));
|
||||
} {{}}
|
||||
}
|
||||
|
||||
for {set i 0} {$i < 10} {incr i} {
|
||||
if {$i == 8} continue
|
||||
do_execsql_test func4-6.1.$i.1 [subst {
|
||||
SELECT tointeger(x'[string repeat 01 $i]');
|
||||
}] {{}}
|
||||
ifcapable floatingpoint {
|
||||
do_execsql_test func4-6.1.$i.2 [subst {
|
||||
SELECT toreal(x'[string repeat 01 $i]');
|
||||
}] {{}}
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test func4-6.2.1 {
|
||||
SELECT tointeger(x'0102030405060708');
|
||||
} {578437695752307201}
|
||||
do_execsql_test func4-6.2.2 {
|
||||
SELECT tointeger(x'0807060504030201');
|
||||
} {72623859790382856}
|
||||
|
||||
ifcapable floatingpoint {
|
||||
do_execsql_test func4-6.3.1 {
|
||||
SELECT toreal(x'ffefffffffffffff');
|
||||
} {-1.7976931348623157e+308}
|
||||
do_execsql_test func4-6.3.2 {
|
||||
SELECT toreal(x'8010000000000000');
|
||||
} {-2.2250738585072014e-308}
|
||||
do_execsql_test func4-6.3.3 {
|
||||
SELECT toreal(x'c000000000000000');
|
||||
} {-2.0}
|
||||
do_execsql_test func4-6.3.4 {
|
||||
SELECT toreal(x'bff0000000000000');
|
||||
} {-1.0}
|
||||
do_execsql_test func4-6.3.5 {
|
||||
SELECT toreal(x'8000000000000000');
|
||||
} {-0.0}
|
||||
do_execsql_test func4-6.3.6 {
|
||||
SELECT toreal(x'0000000000000000');
|
||||
} {0.0}
|
||||
do_execsql_test func4-6.3.7 {
|
||||
SELECT toreal(x'3ff0000000000000');
|
||||
} {1.0}
|
||||
do_execsql_test func4-6.3.8 {
|
||||
SELECT toreal(x'4000000000000000');
|
||||
} {2.0}
|
||||
do_execsql_test func4-6.3.9 {
|
||||
SELECT toreal(x'0010000000000000');
|
||||
} {2.2250738585072014e-308}
|
||||
do_execsql_test func4-6.3.10 {
|
||||
SELECT toreal(x'7fefffffffffffff');
|
||||
} {1.7976931348623157e+308}
|
||||
do_execsql_test func4-6.3.11 {
|
||||
SELECT toreal(x'8000000000000001');
|
||||
} {-5e-324}
|
||||
do_execsql_test func4-6.3.12 {
|
||||
SELECT toreal(x'800fffffffffffff');
|
||||
} {-2.225073858507201e-308}
|
||||
do_execsql_test func4-6.3.13 {
|
||||
SELECT toreal(x'0000000000000001');
|
||||
} {5e-324}
|
||||
do_execsql_test func4-6.3.14 {
|
||||
SELECT toreal(x'000fffffffffffff');
|
||||
} {2.225073858507201e-308}
|
||||
do_execsql_test func4-6.3.15 {
|
||||
SELECT toreal(x'fff0000000000000');
|
||||
} {-Inf}
|
||||
do_execsql_test func4-6.3.16 {
|
||||
SELECT toreal(x'7ff0000000000000');
|
||||
} {Inf}
|
||||
do_execsql_test func4-6.3.17 {
|
||||
SELECT toreal(x'fff8000000000000');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.18 {
|
||||
SELECT toreal(x'fff0000000000001');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.19 {
|
||||
SELECT toreal(x'fff7ffffffffffff');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.20 {
|
||||
SELECT toreal(x'7ff0000000000001');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.21 {
|
||||
SELECT toreal(x'7ff7ffffffffffff');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.22 {
|
||||
SELECT toreal(x'fff8000000000001');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.23 {
|
||||
SELECT toreal(x'ffffffffffffffff');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.24 {
|
||||
SELECT toreal(x'7ff8000000000000');
|
||||
} {{}}
|
||||
do_execsql_test func4-6.3.25 {
|
||||
SELECT toreal(x'7fffffffffffffff');
|
||||
} {{}}
|
||||
}
|
||||
|
||||
set tcl_precision $saved_tcl_precision
|
||||
unset saved_tcl_precision
|
||||
finish_test
|
||||
+43
-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:
|
||||
|
||||
+3
-3
@@ -574,7 +574,7 @@ ifcapable {foreignkey} {
|
||||
execsql {
|
||||
pragma index_list(t3);
|
||||
}
|
||||
} {/0 sqlite_autoindex_t3_1 1 \d+/}
|
||||
} {0 sqlite_autoindex_t3_1 1}
|
||||
}
|
||||
ifcapable {!foreignkey} {
|
||||
execsql {CREATE TABLE t3(a,b UNIQUE)}
|
||||
@@ -647,7 +647,7 @@ do_test pragma-7.1.1 {
|
||||
execsql {
|
||||
pragma index_list(t3);
|
||||
}
|
||||
} {/0 t3i1 0 \d+ 1 sqlite_autoindex_t3_1 1 \d+/}
|
||||
} {0 t3i1 0 1 sqlite_autoindex_t3_1 1}
|
||||
do_test pragma-7.1.2 {
|
||||
execsql {
|
||||
pragma index_list(t3_bogus);
|
||||
@@ -1661,7 +1661,7 @@ do_test 23.3 {
|
||||
CREATE INDEX i3 ON t1(d,b,c);
|
||||
}
|
||||
db2 eval {PRAGMA index_list(t1)}
|
||||
} {/0 i3 0 \d+ 1 i2 0 \d+ 2 i1 0 \d+/}
|
||||
} {0 i3 0 1 i2 0 2 i1 0}
|
||||
do_test 23.4 {
|
||||
db eval {
|
||||
ALTER TABLE t1 ADD COLUMN e;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -172,6 +172,10 @@ set pragma_def {
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+11
-1
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+2
-2
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user