Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -3.35.3 +3.35.5 Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.35.3. +# Generated by GNU Autoconf 2.69 for sqlite 3.35.5. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # @@ -724,12 +724,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.35.3' -PACKAGE_STRING='sqlite 3.35.3' +PACKAGE_VERSION='3.35.5' +PACKAGE_STRING='sqlite 3.35.5' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -1465,11 +1465,11 @@ # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.35.3 to adapt to many kinds of systems. +\`configure' configures sqlite 3.35.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. @@ -1530,11 +1530,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.35.3:";; + short | recursive ) echo "Configuration of sqlite 3.35.5:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1658,11 +1658,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.35.3 +sqlite configure 3.35.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -2077,11 +2077,11 @@ } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.35.3, which was +It was created by sqlite $as_me 3.35.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF @@ -12376,11 +12376,11 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.35.3, which was +This file was extended by sqlite $as_me 3.35.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -12442,11 +12442,11 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.35.3 +sqlite config.status 3.35.5 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation Index: ext/misc/cksumvfs.c ================================================================== --- ext/misc/cksumvfs.c +++ ext/misc/cksumvfs.c @@ -577,10 +577,22 @@ return SQLITE_OK; } }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; + }else if( op==SQLITE_FCNTL_CKSM_FILE ){ + /* This VFS needs to obtain a pointer to the corresponding database + ** file handle from within xOpen() calls to open wal files. To do this, + ** it uses the sqlite3_database_file_object() API to obtain a pointer + ** to the file-handle used by SQLite to access the db file. This is + ** fine if cksmvfs happens to be the top-level VFS, but not if there + ** are one or more wrapper VFS. To handle this case, this file-control + ** is used to extract the cksmvfs file-handle from any wrapper file + ** handle. */ + sqlite3_file **ppFile = (sqlite3_file**)pArg; + *ppFile = (sqlite3_file*)p; + return SQLITE_OK; } rc = pFile->pMethods->xFileControl(pFile, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); } @@ -686,10 +698,12 @@ pFile->pMethods = &cksm_io_methods; rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); if( rc ) goto cksm_open_done; if( flags & SQLITE_OPEN_WAL ){ sqlite3_file *pDb = sqlite3_database_file_object(zName); + rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); + assert( rc==SQLITE_OK ); p->pPartner = (CksmFile*)pDb; assert( p->pPartner->pPartner==0 ); p->pPartner->pPartner = p; p->isWal = 1; p->computeCksm = p->pPartner->computeCksm; Index: ext/rbu/rbu1.test ================================================================== --- ext/rbu/rbu1.test +++ ext/rbu/rbu1.test @@ -130,10 +130,15 @@ 2 { sqlite3rbu_create_vfs -default myrbu "" } { sqlite3rbu_destroy_vfs myrbu } + 3 { + sqlite3_register_cksumvfs + } { + sqlite3_unregister_cksumvfs + } } { eval $create_vfs foreach {tn2 cmd} { Index: ext/rbu/sqlite3rbu.c ================================================================== --- ext/rbu/sqlite3rbu.c +++ ext/rbu/sqlite3rbu.c @@ -1618,11 +1618,13 @@ ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ zSep = ""; for(iCol=0; iColnCol; iCol++){ const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); - if( zQuoted[0]=='N' ){ + if( zQuoted==0 ){ + p->rc = SQLITE_NOMEM; + }else if( zQuoted[0]=='N' ){ bFailed = 1; break; } zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); zSep = ", "; @@ -4990,32 +4992,18 @@ } else if( flags & SQLITE_OPEN_WAL ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ - /* This call is to open a *-wal file. Intead, open the *-oal. This - ** code ensures that the string passed to xOpen() is terminated by a - ** pair of '\0' bytes in case the VFS attempts to extract a URI - ** parameter from it. */ - const char *zBase = zName; - size_t nCopy; - char *zCopy; - if( rbuIsVacuum(pDb->pRbu) ){ - zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); - zBase = sqlite3_filename_wal(zBase); - } - nCopy = strlen(zBase); - zCopy = sqlite3_malloc64(nCopy+2); - if( zCopy ){ - memcpy(zCopy, zBase, nCopy); - zCopy[nCopy-3] = 'o'; - zCopy[nCopy] = '\0'; - zCopy[nCopy+1] = '\0'; - zOpen = (const char*)(pFd->zDel = zCopy); - }else{ - rc = SQLITE_NOMEM; - } + /* This call is to open a *-wal file. Intead, open the *-oal. */ + size_t nOpen; + if( rbuIsVacuum(pDb->pRbu) ){ + zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); + zOpen = sqlite3_filename_wal(zOpen); + } + nOpen = strlen(zOpen); + ((char*)zOpen)[nOpen-3] = 'o'; pFd->pRbu = pDb->pRbu; } pDb->pWalFd = pFd; } } Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -1929,37 +1929,48 @@ Vdbe *v = sqlite3GetVdbe(pParse); iCur = pParse->nTab++; sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); reg = ++pParse->nMem; - pParse->nMem += pTab->nCol; if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg); + pParse->nMem += pTab->nCol; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + pParse->nMem += pPk->nColumn; + for(i=0; inKeyCol; i++){ + sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1); + } + nField = pPk->nKeyCol; } + regRec = ++pParse->nMem; for(i=0; inCol; i++){ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ int regOut; if( pPk ){ int iPos = sqlite3TableColumnToIndex(pPk, i); int iColPos = sqlite3TableColumnToIndex(pPk, iCol); + if( iPosnKeyCol ) continue; regOut = reg+1+iPos-(iPos>iColPos); }else{ regOut = reg+1+nField; } - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); + if( i==pTab->iPKey ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); + }else{ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); + } nField++; } } - regRec = reg + pTab->nCol; sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); }else{ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg); } + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); } Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -956,12 +956,12 @@ }else if( pRight==0 ){ return pLeft; }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) && !IN_RENAME_OBJECT ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); + sqlite3ExprDeferredDelete(pParse, pLeft); + sqlite3ExprDeferredDelete(pParse, pRight); return sqlite3Expr(db, TK_INTEGER, "0"); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } @@ -1154,10 +1154,26 @@ } void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } + +/* +** Arrange to cause pExpr to be deleted when the pParse is deleted. +** This is similar to sqlite3ExprDelete() except that the delete is +** deferred untilthe pParse is deleted. +** +** The pExpr might be deleted immediately on an OOM error. +** +** The deferred delete is (currently) implemented by adding the +** pExpr to the pParse->pConstExpr list with a register number of 0. +*/ +void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ + pParse->pConstExpr = + sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); +} + /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ if( p ){ @@ -5779,22 +5795,20 @@ assert( iAgg>=0 && iAggnColumn ); if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ assert( iAgg>=0 && iAggnFunc ); if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } } } return WRC_Continue; Index: src/resolve.c ================================================================== --- src/resolve.c +++ src/resolve.c @@ -374,19 +374,23 @@ pTab = 0; #ifndef SQLITE_OMIT_TRIGGER if( pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); - if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ + if( pParse->bReturning ){ + if( (pNC->ncFlags & NC_UBaseReg)!=0 + && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) + ){ + pExpr->iTable = op!=TK_DELETE; + pTab = pParse->pTriggerTab; + } + }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; - }else if( pParse->bReturning && (pNC->ncFlags & NC_UBaseReg)!=0 ){ - pExpr->iTable = op!=TK_DELETE; - pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -1127,10 +1127,14 @@ ** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. ** +** +**
  • [[SQLITE_FCNTL_CKSM_FILE]] +** Used by the cksmvfs VFS module only. +** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 @@ -1166,10 +1170,12 @@ #define SQLITE_FCNTL_DATA_VERSION 35 #define SQLITE_FCNTL_SIZE_LIMIT 36 #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 +#define SQLITE_FCNTL_EXTERNAL_READER 40 +#define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -4311,10 +4311,11 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); +void sqlite3ExprDeferredDelete(Parse*, Expr*); void sqlite3ExprUnmapAndDelete(Parse*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); void sqlite3ExprListSetSortOrder(ExprList*,int,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -845,10 +845,29 @@ }else{ sqlite3DbFree(db, zName); } return pSrc; } + +/* +** Return true if the pExpr term from the RETURNING clause argument +** list is of the form "*". Raise an error if the terms if of the +** form "table.*". +*/ +static int isAsteriskTerm( + Parse *pParse, /* Parsing context */ + Expr *pTerm /* A term in the RETURNING clause */ +){ + assert( pTerm!=0 ); + if( pTerm->op==TK_ASTERISK ) return 1; + if( pTerm->op!=TK_DOT ) return 0; + assert( pTerm->pRight!=0 ); + assert( pTerm->pLeft!=0 ); + if( pTerm->pRight->op!=TK_ASTERISK ) return 0; + sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards"); + return 1; +} /* The input list pList is the list of result set terms from a RETURNING ** clause. The table that we are returning from is pTab. ** ** This routine makes a copy of the pList, and at the same time expands @@ -863,11 +882,12 @@ sqlite3 *db = pParse->db; int i; for(i=0; inExpr; i++){ Expr *pOldExpr = pList->a[i].pExpr; - if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){ + if( NEVER(pOldExpr==0) ) continue; + if( isAsteriskTerm(pParse, pOldExpr) ){ int jj; for(jj=0; jjnCol; jj++){ Expr *pNewExpr; if( IsHiddenColumn(pTab->aCol+jj) ) continue; pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName); Index: src/whereexpr.c ================================================================== --- src/whereexpr.c +++ src/whereexpr.c @@ -509,10 +509,11 @@ sqlite3 *db; /* Database connection (for malloc) */ Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ + if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); @@ -1214,10 +1215,11 @@ #ifndef SQLITE_OMIT_WINDOWFUNC if( pSel->pWin ) return; #endif if( pSel->pPrior ) return; if( pSel->pWhere==0 ) return; + if( pSel->pLimit ) return; if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -1467,10 +1467,11 @@ VdbeCoverageIf(v, eCond==0); VdbeCoverageIf(v, eCond==1); VdbeCoverageIf(v, eCond==2); } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC); VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ Index: test/alterdropcol.test ================================================================== --- test/alterdropcol.test +++ test/alterdropcol.test @@ -273,7 +273,47 @@ UPDATE sqlite_schema SET sql='CREATE VIEW t2(x,y,z) AS SELECT b,a,c FROM t1' WHERE name='t2'; PRAGMA writable_schema=OFF; ALTER TABLE t2 DROP COLUMN z; } {1 {database disk image is malformed}} + +# 2021-04-06 dbsqlfuzz crash-331c5c29bb76257b198f1318eef3288f9624c8ce +reset_db +do_execsql_test 7.0 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID; + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(4, 5, 6); +} +do_execsql_test 7.1 { + ALTER TABLE t1 DROP COLUMN c; +} +do_execsql_test 7.2 { + SELECT sql FROM sqlite_schema; +} {{CREATE TABLE t1(a, b, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID}} +do_execsql_test 7.3 { + SELECT * FROM t1; +} {1 2 4 5} + +foreach {tn wo} { + 1 {} + 2 {WITHOUT ROWID} +} { + reset_db + do_execsql_test 9.$tn.0 " + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) $wo; + " + do_execsql_test 9.$tn.1 { + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000 + ) + INSERT INTO t1(a, b, c) SELECT i, 123, 456 FROM s; + } + do_execsql_test 9.$tn.2 { + ALTER TABLE t1 DROP COLUMN b; + } + + do_execsql_test 9.$tn.3 { + SELECT count(*), c FROM t1 GROUP BY c; + } {50000 456} +} finish_test Index: test/exists2.test ================================================================== --- test/exists2.test +++ test/exists2.test @@ -161,10 +161,16 @@ do_execsql_test 2.7a { SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (a,x)=(c,y)) } { four one } + +do_execsql_test 2.7b { + SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (a,x)=(c,y) LIMIT 1) +} { + four one +} # EXISTS clauses using vector expressions in the WHERE clause. # reset_db do_execsql_test 3.0 { Index: test/notnull2.test ================================================================== --- test/notnull2.test +++ test/notnull2.test @@ -95,7 +95,19 @@ do_execsql_test 2.1 { SELECT * FROM (SELECT a, b FROM t1) LEFT JOIN t3 ON a IS NULL; } + + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 3.0 { + CREATE TABLE t0(c0 PRIMARY KEY); + INSERT INTO t0(c0) VALUES (0); +} +do_execsql_test 3.1 { + SELECT * FROM t0 WHERE ((c0 NOT NULL) AND 1) OR (c0 == NULL); +} {0} + finish_test Index: test/returning1.test ================================================================== --- test/returning1.test +++ test/returning1.test @@ -112,8 +112,77 @@ do_execsql_test 5.5 { INSERT INTO t2(b) VALUES('abc'); UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1); } {123} + +# Ticket 132994c8b1063bfb +reset_db +do_catchsql_test 6.0 { + CREATE TABLE t1(id INTEGER PRIMARY KEY); + CREATE TABLE t2(x INT, y INT); + INSERT INTO t1 VALUES(1),(2),(4),(9); + INSERT INTO t2 VALUES(3,7), (4,25), (5,99); + UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING t2.*; +} {1 {RETURNING may not use "TABLE.*" wildcards}} +do_catchsql_test 6.1 { + UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING *, '|'; + SELECT * FROM t1 ORDER BY id; +} {0 {29 | 1 2 9 29}} + +# Forum https://sqlite.org/forum/forumpost/85aef8bc01 +# Do not silently ignore nonsense table names in the RETURNING clause. +# Raise an error. +# +reset_db +do_execsql_test 7.1 { + CREATE TABLE t1(a INT, b INT); + CREATE TABLE t2(x INT, y INT); + INSERT INTO t1(a,b) VALUES(1,2); + INSERT INTO t2(x,y) VALUES(1,30); +} {} +do_catchsql_test 7.2 { + UPDATE t1 SET b=b+1 RETURNING new.b; +} {1 {no such column: new.b}} +do_catchsql_test 7.3 { + UPDATE t1 SET b=b+1 RETURNING old.b; +} {1 {no such column: old.b}} +do_catchsql_test 7.4 { + UPDATE t1 SET b=b+1 RETURNING another.b; +} {1 {no such column: another.b}} +do_catchsql_test 7.5 { + UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t2.x; +} {1 {no such column: t2.x}} +do_catchsql_test 7.6 { + UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t1.b; +} {0 32} + +# This is goofy: The RETURNING clause does not honor the alias +# for the table being modified. This might change in the future. +# +do_catchsql_test 7.7 { + UPDATE t1 AS alias SET b=123 RETURNING alias.b; +} {1 {no such column: alias.b}} +do_catchsql_test 7.8 { + UPDATE t1 AS alias SET b=alias.b+1000 RETURNING t1.b; +} {0 1032} + +# Forum: https://sqlite.org/forum/info/34c81d83c9177f46 +reset_db +do_execsql_test 8.1 { + CREATE TABLE t1(a); + CREATE TABLE t2(b,c); + INSERT INTO t1 VALUES(1); + INSERT INTO t2 VALUES(3,40); +} {} +do_catchsql_test 8.2 { + INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE new.a=t2.b) AS x; +} {1 {no such column: new.a}} +do_catchsql_test 8.3 { + INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE old.a=t2.b) AS x; +} {1 {no such column: old.a}} +do_catchsql_test 8.4 { + INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE t1.a=t2.b) AS x; +} {0 {3 40}} finish_test Index: test/select4.test ================================================================== --- test/select4.test +++ test/select4.test @@ -1023,7 +1023,21 @@ do_execsql_test select4-18.3 { SELECT * FROM t1 AS z1 JOIN t1 AS z2 USING(aa) WHERE abs(z1.aa)=z2.aa AND z1.aa=123; } {123} +# 2021-03-31 Fix an assert() problem in the logic at the end of sqlite3Select() +# that validates AggInfo. The checks to ensure that AggInfo.aCol[].pCExpr +# references a valid expression was looking at an expression that had been +# deleted by the truth optimization in sqlite3ExprAnd() which was invoked by +# the push-down optimization. This is harmless in delivery builds, as that code +# only runs with SQLITE_DEBUG. But it should still be fixed. The problem +# was discovered by dbsqlfuzz (crash-dece7b67a3552ed7e571a7bda903afd1f7bd9b21) +# +reset_db +do_execsql_test select4-19.1 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(99); + SELECT sum((SELECT 1 FROM (SELECT 2 WHERE x IS NULL) WHERE 0)) FROM t1; +} {{}} finish_test Index: test/wherelimit.test ================================================================== --- test/wherelimit.test +++ test/wherelimit.test @@ -235,12 +235,12 @@ execsql {UPDATE t1 SET y=1 WHERE x=1} execsql {SELECT count(*) FROM t1 WHERE y=1} } {11} create_test_data 6 do_test wherelimit-3.2 { - execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, old.y, '|' LIMIT 5} - } {1 1 | 1 2 | 1 3 | 1 4 | 1 5 |} + execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, y, '|' LIMIT 5} + } {1 1 | 1 1 | 1 1 | 1 1 | 1 1 |} do_test wherelimit-3.2cnt { execsql {SELECT count(*) FROM t1 WHERE y=1} } {10} do_test wherelimit-3.3 { # limit 5 Index: test/window9.test ================================================================== --- test/window9.test +++ test/window9.test @@ -262,7 +262,24 @@ SELECT x UNION SELECT sum( avg((SELECT x FROM v1)) ) OVER() ) FROM v1; } {0.0 0.0} + +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 9.0 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(NULL,'bb',356); + INSERT INTO t1 VALUES('CB','aa',158); + INSERT INTO t1 VALUES('BB','aa',399); + INSERT INTO t1 VALUES('FF','bb',938); +} + +do_catchsql_test 9.1 { + SELECT sum(c) OVER ( + ORDER BY c RANGE BETWEEN 0 PRECEDING AND '-700' PRECEDING + ) + FROM t1 +} {1 {frame ending offset must be a non-negative number}} finish_test