From 1b2ecbdd49ae5933f921bf18c2d4f0f7acd2f5a6 Mon Sep 17 00:00:00 2001 From: Dan Kennedy Date: Fri, 15 Jun 2018 19:01:35 +0000 Subject: [PATCH] Fix another problem in lead()/lag(). And some errors that could occur following OOM faults. --- src/parse.y | 6 +++++- src/window.c | 16 ++++++++++++---- test/window4.tcl | 33 +++++++++++++++++++++++++++++++++ test/window4.test | 34 ++++++++++++++++++++++++++++++++++ test/windowfault.test | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 test/windowfault.test diff --git a/src/parse.y b/src/parse.y index fa6064a14f..6120533bdf 100644 --- a/src/parse.y +++ b/src/parse.y @@ -535,7 +535,11 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y) Token s = S; /*A-overwrites-S*/ #endif A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); - if( A ) A->pWinDefn = R; + if( A ){ + A->pWinDefn = R; + }else{ + sqlite3WindowListDelete(pParse->db, R); + } #if SELECTTRACE_ENABLED /* Populate the Select.zSelName[] string that is used to help with ** query planner debugging, to differentiate between multiple Select diff --git a/src/window.c b/src/window.c index 9431771465..845d67907a 100644 --- a/src/window.c +++ b/src/window.c @@ -392,7 +392,11 @@ static void last_valueStepFunc( if( p ){ sqlite3_value_free(p->pVal); p->pVal = sqlite3_value_dup(apArg[0]); - p->nVal++; + if( p->pVal==0 ){ + sqlite3_result_error_nomem(pCtx); + }else{ + p->nVal++; + } } } static void last_valueInvFunc( @@ -741,6 +745,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + assert( p->pSrc || db->mallocFailed ); if( p->pSrc ){ int iTab; ExprList *pList = 0; @@ -753,9 +758,12 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ p->selFlags &= ~SF_Aggregate; sqlite3SelectPrep(pParse, pSub, 0); } - } - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); + }else{ + sqlite3SelectDelete(db, pSub); + } + if( db->mallocFailed ) rc = SQLITE_NOMEM; } return rc; @@ -1162,7 +1170,7 @@ static void windowReturnOneRow( sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); if( pFunc->xSFunc==nth_valueStepFunc ){ - sqlite3VdbeAddOp3(v, OP_Column, pWin->iEphCsr, pWin->iArgCol+1, tmpReg); + sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); }else{ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); } diff --git a/test/window4.tcl b/test/window4.tcl index 29c0a5585d..e75a3f5547 100644 --- a/test/window4.tcl +++ b/test/window4.tcl @@ -271,6 +271,39 @@ execsql_test 7.5 { WINDOW win AS (ORDER BY x) } +========== + +execsql_test 8.0 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER, d INTEGER); + INSERT INTO t1 VALUES(1, 2, 3, 4); + INSERT INTO t1 VALUES(5, 6, 7, 8); + INSERT INTO t1 VALUES(9, 10, 11, 12); +} + +execsql_test 8.1 { + SELECT row_number() OVER win, + nth_value(d,2) OVER win, + lead(d) OVER win + FROM t1 + WINDOW win AS (ORDER BY a) +} + +execsql_test 8.2 { + SELECT row_number() OVER win, + rank() OVER win, + dense_rank() OVER win, + ntile(2) OVER win, + first_value(d) OVER win, + last_value(d) OVER win, + nth_value(d,2) OVER win, + lead(d) OVER win, + lag(d) OVER win, + max(d) OVER win, + min(d) OVER win + FROM t1 + WINDOW win AS (ORDER BY a) +} finish_test diff --git a/test/window4.test b/test/window4.test index 7e99f870f3..6bb8c715f1 100644 --- a/test/window4.test +++ b/test/window4.test @@ -1166,4 +1166,38 @@ do_execsql_test 7.5 { WINDOW win AS (ORDER BY x) } {4 6 8 6 8 10 8 10 -1 10 {} -1 {} {} -1} +#========================================================================== + +do_execsql_test 8.0 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER, d INTEGER); + INSERT INTO t1 VALUES(1, 2, 3, 4); + INSERT INTO t1 VALUES(5, 6, 7, 8); + INSERT INTO t1 VALUES(9, 10, 11, 12); +} {} + +do_execsql_test 8.1 { + SELECT row_number() OVER win, + nth_value(d,2) OVER win, + lead(d) OVER win + FROM t1 + WINDOW win AS (ORDER BY a) +} {1 {} 8 2 8 12 3 8 {}} + +do_execsql_test 8.2 { + SELECT row_number() OVER win, + rank() OVER win, + dense_rank() OVER win, + ntile(2) OVER win, + first_value(d) OVER win, + last_value(d) OVER win, + nth_value(d,2) OVER win, + lead(d) OVER win, + lag(d) OVER win, + max(d) OVER win, + min(d) OVER win + FROM t1 + WINDOW win AS (ORDER BY a) +} {1 1 1 1 4 4 {} 8 {} 4 4 2 2 2 1 4 8 8 12 4 8 4 3 3 3 2 4 12 8 {} 8 12 4} + finish_test diff --git a/test/windowfault.test b/test/windowfault.test new file mode 100644 index 0000000000..5df9dd8c27 --- /dev/null +++ b/test/windowfault.test @@ -0,0 +1,51 @@ +# 2018 May 8 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix windowfault + + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c, d); + INSERT INTO t1 VALUES(1, 2, 3, 4); + INSERT INTO t1 VALUES(5, 6, 7, 8); + INSERT INTO t1 VALUES(9, 10, 11, 12); +} +faultsim_save_and_close + +do_faultsim_test 1 -start 1 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { + SELECT row_number() OVER win, + rank() OVER win, + dense_rank() OVER win, + ntile(2) OVER win, + first_value(d) OVER win, + last_value(d) OVER win, + nth_value(d,2) OVER win, + lead(d) OVER win, + lag(d) OVER win, + max(d) OVER win, + min(d) OVER win + FROM t1 + WINDOW win AS (ORDER BY a) + } +} -test { + faultsim_test_result {0 {1 1 1 1 4 4 {} 8 {} 4 4 2 2 2 1 4 8 8 12 4 8 4 3 3 3 2 4 12 8 {} 8 12 4}} +} + + +finish_test + -- 2.11.4.GIT