Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -20,15 +20,19 @@ # C Compiler and options for use in building executables that # will run on the platform that is doing the build. # BCC = @BUILD_CC@ @BUILD_CFLAGS@ -# C Compile and options for use in building executables that +# TCC is the C Compile and options for use in building executables that # will run on the target platform. (BCC and TCC are usually the -# same unless your are cross-compiling.) +# same unless your are cross-compiling.) Separate CC and CFLAGS macros +# are provide so that these aspects of the build process can be changed +# on the "make" command-line. Ex: "make CC=clang CFLAGS=-fsanitize=undefined" # -TCC = @CC@ @CPPFLAGS@ @CFLAGS@ -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu +CC = @CC@ +CFLAGS = @CPPFLAGS@ @CFLAGS@ +TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session # Define this for the autoconf-based build, so that the code knows it can # include the generated config.h # @@ -937,22 +941,40 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \ -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) - +# A very detailed test running most or all test cases fulltest: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/all.test +# Really really long testing soaktest: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 +# Do extra testing but not aeverything. fulltestonly: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/full.test +# This is the common case. Run many tests but not those that take +# a really long time. +# test: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/veryquick.test + +# Run a test using valgrind. This can take a really long time +# because valgrind is so much slower than a native machine. +# +valgrindtest: testfixture$(TEXE) sqlite3$(TEXE) + OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind + +# A very fast test that checks basic sanity. The name comes from +# the 60s-era electronics testing: "Turn it on and see if smoke +# comes out." +# +smoketest: testfixture$(TEXE) + ./testfixture$(TEXE) $(TOP)/test/main.test sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ echo "static const char *tclsh_main_loop(void){" >> $@ Index: ext/misc/fuzzer.c ================================================================== --- ext/misc/fuzzer.c +++ ext/misc/fuzzer.c @@ -340,11 +340,12 @@ pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo ); if( pRule==0 ){ rc = SQLITE_NOMEM; }else{ memset(pRule, 0, sizeof(*pRule)); - pRule->zFrom = &pRule->zTo[nTo+1]; + pRule->zFrom = pRule->zTo; + pRule->zFrom += nTo + 1; pRule->nFrom = nFrom; memcpy(pRule->zFrom, zFrom, nFrom+1); memcpy(pRule->zTo, zTo, nTo+1); pRule->nTo = nTo; pRule->rCost = nCost; Index: ext/rtree/rtree.c ================================================================== --- ext/rtree/rtree.c +++ ext/rtree/rtree.c @@ -1180,11 +1180,11 @@ } i = pCur->nPoint++; pNew = pCur->aPoint + i; pNew->rScore = rScore; pNew->iLevel = iLevel; - assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH ); + assert( iLevel<=RTREE_MAX_DEPTH ); while( i>0 ){ RtreeSearchPoint *pParent; j = (i-1)/2; pParent = pCur->aPoint + j; if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; Index: src/analyze.c ================================================================== --- src/analyze.c +++ src/analyze.c @@ -446,11 +446,11 @@ p->iGet = -1; p->mxSample = mxSample; p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; - p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565; + p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); /* Set up the Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; p->aBest = &p->a[mxSample]; pSpace = (u8*)(&p->a[mxSample+nCol]); Index: src/global.c ================================================================== --- src/global.c +++ src/global.c @@ -150,10 +150,17 @@ */ #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif +/* The minimum PMA size is set to this value multiplied by the database +** page size in bytes. +*/ +#ifndef SQLITE_SORTER_PMASZ +# define SQLITE_SORTER_PMASZ 250 +#endif + /* ** The following singleton contains the global configuration for ** the SQLite library. */ SQLITE_WSD struct Sqlite3Config sqlite3Config = { @@ -180,10 +187,11 @@ (void*)0, /* pPage */ 0, /* szPage */ 0, /* nPage */ 0, /* mxParserStack */ 0, /* sharedCacheEnabled */ + SQLITE_SORTER_PMASZ, /* szPma */ /* All the rest should always be initialized to zero */ 0, /* isInit */ 0, /* inProgress */ 0, /* isMutexInit */ 0, /* isMallocInit */ Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -591,10 +591,15 @@ ** heap. */ sqlite3GlobalConfig.nHeap = va_arg(ap, int); break; } #endif + + case SQLITE_CONFIG_PMASZ: { + sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); + break; + } default: { rc = SQLITE_ERROR; break; } Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -3715,22 +3715,23 @@ ** at offset (nSize-1), to set the size of the file correctly. ** This is a similar technique to that used by glibc on systems ** that do not have a real fallocate() call. */ int nBlk = buf.st_blksize; /* File-system block size */ + int nWrite = 0; /* Number of bytes written by seekAndWrite */ i64 iWrite; /* Next offset to write to */ iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1; assert( iWrite>=buf.st_size ); assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) ); assert( ((iWrite+1)%nBlk)==0 ); for(/*no-op*/; iWritepWith = W; if( p->pPrior ){ + u16 allValues = SF_Values; pNext = 0; for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; + allValues &= pLoop->selFlags; } - mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; - if( mxSelect && cnt>mxSelect ){ + if( allValues ){ + p->selFlags |= SF_AllValues; + }else if( + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 + && cnt>mxSelect + ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } }else{ sqlite3WithDelete(pParse->db, W); Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -56,24 +56,29 @@ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* -** Delete all the content of a Select structure but do not deallocate -** the select structure itself. +** Delete all the content of a Select structure. Deallocate the structure +** itself only if bFree is true. */ -static void clearSelect(sqlite3 *db, Select *p){ - sqlite3ExprListDelete(db, p->pEList); - sqlite3SrcListDelete(db, p->pSrc); - sqlite3ExprDelete(db, p->pWhere); - sqlite3ExprListDelete(db, p->pGroupBy); - sqlite3ExprDelete(db, p->pHaving); - sqlite3ExprListDelete(db, p->pOrderBy); - sqlite3SelectDelete(db, p->pPrior); - sqlite3ExprDelete(db, p->pLimit); - sqlite3ExprDelete(db, p->pOffset); - sqlite3WithDelete(db, p->pWith); +static void clearSelect(sqlite3 *db, Select *p, int bFree){ + while( p ){ + Select *pPrior = p->pPrior; + sqlite3ExprListDelete(db, p->pEList); + sqlite3SrcListDelete(db, p->pSrc); + sqlite3ExprDelete(db, p->pWhere); + sqlite3ExprListDelete(db, p->pGroupBy); + sqlite3ExprDelete(db, p->pHaving); + sqlite3ExprListDelete(db, p->pOrderBy); + sqlite3ExprDelete(db, p->pLimit); + sqlite3ExprDelete(db, p->pOffset); + sqlite3WithDelete(db, p->pWith); + if( bFree ) sqlite3DbFree(db, p); + p = pPrior; + bFree = 1; + } } /* ** Initialize a SelectDest structure. */ @@ -128,12 +133,11 @@ pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; if( db->mallocFailed ) { - clearSelect(db, pNew); - if( pNew!=&standin ) sqlite3DbFree(db, pNew); + clearSelect(db, pNew, pNew!=&standin); pNew = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } assert( pNew!=&standin ); @@ -154,14 +158,11 @@ /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ - if( p ){ - clearSelect(db, p); - sqlite3DbFree(db, p); - } + clearSelect(db, p, 1); } /* ** Return a pointer to the right-most SELECT statement in a compound. */ @@ -2073,10 +2074,70 @@ Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ); +/* +** Error message for when two or more terms of a compound select have different +** size result sets. +*/ +static void selectWrongNumTermsError(Parse *pParse, Select *p){ + if( p->selFlags & SF_Values ){ + sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); + }else{ + sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" + " do not have the same number of result columns", selectOpName(p->op)); + } +} + +/* +** Handle the special case of a compound-select that originates from a +** VALUES clause. By handling this as a special case, we avoid deep +** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT +** on a VALUES clause. +** +** Because the Select object originates from a VALUES clause: +** (1) It has no LIMIT or OFFSET +** (2) All terms are UNION ALL +** (3) There is no ORDER BY clause +*/ +static int multiSelectValues( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + Select *pPrior; + int nExpr = p->pEList->nExpr; + int nRow = 1; + int rc = 0; + assert( p->pNext==0 ); + assert( p->selFlags & SF_AllValues ); + do{ + assert( p->selFlags & SF_Values ); + assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); + assert( p->pLimit==0 ); + assert( p->pOffset==0 ); + if( p->pEList->nExpr!=nExpr ){ + selectWrongNumTermsError(pParse, p); + return 1; + } + if( p->pPrior==0 ) break; + assert( p->pPrior->pNext==p ); + p = p->pPrior; + nRow++; + }while(1); + while( p ){ + pPrior = p->pPrior; + p->pPrior = 0; + rc = sqlite3Select(pParse, p, pDest); + p->pPrior = pPrior; + if( rc ) break; + p->nSelectRow = nRow; + p = p->pNext; + } + return rc; +} /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or ** INTERSECT @@ -2153,22 +2214,24 @@ assert( p->pEList ); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); dest.eDest = SRT_Table; } + + /* Special handling for a compound-select that originates as a VALUES clause. + */ + if( p->selFlags & SF_AllValues ){ + rc = multiSelectValues(pParse, p, &dest); + goto multi_select_end; + } /* Make sure all SELECTs in the statement have the same number of elements ** in their result sets. */ assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ - if( p->selFlags & SF_Values ){ - sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); - }else{ - sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" - " do not have the same number of result columns", selectOpName(p->op)); - } + selectWrongNumTermsError(pParse, p); rc = 1; goto multi_select_end; } #ifndef SQLITE_OMIT_CTE @@ -4050,11 +4113,13 @@ if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } pTabList = p->pSrc; pEList = p->pEList; - sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + if( pWalker->xSelectCallback2==selectPopWith ){ + sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + } /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. */ sqlite3SrcListAssignCursors(pParse, pTabList); @@ -4341,11 +4406,13 @@ if( pParse->hasCompound ){ w.xSelectCallback = convertCompoundSelectToSubquery; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - w.xSelectCallback2 = selectPopWith; + if( (pSelect->selFlags & SF_AllValues)==0 ){ + w.xSelectCallback2 = selectPopWith; + } sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -1743,10 +1743,21 @@ **
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which ** is a pointer to an integer and writes into that integer the number of extra ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. ** The amount of extra space required can change depending on the compiler, ** target platform, and SQLite version. +** +** [[SQLITE_CONFIG_PMASZ]] +**
SQLITE_CONFIG_PMASZ +**
^The SQLITE_CONFIG_PMASZ option takes a single parameter which +** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded +** sorter to that integer. The default minimum PMA Size is set by the +** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched +** to help with sort operations when multithreaded sorting +** is enabled (using the [PRAGMA threads] command) and the amount of content +** to be sorted exceeds the page size times the minimum of the +** [PRAGMA cache_size] setting and this value. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -1769,10 +1780,11 @@ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ +#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -2355,11 +2355,11 @@ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0040 /* Part of a compound query */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ - /* 0x0100 NOT USED */ +#define SF_AllValues 0x0100 /* All terms of compound are VALUES */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ @@ -2849,10 +2849,11 @@ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ int sharedCacheEnabled; /* true if shared-cache mode enabled */ + u32 szPma; /* Maximum Sorter PMA size */ /* The above might be initialized to non-zero. The following need to always ** initially be zero, however. */ int isInit; /* True after initialization has finished */ int inProgress; /* True while initialization in progress */ int isMutexInit; /* True after mutexes are initialized */ Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -259,10 +259,12 @@ /* ** Usage: clang_sanitize_address ** ** Returns true if the program was compiled using clang with the ** -fsanitize=address switch on the command line. False otherwise. +** +** Also return true if the OMIT_MISUSE environment variable exists. */ static int clang_sanitize_address( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ @@ -272,10 +274,11 @@ #if defined(__has_feature) # if __has_feature(address_sanitizer) res = 1; # endif #endif + if( res==0 && getenv("OMIT_MISUSE")!=0 ) res = 1; Tcl_SetObjResult(interp, Tcl_NewIntObj(res)); return TCL_OK; } /* @@ -6602,10 +6605,64 @@ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); return TCL_OK; } #endif /* SQLITE_USER_AUTHENTICATION */ +/* +** tclcmd: bad_behavior TYPE +** +** Do some things that should trigger a valgrind or -fsanitize=undefined +** warning. This is used to verify that errors and warnings output by those +** tools are detected by the test scripts. +** +** TYPE BEHAVIOR +** 1 Overflow a signed integer +** 2 Jump based on an uninitialized variable +** 3 Read after free +*/ +static int test_bad_behavior( + ClientData clientData, /* Pointer to an integer containing zero */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + int iType; + int xyz; + int i = *(int*)clientData; + int j; + int w[10]; + int *a; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "TYPE"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[1], &iType) ) return TCL_ERROR; + switch( iType ){ + case 1: { + xyz = 0x7fffff00 - i; + xyz += 0x100; + Tcl_SetObjResult(interp, Tcl_NewIntObj(xyz)); + break; + } + case 2: { + w[1] = 5; + if( w[i]>0 ) w[1]++; + Tcl_SetObjResult(interp, Tcl_NewIntObj(w[1])); + break; + } + case 3: { + a = malloc( sizeof(int)*10 ); + for(j=0; j<10; j++) a[j] = j; + free(a); + Tcl_SetObjResult(interp, Tcl_NewIntObj(a[i])); + break; + } + } + return TCL_OK; +} + + /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; @@ -6618,10 +6675,11 @@ extern int sqlite3_hostid_num; #endif extern int sqlite3_max_blobsize; extern int sqlite3BtreeSharedCacheReport(void*, Tcl_Interp*,int,Tcl_Obj*CONST*); + static int iZero = 0; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "db_enter", (Tcl_CmdProc*)db_enter }, @@ -6670,10 +6728,11 @@ static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { + { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, Index: src/test8.c ================================================================== --- src/test8.c +++ src/test8.c @@ -646,16 +646,16 @@ ** in echoBestIndex(), idxNum is set to the corresponding hash value. ** In echoFilter(), code assert()s that the supplied idxNum value is ** indeed the hash of the supplied idxStr. */ static int hashString(const char *zString){ - int val = 0; + u32 val = 0; int ii; for(ii=0; zString[ii]; ii++){ val = (val << 3) + (int)zString[ii]; } - return val; + return (int)(val&0x7fffffff); } /* ** Echo virtual table module xFilter method. */ Index: src/test_malloc.c ================================================================== --- src/test_malloc.c +++ src/test_malloc.c @@ -1258,10 +1258,38 @@ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } +/* +** Usage: sqlite3_config_pmasz INTEGER +** +** Set the minimum PMA size. +*/ +static int test_config_pmasz( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc; + int iPmaSz; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){ + return TCL_ERROR; + } + + rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz); + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + + return TCL_OK; +} + /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME ** @@ -1512,10 +1540,11 @@ { "sqlite3_config_memstatus", test_config_memstatus ,0 }, { "sqlite3_config_lookaside", test_config_lookaside ,0 }, { "sqlite3_config_error", test_config_error ,0 }, { "sqlite3_config_uri", test_config_uri ,0 }, { "sqlite3_config_cis", test_config_cis ,0 }, + { "sqlite3_config_pmasz", test_config_pmasz ,0 }, { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, { "sqlite3_install_memsys3", test_install_memsys3 ,0 }, { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 }, Index: src/threads.c ================================================================== --- src/threads.c +++ src/threads.c @@ -24,10 +24,13 @@ ** This interface exists so that applications that want to take advantage ** of multiple cores can do so, while also allowing applications to stay ** single-threaded if desired. */ #include "sqliteInt.h" +#if SQLITE_OS_WIN +# include "os_win.h" +#endif #if SQLITE_MAX_WORKER_THREADS>0 /********************************* Unix Pthreads ****************************/ #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 Index: src/vdbesort.c ================================================================== --- src/vdbesort.c +++ src/vdbesort.c @@ -150,11 +150,11 @@ /* ** Hard-coded maximum amount of data to accumulate in memory before flushing ** to a level 0 PMA. The purpose of this limit is to prevent various integer ** overflows. 512MiB. */ -#define SQLITE_MAX_MXPMASIZE (1<<29) +#define SQLITE_MAX_PMASZ (1<<29) /* ** Private objects used by the sorter */ typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ @@ -446,15 +446,10 @@ ** ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } */ #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) -/* The minimum PMA size is set to this value multiplied by the database -** page size in bytes. */ -#ifndef SQLITE_SORTER_PMASZ -# define SQLITE_SORTER_PMASZ 10 -#endif /* Maximum number of PMAs that a single MergeEngine can merge */ #define SORTER_MAX_MERGE_COUNT 16 static int vdbeIncrSwap(IncrMerger*); @@ -849,14 +844,15 @@ SortSubtask *pTask = &pSorter->aTask[i]; pTask->pSorter = pSorter; } if( !sqlite3TempInMemory(db) ){ - pSorter->mnPmaSize = SQLITE_SORTER_PMASZ * pgsz; + u32 szPma = sqlite3GlobalConfig.szPma; + pSorter->mnPmaSize = szPma * pgsz; mxCache = db->aDb[0].pSchema->cache_size; - if( mxCachemxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_MXPMASIZE); + if( mxCache<(int)szPma ) mxCache = (int)szPma; + pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary ** large heap allocations. */ Index: test/bigsort.test ================================================================== --- test/bigsort.test +++ test/bigsort.test @@ -18,10 +18,19 @@ # At one point there was an overflow problem if the product of the # cache-size and page-size was larger than 2^31. Causing an infinite # loop if the product was also an integer multiple of 2^32, or # inefficiency otherwise. # +# This test causes thrashing on machines with smaller amounts of +# memory. Make sure the host has at least 8GB available before running +# this test. +# +if {[catch {exec free | grep Mem:} out] || [lindex $out 1]<8000000} { + finish_test + return +} + do_execsql_test 1.0 { PRAGMA page_size = 1024; CREATE TABLE t1(a, b); BEGIN; WITH data(x,y) AS ( @@ -37,7 +46,5 @@ CREATE INDEX i1 ON t1(a, b); } finish_test - - Index: test/fkey5.test ================================================================== --- test/fkey5.test +++ test/fkey5.test @@ -250,17 +250,21 @@ PRAGMA foreign_key_check(c12); } } {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0} do_test fkey5-7.1 { + set res {} db eval { INSERT OR IGNORE INTO c13 SELECT * FROM c12; INSERT OR IGNORE INTO C14 SELECT * FROM c12; DELETE FROM c12; PRAGMA foreign_key_check; + } { + lappend res [list $table $rowid $fkid $parent] } -} {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0 c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0} + lsort $res +} {{c13 1 0 p3} {c13 2 0 p3} {c13 3 0 p3} {c13 4 0 p3} {c13 5 0 p3} {c13 6 0 p3} {c14 1 0 p4} {c14 3 0 p4} {c14 6 0 p4}} do_test fkey5-7.2 { db eval { PRAGMA foreign_key_check(c14); } } {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0} Index: test/main.test ================================================================== --- test/main.test +++ test/main.test @@ -512,7 +512,27 @@ set rc [catch {sqlite3 db test.db -vfs async} msg] list $rc $msg } {1 {no such vfs: async}} } } + +# Print the version number so that it can be picked up by releasetest.tcl. +# +puts [db one {SELECT 'VERSION: ' || + sqlite_version() || ' ' || + sqlite_source_id();}] + +# Do deliberate failures if the TEST_FAILURE environment variable is set. +# This is done to verify that failure notifications are detected by the +# releasetest.tcl script, or possibly by other scripts involved in automatic +# testing. +# +if {[info exists ::env(TEST_FAILURE)]} { + set res 123 + if {$::env(TEST_FAILURE)==0} {set res 234} + do_test main-99.1 { + bad_behavior $::env(TEST_FAILURE) + set x 123 + } $res +} finish_test Index: test/memsubsys1.test ================================================================== --- test/memsubsys1.test +++ test/memsubsys1.test @@ -174,24 +174,24 @@ } 1 do_test memsubsys1-4.6 { set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2] } 1 -# Test 5: Activate both PAGECACHE and SCRATCH. But make the page size +# Test 5: Activate both PAGECACHE and SCRATCH. But make the page size is # such that the SCRATCH allocations are too small. # db close sqlite3_shutdown sqlite3_config_pagecache [expr 4096+$xtra_size] 24 -sqlite3_config_scratch 6000 2 +sqlite3_config_scratch 4000 2 sqlite3_initialize reset_highwater_marks build_test_db memsubsys1-5 {PRAGMA page_size=4096} #show_memstats do_test memsubsys1-5.3 { set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2] -} 24 +} {/^2[34]$/} do_test memsubsys1-5.4 { set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] expr {$maxreq>4096} } 1 do_test memsubsys1-5.5 { @@ -213,11 +213,11 @@ reset_highwater_marks build_test_db memsubsys1-6 {PRAGMA page_size=4096} #show_memstats do_test memsubsys1-6.3 { set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2] -} 24 +} {/^2[34]$/} #do_test memsubsys1-6.4 { # set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] # expr {$maxreq>4096 && $maxreq<=(4096+$xtra_size)} #} 1 do_test memsubsys1-6.5 { Index: test/oserror.test ================================================================== --- test/oserror.test +++ test/oserror.test @@ -49,23 +49,24 @@ # The xOpen() method of the unix VFS calls getcwd() as well as open(). # Although this does not appear to be documented in the man page, on OSX # a call to getcwd() may fail if there are no free file descriptors. So # an error may be reported for either open() or getcwd() here. # -puts "Possible valgrind error about invalid file descriptor follows:" -do_test 1.1.1 { - set ::log [list] - list [catch { - for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } - } msg] $msg -} {1 {unable to open database file}} -do_test 1.1.2 { - catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } -} {1} -do_re_test 1.1.3 { - lindex $::log 0 -} {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - } +if {![clang_sanitize_address]} { + do_test 1.1.1 { + set ::log [list] + list [catch { + for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } + } msg] $msg + } {1 {unable to open database file}} + do_test 1.1.2 { + catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } + } {1} + do_re_test 1.1.3 { + lindex $::log 0 + } {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - } +} # Test a failure in open() due to the path being a directory. # do_test 1.2.1 { Index: test/percentile.test ================================================================== --- test/percentile.test +++ test/percentile.test @@ -198,11 +198,11 @@ 50 2749999.5 10 99999.9 } { do_test percentile-2.1.$in { execsql { - SELECT percentile(x, $in) from t3; + SELECT round(percentile(x, $in),1) from t3; } } $out } } Index: test/permutations.test ================================================================== --- test/permutations.test +++ test/permutations.test @@ -119,10 +119,23 @@ bigsort.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] } +if {[info exists ::env(QUICKTEST_OMIT)]} { + foreach x [split $::env(QUICKTEST_OMIT) ,] { + regsub -all \\y$x\\y $allquicktests {} allquicktests + } +} + +# If the TEST_FAILURE environment variable is set, it means that we what to +# deliberately provoke test failures in order to test the test infrastructure. +# Only the main.test module is needed for this. +# +if {[info exists ::env(TEST_FAILURE)]} { + set allquicktests main.test +} ############################################################################# # Start of tests # @@ -146,15 +159,11 @@ test_suite "mmap" -prefix "mm-" -description { Similar to veryquick. Except with memory mapping enabled. } -presql { pragma mmap_size = 268435456; } -files [ - # Do not run pragma3.test, as it depends on the values returned by - # "PRAGMA data_version". And if mmap is being used these are often, - # but not always, one greater than if it were not. - test_set $allquicktests -exclude *malloc* *ioerr* *fault* pragma3.test \ - -include malloc.test + test_set $allquicktests -exclude *malloc* *ioerr* *fault* -include malloc.test ] test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. Index: test/releasetest.tcl ================================================================== --- test/releasetest.tcl +++ test/releasetest.tcl @@ -11,10 +11,11 @@ --srcdir TOP-OF-SQLITE-TREE (see below) --platform PLATFORM (see below) --config CONFIGNAME (Run only CONFIGNAME) --quick (Run "veryquick.test" only) + --veryquick (Run "make smoketest" only) --buildonly (Just build testfixture - do not run) --dryrun (Print what would have happened) --info (Show diagnostic info) The default value for --srcdir is the parent of the directory holding @@ -29,15 +30,15 @@ } array set ::Configs { "Default" { -O2 + --disable-amalgamation --disable-shared } - "Ftrapv" { - -O2 -ftrapv - -DSQLITE_MAX_ATTACHED=55 - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 + "Sanitize" { + CC=clang -fsanitize=undefined + -DSQLITE_ENABLE_STAT4 } "Unlock-Notify" { -O2 -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_THREADSAFE @@ -65,12 +66,14 @@ -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 + -DSQLITE_ENABLE_STAT4 } "Debug-One" { + --disable-shared -O2 -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 -DSQLITE_MUTEX_NOOP=1 -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 @@ -77,10 +80,12 @@ -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 + -DSQLITE_ENABLE_STAT4 + -DSQLITE_MAX_ATTACHED=125 } "Device-One" { -O2 -DSQLITE_DEBUG=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 @@ -117,10 +122,11 @@ "Locking-Style" { -O2 -DSQLITE_ENABLE_LOCKING_STYLE=1 } "OS-X" { + -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_THREADSAFE=2 -DSQLITE_OS_UNIX=1 -DSQLITE_ENABLE_LOCKING_STYLE=1 @@ -131,10 +137,11 @@ -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_MAX_LENGTH=2147483645 -DSQLITE_MAX_VARIABLE_NUMBER=500000 -DSQLITE_DEBUG=1 -DSQLITE_PREFER_PROXY_LOCKING=1 + -DSQLITE_ENABLE_API_ARMOR=1 } "Extra-Robustness" { -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_MAX_ATTACHED=62 } @@ -145,16 +152,23 @@ -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_PARENTHESIS -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE } - "No-lookaside" { -DSQLITE_TEST_REALLOC_STRESS=1 -DSQLITE_OMIT_LOOKASIDE=1 -DHAVE_USLEEP=1 } + "Valgrind" { + -DSQLITE_ENABLE_STAT4 + -DSQLITE_ENABLE_FTS4 + -DSQLITE_ENABLE_RTREE + } + Fail0 {-O0} + Fail2 {-O0} + Fail3 {-O0} } array set ::Platforms { Linux-x86_64 { "Check-Symbols" checksymbols @@ -162,13 +176,14 @@ "Secure-Delete" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Update-Delete-Limit" test "Extra-Robustness" test "Device-Two" test - "Ftrapv" test "No-lookaside" test "Devkit" test + "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} + "Valgrind" valgrindtest "Default" "threadtest fulltest" "Device-One" fulltest } Linux-i686 { "Devkit" test @@ -179,13 +194,23 @@ } Darwin-i386 { "Locking-Style" "mptest test" "OS-X" "threadtest fulltest" } + Darwin-x86_64 { + "Locking-Style" "mptest test" + "OS-X" "threadtest fulltest" + } "Windows NT-intel" { "Default" "mptest fulltestonly" } + Failure-Detection { + Fail0 "TEST_FAILURE=0 test" + Sanitize "TEST_FAILURE=1 test" + Fail2 "TEST_FAILURE=2 valgrindtest" + Fail3 "TEST_FAILURE=3 valgrindtest" + } } # End of configuration section. ######################################################################### @@ -221,10 +246,33 @@ if {$nerr>0} { set rc 1 set errmsg $line } } + if {[regexp {runtime error: +(.*)} $line all msg]} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $msg + } + } + if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $all + } + } + if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { + set v [string range $line 9 end] + if {$::SQLITE_VERSION eq ""} { + set ::SQLITE_VERSION $v + } elseif {$::SQLITE_VERSION ne $v} { + set rc 1 + set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}" + } + } } close $fd if {!$seen} { set rc 1 set errmsg "Test did not complete" @@ -237,13 +285,21 @@ # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # set cflags "-g" set opts "" + set title ${name}($testtarget) + set configOpts "" + + regsub -all {#[^\n]*\n} $config \n config foreach arg $config { if {[string match -D* $arg]} { lappend opts $arg + } elseif {[string match CC=* $arg]} { + lappend testtarget $arg + } elseif {[regexp {^--(enable|disable)-} $arg]} { + lappend configOpts $arg } else { lappend cflags $arg } } @@ -259,32 +315,32 @@ append opts " -DSQLITE_OS_WIN=1" } else { append opts " -DSQLITE_OS_UNIX=1" } - dryrun file mkdir $dir - if {!$::DRYRUN} { - set title ${name}($testtarget) + if {!$::TRACE} { set n [string length $title] - puts -nonewline "${title}[string repeat . [expr {54-$n}]]" + puts -nonewline "${title}[string repeat . [expr {63-$n}]]" flush stdout } + set rc 0 set tm1 [clock seconds] set origdir [pwd] - dryrun cd $dir + trace_cmd file mkdir $dir + trace_cmd cd $dir set errmsg {} - set rc [catch [configureCommand]] + set rc [catch [configureCommand $configOpts]] if {!$rc} { set rc [catch [makeCommand $testtarget $cflags $opts]] count_tests_and_errors test.log rc errmsg } + trace_cmd cd $origdir set tm2 [clock seconds] - dryrun cd $origdir - if {!$::DRYRUN} { - set hours [expr {($tm2-$tm2)/3600}] + if {!$::TRACE} { + set hours [expr {($tm2-$tm1)/3600}] set minutes [expr {(($tm2-$tm1)/60)%60}] set seconds [expr {($tm2-$tm1)%60}] set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] if {$rc} { puts " FAIL $tm" @@ -297,37 +353,40 @@ } # The following procedure returns the "configure" command to be exectued for # the current platform, which may be Windows (via MinGW, etc). # -proc configureCommand {} { - set result [list dryrun exec] +proc configureCommand {opts} { + set result [list trace_cmd exec] if {$::tcl_platform(platform)=="windows"} { lappend result sh } - lappend result $::SRCDIR/configure -enable-load-extension >& test.log + lappend result $::SRCDIR/configure --enable-load-extension + foreach x $opts {lappend result $x} + lappend result >& test.log } # The following procedure returns the "make" command to be executed for the # specified targets, compiler flags, and options. # proc makeCommand { targets cflags opts } { - set result [list dryrun exec make clean] + set result [list trace_cmd exec make clean] foreach target $targets { lappend result $target } lappend result CFLAGS=$cflags OPTS=$opts >>& test.log } -# The following procedure either prints its arguments (if ::DRYRUN is true) -# or executes the command of its arguments in the calling context -# (if ::DRYRUN is false). -# -proc dryrun {args} { - if {$::DRYRUN} { - puts $args - } else { +# The following procedure prints its arguments if ::TRACE is true. +# And it executes the command of its arguments in the calling context +# if ::DRYRUN is false. +# +proc trace_cmd {args} { + if {$::TRACE} { + puts $args + } + if {!$::DRYRUN} { uplevel 1 $args } } @@ -340,17 +399,18 @@ set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] set ::QUICK 0 set ::BUILDONLY 0 set ::DRYRUN 0 set ::EXEC exec + set ::TRACE 0 set config {} set platform $::tcl_platform(os)-$::tcl_platform(machine) for {set i 0} {$i < [llength $argv]} {incr i} { set x [lindex $argv $i] if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]} - switch -- $x { + switch -glob -- $x { -srcdir { incr i set ::SRCDIR [file normalize [lindex $argv $i]] } @@ -360,10 +420,13 @@ } -quick { set ::QUICK 1 } + -veryquick { + set ::QUICK 2 + } -config { incr i set config [lindex $argv $i] } @@ -373,19 +436,24 @@ } -dryrun { set ::DRYRUN 1 } + + -trace { + set ::TRACE 1 + } -info { puts "Command-line Options:" puts " --srcdir $::SRCDIR" puts " --platform [list $platform]" puts " --config [list $config]" if {$::QUICK} {puts " --quick"} if {$::BUILDONLY} {puts " --buildonly"} if {$::DRYRUN} {puts " --dryrun"} + if {$::TRACE} {puts " --trace"} puts "\nAvailable --platform options:" foreach y [lsort [array names ::Platforms]] { puts " [list $y]" } puts "\nAvailable --config options:" @@ -392,10 +460,18 @@ foreach y [lsort [array names ::Configs]] { puts " [list $y]" } exit } + -g - + -D* - + -O* - + -enable-* - + -disable-* - + *=* { + lappend ::EXTRACONFIG [lindex $argv $i] + } default { puts stderr "" puts stderr [string trim $::USAGE_MESSAGE] exit -1 @@ -424,42 +500,53 @@ puts "Running the following test configurations for $platform:" puts " [string trim $::CONFIGLIST]" puts -nonewline "Flags:" if {$::DRYRUN} {puts -nonewline " --dryrun"} if {$::BUILDONLY} {puts -nonewline " --buildonly"} - if {$::QUICK} {puts -nonewline " --quick"} + switch -- $::QUICK { + 1 {puts -nonewline " --quick"} + 2 {puts -nonewline " --veryquick"} + } puts "" } # Main routine. # proc main {argv} { # Process any command line options. + set ::EXTRACONFIG {} process_options $argv - puts [string repeat * 70] + puts [string repeat * 79] set ::NERR 0 set ::NTEST 0 set ::NTESTCASE 0 set ::NERRCASE 0 + set ::SQLITE_VERSION {} set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { - if {$::QUICK} {set target test} - if {$::BUILDONLY} {set target testfixture} - set config_options $::Configs($zConfig) + if {$target ne "checksymbols"} { + switch -- $::QUICK { + 1 {set target test} + 2 {set target smoketest} + } + if {$::BUILDONLY} {set target testfixture} + } + set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] incr NTEST run_test_suite $zConfig $target $config_options # If the configuration included the SQLITE_DEBUG option, then remove # it and run veryquick.test. If it did not include the SQLITE_DEBUG option # add it and run veryquick.test. - if {$target!="checksymbols" && !$::BUILDONLY} { + if {$target!="checksymbols" && $target!="valgrindtest" + && !$::BUILDONLY && $::QUICK<2} { set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] set xtarget $target - regsub -all {fulltest[a-z]+} $xtarget test xtarget + regsub -all {fulltest[a-z]*} $xtarget test xtarget if {$debug_idx < 0} { incr NTEST append config_options " -DSQLITE_DEBUG=1" run_test_suite "${zConfig}_debug" $xtarget $config_options } else { @@ -474,10 +561,13 @@ set elapsetime [expr {[clock seconds]-$STARTTIME}] set hr [expr {$elapsetime/3600}] set min [expr {($elapsetime/60)%60}] set sec [expr {$elapsetime%60}] set etime [format (%02d:%02d:%02d) $hr $min $sec] - puts [string repeat * 70] - puts "$::NERRCASE failures of $::NTESTCASE tests run in $etime" + puts [string repeat * 79] + puts "$::NERRCASE failures out of $::NTESTCASE tests in $etime" + if {$::SQLITE_VERSION ne ""} { + puts "SQLite $::SQLITE_VERSION" + } } main $argv ADDED test/selectG.test Index: test/selectG.test ================================================================== --- /dev/null +++ test/selectG.test @@ -0,0 +1,39 @@ +# 2015-01-05 +# +# 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 verifies that INSERT operations with a very large number of +# VALUE terms works and does not hit the SQLITE_LIMIT_COMPOUND_SELECT limit. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix selectG + +# Do an INSERT with a VALUES clause that contains 100,000 entries. Verify +# that this insert happens quickly (in less than 10 seconds). Actually, the +# insert will normally happen in less than 0.5 seconds on a workstation, but +# we allow plenty of overhead for slower machines. The speed test checks +# for an O(N*N) inefficiency that was once in the code and that would make +# the insert run for over a minute. +# +do_test 100 { + set sql "CREATE TABLE t1(x);\nINSERT INTO t1(x) VALUES" + for {set i 1} {$i<100000} {incr i} { + append sql "($i)," + } + append sql "($i);" + set microsec [lindex [time {db eval $sql}] 0] + db eval { + SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1; + } +} {100000 5000050000 50000.5 1} + +finish_test Index: test/sort.test ================================================================== --- test/sort.test +++ test/sort.test @@ -14,10 +14,15 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sort +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db # Create a bunch of data to sort against # do_test sort-1.0 { execsql { Index: test/sort2.test ================================================================== --- test/sort2.test +++ test/sort2.test @@ -15,10 +15,15 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sort2 +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db foreach {tn script} { 1 { } 2 { catch { db close } Index: test/sort4.test ================================================================== --- test/sort4.test +++ test/sort4.test @@ -15,10 +15,16 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sort4 +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db + # Configure the sorter to use 3 background threads. db eval {PRAGMA threads=3} # Minimum number of seconds to run for. If the value is 0, each test Index: test/sortfault.test ================================================================== --- test/sortfault.test +++ test/sortfault.test @@ -15,10 +15,16 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sortfault +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db + do_execsql_test 1.0 { PRAGMA cache_size = 5; } Index: test/threadtest3.c ================================================================== --- test/threadtest3.c +++ test/threadtest3.c @@ -445,12 +445,16 @@ p->rc = 0; } static void print_err(Error *p){ if( p->rc!=SQLITE_OK ){ - printf("Error: (%d) \"%s\" at line %d\n", p->rc, p->zErr, p->iLine); - if( sqlite3_strglob("* - no such table: *",p->zErr)!=0 ) nGlobalErr++; + int isWarn = 0; + if( p->rc==SQLITE_SCHEMA ) isWarn = 1; + if( sqlite3_strglob("* - no such table: *",p->zErr)==0 ) isWarn = 1; + printf("%s: (%d) \"%s\" at line %d\n", isWarn ? "Warning" : "Error", + p->rc, p->zErr, p->iLine); + if( !isWarn ) nGlobalErr++; fflush(stdout); } } static void print_and_free_err(Error *p){ @@ -979,10 +983,11 @@ "CREATE TABLE t1(x PRIMARY KEY);" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 SELECT md5sum(x) FROM t1;" ); + closedb(&err, &db); setstoptime(&err, nMs); for(i=0; i1 ){ - int iArg; - for(iArg=1; iArg=sizeof(aTest)/sizeof(aTest[0]) ) goto usage; + } + for(iArg=1; iArg0 ? 255 : 0); Index: tool/lemon.c ================================================================== --- tool/lemon.c +++ tool/lemon.c @@ -1495,21 +1495,25 @@ static int noResort = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, - {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, + {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, + {OPT_FSTR, "O", 0, "Ignored. (Placeholder for '-O' compiler options.)"}, {OPT_FLAG, "p", (char*)&showPrecedenceConflict, "Show conflicts resolved by precedence rules"}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, {OPT_FLAG, "x", (char*)&version, "Print the version number."}, + {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"}, {OPT_FLAG,0,0,0} }; int i; int exitcode; struct lemon lem; @@ -1810,10 +1814,12 @@ if( err ){ fprintf(err,"%sundefined option.\n",emsg); errline(i,1,err); } errcnt++; + }else if( op[j].arg==0 ){ + /* Ignore this option */ }else if( op[j].type==OPT_FLAG ){ *((int*)op[j].arg) = v; }else if( op[j].type==OPT_FFLAG ){ (*(void(*)(int))(op[j].arg))(v); }else if( op[j].type==OPT_FSTR ){ @@ -1999,21 +2005,21 @@ case OPT_FFLAG: fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message); break; case OPT_INT: case OPT_FINT: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); break; case OPT_DBL: case OPT_FDBL: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); break; case OPT_STR: case OPT_FSTR: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } } }