- C Always\suse\savailable\sindices\sto\soptimize\sLIKE\soperators\seven\sif\sthe\spattern\nof\sthe\sLIKE\soperator\shas\sa\sCOLLATE\smodifier.\s\sThis\sfixes\san\sineffiency\sthat\nwas\sintroduced\sinto\s3.7.15\sby\scheck-in\s[8542e6180d4]\son\s2012-12-08.
- D 2014-01-16T15:31:41.806
-C Fix\ssome\sproblems\sto\sdo\swith\sWITH\sclauses\sand\sname\sresolution.
-D 2014-01-17T14:59:27.898
++C Add\ssupport\sfor\scommon\stable\sexpressions\s(WITH\sclauses).
++D 2014-01-17T15:15:10.270
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
- F src/select.c 996d8b88603edbd478aaa70b75d535a3ddea933d
-F src/select.c c77955f93121adc8b4b43a98add62fbaa2b48132
++F src/select.c 231079b8b07ea6f3cf4663e9c0ef2315abe2236c
F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
- F src/sqlite.h.in d94a8b89522f526ba711182ee161e06f8669bcc9
+ F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
- F src/sqliteInt.h 0c65967bb807dee3c9eef2bbd17f880eeb28ea30
+ F src/sqliteInt.h 9600eeb486c274fbdb815d040e4a7f262b7317e1
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
- F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
- F src/where.c 81cec50fe73633144b0730de477e141c53485862
+ F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
-F src/where.c 369b0259fabfb22644d197736ae622f762cbaba8
++F src/where.c 5e11de480a94e6ff8f9922e3a04a31b56d5f33b5
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
- P f61a70589ac7e05008a362bd9d5b7bde5d07a758
- R c3393c71f3ebd7292d430bc7115b905d
- U drh
- Z 57df34b30b12b159eb99c0c8be54bec6
-P f68c6c4d36481526a9348244adc571ea282dc9eb
-R d73fd639096ae3d6dc6dd6a7018ffc11
++P 16bd54783a3f5531c55564ddefdada657c078eb0 6a549187ed8b5ed50daefa676ff666ae2ed43346
++R 3149ee3ed72aa52234b32eaa7e696309
+ U dan
-Z 6339477b00dd8c67441747d0ac03cfea
++Z e17f48449fd6868168f4a2f61958f3af
return WRC_Continue;
}
+ #ifndef SQLITE_OMIT_CTE
+ /*
+ ** Argument pWith (which may be NULL) points to a linked list of nested
+ ** WITH contexts, from inner to outermost. If the table identified by
+ ** FROM clause element pItem is really a common-table-expression (CTE)
+ ** then return a pointer to the CTE definition for that table. Otherwise
+ ** return NULL.
+ */
+ static struct Cte *searchWith(With *pWith, struct SrcList_item *pItem){
+ const char *zName;
+ if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
+ With *p;
+ for(p=pWith; p; p=p->pOuter){
+ int i;
+ for(i=0; i<p->nCte; i++){
+ if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
+ return &p->a[i];
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ /* The code generator maintains a stack of active WITH clauses
+ ** with the inner-most WITH clause being at the top of the stack.
+ **
+ ** This routine pushes the WITH clause passed as the second argument
+ ** onto the top of the stack. If argument bFree is true, then this
+ ** WITH clause will never be popped from the stack. In this case it
+ ** should be freed along with the Parse object. In other cases, when
+ ** bFree==0, the With object will be freed along with the SELECT
+ ** statement with which it is associated.
+ */
+ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
+ assert( bFree==0 || pParse->pWith==0 );
+ if( pWith ){
+ pWith->pOuter = pParse->pWith;
+ pParse->pWith = pWith;
+ pParse->bFreeWith = bFree;
+ }
+ }
+
+ /*
+ ** This function checks if argument pFrom refers to a CTE declared by
+ ** a WITH clause on the stack currently maintained by the parser. And,
+ ** if currently processing a CTE expression, if it is a recursive
+ ** reference to the current CTE.
+ **
+ ** If pFrom falls into either of the two categories above, pFrom->pTab
+ ** and other fields are populated accordingly. The caller should check
+ ** (pFrom->pTab!=0) to determine whether or not a successful match
+ ** was found.
+ **
+ ** Whether or not a match is found, SQLITE_OK is returned if no error
+ ** occurs. If an error does occur, an error message is stored in the
+ ** parser and some error code other than SQLITE_OK returned.
+ */
+ static int withExpand(
+ Walker *pWalker,
+ struct SrcList_item *pFrom
+ ){
+ Table *pTab;
+ Parse *pParse = pWalker->pParse;
+ sqlite3 *db = pParse->db;
+ struct Cte *pCte;
+
+ assert( pFrom->pTab==0 );
+
+ pCte = searchWith(pParse->pWith, pFrom);
+ if( pCte ){
+ ExprList *pEList;
+ Select *pSel;
+ Select *pLeft; /* Left-most SELECT statement */
+ int bMayRecursive; /* True if compound joined by UNION [ALL] */
+
+ /* If pCte->zErr is non-NULL at this point, then this is an illegal
+ ** recursive reference to CTE pCte. Leave an error in pParse and return
+ ** early. If pCte->zErr is NULL, then this is not a recursive reference.
+ ** In this case, proceed. */
+ if( pCte->zErr ){
+ sqlite3ErrorMsg(pParse, pCte->zErr, pCte->zName);
+ return WRC_Abort;
+ }
+
+ pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
+ if( pTab==0 ) return WRC_Abort;
+ pTab->nRef = 1;
+ pTab->zName = sqlite3DbStrDup(db, pCte->zName);
+ pTab->iPKey = -1;
+ pTab->nRowEst = 1048576;
+ pTab->tabFlags |= TF_Ephemeral;
+ pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
+ if( db->mallocFailed ) return SQLITE_NOMEM;
+ assert( pFrom->pSelect );
+
+ /* Check if this is a recursive CTE. */
+ pSel = pFrom->pSelect;
+ bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
+ if( bMayRecursive ){
+ int i;
+ SrcList *pSrc = pFrom->pSelect->pSrc;
+ for(i=0; i<pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &pSrc->a[i];
+ if( pItem->zDatabase==0
+ && pItem->zName!=0
+ && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
+ ){
+ pItem->pTab = pTab;
+ pItem->isRecursive = 1;
+ pTab->nRef++;
+ pSel->selFlags |= SF_Recursive;
+ }
+ }
+ }
+
+ /* Only one recursive reference is permitted. */
+ if( pTab->nRef>2 ){
+ sqlite3ErrorMsg(
+ pParse, "multiple references to recursive table: %s", pCte->zName
+ );
+ return WRC_Abort;
+ }
+ assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
+
+ pCte->zErr = "circular reference: %s";
+ sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
+
+ for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
+ pEList = pLeft->pEList;
+ if( pCte->pCols ){
+ if( pEList->nExpr!=pCte->pCols->nExpr ){
+ sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
+ pCte->zName, pEList->nExpr, pCte->pCols->nExpr
+ );
+ return WRC_Abort;
+ }
+ pEList = pCte->pCols;
+ }
+ selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
+
+ if( bMayRecursive ){
+ if( pSel->selFlags & SF_Recursive ){
+ pCte->zErr = "multiple recursive references: %s";
+ }else{
+ pCte->zErr = "recursive reference in a subquery: %s";
+ }
+ sqlite3WalkSelect(pWalker, pSel);
+ }
+ pCte->zErr = 0;
+ }
+
+ return SQLITE_OK;
+ }
+ #endif
+
+ #ifndef SQLITE_OMIT_CTE
++/*
++** If the SELECT passed as the second argument has an associated WITH
++** clause, pop it from the stack stored as part of the Parse object.
++**
++** This function is used as the xSelectCallback2() callback by
++** sqlite3SelectExpand() when walking a SELECT tree to resolve table
++** names and other FROM clause elements.
++*/
+ static void selectPopWith(Walker *pWalker, Select *p){
+ Parse *pParse = pWalker->pParse;
+ if( p->pWith ){
+ assert( pParse->pWith==p->pWith );
+ pParse->pWith = p->pWith->pOuter;
+ }
+ return WRC_Continue;
+ }
+ #else
+ #define selectPopWith 0
+ #endif
+
/*
** This routine is a Walker callback for "expanding" a SELECT statement.
** "Expanding" means to do the following: