Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | When the sqlite3WindowRewrite() routine detects and error, have it convert the SELECT statement into just "SELECT null" so that it does not leave the parse tree in a goofy state that can cause problems with subsequent code before the stack has a chance to unwind and report the error. Ticket [d87336c81c7d0873] |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
fa58aad48a788802b13a819e49f9b878 |
User & Date: | drh 2019-12-25 23:54:21 |
References
2019-12-26
| ||
00:53 | Fix an incorrect assert() added by check-in [fa58aad48a788802]. Problem found by dbsqlfuzz. (check-in: a17b29f0 user: drh tags: trunk) | |
Context
2019-12-26
| ||
00:20 | Disable the optimization that tries to pull the value of an expression from an index on that expression if the expression is a constant. (check-in: e5fd8b50 user: drh tags: trunk) | |
2019-12-25
| ||
23:54 | When the sqlite3WindowRewrite() routine detects and error, have it convert the SELECT statement into just "SELECT null" so that it does not leave the parse tree in a goofy state that can cause problems with subsequent code before the stack has a chance to unwind and report the error. Ticket [d87336c81c7d0873] (check-in: fa58aad4 user: drh tags: trunk) | |
2019-12-24
| ||
21:42 | Fix a minor performance regression from check-in [401c9d30e06191d9] (check-in: 76f54ee8 user: drh tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
590 591 592 593 594 595 596 597 598 599 600 601 602 603 | int i; int regLeft = 0; int regRight = 0; u8 opx = op; int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; } assert( pExpr->op==TK_EQ || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT || pExpr->op==TK_LT || pExpr->op==TK_GT | > | 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | int i; int regLeft = 0; int regRight = 0; u8 opx = op; int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; } assert( pExpr->op==TK_EQ || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT || pExpr->op==TK_LT || pExpr->op==TK_GT |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | /* ** Load the Parse object passed as the first argument with an error ** message of the form: ** ** "sub-select returns N columns - expected M" */ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ | > | | > | 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 | /* ** Load the Parse object passed as the first argument with an error ** message of the form: ** ** "sub-select returns N columns - expected M" */ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ if( pParse->nErr==0 ){ const char *zFmt = "sub-select returns %d columns - expected %d"; sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); } } #endif /* ** Expression pExpr is a vector that has been used in a context where ** it is not permitted. If pExpr is a sub-select vector, this routine ** loads the Parse object with a message of the form: |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 | #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure | | > > > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure ** itself depending on the value of bFree ** ** If bFree==1, call sqlite3DbFree() on the p object. ** If bFree==0, Leave the first Select object unfreed */ 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); |
︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 | /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } /* ** Return a pointer to the right-most SELECT statement in a compound. */ static Select *findRightmost(Select *p){ while( p->pNext ) p = p->pNext; return p; | > > > > > > > > > > > > > > | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } /* ** Delete all the substructure for p, but keep p allocated. Redefine ** p to be a single SELECT where every column of the result set has a ** value of NULL. */ void sqlite3SelectReset(Parse *pParse, Select *p){ if( ALWAYS(p) ){ clearSelect(pParse->db, p, 0); memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit)); p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(pParse->db,TK_NULL,0,0)); } } /* ** Return a pointer to the right-most SELECT statement in a compound. */ static Select *findRightmost(Select *p){ while( p->pNext ) p = p->pNext; return p; |
︙ | ︙ | |||
2707 2708 2709 2710 2711 2712 2713 | p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); | > | < | 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 | p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); assert( p->pEList || db->mallocFailed ); if( dest.eDest!=priorOp && db->mallocFailed==0 ){ int iCont, iBreak, iStart; iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); |
︙ | ︙ | |||
5734 5735 5736 5737 5738 5739 5740 | #endif if( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC | | > > | 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 | #endif if( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC rc = sqlite3WindowRewrite(pParse, p); if( rc ){ assert( pParse->nErr>0 ); goto select_end; } #if SELECTTRACE_ENABLED if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){ SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n")); sqlite3TreeViewSelect(0, p, 0); } |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2914 2915 2916 2917 2918 2919 2920 | ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences ** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { | < > | 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 | ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences ** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Select *pPrior; /* Prior select in a compound select statement */ Select *pNext; /* Next select to the left in a compound */ |
︙ | ︙ | |||
4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 | void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); | > | 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 | void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); void sqlite3SelectReset(Parse*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); |
︙ | ︙ |
Changes to src/window.c.
︙ | ︙ | |||
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); if( pTab2==0 ){ rc = SQLITE_NOMEM; }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; p->pSrc->a[0].pTab = pTab; pTab = pTab2; } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; sqlite3DbFree(db, pTab); } | > > > > | | | > > | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 | if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); if( pTab2==0 ){ /* Might actually be some other kind of error, but in that case ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get ** the correct error message regardless. */ rc = SQLITE_NOMEM; }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; p->pSrc->a[0].pTab = pTab; pTab = pTab2; } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; sqlite3DbFree(db, pTab); } if( rc ){ if( pParse->nErr==0 ){ assert( pParse->db->mallocFailed ); sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM); } sqlite3SelectReset(pParse, p); } return rc; } /* ** Unlink the Window object from the Select to which it is attached, ** if it is attached. |
︙ | ︙ |
Changes to test/window1.test.
︙ | ︙ | |||
1325 1326 1327 1328 1329 1330 1331 | } {} do_execsql_test 37.20 { DROP VIEW v0; CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1234))) FROM t0; SELECT c FROM v0 WHERE c BETWEEN -10 AND 20; } {} | | | 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | } {} do_execsql_test 37.20 { DROP VIEW v0; CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1234))) FROM t0; SELECT c FROM v0 WHERE c BETWEEN -10 AND 20; } {} # 2019-12-20 mrigger reported problem with a FILTER clause on an aggregate # in a join. # reset_db do_execsql_test 38.10 { CREATE TABLE t0(c0); CREATE TABLE t1(c0, c1 UNIQUE); INSERT INTO t0(c0) VALUES(1); |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 | do_execsql_test 39.3 { SELECT * FROM t0 WHERE(c0, 0) IN(SELECT FIRST_VALUE(0) OVER(), 0); } do_execsql_test 39.4 { SELECT * FROM t0 WHERE (t0.c0, 1) IN(SELECT NTILE(1) OVER(), 0 FROM t0); } | > | > > > > > > > > | 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 | do_execsql_test 39.3 { SELECT * FROM t0 WHERE(c0, 0) IN(SELECT FIRST_VALUE(0) OVER(), 0); } do_execsql_test 39.4 { SELECT * FROM t0 WHERE (t0.c0, 1) IN(SELECT NTILE(1) OVER(), 0 FROM t0); } # 2019-12-25 ticket d87336c81c7d0873 # reset_db do_catchsql_test 40.1 { CREATE VIRTUAL TABLE t0 USING rtree(c0, c1, c2); SELECT * FROM t0 WHERE ((0,0) IN (SELECT COUNT(*),LAG(5)OVER(PARTITION BY 0) FROM t0),0)<=(c1,0); } {1 {1st ORDER BY term out of range - should be between 1 and 3}} finish_test |