diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 4 | ||||
-rw-r--r-- | src/build.c | 2 | ||||
-rw-r--r-- | src/delete.c | 2 | ||||
-rw-r--r-- | src/expr.c | 73 | ||||
-rw-r--r-- | src/fkey.c | 2 | ||||
-rw-r--r-- | src/mem1.c | 4 | ||||
-rw-r--r-- | src/os_unix.c | 20 | ||||
-rw-r--r-- | src/os_win.c | 60 | ||||
-rw-r--r-- | src/resolve.c | 55 | ||||
-rw-r--r-- | src/select.c | 13 | ||||
-rw-r--r-- | src/sqlite.h.in | 5 | ||||
-rw-r--r-- | src/sqliteInt.h | 12 | ||||
-rw-r--r-- | src/test1.c | 2 | ||||
-rw-r--r-- | src/test_config.c | 6 | ||||
-rw-r--r-- | src/test_multiplex.c | 6 | ||||
-rw-r--r-- | src/test_spellfix.c | 40 | ||||
-rw-r--r-- | src/update.c | 2 | ||||
-rw-r--r-- | src/walker.c | 12 | ||||
-rw-r--r-- | src/where.c | 56 |
19 files changed, 287 insertions, 89 deletions
diff --git a/src/btree.c b/src/btree.c index 097f02323..1c2e26ff7 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1461,7 +1461,7 @@ static int btreeInitPage(MemPage *pPage){ size = get2byte(&data[pc+2]); if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){ /* Free blocks must be in ascending order. And the last byte of - ** the free-block must lie on the database page. */ + ** the free-block must lie on the database page. */ return SQLITE_CORRUPT_BKPT; } nFree = nFree + size; @@ -2635,7 +2635,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ pBt->nTransaction++; #ifndef SQLITE_OMIT_SHARED_CACHE if( p->sharable ){ - assert( p->lock.pBtree==p && p->lock.iTable==1 ); + assert( p->lock.pBtree==p && p->lock.iTable==1 ); p->lock.eLock = READ_LOCK; p->lock.pNext = pBt->pLock; pBt->pLock = &p->lock; diff --git a/src/build.c b/src/build.c index 776ffa4db..c7ad2d1e7 100644 --- a/src/build.c +++ b/src/build.c @@ -534,7 +534,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ if( !db || db->pnBytesFreed==0 ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( - &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0 + &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); diff --git a/src/delete.c b/src/delete.c index b04e5a150..76e8ec26f 100644 --- a/src/delete.c +++ b/src/delete.c @@ -378,7 +378,7 @@ void sqlite3DeleteFrom( */ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); pWInfo = sqlite3WhereBegin( - pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK + pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0 ); if( pWInfo==0 ) goto delete_from_cleanup; regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0); diff --git a/src/expr.c b/src/expr.c index 790aa45f3..89172f94b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3123,9 +3123,12 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ }else{ pFarg = pExpr->x.pList; } - sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(", - op==TK_AGG_FUNCTION ? "AGG_" : "", - pExpr->u.zToken); + if( op==TK_AGG_FUNCTION ){ + sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(", + pExpr->op2, pExpr->u.zToken); + }else{ + sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken); + } if( pFarg ){ sqlite3ExplainExprList(pOut, pFarg); } @@ -3816,38 +3819,60 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){ } /* -** This is the expression callback for sqlite3FunctionUsesOtherSrc(). -** -** Determine if an expression references any table other than one of the -** tables in pWalker->u.pSrcList and abort if it does. +** An instance of the following structure is used by the tree walker +** to count references to table columns in the arguments of an +** aggregate function, in order to implement the +** sqlite3FunctionThisSrc() routine. +*/ +struct SrcCount { + SrcList *pSrc; /* One particular FROM clause in a nested query */ + int nThis; /* Number of references to columns in pSrcList */ + int nOther; /* Number of references to columns in other FROM clauses */ +}; + +/* +** Count the number of references to columns. */ -static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){ +static int exprSrcCount(Walker *pWalker, Expr *pExpr){ + /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc() + ** is always called before sqlite3ExprAnalyzeAggregates() and so the + ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If + ** sqlite3FunctionUsesThisSrc() is used differently in the future, the + ** NEVER() will need to be removed. */ + if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){ int i; - SrcList *pSrc = pWalker->u.pSrcList; + struct SrcCount *p = pWalker->u.pSrcCount; + SrcList *pSrc = p->pSrc; for(i=0; i<pSrc->nSrc; i++){ - if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue; + if( pExpr->iTable==pSrc->a[i].iCursor ) break; + } + if( i<pSrc->nSrc ){ + p->nThis++; + }else{ + p->nOther++; } - return WRC_Abort; - }else{ - return WRC_Continue; } + return WRC_Continue; } /* -** Determine if any of the arguments to the pExpr Function references -** any SrcList other than pSrcList. Return true if they do. Return -** false if pExpr has no argument or has only constant arguments or -** only references tables named in pSrcList. +** Determine if any of the arguments to the pExpr Function reference +** pSrcList. Return true if they do. Also return true if the function +** has no arguments or has only constant arguments. Return false if pExpr +** references columns but not columns of tables found in pSrcList. */ -static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){ +int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ Walker w; + struct SrcCount cnt; assert( pExpr->op==TK_AGG_FUNCTION ); memset(&w, 0, sizeof(w)); - w.xExprCallback = exprUsesOtherSrc; - w.u.pSrcList = pSrcList; - if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1; - return 0; + w.xExprCallback = exprSrcCount; + w.u.pSrcCount = &cnt; + cnt.pSrc = pSrcList; + cnt.nThis = 0; + cnt.nOther = 0; + sqlite3WalkExprList(&w, pExpr->x.pList); + return cnt.nThis>0 || cnt.nOther==0; } /* @@ -3966,7 +3991,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ } case TK_AGG_FUNCTION: { if( (pNC->ncFlags & NC_InAggFunc)==0 - && !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList) + && pWalker->walkerDepth==pExpr->op2 ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure diff --git a/src/fkey.c b/src/fkey.c index 82e4cdc47..9db3a71c3 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -560,7 +560,7 @@ static void fkScanChildren( ** clause. If the constraint is not deferred, throw an exception for ** each row found. Otherwise, for deferred constraints, increment the ** deferred constraint counter by nIncr for each row selected. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } diff --git a/src/mem1.c b/src/mem1.c index 8bb8a2f1b..3578496f3 100644 --- a/src/mem1.c +++ b/src/mem1.c @@ -231,14 +231,14 @@ static int sqlite3MemInit(void *NotUsed){ }else{ /* only 1 core, use our own zone to contention over global locks, ** e.g. we have our own dedicated locks */ - bool success; + bool success; malloc_zone_t* newzone = malloc_create_zone(4096, 0); malloc_set_zone_name(newzone, "Sqlite_Heap"); do{ success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, (void * volatile *)&_sqliteZone_); }while(!_sqliteZone_); - if( !success ){ + if( !success ){ /* somebody registered a zone first */ malloc_destroy_zone(newzone); } diff --git a/src/os_unix.c b/src/os_unix.c index 0f11613b0..a0326c963 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -715,9 +715,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { case EACCES: /* EACCES is like EAGAIN during locking operations, but not any other time*/ if( (sqliteIOErr == SQLITE_IOERR_LOCK) || - (sqliteIOErr == SQLITE_IOERR_UNLOCK) || - (sqliteIOErr == SQLITE_IOERR_RDLOCK) || - (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ + (sqliteIOErr == SQLITE_IOERR_UNLOCK) || + (sqliteIOErr == SQLITE_IOERR_RDLOCK) || + (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ return SQLITE_BUSY; } /* else fall through */ @@ -1764,7 +1764,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pInode->eFileLock = NO_LOCK; }else{ rc = SQLITE_IOERR_UNLOCK; - pFile->lastErrno = errno; + pFile->lastErrno = errno; pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } @@ -1780,7 +1780,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ closePendingFds(pFile); } } - + end_unlock: unixLeaveMutex(); if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; @@ -2047,7 +2047,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, - pFile->eFileLock, getpid())); + pFile->eFileLock, getpid())); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ @@ -2434,7 +2434,7 @@ static int semUnlock(sqlite3_file *id, int eFileLock) { assert( pFile ); assert( pSem ); OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, - pFile->eFileLock, getpid())); + pFile->eFileLock, getpid())); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ @@ -3024,7 +3024,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ - ((unixFile*)id)->lastErrno = 0; + ((unixFile*)id)->lastErrno = 0; } return -1; } @@ -3112,7 +3112,7 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ - ((unixFile*)id)->lastErrno = 0; + ((unixFile*)id)->lastErrno = 0; } return -1; } @@ -5626,7 +5626,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** address in the shared range is taken for a SHARED lock, the entire ** shared range is taken for an EXCLUSIVE lock): ** -** PENDING_BYTE 0x40000000 +** PENDING_BYTE 0x40000000 ** RESERVED_BYTE 0x40000001 ** SHARED_RANGE 0x40000002 -> 0x40000200 ** diff --git a/src/os_win.c b/src/os_win.c index 2cbd2cee5..1beb40b0c 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -46,9 +46,11 @@ # define FILE_ATTRIBUTE_MASK (0x0003FFF7) #endif +#ifndef SQLITE_OMIT_WAL /* Forward references */ typedef struct winShm winShm; /* A connection to shared-memory */ typedef struct winShmNode winShmNode; /* A region of shared-memory */ +#endif /* ** WinCE lacks native support for file locking so we have to fake it @@ -76,7 +78,9 @@ struct winFile { short sharedLockByte; /* Randomly chosen byte used as a shared lock */ u8 ctrlFlags; /* Flags. See WINFILE_* below */ DWORD lastErrno; /* The Windows errno from the last I/O error */ +#ifndef SQLITE_OMIT_WAL winShm *pShm; /* Instance of shared memory on this file */ +#endif const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE @@ -102,6 +106,22 @@ struct winFile { #endif /* + * The value used with sqlite3_win32_set_directory() to specify that + * the data directory should be changed. + */ +#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE +# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1) +#endif + +/* + * The value used with sqlite3_win32_set_directory() to specify that + * the temporary directory should be changed. + */ +#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE +# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2) +#endif + +/* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. */ @@ -1314,6 +1334,42 @@ char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ return zFilenameMbcs; } +/* +** This function sets the data directory or the temporary directory based on +** the provided arguments. The type argument must be 1 in order to set the +** data directory or 2 in order to set the temporary directory. The zValue +** argument is the name of the directory to use. The return value will be +** SQLITE_OK if successful. +*/ +int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ + char **ppDirectory = 0; +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){ + ppDirectory = &sqlite3_data_directory; + }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){ + ppDirectory = &sqlite3_temp_directory; + } + assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE + || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE + ); + assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); + if( ppDirectory ){ + char *zValueUtf8 = 0; + if( zValue && zValue[0] ){ + zValueUtf8 = unicodeToUtf8(zValue); + if ( zValueUtf8==0 ){ + return SQLITE_NOMEM; + } + } + sqlite3_free(*ppDirectory); + *ppDirectory = zValueUtf8; + return SQLITE_OK; + } + return SQLITE_ERROR; +} /* ** The return value of getLastErrorMsg @@ -1930,7 +1986,9 @@ static int winClose(sqlite3_file *id){ winFile *pFile = (winFile*)id; assert( id!=0 ); +#ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); +#endif OSTRACE(("CLOSE %d\n", pFile->h)); do{ rc = osCloseHandle(pFile->h); @@ -3680,7 +3738,9 @@ static int winOpen( pFile->h = h; pFile->lastErrno = NO_ERROR; pFile->pVfs = pVfs; +#ifndef SQLITE_OMIT_WAL pFile->pShm = 0; +#endif pFile->zPath = zName; if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; diff --git a/src/resolve.c b/src/resolve.c index a66f88fdc..b87d231ac 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -19,6 +19,29 @@ #include <string.h> /* +** Walk the expression tree pExpr and increase the aggregate function +** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. +** This needs to occur when copying a TK_AGG_FUNCTION node from an +** outer query into an inner subquery. +** +** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) +** is a helper function - a callback for the tree walker. +*/ +static int incrAggDepth(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i; + return WRC_Continue; +} +static void incrAggFunctionDepth(Expr *pExpr, int N){ + if( N>0 ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = incrAggDepth; + w.u.i = N; + sqlite3WalkExpr(&w, pExpr); + } +} + +/* ** Turn the pExpr expression into an alias for the iCol-th column of the ** result set in pEList. ** @@ -44,13 +67,20 @@ ** The result of random()%5 in the GROUP BY clause is probably different ** from the result in the result-set. We might fix this someday. Or ** then again, we might not... +** +** The nSubquery parameter specifies how many levels of subquery the +** alias is removed from the original expression. The usually value is +** zero but it might be more if the alias is contained within a subquery +** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION +** structures must be increased by the nSubquery amount. */ static void resolveAlias( Parse *pParse, /* Parsing context */ ExprList *pEList, /* A result set */ int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ Expr *pExpr, /* Transform this into an alias to the result set */ - const char *zType /* "GROUP" or "ORDER" or "" */ + const char *zType, /* "GROUP" or "ORDER" or "" */ + int nSubquery /* Number of subqueries that the label is moving */ ){ Expr *pOrig; /* The iCol-th column of the result set */ Expr *pDup; /* Copy of pOrig */ @@ -63,6 +93,7 @@ static void resolveAlias( db = pParse->db; if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){ pDup = sqlite3ExprDup(db, pOrig, 0); + incrAggFunctionDepth(pDup, nSubquery); pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0); if( pDup==0 ) return; if( pEList->a[iCol].iAlias==0 ){ @@ -151,9 +182,10 @@ static int lookupName( NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ ){ - int i, j; /* Loop counters */ + int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ + int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ struct SrcList_item *pItem; /* Use for looping over pSrcList items */ struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ @@ -315,7 +347,7 @@ static int lookupName( sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } - resolveAlias(pParse, pEList, j, pExpr, ""); + resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); @@ -329,6 +361,7 @@ static int lookupName( */ if( cnt==0 ){ pNC = pNC->pNext; + nSubquery++; } } @@ -568,13 +601,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ nId, zId); pNC->nErr++; } + if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg; + sqlite3WalkExprList(pWalker, pList); if( is_agg ){ + NameContext *pNC2 = pNC; pExpr->op = TK_AGG_FUNCTION; - pNC->ncFlags |= NC_HasAgg; + pExpr->op2 = 0; + while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ + pExpr->op2++; + pNC2 = pNC2->pNext; + } + if( pNC2 ) pNC2->ncFlags |= NC_HasAgg; + pNC->ncFlags |= NC_AllowAgg; } - if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg; - sqlite3WalkExprList(pWalker, pList); - if( is_agg ) pNC->ncFlags |= NC_AllowAgg; /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ @@ -853,7 +892,7 @@ int sqlite3ResolveOrderGroupBy( resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr); return 1; } - resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType); + resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType,0); } } return 0; diff --git a/src/select.c b/src/select.c index 491356acb..b3860b0e3 100644 --- a/src/select.c +++ b/src/select.c @@ -3149,7 +3149,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ if( IsVirtual(pTab) ) return 0; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; - if( pAggInfo->nFunc==0 ) return 0; + if( NEVER(pAggInfo->nFunc==0) ) return 0; if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0; if( pExpr->flags&EP_Distinct ) return 0; @@ -3521,7 +3521,7 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ /* -** This routine sets of a SELECT statement for processing. The +** This routine sets up a SELECT statement for processing. The ** following is accomplished: ** ** * VDBE Cursor numbers are assigned to all FROM-clause terms. @@ -3553,7 +3553,8 @@ void sqlite3SelectPrep( ** ** The aggregate accumulator is a set of memory cells that hold ** intermediate results while calculating an aggregate. This -** routine simply stores NULLs in all of those memory cells. +** routine generates code that stores NULLs in all of those memory +** cells. */ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; @@ -4023,7 +4024,7 @@ int sqlite3Select( ExprList *pDist = (isDistinct ? p->pEList : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0); if( pWInfo==0 ) goto select_end; if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; @@ -4196,7 +4197,7 @@ int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0); if( pWInfo==0 ) goto select_end; if( pGroupBy==0 ){ /* The optimizer is able to deliver rows in group by order so @@ -4465,7 +4466,7 @@ int sqlite3Select( ** of output. */ resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, 0, flag); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDel); goto select_end; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 78d63ff2f..f30a39b04 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -3154,8 +3154,11 @@ typedef struct sqlite3_context sqlite3_context; ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of <u>bytes</u> in the value, not the number of characters.)^ -** ^If the fourth parameter is negative, the length of the string is +** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() +** is negative, then the length of the string is ** the number of bytes up to the first zero terminator. +** If the fourth parameter to sqlite3_bind_blob() is negative, then +** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() ** or sqlite3_bind_text16() then that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 17ec0b0b9..18a508862 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1698,8 +1698,9 @@ struct Expr { i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 flags2; /* Second set of flags. EP2_... */ - u8 op2; /* If a TK_REGISTER, the original value of Expr.op */ - /* If TK_COLUMN, the value of p5 for OP_Column */ + u8 op2; /* TK_REGISTER: original value of Expr.op + ** TK_COLUMN: the value of p5 for OP_Column + ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ Table *pTab; /* Table for TK_COLUMN expressions. */ #if SQLITE_MAX_EXPR_DEPTH>0 @@ -1954,6 +1955,7 @@ struct WhereLevel { int addrInTop; /* Top of the IN loop */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ + Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; /* The following field is really not part of the current level. But @@ -2510,10 +2512,12 @@ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ Parse *pParse; /* Parser context. */ + int walkerDepth; /* Number of subqueries */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int i; /* Integer value */ SrcList *pSrcList; /* FROM clause */ + struct SrcCount *pSrcCount; /* Counting column references */ } u; }; @@ -2815,7 +2819,8 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16); +WhereInfo *sqlite3WhereBegin( + Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); @@ -2847,6 +2852,7 @@ int sqlite3ExprCompare(Expr*, Expr*); int sqlite3ExprListCompare(ExprList*, ExprList*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); +int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); diff --git a/src/test1.c b/src/test1.c index 445f4f2bf..c3dac0621 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5928,7 +5928,7 @@ static int optimization_control( sqlite3 *db; const char *zOpt; int onoff; - int mask; + int mask = 0; static const struct { const char *zOptName; int mask; diff --git a/src/test_config.c b/src/test_config.c index 4b4ad6894..0b08910c1 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -325,6 +325,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "fts3_unicode", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_DISABLE_FTS4_DEFERRED + Tcl_SetVar2(interp, "sqlite_options", "fts4_deferred", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "fts4_deferred", "1", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_GET_TABLE Tcl_SetVar2(interp, "sqlite_options", "gettable", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/test_multiplex.c b/src/test_multiplex.c index a3b3e2f27..23df347de 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -502,11 +502,11 @@ static int multiplexOpen( ){ int rc = SQLITE_OK; /* Result code */ multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */ - multiplexGroup *pGroup; /* Corresponding multiplexGroup object */ + multiplexGroup *pGroup = 0; /* Corresponding multiplexGroup object */ sqlite3_file *pSubOpen = 0; /* Real file descriptor */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - int nName; - int sz; + int nName = 0; + int sz = 0; char *zToFree = 0; UNUSED_PARAMETER(pVfs); diff --git a/src/test_spellfix.c b/src/test_spellfix.c index 92755cd1d..68247fed0 100644 --- a/src/test_spellfix.c +++ b/src/test_spellfix.c @@ -659,7 +659,7 @@ static int editDist3ConfigLoad( int rc, rc2; char *zSql; int iLangPrev = -9999; - EditDist3Lang *pLang; + EditDist3Lang *pLang = 0; zSql = sqlite3_mprintf("SELECT iLang, cFrom, cTo, iCost" " FROM \"%w\" WHERE iLang>=0 ORDER BY iLang", zTable); @@ -680,7 +680,7 @@ static int editDist3ConfigLoad( assert( zTo!=0 || nTo==0 ); if( nFrom>100 || nTo>100 ) continue; if( iCost<0 ) continue; - if( iLang!=iLangPrev ){ + if( pLang==0 || iLang!=iLangPrev ){ EditDist3Lang *pNew; pNew = sqlite3_realloc(p->a, (p->nLang+1)*sizeof(p->a[0])); if( pNew==0 ){ rc = SQLITE_NOMEM; break; } @@ -863,9 +863,9 @@ static void updateCost( int j, int iCost ){ - int b; + assert( iCost>=0 ); if( iCost<10000 ){ - b = m[j] + iCost; + unsigned int b = m[j] + iCost; if( b<m[i] ) m[i] = b; } } @@ -2508,15 +2508,17 @@ static int spellfix1Filter( */ static int spellfix1Next(sqlite3_vtab_cursor *cur){ spellfix1_cursor *pCur = (spellfix1_cursor *)cur; + int rc = SQLITE_OK; if( pCur->iRow < pCur->nRow ){ if( pCur->pFullScan ){ - int rc = sqlite3_step(pCur->pFullScan); + rc = sqlite3_step(pCur->pFullScan); if( rc!=SQLITE_ROW ) pCur->iRow = pCur->nRow; + if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK; }else{ pCur->iRow++; } } - return SQLITE_OK; + return rc; } /* @@ -2773,25 +2775,35 @@ static sqlite3_module spellfix1Module = { ** Register the various functions and the virtual table. */ static int spellfix1Register(sqlite3 *db){ - int nErr = 0; + int rc = SQLITE_OK; int i; - nErr += sqlite3_create_function(db, "spellfix1_translit", 1, SQLITE_UTF8, 0, + rc = sqlite3_create_function(db, "spellfix1_translit", 1, SQLITE_UTF8, 0, transliterateSqlFunc, 0, 0); - nErr += sqlite3_create_function(db, "spellfix1_editdist", 2, SQLITE_UTF8, 0, + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "spellfix1_editdist", 2, SQLITE_UTF8, 0, editdistSqlFunc, 0, 0); - nErr += sqlite3_create_function(db, "spellfix1_phonehash", 1, SQLITE_UTF8, 0, + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "spellfix1_phonehash", 1, SQLITE_UTF8, 0, phoneticHashSqlFunc, 0, 0); - nErr += sqlite3_create_function(db, "spellfix1_scriptcode", 1, SQLITE_UTF8, 0, + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "spellfix1_scriptcode", 1, SQLITE_UTF8, 0, scriptCodeSqlFunc, 0, 0); - nErr += sqlite3_create_module(db, "spellfix1", &spellfix1Module, 0); - nErr += editDist3Install(db); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "spellfix1", &spellfix1Module, 0); + } + if( rc==SQLITE_OK ){ + rc = editDist3Install(db); + } /* Verify sanity of the translit[] table */ for(i=0; i<sizeof(translit)/sizeof(translit[0])-1; i++){ assert( translit[i].cFrom<translit[i+1].cFrom ); } - return nErr ? SQLITE_ERROR : SQLITE_OK; + return rc; } #if SQLITE_CORE || defined(SQLITE_TEST) diff --git a/src/update.c b/src/update.c index 5b6df66eb..d94297aa7 100644 --- a/src/update.c +++ b/src/update.c @@ -313,7 +313,7 @@ void sqlite3Update( */ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); pWInfo = sqlite3WhereBegin( - pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED + pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0 ); if( pWInfo==0 ) goto update_cleanup; okOnePass = pWInfo->okOnePass; diff --git a/src/walker.c b/src/walker.c index c95a9c169..eab96ea24 100644 --- a/src/walker.c +++ b/src/walker.c @@ -125,12 +125,18 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue; rc = WRC_Continue; - while( p ){ + pWalker->walkerDepth++; + while( p ){ rc = pWalker->xSelectCallback(pWalker, p); if( rc ) break; - if( sqlite3WalkSelectExpr(pWalker, p) ) return WRC_Abort; - if( sqlite3WalkSelectFrom(pWalker, p) ) return WRC_Abort; + if( sqlite3WalkSelectExpr(pWalker, p) + || sqlite3WalkSelectFrom(pWalker, p) + ){ + pWalker->walkerDepth--; + return WRC_Abort; + } p = p->pPrior; } + pWalker->walkerDepth--; return rc & WRC_Abort; } diff --git a/src/where.c b/src/where.c index d324228c9..a460abc2d 100644 --- a/src/where.c +++ b/src/where.c @@ -3622,7 +3622,7 @@ static int codeAllEqualityTerms( int r1; int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); - if( NEVER(pTerm==0) ) break; + if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); @@ -4297,6 +4297,8 @@ static Bitmask codeOneLoopStart( */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ + Index *pCov = 0; /* Potential covering index (or NULL) */ + int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ @@ -4315,7 +4317,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Return; pLevel->p1 = regReturn; - /* Set up a new SrcList ni pOrTab containing the table being scanned + /* Set up a new SrcList in pOrTab containing the table being scanned ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). */ @@ -4392,8 +4394,10 @@ static Bitmask codeOneLoopStart( /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); + assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed ); if( pSubWInfo ){ + WhereLevel *pLvl; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); @@ -4414,11 +4418,36 @@ static Bitmask codeOneLoopStart( */ if( pSubWInfo->untestedTerms ) untestedTerms = 1; + /* If all of the OR-connected terms are optimized using the same + ** index, and the index is opened using the same cursor number + ** by each call to sqlite3WhereBegin() made by this loop, it may + ** be possible to use that index as a covering index. + ** + ** If the call to sqlite3WhereBegin() above resulted in a scan that + ** uses an index, and this is either the first OR-connected term + ** processed or the index is the same as that used by all previous + ** terms, set pCov to the candidate covering index. Otherwise, set + ** pCov to NULL to indicate that no candidate covering index will + ** be available. + */ + pLvl = &pSubWInfo->a[0]; + if( (pLvl->plan.wsFlags & WHERE_INDEXED)!=0 + && (pLvl->plan.wsFlags & WHERE_TEMP_INDEX)==0 + && (ii==0 || pLvl->plan.u.pIdx==pCov) + ){ + assert( pLvl->iIdxCur==iCovCur ); + pCov = pLvl->plan.u.pIdx; + }else{ + pCov = 0; + } + /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); } } } + pLevel->u.pCovidx = pCov; + pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; sqlite3ExprDelete(pParse->db, pAndExpr); @@ -4636,7 +4665,8 @@ WhereInfo *sqlite3WhereBegin( Expr *pWhere, /* The WHERE clause */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */ - u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */ + u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ + int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ int i; /* Loop counter */ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ @@ -4956,7 +4986,13 @@ WhereInfo *sqlite3WhereBegin( testcase( bestPlan.plan.wsFlags & WHERE_INDEXED ); testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX ); if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){ - pLevel->iIdxCur = pParse->nTab++; + if( (wctrlFlags & WHERE_ONETABLE_ONLY) + && (bestPlan.plan.wsFlags & WHERE_TEMP_INDEX)==0 + ){ + pLevel->iIdxCur = iIdxCur; + }else{ + pLevel->iIdxCur = pParse->nTab++; + } }else{ pLevel->iIdxCur = -1; } @@ -5208,6 +5244,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ */ assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){ + Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); @@ -5237,12 +5274,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** that reference the table and converts them into opcodes that ** reference the index. */ - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 && !db->mallocFailed){ + if( pLevel->plan.wsFlags & WHERE_INDEXED ){ + pIdx = pLevel->plan.u.pIdx; + }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){ + pIdx = pLevel->u.pCovidx; + } + if( pIdx && !db->mallocFailed){ int k, j, last; VdbeOp *pOp; - Index *pIdx = pLevel->plan.u.pIdx; - assert( pIdx!=0 ); pOp = sqlite3VdbeGetOp(v, pWInfo->iTop); last = sqlite3VdbeCurrentAddr(v); for(k=pWInfo->iTop; k<last; k++, pOp++){ |