1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Allow real values to be used in PRECEDING and FOLLOWING expressions for RANGE window frames.

FossilOrigin-Name: 25ff7091cb12c63b1864ce68a9151f8432af5804b5ae905a2175761ab4b9fdd8
This commit is contained in:
dan
2019-03-12 18:28:51 +00:00
parent 935d9d8260
commit bb40727857
6 changed files with 82 additions and 34 deletions

View File

@@ -1,5 +1,5 @@
C Expand\son\sheader\scomment\sfor\ssqlite3WindowCodeStep().\sFurther\ssimplify\sthe\simplementation\sof\sthe\ssame. C Allow\sreal\svalues\sto\sbe\sused\sin\sPRECEDING\sand\sFOLLOWING\sexpressions\sfor\sRANGE\swindow\sframes.
D 2019-03-12T15:21:51.703 D 2019-03-12T18:28:51.117
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 236d2739dc3e823c3c909bca2d6cef93009bafbefd7018a8f3281074ecb92954 F Makefile.in 236d2739dc3e823c3c909bca2d6cef93009bafbefd7018a8f3281074ecb92954
@@ -586,7 +586,7 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c 82a2e3f691a3b654be872e305dab1f455e565dedf5e6a90c818c1ab307c00432 F src/util.c 82a2e3f691a3b654be872e305dab1f455e565dedf5e6a90c818c1ab307c00432
F src/vacuum.c a9f389f41556c0ec310bc9169dc9476603c30a0a913ad92bfbc75c86886967ca F src/vacuum.c a9f389f41556c0ec310bc9169dc9476603c30a0a913ad92bfbc75c86886967ca
F src/vdbe.c f1e7b5320df80ff58c67176e35cb48062cbda2a9c9811f11db5faa48071d3fe4 F src/vdbe.c 6e7a279ea2f1eab28b19cf41b1012379d38e182de571f50f41adc6b7911ec6c0
F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
F src/vdbeInt.h a76d5eed62c76bcd8de7afd3147fac1bc40c5a870582664bcd7d071ef437c37f F src/vdbeInt.h a76d5eed62c76bcd8de7afd3147fac1bc40c5a870582664bcd7d071ef437c37f
F src/vdbeapi.c 7a052df80d7e2e55382076174633e888f21fe200feb5d49b1b441b4c38ab851a F src/vdbeapi.c 7a052df80d7e2e55382076174633e888f21fe200feb5d49b1b441b4c38ab851a
@@ -604,7 +604,7 @@ F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88 F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6 F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442 F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
F src/window.c 4763c2e81e8bb5d79fc378ba650cfcf076653d78065bd85790d592d441c9ae7a F src/window.c 536bc80552d11f95a3524f8a7239727f94115ada67d1dd900e4988196346c225
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -1687,8 +1687,8 @@ F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652
F test/window6.test 604890f2b0f976339e6a1774cd90d48840e57a54b4f21a8b4b3047aa2c9787d1 F test/window6.test 604890f2b0f976339e6a1774cd90d48840e57a54b4f21a8b4b3047aa2c9787d1
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f
F test/window8.tcl d296629022e098c9860933fa1ed61e698b60a7b0d50cf3ea77e9949b87012adc F test/window8.tcl 2aa94709defda0bbe05883cdb61ec51346ab0bacb4d84d724758fc62818c610a
F test/window8.test 5bf663c76a9056235ae864f071d97056c7391f8b1dd18b184d4ea907951eaf08 F test/window8.test e33941d2b31a8641dbe40ee38ed08430e81cd884ad409ec9eeaec315e7ae1c3b
F test/windowerr.tcl 4f0b111cdbb8de401a8135cd116604fb8add13042bb47a1f1496dd47a690e864 F test/windowerr.tcl 4f0b111cdbb8de401a8135cd116604fb8add13042bb47a1f1496dd47a690e864
F test/windowerr.test 461bc504d4af0ae16a081e0c3bdb3724356cdcfb07bdc4b1b2dc4ad91b69bb7e F test/windowerr.test 461bc504d4af0ae16a081e0c3bdb3724356cdcfb07bdc4b1b2dc4ad91b69bb7e
F test/windowfault.test 12ceb6bbb355d13e8fcd88c5731a57256dfdf77b9a7ae20842a76fcd4623df5b F test/windowfault.test 12ceb6bbb355d13e8fcd88c5731a57256dfdf77b9a7ae20842a76fcd4623df5b
@@ -1812,7 +1812,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 081263538332bb9c07e62630629007ccbba31bef5dc890f60b4ba58a355f70ac P 5129bcc996b3c9f78ab6b674a4364787e7b353b90f15f027cad4431012022c30
R b359af1c195991083b8f00df3e4dfe08 R f73d694ac4c1f1f064a3ca7465b32f6d
U dan U dan
Z 98fef6b18eded687d4fe3a47cb60a7a7 Z ea7ae61d59972a80f1c852bccb429b9d

View File

@@ -1 +1 @@
5129bcc996b3c9f78ab6b674a4364787e7b353b90f15f027cad4431012022c30 25ff7091cb12c63b1864ce68a9151f8432af5804b5ae905a2175761ab4b9fdd8

View File

@@ -1723,19 +1723,25 @@ case OP_AddImm: { /* in1 */
break; break;
} }
/* Opcode: MustBeInt P1 P2 * * * /* Opcode: MustBeInt P1 P2 * * P5
** **
** Force the value in register P1 to be an integer. If the value ** If P5 is 0, force the value in register P1 to be an integer. If
** in P1 is not an integer and cannot be converted into an integer ** the value in P1 is not an integer and cannot be converted into an
** without data loss, then jump immediately to P2, or if P2==0 ** integer without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception. ** raise an SQLITE_MISMATCH exception.
**
** Or, if P5 is non-zero, then force the register in P1 to be a number
** (real or integer). Jump to P2 if this cannot be accomplished without
** data loss. P2 must be non-zero in this case.
*/ */
case OP_MustBeInt: { /* jump, in1 */ case OP_MustBeInt: { /* jump, in1 */
u8 f;
f = (pOp->p5 ? (MEM_Int|MEM_Real) : MEM_Int);
pIn1 = &aMem[pOp->p1]; pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Int)==0 ){ if( (pIn1->flags & f)==0 ){
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); VdbeBranchTaken((pIn1->flags&f)==0, 2);
if( (pIn1->flags & MEM_Int)==0 ){ if( (pIn1->flags & f)==0 ){
if( pOp->p2==0 ){ if( pOp->p2==0 ){
rc = SQLITE_MISMATCH; rc = SQLITE_MISMATCH;
goto abort_due_to_error; goto abort_due_to_error;
@@ -1744,7 +1750,7 @@ case OP_MustBeInt: { /* jump, in1 */
} }
} }
} }
MemSetTypeFlag(pIn1, MEM_Int); if( f==MEM_Int ) MemSetTypeFlag(pIn1, MEM_Int);
break; break;
} }

View File

@@ -1168,6 +1168,12 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
} }
} }
#define WINDOW_STARTING_INT 0
#define WINDOW_ENDING_INT 1
#define WINDOW_NTH_VALUE_INT 2
#define WINDOW_STARTING_NUM 3
#define WINDOW_ENDING_NUM 4
/* /*
** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the ** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the
** value of the second argument to nth_value() (eCond==2) has just been ** value of the second argument to nth_value() (eCond==2) has just been
@@ -1175,18 +1181,21 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
** code to check that the value is a non-negative integer and throws an ** code to check that the value is a non-negative integer and throws an
** exception if it is not. ** exception if it is not.
*/ */
static void windowCheckIntValue(Parse *pParse, int reg, int eCond){ static void windowCheckValue(Parse *pParse, int reg, int eCond){
static const char *azErr[] = { static const char *azErr[] = {
"frame starting offset must be a non-negative integer", "frame starting offset must be a non-negative integer",
"frame ending offset must be a non-negative integer", "frame ending offset must be a non-negative integer",
"second argument to nth_value must be a positive integer" "second argument to nth_value must be a positive integer",
"frame starting offset must be a non-negative number",
"frame ending offset must be a non-negative number",
}; };
static int aOp[] = { OP_Ge, OP_Ge, OP_Gt }; static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge };
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
int regZero = sqlite3GetTempReg(pParse); int regZero = sqlite3GetTempReg(pParse);
assert( eCond==0 || eCond==1 || eCond==2 ); assert( eCond>=0 && eCond<ArraySize(azErr) );
sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero); sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
if( eCond>=WINDOW_STARTING_NUM ) sqlite3VdbeChangeP5(v, 1);
VdbeCoverageIf(v, eCond==0); VdbeCoverageIf(v, eCond==0);
VdbeCoverageIf(v, eCond==1); VdbeCoverageIf(v, eCond==1);
VdbeCoverageIf(v, eCond==2); VdbeCoverageIf(v, eCond==2);
@@ -1383,7 +1392,7 @@ static void windowReturnOneRow(
if( pFunc->zName==nth_valueName ){ if( pFunc->zName==nth_valueName ){
sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg);
windowCheckIntValue(pParse, tmpReg, 2); windowCheckValue(pParse, tmpReg, 2);
}else{ }else{
sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg);
} }
@@ -2214,11 +2223,11 @@ void sqlite3WindowCodeStep(
if( regStart ){ if( regStart ){
sqlite3ExprCode(pParse, pMWin->pStart, regStart); sqlite3ExprCode(pParse, pMWin->pStart, regStart);
windowCheckIntValue(pParse, regStart, 0); windowCheckValue(pParse, regStart, 0 + (pMWin->eType==TK_RANGE ? 3 : 0));
} }
if( regEnd ){ if( regEnd ){
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
windowCheckIntValue(pParse, regEnd, 1); windowCheckValue(pParse, regEnd, 1 + (pMWin->eType==TK_RANGE ? 3 : 0));
} }
if( pMWin->eStart==pMWin->eEnd && regStart && regEnd ){ if( pMWin->eStart==pMWin->eEnd && regStart && regEnd ){

View File

@@ -93,7 +93,7 @@ foreach {tn frame} {
execsql_test 2.0 { execsql_test 2.0 {
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER); CREATE TABLE t1(a REAL, b INTEGER);
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
(5, 10), (10, 20), (13, 26), (13, 26), (5, 10), (10, 20), (13, 26), (13, 26),
(15, 30), (20, 40), (22,80), (30, 90); (15, 30), (20, 40), (22,80), (30, 90);
@@ -106,8 +106,17 @@ foreach {tn frame} {
4 { ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING } 4 { ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING }
5 { ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING } 5 { ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING }
6 { ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING } 6 { ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING }
7 { ORDER BY a RANGE BETWEEN 5.1 PRECEDING AND 5.3 FOLLOWING }
8 { ORDER BY a RANGE BETWEEN 10.2 PRECEDING AND 5.4 PRECEDING }
9 { ORDER BY a RANGE BETWEEN 2.6 FOLLOWING AND 3.5 FOLLOWING }
10 { ORDER BY a DESC RANGE BETWEEN 5.7 PRECEDING AND 5.8 FOLLOWING }
11 { ORDER BY a DESC RANGE BETWEEN UNBOUNDED PRECEDING AND 5.9 PRECEDING }
12 { ORDER BY a DESC RANGE BETWEEN 2.1 FOLLOWING AND UNBOUNDED FOLLOWING }
} { } {
execsql_test 2.$tn "SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ($frame)" execsql_test 2.$tn "
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ($frame)
"
} }

View File

@@ -437,34 +437,58 @@ do_execsql_test 1.19.5 {
do_execsql_test 2.0 { do_execsql_test 2.0 {
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER); CREATE TABLE t1(a REAL, b INTEGER);
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
(5, 10), (10, 20), (13, 26), (13, 26), (5, 10), (10, 20), (13, 26), (13, 26),
(15, 30), (20, 40), (22,80), (30, 90); (15, 30), (20, 40), (22,80), (30, 90);
} {} } {}
do_execsql_test 2.1 { do_execsql_test 2.1 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING )
} {5 30 10 112 13 102 13 102 15 142 20 150 22 120 30 90} } {5 30 10 112 13 102 13 102 15 142 20 150 22 120 30 90}
do_execsql_test 2.2 { do_execsql_test 2.2 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING )
} {5 {} 10 10 13 10 13 10 15 30 20 102 22 82 30 120} } {5 {} 10 10 13 10 13 10 15 30 20 102 22 82 30 120}
do_execsql_test 2.3 { do_execsql_test 2.3 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING )
} {5 {} 10 52 13 30 13 30 15 {} 20 80 22 {} 30 {}} } {5 {} 10 52 13 30 13 30 15 {} 20 80 22 {} 30 {}}
do_execsql_test 2.4 { do_execsql_test 2.4 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING )
} {30 90 22 120 20 150 15 142 13 102 13 102 10 112 5 30} } {30 90 22 120 20 150 15 142 13 102 13 102 10 112 5 30}
do_execsql_test 2.5 { do_execsql_test 2.5 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING )
} {30 {} 22 90 20 90 15 120 13 120 13 120 10 70 5 102} } {30 {} 22 90 20 90 15 120 13 120 13 120 10 70 5 102}
do_execsql_test 2.6 { do_execsql_test 2.6 {
SELECT a, sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING ) SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING )
} {30 {} 22 40 20 {} 15 52 13 20 13 20 10 {} 5 {}} } {30 {} 22 40 20 {} 15 52 13 20 13 20 10 {} 5 {}}
do_execsql_test 2.7 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 5.1 PRECEDING AND 5.3 FOLLOWING )
} {5 30 10 112 13 102 13 102 15 142 20 150 22 120 30 90}
do_execsql_test 2.8 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 10.2 PRECEDING AND 5.4 PRECEDING )
} {5 {} 10 {} 13 10 13 10 15 10 20 72 22 82 30 120}
do_execsql_test 2.9 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 2.6 FOLLOWING AND 3.5 FOLLOWING )
} {5 {} 10 52 13 {} 13 {} 15 {} 20 {} 22 {} 30 {}}
do_execsql_test 2.10 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 5.7 PRECEDING AND 5.8 FOLLOWING )
} {30 90 22 120 20 150 15 142 13 102 13 102 10 112 5 30}
do_execsql_test 2.11 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN UNBOUNDED PRECEDING AND 5.9 PRECEDING )
} {30 {} 22 90 20 90 15 170 13 210 13 210 10 210 5 292}
do_execsql_test 2.12 {
SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 2.1 FOLLOWING AND UNBOUNDED FOLLOWING )
} {30 232 22 112 20 112 15 30 13 30 13 30 10 10 5 {}}
finish_test finish_test