mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-19 21:43:15 +03:00
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] FossilOrigin-Name: fa58aad48a788802b13a819e49f9b8787f713bbe395c46c7295e821c52c81738
This commit is contained in:
@@ -594,6 +594,7 @@ static void codeVectorCompare(
|
||||
int addrDone = sqlite3VdbeMakeLabel(pParse);
|
||||
int isCommuted = ExprHasProperty(pExpr,EP_Commuted);
|
||||
|
||||
if( pParse->nErr ) return;
|
||||
if( nLeft!=sqlite3ExprVectorSize(pRight) ){
|
||||
sqlite3ErrorMsg(pParse, "row value misused");
|
||||
return;
|
||||
@@ -2686,8 +2687,10 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
|
||||
** "sub-select returns N columns - expected M"
|
||||
*/
|
||||
void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
|
||||
const char *zFmt = "sub-select returns %d columns - expected %d";
|
||||
sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
|
||||
if( pParse->nErr==0 ){
|
||||
const char *zFmt = "sub-select returns %d columns - expected %d";
|
||||
sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
27
src/select.c
27
src/select.c
@@ -84,7 +84,10 @@ struct SortCtx {
|
||||
|
||||
/*
|
||||
** Delete all the content of a Select structure. Deallocate the structure
|
||||
** itself only if bFree is true.
|
||||
** 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 ){
|
||||
@@ -188,6 +191,20 @@ 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.
|
||||
*/
|
||||
@@ -2711,9 +2728,9 @@ static int multiSelect(
|
||||
** it is that we currently need.
|
||||
*/
|
||||
assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
|
||||
if( dest.eDest!=priorOp ){
|
||||
assert( p->pEList || db->mallocFailed );
|
||||
if( dest.eDest!=priorOp && db->mallocFailed==0 ){
|
||||
int iCont, iBreak, iStart;
|
||||
assert( p->pEList );
|
||||
iBreak = sqlite3VdbeMakeLabel(pParse);
|
||||
iCont = sqlite3VdbeMakeLabel(pParse);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
@@ -5738,7 +5755,9 @@ int sqlite3Select(
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( sqlite3WindowRewrite(pParse, p) ){
|
||||
rc = sqlite3WindowRewrite(pParse, p);
|
||||
if( rc ){
|
||||
assert( pParse->nErr>0 );
|
||||
goto select_end;
|
||||
}
|
||||
#if SELECTTRACE_ENABLED
|
||||
|
||||
@@ -2918,13 +2918,13 @@ struct Upsert {
|
||||
** sequences for the ORDER BY clause.
|
||||
*/
|
||||
struct Select {
|
||||
ExprList *pEList; /* The fields of the result */
|
||||
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 */
|
||||
@@ -4092,6 +4092,7 @@ 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);
|
||||
|
||||
12
src/window.c
12
src/window.c
@@ -1021,6 +1021,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
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));
|
||||
@@ -1039,9 +1042,12 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
sqlite3DbFree(db, pTab);
|
||||
}
|
||||
|
||||
if( rc && pParse->nErr==0 ){
|
||||
assert( pParse->db->mallocFailed );
|
||||
return sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
|
||||
if( rc ){
|
||||
if( pParse->nErr==0 ){
|
||||
assert( pParse->db->mallocFailed );
|
||||
sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
|
||||
}
|
||||
sqlite3SelectReset(pParse, p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user