!26 update package to 3.32.3
Merge pull request !26 from Markeryang/openEuler-20.03-LTS
This commit is contained in:
commit
5df5511783
@ -1,105 +0,0 @@
|
||||
Index: src/expr.c
|
||||
==================================================================
|
||||
--- src/expr.c
|
||||
+++ src/expr.c
|
||||
@@ -2241,10 +2241,19 @@
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+** Return true if p is a Column node that references a virtual table.
|
||||
+*/
|
||||
+int sqlite3ExprIsVtabRef(Expr *p){
|
||||
+ if( p->op!=TK_COLUMN ) return 0;
|
||||
+ if( p->y.pTab==0 ) return 0;
|
||||
+ return IsVirtual(p->y.pTab);
|
||||
+}
|
||||
|
||||
/*
|
||||
** Return FALSE if there is no chance that the expression can be NULL.
|
||||
**
|
||||
** If the expression might be NULL or if the expression is too complex
|
||||
@@ -5477,12 +5486,12 @@
|
||||
testcase( pExpr->op==TK_NE );
|
||||
testcase( pExpr->op==TK_LT );
|
||||
testcase( pExpr->op==TK_LE );
|
||||
testcase( pExpr->op==TK_GT );
|
||||
testcase( pExpr->op==TK_GE );
|
||||
- if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab))
|
||||
- || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab))
|
||||
+ if( sqlite3ExprIsVtabRef(pExpr->pLeft)
|
||||
+ || sqlite3ExprIsVtabRef(pExpr->pRight)
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
Index: src/sqliteInt.h
|
||||
==================================================================
|
||||
--- src/sqliteInt.h
|
||||
+++ src/sqliteInt.h
|
||||
@@ -4276,10 +4276,11 @@
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
int sqlite3ExprIsInteger(Expr*, int*);
|
||||
+int sqlite3ExprIsVtabRef(Expr*);
|
||||
int sqlite3ExprCanBeNull(const Expr*);
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(
|
||||
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
|
||||
|
||||
Index: src/whereexpr.c
|
||||
==================================================================
|
||||
--- src/whereexpr.c
|
||||
+++ src/whereexpr.c
|
||||
@@ -375,11 +375,11 @@
|
||||
**
|
||||
** vtab_column MATCH expression
|
||||
** MATCH(expression,vtab_column)
|
||||
*/
|
||||
pCol = pList->a[1].pExpr;
|
||||
- if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
||||
+ if( sqlite3ExprIsVtabRef(pCol) ){
|
||||
for(i=0; i<ArraySize(aOp); i++){
|
||||
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
|
||||
*peOp2 = aOp[i].eOp2;
|
||||
*ppRight = pList->a[0].pExpr;
|
||||
*ppLeft = pCol;
|
||||
@@ -397,11 +397,11 @@
|
||||
** Historically, xFindFunction expected to see lower-case function
|
||||
** names. But for this use case, xFindFunction is expected to deal
|
||||
** with function names in an arbitrary case.
|
||||
*/
|
||||
pCol = pList->a[0].pExpr;
|
||||
- if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
||||
+ if( sqlite3ExprIsVtabRef(pCol) ){
|
||||
sqlite3_vtab *pVtab;
|
||||
sqlite3_module *pMod;
|
||||
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
|
||||
void *pNotUsed;
|
||||
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
|
||||
@@ -420,14 +420,14 @@
|
||||
}
|
||||
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
|
||||
int res = 0;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
- if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){
|
||||
+ if( sqlite3ExprIsVtabRef(pLeft) ){
|
||||
res++;
|
||||
}
|
||||
- if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){
|
||||
+ if( pRight && sqlite3ExprIsVtabRef(pRight) ){
|
||||
res++;
|
||||
SWAP(Expr*, pLeft, pRight);
|
||||
}
|
||||
*ppLeft = pLeft;
|
||||
*ppRight = pRight;
|
||||
|
||||
@ -1,145 +0,0 @@
|
||||
Index: src/expr.c
|
||||
==================================================================
|
||||
--- src/expr.c
|
||||
+++ src/expr.c
|
||||
@@ -2242,19 +2242,10 @@
|
||||
default: break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
-/*
|
||||
-** Return true if p is a Column node that references a virtual table.
|
||||
-*/
|
||||
-int sqlite3ExprIsVtabRef(Expr *p){
|
||||
- if( p->op!=TK_COLUMN ) return 0;
|
||||
- if( p->y.pTab==0 ) return 0;
|
||||
- return IsVirtual(p->y.pTab);
|
||||
-}
|
||||
-
|
||||
/*
|
||||
** Return FALSE if there is no chance that the expression can be NULL.
|
||||
**
|
||||
** If the expression might be NULL or if the expression is too complex
|
||||
** to tell return TRUE.
|
||||
@@ -5479,23 +5470,29 @@
|
||||
case TK_EQ:
|
||||
case TK_NE:
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_GT:
|
||||
- case TK_GE:
|
||||
+ case TK_GE: {
|
||||
+ Expr *pLeft = pExpr->pLeft;
|
||||
+ Expr *pRight = pExpr->pRight;
|
||||
testcase( pExpr->op==TK_EQ );
|
||||
testcase( pExpr->op==TK_NE );
|
||||
testcase( pExpr->op==TK_LT );
|
||||
testcase( pExpr->op==TK_LE );
|
||||
testcase( pExpr->op==TK_GT );
|
||||
testcase( pExpr->op==TK_GE );
|
||||
- if( sqlite3ExprIsVtabRef(pExpr->pLeft)
|
||||
- || sqlite3ExprIsVtabRef(pExpr->pRight)
|
||||
+ /* The y.pTab=0 assignment in wherecode.c always happens after the
|
||||
+ ** impliesNotNullRow() test */
|
||||
+ if( (pLeft->op==TK_COLUMN && ALWAYS(pLeft->y.pTab!=0)
|
||||
+ && IsVirtual(pLeft->y.pTab))
|
||||
+ || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
|
||||
+ && IsVirtual(pRight->y.pTab))
|
||||
){
|
||||
- return WRC_Prune;
|
||||
+ return WRC_Prune;
|
||||
}
|
||||
-
|
||||
+ }
|
||||
default:
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Index: src/sqliteInt.h
|
||||
==================================================================
|
||||
--- src/sqliteInt.h
|
||||
+++ src/sqliteInt.h
|
||||
@@ -2151,12 +2151,15 @@
|
||||
** done as a macro so that it will be optimized out when virtual
|
||||
** table support is omitted from the build.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
# define IsVirtual(X) ((X)->nModuleArg)
|
||||
+# define ExprIsVtab(X) \
|
||||
+ ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->nModuleArg)
|
||||
#else
|
||||
# define IsVirtual(X) 0
|
||||
+# define ExprIsVtab(X) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn()
|
||||
** only works for non-virtual tables (ordinary tables and views) and is
|
||||
@@ -4276,11 +4279,10 @@
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
int sqlite3ExprIsInteger(Expr*, int*);
|
||||
-int sqlite3ExprIsVtabRef(Expr*);
|
||||
int sqlite3ExprCanBeNull(const Expr*);
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(
|
||||
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
|
||||
|
||||
Index: src/whereexpr.c
|
||||
==================================================================
|
||||
--- src/whereexpr.c
|
||||
+++ src/whereexpr.c
|
||||
@@ -375,11 +375,12 @@
|
||||
**
|
||||
** vtab_column MATCH expression
|
||||
** MATCH(expression,vtab_column)
|
||||
*/
|
||||
pCol = pList->a[1].pExpr;
|
||||
- if( sqlite3ExprIsVtabRef(pCol) ){
|
||||
+ testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
|
||||
+ if( ExprIsVtab(pCol) ){
|
||||
for(i=0; i<ArraySize(aOp); i++){
|
||||
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
|
||||
*peOp2 = aOp[i].eOp2;
|
||||
*ppRight = pList->a[0].pExpr;
|
||||
*ppLeft = pCol;
|
||||
@@ -397,11 +398,12 @@
|
||||
** Historically, xFindFunction expected to see lower-case function
|
||||
** names. But for this use case, xFindFunction is expected to deal
|
||||
** with function names in an arbitrary case.
|
||||
*/
|
||||
pCol = pList->a[0].pExpr;
|
||||
- if( sqlite3ExprIsVtabRef(pCol) ){
|
||||
+ testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
|
||||
+ if( ExprIsVtab(pCol) ){
|
||||
sqlite3_vtab *pVtab;
|
||||
sqlite3_module *pMod;
|
||||
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
|
||||
void *pNotUsed;
|
||||
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
|
||||
@@ -420,14 +422,16 @@
|
||||
}
|
||||
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
|
||||
int res = 0;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
- if( sqlite3ExprIsVtabRef(pLeft) ){
|
||||
+ testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
|
||||
+ if( ExprIsVtab(pLeft) ){
|
||||
res++;
|
||||
}
|
||||
- if( pRight && sqlite3ExprIsVtabRef(pRight) ){
|
||||
+ testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
|
||||
+ if( pRight && ExprIsVtab(pRight) ){
|
||||
res++;
|
||||
SWAP(Expr*, pLeft, pRight);
|
||||
}
|
||||
*ppLeft = pLeft;
|
||||
*ppRight = pRight;
|
||||
|
||||
66
0002-remove-fail-testcase-in-no-free-fd-situation.patch
Normal file
66
0002-remove-fail-testcase-in-no-free-fd-situation.patch
Normal file
@ -0,0 +1,66 @@
|
||||
From defded46ea50037500590122d847ba6a7cb96110 Mon Sep 17 00:00:00 2001
|
||||
From: eulerstorage <eulerstoragemt@huawei.com>
|
||||
Date: Sat, 11 Jan 2020 11:33:54 +0800
|
||||
Subject: [PATCH] remove fail testcase in no free fd situation
|
||||
|
||||
Remove testcase 1.1.1, 1.1.2 and 1.1.3, since it can not success in
|
||||
some situation if there is no enough fd resource.
|
||||
---
|
||||
test/oserror.test | 27 ---------------------------
|
||||
1 file changed, 27 deletions(-)
|
||||
|
||||
diff --git a/test/oserror.test b/test/oserror.test
|
||||
index a51301c..d46218f 100644
|
||||
--- a/test/oserror.test
|
||||
+++ b/test/oserror.test
|
||||
@@ -40,47 +40,6 @@ proc do_re_test {tn script expression} {
|
||||
|
||||
}
|
||||
|
||||
-#--------------------------------------------------------------------------
|
||||
-# Tests oserror-1.* test failures in the open() system call.
|
||||
-#
|
||||
-
|
||||
-# Test a failure in open() due to too many files.
|
||||
-#
|
||||
-# The xOpen() method of the unix VFS calls getcwd() as well as open().
|
||||
-# Although this does not appear to be documented in the man page, on OSX
|
||||
-# a call to getcwd() may fail if there are no free file descriptors. So
|
||||
-# an error may be reported for either open() or getcwd() here.
|
||||
-#
|
||||
-if {![clang_sanitize_address]} {
|
||||
- unset -nocomplain rc
|
||||
- unset -nocomplain nOpen
|
||||
- set nOpen 20000
|
||||
- do_test 1.1.1 {
|
||||
- set ::log [list]
|
||||
- set ::rc [catch {
|
||||
- for {set i 0} {$i < $::nOpen} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
|
||||
- } msg]
|
||||
- if {$::rc==0} {
|
||||
- # Some system (ex: Debian) are able to create 20000+ file descriptiors
|
||||
- # such systems will not fail here
|
||||
- set x ok
|
||||
- } elseif {$::rc==1 && $msg=="unable to open database file"} {
|
||||
- set x ok
|
||||
- } else {
|
||||
- set x [list $::rc $msg]
|
||||
- }
|
||||
- } {ok}
|
||||
- do_test 1.1.2 {
|
||||
- catch { for {set i 0} {$i < $::nOpen} {incr i} { dbh_$i close } }
|
||||
- } $::rc
|
||||
- if {$rc} {
|
||||
- do_re_test 1.1.3 {
|
||||
- lindex $::log 0
|
||||
- } {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-
|
||||
# Test a failure in open() due to the path being a directory.
|
||||
#
|
||||
do_test 1.2.1 {
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
From 156cc9423d4c4bade28468b2232226e2cd61aa6c Mon Sep 17 00:00:00 2001
|
||||
From: shenkai8 <shenkai8@huawei.com>
|
||||
Date: Thu, 16 Apr 2020 17:04:17 +0000
|
||||
Subject: [PATCH] backport-Fix-CVE-2020-11655
|
||||
|
||||
In the event of a semantic error in an aggregate query,
|
||||
early-out the resetAccumulator() function to prevent
|
||||
problems due to incomplete or incorrect initialization
|
||||
of the AggInfo object. Fix for ticket [af4556bb5c285c08].
|
||||
|
||||
Signed-off-by: drh <drh@noemail.net>
|
||||
---
|
||||
src/select.c | 1 +
|
||||
test/window1.test | 9 +++++++++
|
||||
2 files changed, 10 insertions(+)
|
||||
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index 595b6eb..b5e5a75 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -5352,6 +5352,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
struct AggInfo_func *pFunc;
|
||||
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
|
||||
if( nReg==0 ) return;
|
||||
+ if( pParse->nErr ) return;
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify that all AggInfo registers are within the range specified by
|
||||
** AggInfo.mnReg..AggInfo.mxReg */
|
||||
diff --git a/test/window1.test b/test/window1.test
|
||||
index 833e211..18b9bdc 100644
|
||||
--- a/test/window1.test
|
||||
+++ b/test/window1.test
|
||||
@@ -1593,5 +1593,14 @@ do_execsql_test 48.1 {
|
||||
FROM (SELECT (SELECT sum(a) FROM t1 GROUP BY a) AS x FROM t1);
|
||||
} {2 2 2}
|
||||
|
||||
+# 2020-04-03 ticket af4556bb5c285c08
|
||||
+#
|
||||
+reset_db
|
||||
+do_catchsql_test 51.1 {
|
||||
+ CREATE TABLE a(b, c);
|
||||
+ SELECT c FROM a GROUP BY c
|
||||
+ HAVING(SELECT(sum(b) OVER(ORDER BY b),
|
||||
+ sum(b) OVER(PARTITION BY min(DISTINCT c), c ORDER BY b)));
|
||||
+} {1 {row value misused}}
|
||||
|
||||
finish_test
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
From 9b063329ebbd9aafdad82ebf0b9103ce2dd1af18 Mon Sep 17 00:00:00 2001
|
||||
From: shenkai8 <shenkai8@huawei.com>
|
||||
Date: Thu, 16 Apr 2020 17:22:49 +0000
|
||||
Subject: [PATCH] backport Fix CVE-2020-11656
|
||||
|
||||
Fix a case when a pointer might be used after being freed in
|
||||
the ALTER TABLE code. Fix for [4722bdab08cb1].
|
||||
(check-in: d09f8c36 user: dan tags: trunk)
|
||||
|
||||
Do not suppress errors when resolving references in an ORDER BY
|
||||
clause belonging to a compound SELECT within a view or trigger
|
||||
within ALTER TABLE. Fix for ticket [a10a14e9b4ba2].
|
||||
(check-in: 68429388 user: dan tags: trunk)
|
||||
|
||||
Signed-off-by: dan <<dan@noemail.net>>
|
||||
---
|
||||
src/alter.c | 16 ++++++++++++++++
|
||||
src/resolve.c | 2 +-
|
||||
test/altertab.test | 31 ++++++++++++++++++++++++++++++-
|
||||
3 files changed, 47 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/alter.c b/src/alter.c
|
||||
index ee193d1..918df77 100644
|
||||
--- a/src/alter.c
|
||||
+++ b/src/alter.c
|
||||
@@ -756,6 +756,21 @@ static void renameWalkWith(Walker *pWalker, Select *pSelect){
|
||||
}
|
||||
|
||||
/*
|
||||
+** Unmap all tokens in the IdList object passed as the second argument.
|
||||
+*/
|
||||
+static void unmapColumnIdlistNames(
|
||||
+ Parse *pParse,
|
||||
+ IdList *pIdList
|
||||
+){
|
||||
+ if( pIdList ){
|
||||
+ int ii;
|
||||
+ for(ii=0; ii<pIdList->nId; ii++){
|
||||
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
** Walker callback used by sqlite3RenameExprUnmap().
|
||||
*/
|
||||
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
@@ -776,6 +791,7 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
|
||||
if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
|
||||
+ unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/resolve.c b/src/resolve.c
|
||||
index 119a07f..894958c 100644
|
||||
--- a/src/resolve.c
|
||||
+++ b/src/resolve.c
|
||||
@@ -1177,7 +1177,7 @@ static int resolveOrderByTermToExprList(
|
||||
nc.nErr = 0;
|
||||
db = pParse->db;
|
||||
savedSuppErr = db->suppressErr;
|
||||
- db->suppressErr = 1;
|
||||
+ if( IN_RENAME_OBJECT==0 ) db->suppressErr = 1;
|
||||
rc = sqlite3ResolveExprNames(&nc, pE);
|
||||
db->suppressErr = savedSuppErr;
|
||||
if( rc ) return 0;
|
||||
diff --git a/test/altertab.test b/test/altertab.test
|
||||
index 7dcf8a5..01dd61a 100644
|
||||
--- a/test/altertab.test
|
||||
+++ b/test/altertab.test
|
||||
@@ -594,7 +594,6 @@ reset_db
|
||||
do_execsql_test 18.1.0 {
|
||||
CREATE TABLE t0 (c0 INTEGER, PRIMARY KEY(c0)) WITHOUT ROWID;
|
||||
}
|
||||
-breakpoint
|
||||
do_execsql_test 18.1.1 {
|
||||
ALTER TABLE t0 RENAME COLUMN c0 TO c1;
|
||||
}
|
||||
@@ -613,4 +612,34 @@ do_execsql_test 18.2.2 {
|
||||
SELECT sql FROM sqlite_master;
|
||||
} {{CREATE TABLE t0 (c1 INTEGER, PRIMARY KEY(c1))}}
|
||||
|
||||
+# Ticket 4722bdab08cb14
|
||||
+reset_db
|
||||
+do_execsql_test 20.0 {
|
||||
+ CREATE TABLE a(a);
|
||||
+ CREATE VIEW b AS SELECT(SELECT *FROM c JOIN a USING(d, a, a, a) JOIN a) IN();
|
||||
+}
|
||||
+
|
||||
+do_execsql_test 20.1 {
|
||||
+ ALTER TABLE a RENAME a TO e;
|
||||
+} {}
|
||||
+
|
||||
+reset_db
|
||||
+do_execsql_test 21.0 {
|
||||
+ CREATE TABLE a(b);
|
||||
+ CREATE VIEW c AS
|
||||
+ SELECT NULL INTERSECT
|
||||
+ SELECT NULL ORDER BY
|
||||
+ likelihood(NULL, (d, (SELECT c)));
|
||||
+} {}
|
||||
+do_catchsql_test 21.1 {
|
||||
+ SELECT likelihood(NULL, (d, (SELECT c)));
|
||||
+} {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}}
|
||||
+do_catchsql_test 21.2 {
|
||||
+ SELECT * FROM c;
|
||||
+} {1 {1st ORDER BY term does not match any column in the result set}}
|
||||
+
|
||||
+do_catchsql_test 21.3 {
|
||||
+ ALTER TABLE a RENAME TO e;
|
||||
+} {1 {error in view c: 1st ORDER BY term does not match any column in the result set}}
|
||||
+
|
||||
finish_test
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
From a144b923c5f3a60e4f7caa77305a3e4765bdba5d Mon Sep 17 00:00:00 2001
|
||||
From: Peibao Liu <peibao.liu@windriver.com>
|
||||
Date: Mon, 6 Jul 2020 15:59:47 -0400
|
||||
Subject: [PATCH] backport-Fix-CVE-2020-15358
|
||||
|
||||
Signed-off-by: Peibao Liu <peibao.liu@windriver.com>
|
||||
---
|
||||
src/select.c | 7 +++----
|
||||
src/sqliteInt.h | 1 +
|
||||
test/selectA.test | 21 +++++++++++++++++++++
|
||||
3 files changed, 25 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index b5e5a75..7f88e35 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -2717,9 +2717,7 @@ static int multiSelect(
|
||||
selectOpName(p->op)));
|
||||
rc = sqlite3Select(pParse, p, &uniondest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
- /* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
||||
- ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
||||
- sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
+ assert( p->pOrderBy==0 );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = 0;
|
||||
@@ -4068,7 +4066,7 @@ static int flattenSubquery(
|
||||
** We look at every expression in the outer query and every place we see
|
||||
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
||||
*/
|
||||
- if( pSub->pOrderBy ){
|
||||
+ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
|
||||
/* At this point, any non-zero iOrderByCol values indicate that the
|
||||
** ORDER BY column expression is identical to the iOrderByCol'th
|
||||
** expression returned by SELECT statement pSub. Since these values
|
||||
@@ -5769,6 +5767,7 @@ int sqlite3Select(
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
p->pOrderBy = 0;
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
+ p->selFlags |= SF_NoopOrderBy;
|
||||
}
|
||||
sqlite3SelectPrep(pParse, p, 0);
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
|
||||
index aa9556b..514df18 100644
|
||||
--- a/src/sqliteInt.h
|
||||
+++ b/src/sqliteInt.h
|
||||
@@ -3074,6 +3074,7 @@ struct Select {
|
||||
#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
|
||||
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
|
||||
#define SF_View 0x0200000 /* SELECT statement is a view */
|
||||
+#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
diff --git a/test/selectA.test b/test/selectA.test
|
||||
index 838e5f4..7ca0096 100644
|
||||
--- a/test/selectA.test
|
||||
+++ b/test/selectA.test
|
||||
@@ -1446,5 +1446,26 @@ do_execsql_test 6.1 {
|
||||
SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a;
|
||||
} {12345}
|
||||
|
||||
+# 2020-06-15 ticket 8f157e8010b22af0
|
||||
+#
|
||||
+reset_db
|
||||
+do_execsql_test 7.1 {
|
||||
+ CREATE TABLE t1(c1); INSERT INTO t1 VALUES(12),(123),(1234),(NULL),('abc');
|
||||
+ CREATE TABLE t2(c2); INSERT INTO t2 VALUES(44),(55),(123);
|
||||
+ CREATE TABLE t3(c3,c4); INSERT INTO t3 VALUES(66,1),(123,2),(77,3);
|
||||
+ CREATE VIEW t4 AS SELECT c3 FROM t3;
|
||||
+ CREATE VIEW t5 AS SELECT c3 FROM t3 ORDER BY c4;
|
||||
+}
|
||||
+do_execsql_test 7.2 {
|
||||
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t4) AND c1=123;
|
||||
+} {123 123}
|
||||
+do_execsql_test 7.3 {
|
||||
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t5) AND c1=123;
|
||||
+} {123 123}
|
||||
+do_execsql_test 7.4 {
|
||||
+ CREATE TABLE a(b);
|
||||
+ CREATE VIEW c(d) AS SELECT b FROM a ORDER BY b;
|
||||
+ SELECT sum(d) OVER( PARTITION BY(SELECT 0 FROM c JOIN a WHERE b =(SELECT b INTERSECT SELECT d FROM c) AND b = 123)) FROM c;
|
||||
+} {}
|
||||
|
||||
finish_test
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
diff -Naur 1/src/alter.c 2/src/alter.c
|
||||
--- 1/src/alter.c 2020-06-02 16:02:38.294309518 -0400
|
||||
+++ 2/src/alter.c 2020-06-02 16:05:27.248309518 -0400
|
||||
@@ -123,7 +123,10 @@
|
||||
/* Check that a table or index named 'zName' does not already exist
|
||||
** in database iDb. If so, this is an error.
|
||||
*/
|
||||
- if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
|
||||
+ if( sqlite3FindTable(db, zName, zDb)
|
||||
+ || sqlite3FindIndex(db, zName, zDb)
|
||||
+ || sqlite3IsShadowTableOf(db, pTab, zName)
|
||||
+ ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"there is already another table or index with this name: %s", zName);
|
||||
goto exit_rename_table;
|
||||
diff -Naur 1/src/build.c 2/src/build.c
|
||||
--- 1/src/build.c 2020-06-02 16:02:38.325309518 -0400
|
||||
+++ 2/src/build.c 2020-06-02 16:11:12.023309518 -0400
|
||||
@@ -2129,6 +2129,28 @@
|
||||
recomputeColumnsNotIndexed(pPk);
|
||||
}
|
||||
|
||||
+
|
||||
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
+/*
|
||||
+ * ** Return true if pTab is a virtual table and zName is a shadow table name
|
||||
+ * ** for that virtual table.
|
||||
+ * */
|
||||
+int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
|
||||
+ int nName; /* Length of zName */
|
||||
+ Module *pMod; /* Module for the virtual table */
|
||||
+
|
||||
+ if( !IsVirtual(pTab) ) return 0;
|
||||
+ nName = sqlite3Strlen30(pTab->zName);
|
||||
+ if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
|
||||
+ if( zName[nName]!='_' ) return 0;
|
||||
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
|
||||
+ if( pMod==0 ) return 0;
|
||||
+ if( pMod->pModule->iVersion<3 ) return 0;
|
||||
+ if( pMod->pModule->xShadowName==0 ) return 0;
|
||||
+ return pMod->pModule->xShadowName(zName+nName+1);
|
||||
+}
|
||||
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
+
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Return true if zName is a shadow table name in the current database
|
||||
@@ -2140,7 +2162,6 @@
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
||||
char *zTail; /* Pointer to the last "_" in zName */
|
||||
Table *pTab; /* Table that zName is a shadow of */
|
||||
- Module *pMod; /* Module for the virtual table */
|
||||
|
||||
zTail = strrchr(zName, '_');
|
||||
if( zTail==0 ) return 0;
|
||||
@@ -2149,11 +2170,7 @@
|
||||
*zTail = '_';
|
||||
if( pTab==0 ) return 0;
|
||||
if( !IsVirtual(pTab) ) return 0;
|
||||
- pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
|
||||
- if( pMod==0 ) return 0;
|
||||
- if( pMod->pModule->iVersion<3 ) return 0;
|
||||
- if( pMod->pModule->xShadowName==0 ) return 0;
|
||||
- return pMod->pModule->xShadowName(zTail+1);
|
||||
+ return sqlite3IsShadowTableOf(db, pTab, zName);
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
diff -Naur 1/src/sqliteInt.h 2/src/sqliteInt.h
|
||||
--- 1/src/sqliteInt.h 2020-06-02 16:02:38.291309518 -0400
|
||||
+++ 2/src/sqliteInt.h 2020-06-02 16:14:49.356309518 -0400
|
||||
@@ -4673,8 +4673,10 @@
|
||||
int sqlite3ReadOnlyShadowTables(sqlite3 *db);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
|
||||
+ int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
|
||||
#else
|
||||
# define sqlite3ShadowTableName(A,B) 0
|
||||
+# define sqlite3IsShadowTableOf(A,B,C) 0
|
||||
#endif
|
||||
int sqlite3VtabEponymousTableInit(Parse*,Module*);
|
||||
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
|
||||
@ -1,352 +0,0 @@
|
||||
From afa1ecac9b6fba76861dca85b211ca1022f9e378 Mon Sep 17 00:00:00 2001
|
||||
From: drh <drh@noemail.net>
|
||||
Date: Mon, 9 Mar 2020 18:26:11 +0000
|
||||
Subject: [PATCH] Cleaner separation of the STAT4-specific logic in the
|
||||
implementation of ANALYZE.
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/3df07e5a9a3781a4
|
||||
|
||||
FossilOrigin-Name: 3df07e5a9a3781a4cf866fc6ee0e5c6f9cd7ca35ce0a6eb3aa7f5f3502e0ffae
|
||||
---
|
||||
src/analyze.c | 113 +++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 56 insertions(+), 57 deletions(-)
|
||||
|
||||
diff --git a/src/analyze.c b/src/analyze.c
|
||||
index 2a071ef..daf3af7 100644
|
||||
--- a/src/analyze.c
|
||||
+++ b/src/analyze.c
|
||||
@@ -256,9 +256,9 @@ static void openStatTable(
|
||||
** share an instance of the following structure to hold their state
|
||||
** information.
|
||||
*/
|
||||
-typedef struct Stat4Accum Stat4Accum;
|
||||
-typedef struct Stat4Sample Stat4Sample;
|
||||
-struct Stat4Sample {
|
||||
+typedef struct StatAccum StatAccum;
|
||||
+typedef struct StatSample StatSample;
|
||||
+struct StatSample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
@@ -273,27 +273,30 @@ struct Stat4Sample {
|
||||
u32 iHash; /* Tiebreaker hash */
|
||||
#endif
|
||||
};
|
||||
-struct Stat4Accum {
|
||||
+struct StatAccum {
|
||||
+ sqlite3 *db; /* Database connection, for malloc() */
|
||||
tRowcnt nRow; /* Number of rows in the entire table */
|
||||
- tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
int nCol; /* Number of columns in index + pk/rowid */
|
||||
int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
||||
+ StatSample current; /* Current row as a StatSample */
|
||||
+#ifdef SQLITE_ENABLE_STAT4
|
||||
+ tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
int mxSample; /* Maximum number of samples to accumulate */
|
||||
Stat4Sample current; /* Current row as a Stat4Sample */
|
||||
u32 iPrn; /* Pseudo-random number used for sampling */
|
||||
- Stat4Sample *aBest; /* Array of nCol best samples */
|
||||
+ StatSample *aBest; /* Array of nCol best samples */
|
||||
int iMin; /* Index in a[] of entry with minimum score */
|
||||
int nSample; /* Current number of samples */
|
||||
int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
|
||||
int iGet; /* Index of current sample accessed by stat_get() */
|
||||
- Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
||||
- sqlite3 *db; /* Database connection, for malloc() */
|
||||
+ StatSample *a; /* Array of mxSample StatSample objects */
|
||||
+#endif
|
||||
};
|
||||
|
||||
-/* Reclaim memory used by a Stat4Sample
|
||||
+/* Reclaim memory used by a StatSample
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
-static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
+static void sampleClear(sqlite3 *db, StatSample *p){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ){
|
||||
sqlite3DbFree(db, p->u.aRowid);
|
||||
@@ -305,7 +308,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
/* Initialize the BLOB value of a ROWID
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
-static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
+static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
|
||||
@@ -321,7 +324,7 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
/* Initialize the INTEGER value of a ROWID.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
-static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
+static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->nRowid = 0;
|
||||
@@ -334,7 +337,7 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
** Copy the contents of object (*pFrom) into (*pTo).
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
-static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
+static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
||||
pTo->isPSample = pFrom->isPSample;
|
||||
pTo->iCol = pFrom->iCol;
|
||||
pTo->iHash = pFrom->iHash;
|
||||
@@ -352,8 +355,8 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
/*
|
||||
** Reclaim all memory of a Stat4Accum structure.
|
||||
*/
|
||||
-static void stat4Destructor(void *pOld){
|
||||
- Stat4Accum *p = (Stat4Accum*)pOld;
|
||||
+ static void statAccumDestructor(void *pOld){
|
||||
+ StatAccum *p = (StatAccum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
@@ -381,8 +384,8 @@ static void stat4Destructor(void *pOld){
|
||||
** PRIMARY KEY of the table. The covering index that implements the
|
||||
** original WITHOUT ROWID table as N==K as a special case.
|
||||
**
|
||||
-** This routine allocates the Stat4Accum object in heap memory. The return
|
||||
-** value is a pointer to the Stat4Accum object. The datatype of the
|
||||
+** This routine allocates the StatAccum object in heap memory. The return
|
||||
+** value is a pointer to the StatAccum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
||||
** object.
|
||||
*/
|
||||
@@ -391,7 +394,7 @@ static void statInit(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
- Stat4Accum *p;
|
||||
+ StatAccum *p;
|
||||
int nCol; /* Number of columns in index being sampled */
|
||||
int nKeyCol; /* Number of key columns */
|
||||
int nColUp; /* nCol rounded up for alignment */
|
||||
@@ -410,13 +413,13 @@ static void statInit(
|
||||
assert( nKeyCol<=nCol );
|
||||
assert( nKeyCol>0 );
|
||||
|
||||
- /* Allocate the space required for the Stat4Accum object */
|
||||
+ /* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
||||
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
||||
+ + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
+ + sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
||||
- + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
||||
+ + sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
#endif
|
||||
;
|
||||
@@ -445,8 +448,8 @@ static void statInit(
|
||||
p->current.anLt = &p->current.anEq[nColUp];
|
||||
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
||||
|
||||
- /* Set up the Stat4Accum.a[] and aBest[] arrays */
|
||||
- p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
|
||||
+ /* Set up the StatAccum.a[] and aBest[] arrays */
|
||||
+ p->a = (struct StatSample*)&p->current.anLt[nColUp];
|
||||
p->aBest = &p->a[mxSample];
|
||||
pSpace = (u8*)(&p->a[mxSample+nCol]);
|
||||
for(i=0; i<(mxSample+nCol); i++){
|
||||
@@ -466,7 +469,7 @@ static void statInit(
|
||||
** only the pointer (the 2nd parameter) matters. The size of the object
|
||||
** (given by the 3rd parameter) is never used and can be any positive
|
||||
** value. */
|
||||
- sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
||||
+ sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
|
||||
}
|
||||
static const FuncDef statInitFuncdef = {
|
||||
2+IsStat4, /* nArg */
|
||||
@@ -493,9 +496,9 @@ static const FuncDef statInitFuncdef = {
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetterPost(
|
||||
- Stat4Accum *pAccum,
|
||||
- Stat4Sample *pNew,
|
||||
- Stat4Sample *pOld
|
||||
+ StatAccum *pAccum,
|
||||
+ StatSample *pNew,
|
||||
+ StatSample *pOld
|
||||
){
|
||||
int nCol = pAccum->nCol;
|
||||
int i;
|
||||
@@ -517,9 +520,9 @@ static int sampleIsBetterPost(
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetter(
|
||||
- Stat4Accum *pAccum,
|
||||
- Stat4Sample *pNew,
|
||||
- Stat4Sample *pOld
|
||||
+ StatAccum *pAccum,
|
||||
+ StatSample *pNew,
|
||||
+ StatSample *pOld
|
||||
){
|
||||
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
|
||||
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
|
||||
@@ -539,21 +542,21 @@ static int sampleIsBetter(
|
||||
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
|
||||
** remove the least desirable sample from p->a[] to make room.
|
||||
*/
|
||||
-static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
- Stat4Sample *pSample = 0;
|
||||
+static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
|
||||
+ StatSample *pSample = 0;
|
||||
int i;
|
||||
|
||||
assert( IsStat4 || nEqZero==0 );
|
||||
|
||||
- /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
||||
- ** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
||||
+ /* StatAccum.nMaxEqZero is set to the maximum number of leading 0
|
||||
+ ** values in the anEq[] array of any sample in StatAccum.a[]. In
|
||||
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
||||
** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
|
||||
if( nEqZero>p->nMaxEqZero ){
|
||||
p->nMaxEqZero = nEqZero;
|
||||
}
|
||||
if( pNew->isPSample==0 ){
|
||||
- Stat4Sample *pUpgrade = 0;
|
||||
+ StatSample *pUpgrade = 0;
|
||||
assert( pNew->anEq[pNew->iCol]>0 );
|
||||
|
||||
/* This sample is being added because the prefix that ends in column
|
||||
@@ -562,7 +565,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
** this one. Instead, upgrade the priority of the highest priority
|
||||
** existing sample that shares this prefix. */
|
||||
for(i=p->nSample-1; i>=0; i--){
|
||||
- Stat4Sample *pOld = &p->a[i];
|
||||
+ StatSample *pOld = &p->a[i];
|
||||
if( pOld->anEq[pNew->iCol]==0 ){
|
||||
if( pOld->isPSample ) return;
|
||||
assert( pOld->iCol>pNew->iCol );
|
||||
@@ -581,7 +584,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
|
||||
/* If necessary, remove sample iMin to make room for the new sample. */
|
||||
if( p->nSample>=p->mxSample ){
|
||||
- Stat4Sample *pMin = &p->a[p->iMin];
|
||||
+ StatSample *pMin = &p->a[p->iMin];
|
||||
tRowcnt *anEq = pMin->anEq;
|
||||
tRowcnt *anLt = pMin->anLt;
|
||||
tRowcnt *anDLt = pMin->anDLt;
|
||||
@@ -623,6 +626,7 @@ find_new_min:
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
+#ifdef SQLITE_ENABLE_STAT4
|
||||
|
||||
/*
|
||||
** Field iChng of the index being scanned has changed. So at this point
|
||||
@@ -630,14 +634,13 @@ find_new_min:
|
||||
** index. The value of anEq[iChng] and subsequent anEq[] elements are
|
||||
** correct at this point.
|
||||
*/
|
||||
-static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
-#ifdef SQLITE_ENABLE_STAT4
|
||||
+static void samplePushPrevious(StatAccum *p, int iChng){
|
||||
int i;
|
||||
|
||||
/* Check if any samples from the aBest[] array should be pushed
|
||||
** into IndexSample.a[] at this point. */
|
||||
for(i=(p->nCol-2); i>=iChng; i--){
|
||||
- Stat4Sample *pBest = &p->aBest[i];
|
||||
+ StatSample *pBest = &p->aBest[i];
|
||||
pBest->anEq[i] = p->current.anEq[i];
|
||||
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
|
||||
sampleInsert(p, pBest, i);
|
||||
@@ -661,19 +664,14 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
}
|
||||
p->nMaxEqZero = iChng;
|
||||
}
|
||||
-#endif
|
||||
-
|
||||
-#ifndef SQLITE_ENABLE_STAT4
|
||||
- UNUSED_PARAMETER( p );
|
||||
- UNUSED_PARAMETER( iChng );
|
||||
-#endif
|
||||
}
|
||||
+#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
||||
** Arguments:
|
||||
**
|
||||
-** P Pointer to the Stat4Accum object created by stat_init()
|
||||
+** P Pointer to the StatAccum object created by stat_init()
|
||||
** C Index of left-most column to differ from previous row
|
||||
** R Rowid for the current row. Might be a key record for
|
||||
** WITHOUT ROWID tables.
|
||||
@@ -693,7 +691,7 @@ static void statPush(
|
||||
int i;
|
||||
|
||||
/* The three function arguments */
|
||||
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
int iChng = sqlite3_value_int(argv[1]);
|
||||
|
||||
UNUSED_PARAMETER( argc );
|
||||
@@ -706,8 +704,9 @@ static void statPush(
|
||||
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
+#ifdef SQLITE_ENABLE_STAT4
|
||||
samplePushPrevious(p, iChng);
|
||||
-
|
||||
+#endif
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
for(i=0; i<iChng; i++){
|
||||
@@ -775,15 +774,15 @@ static const FuncDef statPushFuncdef = {
|
||||
/*
|
||||
** Implementation of the stat_get(P,J) SQL function. This routine is
|
||||
** used to query statistical information that has been gathered into
|
||||
-** the Stat4Accum object by prior calls to stat_push(). The P parameter
|
||||
-** has type BLOB but it is really just a pointer to the Stat4Accum object.
|
||||
+** the StatAccum object by prior calls to stat_push(). The P parameter
|
||||
+** has type BLOB but it is really just a pointer to the StatAccum object.
|
||||
** The content to returned is determined by the parameter J
|
||||
** which is one of the STAT_GET_xxxx values defined above.
|
||||
**
|
||||
** The stat_get(P,J) function is not available to generic SQL. It is
|
||||
** inserted as part of a manually constructed bytecode program. (See
|
||||
** the callStatGet() routine below.) It is guaranteed that the P
|
||||
-** parameter will always be a poiner to a Stat4Accum object, never a
|
||||
+** parameter will always be a poiner to a StatAccum object, never a
|
||||
** NULL.
|
||||
**
|
||||
** If STAT4 is not enabled, then J is always
|
||||
@@ -796,7 +795,7 @@ static void statGet(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* STAT4 has a parameter on this routine. */
|
||||
int eCall = sqlite3_value_int(argv[1]);
|
||||
@@ -860,7 +859,7 @@ static void statGet(
|
||||
p->iGet = 0;
|
||||
}
|
||||
if( p->iGet<p->nSample ){
|
||||
- Stat4Sample *pS = p->a + p->iGet;
|
||||
+ StatSample *pS = p->a + p->iGet;
|
||||
if( pS->nRowid==0 ){
|
||||
sqlite3_result_int64(context, pS->u.iRowid);
|
||||
}else{
|
||||
@@ -951,7 +950,7 @@ static void analyzeOneTable(
|
||||
int iDb; /* Index of database containing pTab */
|
||||
u8 needTableCnt = 1; /* True to count the table */
|
||||
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
||||
- int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
||||
+ int regStat4 = iMem++; /* Register to hold StatAccum object */
|
||||
int regChng = iMem++; /* Index of changed index field */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,211 +0,0 @@
|
||||
From 9d33d9e7ac064aed9de16d25544c7f45dcb76465 Mon Sep 17 00:00:00 2001
|
||||
From: drh <drh@noemail.net>
|
||||
Date: Tue, 10 Mar 2020 01:24:13 +0000
|
||||
Subject: [PATCH] Background work for experiments trying to enhance ANALYZE so
|
||||
that it runs off of samples of the entire index and does not need to read the
|
||||
entire index.
|
||||
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/29d1cc5c3619a882
|
||||
|
||||
FossilOrigin-Name: 29d1cc5c3619a88229f18c3c8131228f8a2d151ac3d9203f0c7fc538a996ecec
|
||||
---
|
||||
src/analyze.c | 90 ++++++++++++++++++++++++++++-----------------------
|
||||
1 file changed, 50 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/src/analyze.c b/src/analyze.c
|
||||
index daf3af7..11ac430 100644
|
||||
--- a/src/analyze.c
|
||||
+++ b/src/analyze.c
|
||||
@@ -188,6 +188,11 @@ static void openStatTable(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int aRoot[ArraySize(aTable)];
|
||||
u8 aCreateTbl[ArraySize(aTable)];
|
||||
+#ifdef SQLITE_ENABLE_STAT4
|
||||
+ const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
|
||||
+#else
|
||||
+ const int nToOpen = 1;
|
||||
+#endif
|
||||
|
||||
if( v==0 ) return;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
@@ -200,8 +205,9 @@ static void openStatTable(
|
||||
for(i=0; i<ArraySize(aTable); i++){
|
||||
const char *zTab = aTable[i].zName;
|
||||
Table *pStat;
|
||||
+ aCreateTbl[i] = 0;
|
||||
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
|
||||
- if( aTable[i].zCols ){
|
||||
+ if( i<nToOpen ){
|
||||
/* The sqlite_statN table does not exist. Create it. Note that a
|
||||
** side-effect of the CREATE TABLE statement is to leave the rootpage
|
||||
** of the new table in register pParse->regRoot. This is important
|
||||
@@ -217,7 +223,6 @@ static void openStatTable(
|
||||
** associated with the table zWhere. If zWhere is NULL, delete the
|
||||
** entire contents of the table. */
|
||||
aRoot[i] = pStat->tnum;
|
||||
- aCreateTbl[i] = 0;
|
||||
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
|
||||
if( zWhere ){
|
||||
sqlite3NestedParse(pParse,
|
||||
@@ -236,7 +241,7 @@ static void openStatTable(
|
||||
}
|
||||
|
||||
/* Open the sqlite_stat[134] tables for writing. */
|
||||
- for(i=0; aTable[i].zCols; i++){
|
||||
+ for(i=0; i<nToOpen; i++){
|
||||
assert( i<ArraySize(aTable) );
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
||||
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
||||
@@ -358,10 +363,12 @@ static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
||||
static void statAccumDestructor(void *pOld){
|
||||
StatAccum *p = (StatAccum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- int i;
|
||||
- for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
- for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
||||
- sampleClear(p->db, &p->current);
|
||||
+ if( p->mxSample ){
|
||||
+ int i;
|
||||
+ for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
+ for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
||||
+ sampleClear(p->db, &p->current);
|
||||
+ }
|
||||
#endif
|
||||
sqlite3DbFree(p->db, p);
|
||||
}
|
||||
@@ -401,7 +408,7 @@ static void statInit(
|
||||
int n; /* Bytes of space to allocate */
|
||||
sqlite3 *db; /* Database connection */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- int mxSample = SQLITE_STAT4_SAMPLES;
|
||||
+ int mxSample = sqlite3_value_int(argv[2]) ? SQLITE_STAT4_SAMPLES : 0;
|
||||
#endif
|
||||
|
||||
/* Decode the three function arguments */
|
||||
@@ -438,7 +445,7 @@ static void statInit(
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- {
|
||||
+ if( mxSample ){
|
||||
u8 *pSpace; /* Allocated space not yet assigned */
|
||||
int i; /* Used to iterate through p->aSample[] */
|
||||
|
||||
@@ -705,7 +712,7 @@ static void statPush(
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- samplePushPrevious(p, iChng);
|
||||
+ if( p->mxSample ) samplePushPrevious(p, iChng);
|
||||
#endif
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
@@ -715,26 +722,22 @@ static void statPush(
|
||||
for(i=iChng; i<p->nCol; i++){
|
||||
p->current.anDLt[i]++;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- p->current.anLt[i] += p->current.anEq[i];
|
||||
+ if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
|
||||
#endif
|
||||
p->current.anEq[i] = 1;
|
||||
}
|
||||
}
|
||||
p->nRow++;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
||||
- sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
||||
- }else{
|
||||
- sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
||||
- sqlite3_value_blob(argv[2]));
|
||||
- }
|
||||
- p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
||||
-#endif
|
||||
-
|
||||
-#ifdef SQLITE_ENABLE_STAT4
|
||||
- {
|
||||
- tRowcnt nLt = p->current.anLt[p->nCol-1];
|
||||
-
|
||||
+ if( p->mxSample ){
|
||||
+ tRowcnt nLt;
|
||||
+ if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
||||
+ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
||||
+ }else{
|
||||
+ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),sqlite3_value_blob(argv[2]));
|
||||
+ }
|
||||
+ p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
||||
+ nLt = p->current.anLt[p->nCol-1];
|
||||
/* Check if this is to be a periodic sample. If so, add it. */
|
||||
if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
|
||||
p->current.isPSample = 1;
|
||||
@@ -804,6 +807,7 @@ static void statGet(
|
||||
|| eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
|
||||
|| eCall==STAT_GET_NDLT
|
||||
);
|
||||
+ assert( eCall==STAT_GET_STAT1 || p->mxSample );
|
||||
if( eCall==STAT_GET_STAT1 )
|
||||
#else
|
||||
assert( argc==1 );
|
||||
@@ -1089,7 +1093,11 @@ static void analyzeOneTable(
|
||||
** The third argument is only used for STAT4
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
||||
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
||||
+ }else{
|
||||
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regStat4+3);
|
||||
+ }
|
||||
#endif
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
||||
@@ -1171,21 +1179,23 @@ static void analyzeOneTable(
|
||||
** if !eof(csr) goto next_row;
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- assert( regRowid==(regStat4+2) );
|
||||
- if( HasRowid(pTab) ){
|
||||
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
||||
- }else{
|
||||
- Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
- int j, k, regKey;
|
||||
- regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
- for(j=0; j<pPk->nKeyCol; j++){
|
||||
- k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
- assert( k>=0 && k<pIdx->nColumn );
|
||||
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
- VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
+ assert( regRowid==(regStat4+2) );
|
||||
+ if( HasRowid(pTab) ){
|
||||
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
||||
+ }else{
|
||||
+ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
+ int j, k, regKey;
|
||||
+ regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
+ for(j=0; j<pPk->nKeyCol; j++){
|
||||
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
+ assert( k>=0 && k<pIdx->nColumn );
|
||||
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
+ VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
+ }
|
||||
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
||||
+ sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
||||
}
|
||||
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
||||
- sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
||||
}
|
||||
#endif
|
||||
assert( regChng==(regStat4+1) );
|
||||
@@ -1206,7 +1216,7 @@ static void analyzeOneTable(
|
||||
|
||||
/* Add the entries to the stat4 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- {
|
||||
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
int regEq = regStat1;
|
||||
int regLt = regStat1+1;
|
||||
int regDLt = regStat1+2;
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,145 +0,0 @@
|
||||
From 553948e51433715f32d57e6977db6e0992b7f8cd Mon Sep 17 00:00:00 2001
|
||||
From: dan <dan@noemail.net>
|
||||
Date: Mon, 16 Mar 2020 18:52:53 +0000
|
||||
Subject: [PATCH] Fix handling of window functions in aggregate queries that
|
||||
have no GROUP BY clause. Also remove a faulty assert causing the error
|
||||
reported in [618156e3].
|
||||
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/38e3dd389d142e52
|
||||
|
||||
---
|
||||
src/select.c | 1 -
|
||||
src/window.c | 2 ++
|
||||
test/window4.tcl | 14 ++++++++++++++
|
||||
test/window4.test | 14 ++++++++++++++
|
||||
test/window9.test | 33 +++++++++++++++++++++++++++++++++
|
||||
5 files changed, 63 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index 7f88e35..f61fbce 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -103,7 +103,6 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
|
||||
sqlite3WindowListDelete(db, p->pWinDefn);
|
||||
}
|
||||
- assert( p->pWin==0 );
|
||||
#endif
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
diff --git a/src/window.c b/src/window.c
|
||||
index a72ec0d..9bb3217 100644
|
||||
--- a/src/window.c
|
||||
+++ b/src/window.c
|
||||
@@ -933,6 +933,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
Window *pMWin = p->pWin; /* Master window object */
|
||||
Window *pWin; /* Window object iterator */
|
||||
Table *pTab;
|
||||
+ u32 selFlags = p->selFlags;
|
||||
|
||||
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ){
|
||||
@@ -1022,6 +1023,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
sqlite3SrcListAssignCursors(pParse, p->pSrc);
|
||||
pSub->selFlags |= SF_Expanded;
|
||||
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
|
||||
+ pSub->selFlags |= (selFlags & SF_Aggregate);
|
||||
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
|
||||
diff --git a/test/window4.tcl b/test/window4.tcl
|
||||
index 1b2b2ef..0b91d76 100644
|
||||
--- a/test/window4.tcl
|
||||
+++ b/test/window4.tcl
|
||||
@@ -385,6 +385,20 @@ execsql_test 11.4 {
|
||||
) sub;
|
||||
}
|
||||
|
||||
+execsql_test 11.5 {
|
||||
+ SELECT sum( min(t) ) OVER () FROM t8 GROUP BY total;
|
||||
+}
|
||||
+execsql_test 11.5 {
|
||||
+ SELECT sum( max(t) ) OVER () FROM t8 GROUP BY total;
|
||||
+}
|
||||
+
|
||||
+execsql_test 11.7 {
|
||||
+ SELECT sum( min(t) ) OVER () FROM t8;
|
||||
+}
|
||||
+execsql_test 11.8 {
|
||||
+ SELECT sum( max(t) ) OVER () FROM t8;
|
||||
+}
|
||||
+
|
||||
execsql_test 12.0 {
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(a INTEGER);
|
||||
diff --git a/test/window4.test b/test/window4.test
|
||||
index 6951a23..a0344e0 100644
|
||||
--- a/test/window4.test
|
||||
+++ b/test/window4.test
|
||||
@@ -1324,6 +1324,20 @@ do_execsql_test 11.4 {
|
||||
) sub;
|
||||
} {0 1 2}
|
||||
|
||||
+do_execsql_test 11.5 {
|
||||
+ SELECT sum( min(t) ) OVER () FROM t8 GROUP BY total;
|
||||
+} {5 5}
|
||||
+
|
||||
+do_execsql_test 11.5 {
|
||||
+ SELECT sum( max(t) ) OVER () FROM t8 GROUP BY total;
|
||||
+} {10 10}
|
||||
+do_execsql_test 11.7 {
|
||||
+ SELECT sum( min(t) ) OVER () FROM t8;
|
||||
+} {0}
|
||||
+do_execsql_test 11.8 {
|
||||
+ SELECT sum( max(t) ) OVER () FROM t8;
|
||||
+} {10}
|
||||
+
|
||||
do_execsql_test 12.0 {
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(a INTEGER);
|
||||
diff --git a/test/window9.test b/test/window9.test
|
||||
index adfeaba..686afc9 100644
|
||||
--- a/test/window9.test
|
||||
+++ b/test/window9.test
|
||||
@@ -232,4 +232,37 @@ do_execsql_test 7.4 {
|
||||
7.2 8.75 10.0 11.0 15.0
|
||||
}
|
||||
|
||||
+#-------------------------------------------------------------------------
|
||||
+reset_db
|
||||
+do_execsql_test 8.1.1 {
|
||||
+ CREATE TABLE t1(a, b);
|
||||
+ INSERT INTO t1 VALUES(1, 2), (3, 4);
|
||||
+ SELECT min( sum(a) ) OVER () FROM t1;
|
||||
+} {4}
|
||||
+
|
||||
+do_execsql_test 8.1.2 {
|
||||
+ SELECT min( sum(a) ) OVER () FROM t1 GROUP BY a;
|
||||
+} {1 1}
|
||||
+
|
||||
+do_execsql_test 8.2 {
|
||||
+ CREATE VIEW v1 AS
|
||||
+ SELECT 0 AS x
|
||||
+ UNION
|
||||
+ SELECT count() OVER() FROM (SELECT 0)
|
||||
+ ORDER BY 1
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+do_catchsql_test 8.3 {
|
||||
+ SELECT min( max((SELECT x FROM v1)) ) OVER()
|
||||
+} {1 {misuse of aggregate: max()}}
|
||||
+
|
||||
+do_execsql_test 8.4 {
|
||||
+ SELECT(
|
||||
+ SELECT x UNION
|
||||
+ SELECT sum( avg((SELECT x FROM v1)) ) OVER()
|
||||
+ )
|
||||
+ FROM v1;
|
||||
+} {0.0}
|
||||
+
|
||||
finish_test
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,168 +0,0 @@
|
||||
From e50478d7279b72a9df4836729c9974abfbce08ff Mon Sep 17 00:00:00 2001
|
||||
From: drh <drh@noemail.net>
|
||||
Date: Tue, 17 Mar 2020 13:41:51 +0000
|
||||
Subject: [PATCH] Remove the SQLITE_OMIT_BTREECOUNT option. Btree count is
|
||||
required.
|
||||
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/a9bfa47aeea27e91
|
||||
---
|
||||
src/analyze.c | 14 ++++++++------
|
||||
src/btree.c | 2 --
|
||||
src/btree.h | 2 --
|
||||
src/ctime.c | 3 ---
|
||||
src/pragma.c | 2 --
|
||||
src/select.c | 7 ++-----
|
||||
src/vdbe.c | 2 --
|
||||
7 files changed, 10 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/src/analyze.c b/src/analyze.c
|
||||
index 11ac430..fa01925 100644
|
||||
--- a/src/analyze.c
|
||||
+++ b/src/analyze.c
|
||||
@@ -408,7 +408,8 @@ static void statInit(
|
||||
int n; /* Bytes of space to allocate */
|
||||
sqlite3 *db; /* Database connection */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- int mxSample = sqlite3_value_int(argv[2]) ? SQLITE_STAT4_SAMPLES : 0;
|
||||
+ /* Maximum number of samples. 0 if STAT4 data is not collected */
|
||||
+ int mxSample = sqlite3_value_int64(argv[2]) ? SQLITE_STAT4_SAMPLES : 0;
|
||||
#endif
|
||||
|
||||
/* Decode the three function arguments */
|
||||
@@ -423,13 +424,14 @@ static void statInit(
|
||||
/* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
- + sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
|
||||
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
- + sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
- + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
- + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
+ if( mxSample ){
|
||||
+ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
|
||||
+ }
|
||||
#endif
|
||||
- ;
|
||||
db = sqlite3_context_db_handle(context);
|
||||
p = sqlite3DbMallocZero(db, n);
|
||||
if( p==0 ){
|
||||
diff --git a/src/btree.c b/src/btree.c
|
||||
index be5d639..78a99d2 100644
|
||||
--- a/src/btree.c
|
||||
+++ b/src/btree.c
|
||||
@@ -9514,7 +9514,6 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
|
||||
return rc;
|
||||
}
|
||||
|
||||
-#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
/*
|
||||
** The first argument, pCur, is a cursor opened on some b-tree. Count the
|
||||
** number of entries in the b-tree and write the result to *pnEntry.
|
||||
@@ -9587,7 +9586,6 @@ int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
||||
/* An error has occurred. Return an error code. */
|
||||
return rc;
|
||||
}
|
||||
-#endif
|
||||
|
||||
/*
|
||||
** Return the pager associated with a BTree. This routine is used for
|
||||
diff --git a/src/btree.h b/src/btree.h
|
||||
index 4bd41f7..2085c07 100644
|
||||
--- a/src/btree.h
|
||||
+++ b/src/btree.h
|
||||
@@ -336,9 +336,7 @@ int sqlite3BtreeCursorIsValid(BtCursor*);
|
||||
#endif
|
||||
int sqlite3BtreeCursorIsValidNN(BtCursor*);
|
||||
|
||||
-#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
|
||||
-#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
diff --git a/src/ctime.c b/src/ctime.c
|
||||
index 013a0c2..aeaaa4f 100644
|
||||
--- a/src/ctime.c
|
||||
+++ b/src/ctime.c
|
||||
@@ -514,9 +514,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_OMIT_BLOB_LITERAL
|
||||
"OMIT_BLOB_LITERAL",
|
||||
#endif
|
||||
-#if SQLITE_OMIT_BTREECOUNT
|
||||
- "OMIT_BTREECOUNT",
|
||||
-#endif
|
||||
#if SQLITE_OMIT_CAST
|
||||
"OMIT_CAST",
|
||||
#endif
|
||||
diff --git a/src/pragma.c b/src/pragma.c
|
||||
index 4d33e8c..0de9dc3 100644
|
||||
--- a/src/pragma.c
|
||||
+++ b/src/pragma.c
|
||||
@@ -1729,7 +1729,6 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
-#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
if( !isQuick ){
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
@@ -1743,7 +1742,6 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
-#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
}
|
||||
}
|
||||
{
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index f61fbce..0cc6b87 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -6620,7 +6620,6 @@ int sqlite3Select(
|
||||
|
||||
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
||||
else {
|
||||
-#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
Table *pTab;
|
||||
if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
||||
/* If isSimpleCount() returns a pointer to a Table structure, then
|
||||
@@ -6678,10 +6677,8 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
- }else
|
||||
-#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
- {
|
||||
- int regAcc = 0; /* "populate accumulators" flag */
|
||||
+ }else{
|
||||
+ int regAcc = 0; /* "populate accumulators" flag */
|
||||
|
||||
/* If there are accumulator registers but no min() or max() functions
|
||||
** without FILTER clauses, allocate register regAcc. Register regAcc
|
||||
diff --git a/src/vdbe.c b/src/vdbe.c
|
||||
index b9d2d12..acb4a14 100644
|
||||
--- a/src/vdbe.c
|
||||
+++ b/src/vdbe.c
|
||||
@@ -3194,7 +3194,6 @@ case OP_MakeRecord: {
|
||||
** Store the number of entries (an integer value) in the table or index
|
||||
** opened by cursor P1 in register P2
|
||||
*/
|
||||
-#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
case OP_Count: { /* out2 */
|
||||
i64 nEntry;
|
||||
BtCursor *pCrsr;
|
||||
@@ -3209,7 +3208,6 @@ case OP_Count: { /* out2 */
|
||||
pOut->u.i = nEntry;
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
-#endif
|
||||
|
||||
/* Opcode: Savepoint P1 * * P4 *
|
||||
**
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
From ca74fbf6f164ad6fa9c6bd79050dc57cdcd69388 Mon Sep 17 00:00:00 2001
|
||||
From: drh <drh@noemail.net>
|
||||
Date: Sun, 24 May 2020 02:05:04 +0000
|
||||
Subject: [PATCH] Improvements to parse-tree tracing logic. No changes in
|
||||
deliverable code.
|
||||
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/f7e5a68a7ebbb97a
|
||||
|
||||
FossilOrigin-Name: f7e5a68a7ebbb97a5beb050a75b3b4cf2fd6adc54653da993a8950fb3a5799f7
|
||||
---
|
||||
src/select.c | 2 +-
|
||||
src/treeview.c | 5 +++--
|
||||
2 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index 0cc6b87..9a16e8e 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -6379,7 +6379,7 @@ int sqlite3Select(
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
int ii;
|
||||
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
|
||||
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
for(ii=0; ii<sAggInfo.nColumn; ii++){
|
||||
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
||||
diff --git a/src/treeview.c b/src/treeview.c
|
||||
index 90a1d2d..f0751d1 100644
|
||||
--- a/src/treeview.c
|
||||
+++ b/src/treeview.c
|
||||
@@ -578,8 +578,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
#endif
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
|
||||
- pExpr->op2, pExpr->u.zToken, zFlgs);
|
||||
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s iAgg=%d agg=%p",
|
||||
+ pExpr->op2, pExpr->u.zToken, zFlgs,
|
||||
+ pExpr->iAgg, pExpr->pAggInfo);
|
||||
}else if( pExpr->op2!=0 ){
|
||||
const char *zOp2;
|
||||
char zBuf[8];
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,706 +0,0 @@
|
||||
From 896366282dae3789fb277c2dad8660784a0895a3 Mon Sep 17 00:00:00 2001
|
||||
From: drh <drh@noemail.net>
|
||||
Date: Sun, 7 Jun 2020 17:33:18 +0000
|
||||
Subject: [PATCH 1/3] Alternative fix to ticket [c8d3b9f0a750a529]: Prior to
|
||||
deleting or modifying an Expr not that is referenced by an AggInfo, modify
|
||||
the AggInfo to get its own copy of the original Expr.
|
||||
|
||||
patch reference:
|
||||
https://www.sqlite.org/src/info/6e6b3729e0549de0
|
||||
|
||||
FossilOrigin-Name: 7682d8a768fbccfe0cc956e9f6481637146e1ab9763b248ff11052761ce32e32
|
||||
---
|
||||
src/build.c | 12 +++-
|
||||
src/expr.c | 61 ++++++++++++++++++-
|
||||
src/prepare.c | 15 +++++
|
||||
src/select.c | 128 ++++++++++++++++++++++++----------------
|
||||
src/sqliteInt.h | 12 +++-
|
||||
src/window.c | 4 ++
|
||||
test/window1.test | 146 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
7 files changed, 324 insertions(+), 54 deletions(-)
|
||||
|
||||
diff --git a/src/build.c b/src/build.c
|
||||
index f1d078f..5846215 100644
|
||||
--- a/src/build.c
|
||||
+++ b/src/build.c
|
||||
@@ -208,11 +208,21 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
sqlite3AutoincrementBegin(pParse);
|
||||
|
||||
/* Code constant expressions that where factored out of inner loops */
|
||||
+ /* Code constant expressions that where factored out of inner loops.
|
||||
+ **
|
||||
+ ** The pConstExpr list might also contain expressions that we simply
|
||||
+ ** want to keep around until the Parse object is deleted. Such
|
||||
+ ** expressions have iConstExprReg==0. Do not generate code for
|
||||
+ ** those expressions, of course.
|
||||
+ */
|
||||
if( pParse->pConstExpr ){
|
||||
ExprList *pEL = pParse->pConstExpr;
|
||||
pParse->okConstFactor = 0;
|
||||
for(i=0; i<pEL->nExpr; i++){
|
||||
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
||||
+ int iReg = pEL->a[i].u.iConstExprReg;
|
||||
+ if( iReg>0 ){
|
||||
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/expr.c b/src/expr.c
|
||||
index af779d3..07e1612 100644
|
||||
--- a/src/expr.c
|
||||
+++ b/src/expr.c
|
||||
@@ -52,7 +52,12 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
- return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
+ if( ALWAYS(pExpr->x.pSelect)
|
||||
+ && pExpr->x.pSelect->pEList
|
||||
+ && ALWAYS(pExpr->x.pSelect->pEList->a[0].pExpr)
|
||||
+ ){
|
||||
+ return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
+ }
|
||||
}
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -5658,6 +5663,60 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
#endif
|
||||
return cnt.nThis>0 || cnt.nOther==0;
|
||||
}
|
||||
+/*
|
||||
+** This is a Walker expression node callback.
|
||||
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
|
||||
+** object that is referenced does not refer directly to the Expr. If
|
||||
+** it does, make a copy. This is done because the pExpr argument is
|
||||
+** subject to change.
|
||||
+**
|
||||
+** The copy is stored on pParse->pConstExpr with a register number of 0.
|
||||
+** This will cause the expression to be deleted automatically when the
|
||||
+** Parse object is destroyed, but the zero register number means that it
|
||||
+** will not generate any code in the preamble.
|
||||
+*/
|
||||
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
+ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
|
||||
+ && pExpr->pAggInfo!=0
|
||||
+ ){
|
||||
+ AggInfo *pAggInfo = pExpr->pAggInfo;
|
||||
+ int iAgg = pExpr->iAgg;
|
||||
+ Parse *pParse = pWalker->pParse;
|
||||
+ sqlite3 *db = pParse->db;
|
||||
+ assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
|
||||
+ if( pExpr->op==TK_AGG_COLUMN ){
|
||||
+ assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
|
||||
+ if( pAggInfo->aCol[iAgg].pExpr==pExpr ){
|
||||
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
+ if( pExpr ){
|
||||
+ pAggInfo->aCol[iAgg].pExpr = pExpr;
|
||||
+ pParse->pConstExpr = sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
+ }
|
||||
+ }
|
||||
+ }else{
|
||||
+ assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
|
||||
+ if( pAggInfo->aFunc[iAgg].pExpr==pExpr ){
|
||||
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
+ if( pExpr ){
|
||||
+ pAggInfo->aFunc[iAgg].pExpr = pExpr;
|
||||
+ pParse->pConstExpr = sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return WRC_Continue;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+** Initialize a Walker object so that will persist AggInfo entries referenced
|
||||
+** by the tree that is walked.
|
||||
+*/
|
||||
+void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
|
||||
+ memset(pWalker, 0, sizeof(*pWalker));
|
||||
+ pWalker->pParse = pParse;
|
||||
+ pWalker->xExprCallback = agginfoPersistExprCb;
|
||||
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
|
||||
+}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
diff --git a/src/prepare.c b/src/prepare.c
|
||||
index 2d928f1..e012ad4 100644
|
||||
--- a/src/prepare.c
|
||||
+++ b/src/prepare.c
|
||||
@@ -530,11 +530,26 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
return i;
|
||||
}
|
||||
|
||||
+/*
|
||||
+** Deallocate a single AggInfo object
|
||||
+*/
|
||||
+static void agginfoFree(sqlite3 *db, AggInfo *p){
|
||||
+ sqlite3DbFree(db, p->aCol);
|
||||
+ sqlite3DbFree(db, p->aFunc);
|
||||
+ sqlite3DbFree(db, p);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
+ AggInfo *pThis = pParse->pAggList;
|
||||
+ while( pThis ){
|
||||
+ AggInfo *pNext = pThis->pNext;
|
||||
+ agginfoFree(db, pThis);
|
||||
+ pThis = pNext;
|
||||
+ }
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
if( db ){
|
||||
diff --git a/src/select.c b/src/select.c
|
||||
index 9a16e8e..f117cd1 100644
|
||||
--- a/src/select.c
|
||||
+++ b/src/select.c
|
||||
@@ -3752,6 +3752,7 @@ static int flattenSubquery(
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
sqlite3 *db = pParse->db;
|
||||
+ Walker w; /* Walker to persist agginfo data */
|
||||
|
||||
/* Check to see if flattening is permitted. Return 0 if not.
|
||||
*/
|
||||
@@ -4120,6 +4121,8 @@ static int flattenSubquery(
|
||||
/* Finially, delete what is left of the subquery and return
|
||||
** success.
|
||||
*/
|
||||
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
||||
+ sqlite3WalkSelect(&w,pSub1);
|
||||
sqlite3SelectDelete(db, pSub1);
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
@@ -5729,10 +5732,10 @@ int sqlite3Select(
|
||||
Expr *pWhere; /* The WHERE clause. May be NULL */
|
||||
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
||||
Expr *pHaving; /* The HAVING clause. May be NULL */
|
||||
+ AggInfo *pAggInfo = 0; /* Aggregate information */
|
||||
int rc = 1; /* Value to return from this function */
|
||||
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
||||
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
||||
- AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||
int iEnd; /* Address of the end of the query */
|
||||
sqlite3 *db; /* The database connection */
|
||||
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
|
||||
@@ -5744,7 +5747,6 @@ int sqlite3Select(
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
- memset(&sAggInfo, 0, sizeof(sAggInfo));
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
@@ -6335,14 +6337,20 @@ int sqlite3Select(
|
||||
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
|
||||
** SELECT statement.
|
||||
*/
|
||||
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
||||
+ if( pAggInfo==0 ){
|
||||
+ goto select_end;
|
||||
+ }
|
||||
+ pAggInfo->pNext = pParse->pAggList;
|
||||
+ pParse->pAggList = pAggInfo;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
- sNC.uNC.pAggInfo = &sAggInfo;
|
||||
+ sNC.uNC.pAggInfo = pAggInfo;
|
||||
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
|
||||
- sAggInfo.mnReg = pParse->nMem+1;
|
||||
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
||||
- sAggInfo.pGroupBy = pGroupBy;
|
||||
+ pAggInfo->mnReg = pParse->nMem+1;
|
||||
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
||||
+ pAggInfo->pGroupBy = pGroupBy;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||
if( pHaving ){
|
||||
@@ -6355,14 +6363,14 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||
}
|
||||
- sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||
- if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
|
||||
- minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
|
||||
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
|
||||
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
|
||||
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pExpr, &pMinMaxOrderBy);
|
||||
}else{
|
||||
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
||||
}
|
||||
- for(i=0; i<sAggInfo.nFunc; i++){
|
||||
- Expr *pExpr = sAggInfo.aFunc[i].pExpr;
|
||||
+ for(i=0; i<pAggInfo->nFunc; i++){
|
||||
+ Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
||||
@@ -6374,22 +6382,22 @@ int sqlite3Select(
|
||||
#endif
|
||||
sNC.ncFlags &= ~NC_InAggFunc;
|
||||
}
|
||||
- sAggInfo.mxReg = pParse->nMem;
|
||||
+ pAggInfo->mxReg = pParse->nMem;
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
int ii;
|
||||
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
|
||||
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
- for(ii=0; ii<sAggInfo.nColumn; ii++){
|
||||
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
|
||||
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
||||
- ii, sAggInfo.aCol[ii].iMem);
|
||||
- sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
|
||||
+ ii,pAggInfo->aCol[ii].iMem);
|
||||
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pExpr, 0);
|
||||
}
|
||||
- for(ii=0; ii<sAggInfo.nFunc; ii++){
|
||||
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
|
||||
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
||||
- ii, sAggInfo.aFunc[ii].iMem);
|
||||
- sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
|
||||
+ ii, pAggInfo->aFunc[ii].iMem);
|
||||
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pExpr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6414,10 +6422,11 @@ int sqlite3Select(
|
||||
** that we do not need it after all, the OP_SorterOpen instruction
|
||||
** will be converted into a Noop.
|
||||
*/
|
||||
- sAggInfo.sortingIdx = pParse->nTab++;
|
||||
- pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
|
||||
- addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
||||
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
||||
+ pAggInfo->sortingIdx = pParse->nTab++;
|
||||
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
|
||||
+ 0, pAggInfo->nColumn);
|
||||
+ addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
||||
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
|
||||
0, (char*)pKeyInfo, P4_KEYINFO);
|
||||
|
||||
/* Initialize memory locations used by GROUP BY aggregate processing
|
||||
@@ -6472,8 +6481,8 @@ int sqlite3Select(
|
||||
nGroupBy = pGroupBy->nExpr;
|
||||
nCol = nGroupBy;
|
||||
j = nGroupBy;
|
||||
- for(i=0; i<sAggInfo.nColumn; i++){
|
||||
- if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
||||
+ for(i=0; i<pAggInfo->nColumn; i++){
|
||||
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
|
||||
nCol++;
|
||||
j++;
|
||||
}
|
||||
@@ -6481,8 +6490,8 @@ int sqlite3Select(
|
||||
regBase = sqlite3GetTempRange(pParse, nCol);
|
||||
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
|
||||
j = nGroupBy;
|
||||
- for(i=0; i<sAggInfo.nColumn; i++){
|
||||
- struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
||||
+ for(i=0; i<pAggInfo->nColumn; i++){
|
||||
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
|
||||
if( pCol->iSorterColumn>=j ){
|
||||
int r1 = j + regBase;
|
||||
sqlite3ExprCodeGetColumnOfTable(v,
|
||||
@@ -6492,16 +6501,16 @@ int sqlite3Select(
|
||||
}
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
||||
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
|
||||
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
sortOut = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
||||
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
|
||||
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
|
||||
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
||||
- sAggInfo.useSortingIdx = 1;
|
||||
+ pAggInfo->useSortingIdx = 1;
|
||||
}
|
||||
|
||||
/* If the index or temporary table used by the GROUP BY sort
|
||||
@@ -6525,14 +6534,14 @@ int sqlite3Select(
|
||||
*/
|
||||
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
if( groupBySort ){
|
||||
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
||||
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
|
||||
sortOut, sortPTab);
|
||||
}
|
||||
for(j=0; j<pGroupBy->nExpr; j++){
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
|
||||
}else{
|
||||
- sAggInfo.directMode = 1;
|
||||
+ pAggInfo->directMode = 1;
|
||||
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
||||
}
|
||||
}
|
||||
@@ -6562,14 +6571,14 @@ int sqlite3Select(
|
||||
** the current row
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
- updateAccumulator(pParse, iUseFlag, &sAggInfo);
|
||||
+ updateAccumulator(pParse, iUseFlag, pAggInfo);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
||||
VdbeComment((v, "indicate data in accumulator"));
|
||||
|
||||
/* End of the loop
|
||||
*/
|
||||
if( groupBySort ){
|
||||
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
|
||||
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
@@ -6602,7 +6611,7 @@ int sqlite3Select(
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "Groupby result generator entry point"));
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
- finalizeAggFunctions(pParse, &sAggInfo);
|
||||
+ finalizeAggFunctions(pParse, pAggInfo);
|
||||
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
||||
selectInnerLoop(pParse, p, -1, &sSort,
|
||||
&sDistinct, pDest,
|
||||
@@ -6613,7 +6622,7 @@ int sqlite3Select(
|
||||
/* Generate a subroutine that will reset the group-by accumulator
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, addrReset);
|
||||
- resetAccumulator(pParse, &sAggInfo);
|
||||
+ resetAccumulator(pParse, pAggInfo);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
||||
VdbeComment((v, "indicate accumulator empty"));
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
||||
@@ -6621,7 +6630,7 @@ int sqlite3Select(
|
||||
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
||||
else {
|
||||
Table *pTab;
|
||||
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
||||
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
|
||||
/* If isSimpleCount() returns a pointer to a Table structure, then
|
||||
** the SQL statement is of the form:
|
||||
**
|
||||
@@ -6674,7 +6683,7 @@ int sqlite3Select(
|
||||
if( pKeyInfo ){
|
||||
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
||||
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
}else{
|
||||
@@ -6689,12 +6698,16 @@ int sqlite3Select(
|
||||
** first row visited by the aggregate, so that they are updated at
|
||||
** least once even if the FILTER clause means the min() or max()
|
||||
** function visits zero rows. */
|
||||
- if( sAggInfo.nAccumulator ){
|
||||
- for(i=0; i<sAggInfo.nFunc; i++){
|
||||
- if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
|
||||
- if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
||||
+ if( pAggInfo->nAccumulator ){
|
||||
+ for(i=0; i<pAggInfo->nFunc; i++){
|
||||
+ if( ExprHasProperty(pAggInfo->aFunc[i].pExpr, EP_WinFunc) ){
|
||||
+ continue;
|
||||
+ }
|
||||
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- if( i==sAggInfo.nFunc ){
|
||||
+ if( i==pAggInfo->nFunc ){
|
||||
regAcc = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
|
||||
}
|
||||
@@ -6705,7 +6718,7 @@ int sqlite3Select(
|
||||
** of output.
|
||||
*/
|
||||
assert( p->pGroupBy==0 );
|
||||
- resetAccumulator(pParse, &sAggInfo);
|
||||
+ resetAccumulator(pParse, pAggInfo);
|
||||
|
||||
/* If this query is a candidate for the min/max optimization, then
|
||||
** minMaxFlag will have been previously set to either
|
||||
@@ -6721,7 +6734,7 @@ int sqlite3Select(
|
||||
if( pWInfo==0 ){
|
||||
goto select_end;
|
||||
}
|
||||
- updateAccumulator(pParse, regAcc, &sAggInfo);
|
||||
+ updateAccumulator(pParse, regAcc, pAggInfo);
|
||||
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
||||
@@ -6729,7 +6742,7 @@ int sqlite3Select(
|
||||
(minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
- finalizeAggFunctions(pParse, &sAggInfo);
|
||||
+ finalizeAggFunctions(pParse, pAggInfo);
|
||||
}
|
||||
|
||||
sSort.pOrderBy = 0;
|
||||
@@ -6768,8 +6781,25 @@ int sqlite3Select(
|
||||
*/
|
||||
select_end:
|
||||
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
||||
- sqlite3DbFree(db, sAggInfo.aCol);
|
||||
- sqlite3DbFree(db, sAggInfo.aFunc);
|
||||
+#ifdef SQLITE_DEBUG
|
||||
+ if( pAggInfo ){
|
||||
+ for(i=0; i<pAggInfo->nColumn; i++){
|
||||
+ Expr *pExpr = pAggInfo->aCol[i].pExpr;
|
||||
+ assert( pExpr!=0 || db->mallocFailed );
|
||||
+ if( pExpr==0 ) continue;
|
||||
+ assert( pExpr->pAggInfo==pAggInfo );
|
||||
+ assert( pExpr->iAgg==i );
|
||||
+ }
|
||||
+ for(i=0; i<pAggInfo->nFunc; i++){
|
||||
+ Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
||||
+ assert( pExpr!=0 || db->mallocFailed );
|
||||
+ if( pExpr==0 ) continue;
|
||||
+ assert( pExpr->pAggInfo==pAggInfo );
|
||||
+ assert( pExpr->iAgg==i );
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(0x1,pParse,p,("end processing\n"));
|
||||
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
|
||||
index 514df18..fe24c3a 100644
|
||||
--- a/src/sqliteInt.h
|
||||
+++ b/src/sqliteInt.h
|
||||
@@ -2489,11 +2489,11 @@ struct AggInfo {
|
||||
ExprList *pGroupBy; /* The group by clause */
|
||||
struct AggInfo_col { /* For each column used in source tables */
|
||||
Table *pTab; /* Source table */
|
||||
+ Expr *pExpr; /* The original expression */
|
||||
int iTable; /* Cursor number of the source table */
|
||||
- int iColumn; /* Column number within the source table */
|
||||
- int iSorterColumn; /* Column number in the sorting index */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
- Expr *pExpr; /* The original expression */
|
||||
+ i16 iColumn; /* Column number within the source table */
|
||||
+ i16 iSorterColumn; /* Column number in the sorting index */
|
||||
} *aCol;
|
||||
int nColumn; /* Number of used entries in aCol[] */
|
||||
int nAccumulator; /* Number of columns that show through to the output.
|
||||
@@ -2506,6 +2506,10 @@ struct AggInfo {
|
||||
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
|
||||
} *aFunc;
|
||||
int nFunc; /* Number of entries in aFunc[] */
|
||||
+#ifdef SQLITE_DEBUG
|
||||
+ int iAggMagic; /* Magic number when valid */
|
||||
+#endif
|
||||
+ AggInfo *pNext; /* Next in list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3291,6 +3295,7 @@ struct Parse {
|
||||
Parse *pToplevel; /* Parse structure for main program (or NULL) */
|
||||
Table *pTriggerTab; /* Table triggers are being coded for */
|
||||
Parse *pParentParse; /* Parent parser if this parser is nested */
|
||||
+ AggInfo *pAggList; /* List of all AggInfo objects */
|
||||
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
||||
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
||||
u32 oldmask; /* Mask of old.* columns referenced */
|
||||
@@ -4254,6 +4259,7 @@ int sqlite3ExprCompareSkip(Expr*, Expr*, int);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
||||
int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
|
||||
int sqlite3ExprImpliesNonNullRow(Expr*,int);
|
||||
+void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
|
||||
diff --git a/src/window.c b/src/window.c
|
||||
index 9bb3217..f4919d6 100644
|
||||
--- a/src/window.c
|
||||
+++ b/src/window.c
|
||||
@@ -933,12 +933,16 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
Window *pMWin = p->pWin; /* Master window object */
|
||||
Window *pWin; /* Window object iterator */
|
||||
Table *pTab;
|
||||
+ Walker w;
|
||||
+
|
||||
u32 selFlags = p->selFlags;
|
||||
|
||||
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ){
|
||||
return sqlite3ErrorToParser(db, SQLITE_NOMEM);
|
||||
}
|
||||
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
||||
+ sqlite3WalkSelect(&w, p);
|
||||
|
||||
p->pSrc = 0;
|
||||
p->pWhere = 0;
|
||||
diff --git a/test/window1.test b/test/window1.test
|
||||
index 18b9bdc..1d554f9 100644
|
||||
--- a/test/window1.test
|
||||
+++ b/test/window1.test
|
||||
@@ -1603,4 +1603,150 @@ do_catchsql_test 51.1 {
|
||||
sum(b) OVER(PARTITION BY min(DISTINCT c), c ORDER BY b)));
|
||||
} {1 {row value misused}}
|
||||
|
||||
+#-------------------------------------------------------------------------
|
||||
+reset_db
|
||||
+do_execsql_test 54.1 {
|
||||
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
|
||||
+ INSERT INTO t1 VALUES('1',10.0);
|
||||
+}
|
||||
+
|
||||
+do_catchsql_test 54.2 {
|
||||
+ SELECT * FROM (
|
||||
+ SELECT sum(b) OVER() AS c FROM t1
|
||||
+ UNION
|
||||
+ SELECT b AS c FROM t1
|
||||
+ ) WHERE c>10;
|
||||
+} {1 {misuse of window function sum()}}
|
||||
+
|
||||
+do_execsql_test 54.3 {
|
||||
+ INSERT INTO t1 VALUES('2',5.0);
|
||||
+ INSERT INTO t1 VALUES('3',15.0);
|
||||
+}
|
||||
+
|
||||
+do_catchsql_test 54.4 {
|
||||
+ SELECT * FROM (
|
||||
+ SELECT sum(b) OVER() AS c FROM t1
|
||||
+ UNION
|
||||
+ SELECT b AS c FROM t1
|
||||
+ ) WHERE c>10;
|
||||
+} {1 {misuse of window function sum()}}
|
||||
+
|
||||
+# 2020-06-05 ticket c8d3b9f0a750a529
|
||||
+reset_db
|
||||
+do_execsql_test 55.1 {
|
||||
+ CREATE TABLE a(b);
|
||||
+ SELECT
|
||||
+ (SELECT b FROM a
|
||||
+ GROUP BY b
|
||||
+ HAVING (SELECT COUNT()OVER() + lead(b)OVER(ORDER BY SUM(DISTINCT b) + b))
|
||||
+ )
|
||||
+ FROM a
|
||||
+ UNION
|
||||
+ SELECT 99
|
||||
+ ORDER BY 1;
|
||||
+} {99}
|
||||
+
|
||||
+#------------------------------------------------------------------------
|
||||
+reset_db
|
||||
+do_execsql_test 56.1 {
|
||||
+ CREATE TABLE t1(a, b INTEGER);
|
||||
+ CREATE TABLE t2(c, d);
|
||||
+}
|
||||
+do_catchsql_test 56.2 {
|
||||
+ SELECT avg(b) FROM t1
|
||||
+ UNION ALL
|
||||
+ SELECT min(c) OVER () FROM t2
|
||||
+ ORDER BY nosuchcolumn;
|
||||
+} {1 {1st ORDER BY term does not match any column in the result set}}
|
||||
+
|
||||
+reset_db
|
||||
+do_execsql_test 57.1 {
|
||||
+ CREATE TABLE t4(a, b, c, d, e);
|
||||
+}
|
||||
+
|
||||
+do_catchsql_test 57.2 {
|
||||
+ SELECT b FROM t4
|
||||
+ UNION
|
||||
+ SELECT a FROM t4
|
||||
+ ORDER BY (
|
||||
+ SELECT sum(x) OVER() FROM (
|
||||
+ SELECT c AS x FROM t4
|
||||
+ UNION
|
||||
+ SELECT d FROM t4
|
||||
+ ORDER BY (SELECT e FROM t4)
|
||||
+ )
|
||||
+ );
|
||||
+} {1 {1st ORDER BY term does not match any column in the result set}}
|
||||
+
|
||||
+# 2020-06-06 various dbsqlfuzz finds and
|
||||
+# ticket 0899cf62f597d7e7
|
||||
+#
|
||||
+reset_db
|
||||
+do_execsql_test 57.1 {
|
||||
+ CREATE TABLE t1(a, b, c);
|
||||
+ INSERT INTO t1 VALUES(NULL,NULL,NULL);
|
||||
+ SELECT
|
||||
+ sum(a),
|
||||
+ min(b) OVER (),
|
||||
+ count(c) OVER (ORDER BY b)
|
||||
+ FROM t1;
|
||||
+} {{} {} 0}
|
||||
+do_execsql_test 57.2 {
|
||||
+ CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ;
|
||||
+ INSERT INTO v0 VALUES ( 10 ) ;
|
||||
+ SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2;
|
||||
+} {10 {}}
|
||||
+do_catchsql_test 57.3 {
|
||||
+ DROP TABLE t1;
|
||||
+ CREATE TABLE t1(a);
|
||||
+ INSERT INTO t1(a) VALUES(22);
|
||||
+ CREATE TABLE t3(y);
|
||||
+ INSERT INTO t3(y) VALUES(5),(11),(-9);
|
||||
+ SELECT (
|
||||
+ SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
|
||||
+ )
|
||||
+ FROM t3;
|
||||
+} {1 {misuse of aggregate: sum()}}
|
||||
+
|
||||
+# 2020-06-06 ticket 1f6f353b684fc708
|
||||
+reset_db
|
||||
+do_execsql_test 58.1 {
|
||||
+ CREATE TABLE a(a, b, c);
|
||||
+ INSERT INTO a VALUES(1, 2, 3);
|
||||
+ INSERT INTO a VALUES(4, 5, 6);
|
||||
+ SELECT sum(345+b) OVER (ORDER BY b),
|
||||
+ sum(avg(678)) OVER (ORDER BY c) FROM a;
|
||||
+} {347 678.0}
|
||||
+
|
||||
+# 2020-06-06 ticket e5504e987e419fb0
|
||||
+do_catchsql_test 59.1 {
|
||||
+ DROP TABLE IF EXISTS t1;
|
||||
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
|
||||
+ INSERT INTO t1 VALUES (123);
|
||||
+ SELECT
|
||||
+ ntile( (SELECT sum(x)) ) OVER(ORDER BY x),
|
||||
+ min(x) OVER(ORDER BY x)
|
||||
+ FROM t1;
|
||||
+} {1 {misuse of aggregate: sum()}}
|
||||
+
|
||||
+# 2020-06-07 ticket f7d890858f361402
|
||||
+do_execsql_test 60.1 {
|
||||
+ DROP TABLE IF EXISTS t1;
|
||||
+ CREATE TABLE t1 (x INTEGER PRIMARY KEY);
|
||||
+ INSERT INTO t1 VALUES (99);
|
||||
+ SELECT EXISTS(SELECT count(*) OVER() FROM t1 ORDER BY sum(x) OVER());
|
||||
+} {1}
|
||||
+
|
||||
+# 2020-06-07 test case generated by dbsqlfuzz showing how an AggInfo
|
||||
+# object might be referenced after the sqlite3Select() call that created
|
||||
+# it returns. This proves the need to persist all AggInfo objects until
|
||||
+# the Parse object is destroyed.
|
||||
+#
|
||||
+reset_db
|
||||
+do_execsql_test 61.1 {
|
||||
+CREATE TABLE t1(a);
|
||||
+INSERT INTO t1 VALUES(5),(NULL),('seventeen');
|
||||
+SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1);
|
||||
+} {{} {} {}}
|
||||
+
|
||||
finish_test
|
||||
--
|
||||
2.23.0
|
||||
|
||||
Binary file not shown.
BIN
sqlite-autoconf-3320300.tar.gz
Normal file
BIN
sqlite-autoconf-3320300.tar.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
39
sqlite.spec
39
sqlite.spec
@ -1,13 +1,13 @@
|
||||
%bcond_without check
|
||||
|
||||
%global extver 3310100
|
||||
%global extver 3320300
|
||||
%global tcl_version 8.6
|
||||
%global tcl_sitearch %{_libdir}/tcl%{tcl_version}
|
||||
%global year 2020
|
||||
|
||||
Name: sqlite
|
||||
Version: 3.31.1
|
||||
Release: 2
|
||||
Version: 3.32.3
|
||||
Release: 1
|
||||
Summary: Embeded SQL database
|
||||
License: Public Domain
|
||||
URL: http://www.sqlite.org/
|
||||
@ -16,19 +16,8 @@ Source0: http://www.sqlite.org/%{year}/sqlite-src-%{extver}.zip
|
||||
Source1: http://www.sqlite.org/%{year}/sqlite-doc-%{extver}.zip
|
||||
Source2: https://www.sqlite.org/%{year}/sqlite-autoconf-%{extver}.tar.gz
|
||||
|
||||
Patch1: 0001-Fix-CVE-2020-9327.patch
|
||||
Patch2: 0002-Fix-CVE-2020-9327.patch
|
||||
Patch3: 0003-Fix-CVE-2020-11655.patch
|
||||
Patch4: 0004-Fix-CVE-2020-11656.patch
|
||||
Patch5: 0005-Fix-CVE-2020-15358.patch
|
||||
Patch6: 0006-Fix-CVE-2020-13631.patch
|
||||
Patch7: 0007-sqlite-no-malloc-usable-size.patch
|
||||
Patch8: 0008-Cleaner_separation_of_the_STAT4-specific_logic.patch
|
||||
Patch9: 0009-Background_work_for_experiments.patch
|
||||
Patch10: 0010-Fix_handling_of_window_functions.patch
|
||||
Patch11: 0011-Remove_the_SQLITE_OMIT_BTREECOUNT_option.patch
|
||||
Patch12: 0012-Improvements_to_parse-tree_tracing_logic.patch
|
||||
Patch13: 0013-Fix-CVE-2020-13871.patch
|
||||
Patch1: 0001-sqlite-no-malloc-usable-size.patch
|
||||
Patch2: 0002-remove-fail-testcase-in-no-free-fd-situation.patch
|
||||
|
||||
BuildRequires: gcc autoconf tcl tcl-devel
|
||||
BuildRequires: ncurses-devel readline-devel glibc-devel
|
||||
@ -71,19 +60,8 @@ This contains man files and HTML files for the using of sqlite.
|
||||
%prep
|
||||
#autosetup will fail because of 2 zip files
|
||||
%setup -q -a1 -n %{name}-src-%{extver}
|
||||
%patch1 -p0
|
||||
%patch2 -p0
|
||||
%patch3 -p1
|
||||
%patch4 -p1
|
||||
%patch5 -p1
|
||||
%patch6 -p1
|
||||
%patch7 -p1
|
||||
%patch8 -p1
|
||||
%patch9 -p1
|
||||
%patch10 -p1
|
||||
%patch11 -p1
|
||||
%patch12 -p1
|
||||
%patch13 -p1
|
||||
%patch1 -p1
|
||||
%patch2 -p1
|
||||
|
||||
|
||||
rm -f %{name}-doc-%{extver}/sqlite.css~ || :
|
||||
@ -157,6 +135,9 @@ make test
|
||||
%{_mandir}/man*/*
|
||||
|
||||
%changelog
|
||||
* Tue Aug 25 2020 yanglongkang <yanglongkang@huawei.com> - 3.32.3-1
|
||||
- update package to 3.32.3
|
||||
|
||||
* Tue Aug 4 2020 yanglongkang <yanglongkang@huawei.com> - 3.31.1-2
|
||||
- Type:cves
|
||||
- ID:CVE-2020-13871
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user