mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
First pass at optimizing max()/min() as described in #2853. Some refinements to come. (CVS 4687)
FossilOrigin-Name: c449e04f1870b1ff726c95c0bf1c6c6a22ca588a
This commit is contained in:
29
manifest
29
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Registerify\sbinary\soperators.\s\sAdd\sregister\stracing\sto\sdebugging\soutput.\s(CVS\s4686)
|
C First\spass\sat\soptimizing\smax()/min()\sas\sdescribed\sin\s#2853.\sSome\srefinements\sto\scome.\s(CVS\s4687)
|
||||||
D 2008-01-05T16:29:28
|
D 2008-01-05T17:39:30
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -90,7 +90,7 @@ F src/build.c 60a3ec74b45634654e06a72224ac01bd33ac69f1
|
|||||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||||
F src/delete.c cb1d5be17c99e41d1675763a57848bb5dd45191c
|
F src/delete.c 209f33fdf34dcbaa08752437bf53aff0cef0eca6
|
||||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||||
F src/expr.c cb8b65c3adc8bb39f67503dfe8db8da24ebe5d21
|
F src/expr.c cb8b65c3adc8bb39f67503dfe8db8da24ebe5d21
|
||||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||||
@@ -131,12 +131,12 @@ F src/pragma.c dfb200ec383b5ab3e81cd7bc4e1305e71053ef9a
|
|||||||
F src/prepare.c f1bb8eb642082e618a359c08e3e107490eafe0e3
|
F src/prepare.c f1bb8eb642082e618a359c08e3e107490eafe0e3
|
||||||
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
||||||
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
||||||
F src/select.c 102eb03b6daa3c113fac32019dd281f01a38baa8
|
F src/select.c 33c60380c81283c16414040d034b76f1732ffb4e
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
||||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||||
F src/sqliteInt.h 80f81e0a0b712a74f1c841e6336b51126d781df0
|
F src/sqliteInt.h 1e7a6545eda5e5e670000775f5d74003e0bc4fbb
|
||||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||||
@@ -164,7 +164,7 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
|||||||
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
||||||
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
||||||
F src/trigger.c 91ff1552b5c2cd66a077563a026d183c1dc993d6
|
F src/trigger.c 91ff1552b5c2cd66a077563a026d183c1dc993d6
|
||||||
F src/update.c ac6cdfebf88340fd68550b1d7fd6a15ad7144fd8
|
F src/update.c f322317ee492c0a648f8a44fd805dd85dbbe2f05
|
||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
||||||
@@ -177,7 +177,7 @@ F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf
|
|||||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||||
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
|
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
|
||||||
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
|
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
|
||||||
F src/where.c 941635bb007484330bc1a0f3cc013b67f1c41864
|
F src/where.c 0d72b6431c23da6fb1b72422e364ac8fe7eb1d3a
|
||||||
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba
|
F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba
|
||||||
@@ -227,7 +227,7 @@ F test/check.test 024ed399600b799160378cf9d9f436bdf5dfd184
|
|||||||
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||||
F test/collate2.test 701d9651c5707024fd86a20649af9ea55e2c0eb8
|
F test/collate2.test 701d9651c5707024fd86a20649af9ea55e2c0eb8
|
||||||
F test/collate3.test 947a77f5b8227e037a7094d0e338a5504f155cc4
|
F test/collate3.test 947a77f5b8227e037a7094d0e338a5504f155cc4
|
||||||
F test/collate4.test daf498e294dcd596b961d425c3f2dda117e4717e
|
F test/collate4.test 4545554388daaa604e5b3def3aa2f7ed6d56e8da
|
||||||
F test/collate5.test e54df13eb9e1140273680b3153c6e19b39e59888
|
F test/collate5.test e54df13eb9e1140273680b3153c6e19b39e59888
|
||||||
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
|
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
|
||||||
F test/collate7.test e23677b1fd271505302643a98178952bb65b6f21
|
F test/collate7.test e23677b1fd271505302643a98178952bb65b6f21
|
||||||
@@ -379,8 +379,9 @@ F test/malloc_common.tcl b47137fb36e95fdafb0267745afefcd6b0a5b9dc
|
|||||||
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
|
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
|
||||||
F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
|
F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
|
||||||
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
||||||
F test/minmax.test 66434d8ee04869fe4c220b665b73748accbb9163
|
F test/minmax.test 5d56f08a7765dfb5c1fb303333f7444dacb37bef
|
||||||
F test/minmax2.test 8294b6728819608861ba0e06ac1d9a87c4d815b5
|
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||||
|
F test/minmax3.test 5b89f055df7ed03334e96eec0efb804afb7de638
|
||||||
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
|
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
|
||||||
F test/misc2.test 1ee89298de9c16b61454658b24999c403e86afe4
|
F test/misc2.test 1ee89298de9c16b61454658b24999c403e86afe4
|
||||||
F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03
|
F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03
|
||||||
@@ -603,7 +604,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 6c78d2a49a3e6ee8bc31f16488a430cba9eda59d
|
P 66396d2f0289e36b5fc0af5078c08d1b17f342ae
|
||||||
R fdff0af63eb57b92a8e5bcade477a016
|
R b1dacf0522dc83de3d6ddccfc407074e
|
||||||
U drh
|
U danielk1977
|
||||||
Z c3fdc5267d8f427a421314acf39cdbc6
|
Z 85372970e5aef600b6f97b67c85860f6
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
66396d2f0289e36b5fc0af5078c08d1b17f342ae
|
c449e04f1870b1ff726c95c0bf1c6c6a22ca588a
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** in order to generate code for DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.150 2008/01/05 05:20:10 drh Exp $
|
** $Id: delete.c,v 1.151 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ void sqlite3DeleteFrom(
|
|||||||
|
|
||||||
/* Begin the database scan
|
/* Begin the database scan
|
||||||
*/
|
*/
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
|
||||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||||
|
|
||||||
/* Remember the rowid of every item to be deleted.
|
/* Remember the rowid of every item to be deleted.
|
||||||
|
|||||||
57
src/select.c
57
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.386 2008/01/05 05:20:10 drh Exp $
|
** $Id: select.c,v 1.387 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -2625,6 +2625,33 @@ static int flattenSubquery(
|
|||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_VIEW */
|
#endif /* SQLITE_OMIT_VIEW */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Analyze the SELECT statement passed as an argument to see if it
|
||||||
|
** is a min() or max() query. Return ORDERBY_MIN or ORDERBY_MAX if
|
||||||
|
** it is, or 0 otherwise. At present, a query is considered to be
|
||||||
|
** a min()/max() query if:
|
||||||
|
**
|
||||||
|
** 1. The result set contains exactly one element, either
|
||||||
|
** min(x) or max(x), where x is a column identifier.
|
||||||
|
*/
|
||||||
|
static int minMaxQuery(Parse *pParse, Select *p){
|
||||||
|
Expr *pExpr;
|
||||||
|
ExprList *pEList = p->pEList;
|
||||||
|
|
||||||
|
if( pEList->nExpr!=1 ) return ORDERBY_NORMAL;
|
||||||
|
pExpr = pEList->a[0].pExpr;
|
||||||
|
pEList = pExpr->pList;
|
||||||
|
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
|
||||||
|
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return ORDERBY_NORMAL;
|
||||||
|
if( pExpr->token.n!=3 ) return ORDERBY_NORMAL;
|
||||||
|
if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
|
||||||
|
return ORDERBY_MIN;
|
||||||
|
}else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
|
||||||
|
return ORDERBY_MAX;
|
||||||
|
}
|
||||||
|
return ORDERBY_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Analyze the SELECT statement passed in as an argument to see if it
|
** Analyze the SELECT statement passed in as an argument to see if it
|
||||||
** is a simple min() or max() query. If it is and this query can be
|
** is a simple min() or max() query. If it is and this query can be
|
||||||
@@ -2645,6 +2672,7 @@ static int flattenSubquery(
|
|||||||
** The parameters to this routine are the same as for sqlite3Select().
|
** The parameters to this routine are the same as for sqlite3Select().
|
||||||
** See the header comment on that routine for additional information.
|
** See the header comment on that routine for additional information.
|
||||||
*/
|
*/
|
||||||
|
#if 0
|
||||||
static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){
|
static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){
|
||||||
Expr *pExpr;
|
Expr *pExpr;
|
||||||
int iCol;
|
int iCol;
|
||||||
@@ -2781,6 +2809,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine resolves any names used in the result set of the
|
** This routine resolves any names used in the result set of the
|
||||||
@@ -3268,10 +3297,12 @@ int sqlite3Select(
|
|||||||
/* Check for the special case of a min() or max() function by itself
|
/* Check for the special case of a min() or max() function by itself
|
||||||
** in the result set.
|
** in the result set.
|
||||||
*/
|
*/
|
||||||
|
#if 0
|
||||||
if( simpleMinMaxQuery(pParse, p, pDest) ){
|
if( simpleMinMaxQuery(pParse, p, pDest) ){
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Check to see if this is a subquery that can be "flattened" into its parent.
|
/* Check to see if this is a subquery that can be "flattened" into its parent.
|
||||||
** If flattening is a possiblity, do so and return immediately.
|
** If flattening is a possiblity, do so and return immediately.
|
||||||
@@ -3345,7 +3376,7 @@ int sqlite3Select(
|
|||||||
/* This case is for non-aggregate queries
|
/* This case is for non-aggregate queries
|
||||||
** Begin the database scan
|
** Begin the database scan
|
||||||
*/
|
*/
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
|
||||||
if( pWInfo==0 ) goto select_end;
|
if( pWInfo==0 ) goto select_end;
|
||||||
|
|
||||||
/* If sorting index that was created by a prior OP_OpenEphemeral
|
/* If sorting index that was created by a prior OP_OpenEphemeral
|
||||||
@@ -3501,7 +3532,7 @@ int sqlite3Select(
|
|||||||
*/
|
*/
|
||||||
sqlite3VdbeResolveLabel(v, addrInitializeLoop);
|
sqlite3VdbeResolveLabel(v, addrInitializeLoop);
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrReset);
|
sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrReset);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
|
||||||
if( pWInfo==0 ) goto select_end;
|
if( pWInfo==0 ) goto select_end;
|
||||||
if( pGroupBy==0 ){
|
if( pGroupBy==0 ){
|
||||||
/* The optimizer is able to deliver rows in group by order so
|
/* The optimizer is able to deliver rows in group by order so
|
||||||
@@ -3606,14 +3637,30 @@ int sqlite3Select(
|
|||||||
|
|
||||||
} /* endif pGroupBy */
|
} /* endif pGroupBy */
|
||||||
else {
|
else {
|
||||||
|
ExprList *pMinMax = 0;
|
||||||
|
u8 flag;
|
||||||
|
|
||||||
|
flag = minMaxQuery(pParse, p);
|
||||||
|
if( flag ){
|
||||||
|
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
|
||||||
|
if( pMinMax ){
|
||||||
|
pMinMax->a[0].sortOrder = ((flag==ORDERBY_MIN)?0:1);
|
||||||
|
pMinMax->a[0].pExpr->op = TK_COLUMN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This case runs if the aggregate has no GROUP BY clause. The
|
/* This case runs if the aggregate has no GROUP BY clause. The
|
||||||
** processing is much simpler since there is only a single row
|
** processing is much simpler since there is only a single row
|
||||||
** of output.
|
** of output.
|
||||||
*/
|
*/
|
||||||
resetAccumulator(pParse, &sAggInfo);
|
resetAccumulator(pParse, &sAggInfo);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
|
||||||
if( pWInfo==0 ) goto select_end;
|
if( pWInfo==0 ) goto select_end;
|
||||||
updateAccumulator(pParse, &sAggInfo);
|
updateAccumulator(pParse, &sAggInfo);
|
||||||
|
if( !pMinMax && flag ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
|
||||||
|
VdbeComment((v, "%s() by index", (flag==ORDERBY_MIN?"min":"max")));
|
||||||
|
}
|
||||||
sqlite3WhereEnd(pWInfo);
|
sqlite3WhereEnd(pWInfo);
|
||||||
finalizeAggFunctions(pParse, &sAggInfo);
|
finalizeAggFunctions(pParse, &sAggInfo);
|
||||||
pOrderBy = 0;
|
pOrderBy = 0;
|
||||||
@@ -3622,6 +3669,8 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
|
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
|
||||||
pDest, addrEnd, addrEnd, aff);
|
pDest, addrEnd, addrEnd, aff);
|
||||||
|
|
||||||
|
sqlite3ExprListDelete(pMinMax);
|
||||||
}
|
}
|
||||||
sqlite3VdbeResolveLabel(v, addrEnd);
|
sqlite3VdbeResolveLabel(v, addrEnd);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.638 2008/01/04 19:10:29 danielk1977 Exp $
|
** @(#) $Id: sqliteInt.h,v 1.639 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1229,6 +1229,10 @@ struct WhereLevel {
|
|||||||
sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
|
sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ORDERBY_NORMAL 0
|
||||||
|
#define ORDERBY_MIN 1
|
||||||
|
#define ORDERBY_MAX 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The WHERE clause processing routine has two halves. The
|
** The WHERE clause processing routine has two halves. The
|
||||||
** first part does the start of the WHERE loop and the second
|
** first part does the start of the WHERE loop and the second
|
||||||
@@ -1735,7 +1739,7 @@ int sqlite3IsReadOnly(Parse*, Table*, int);
|
|||||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
|
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
|
||||||
void sqlite3WhereEnd(WhereInfo*);
|
void sqlite3WhereEnd(WhereInfo*);
|
||||||
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
|
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
|
||||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.160 2008/01/05 05:20:10 drh Exp $
|
** $Id: update.c,v 1.161 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ void sqlite3Update(
|
|||||||
|
|
||||||
/* Begin the database scan
|
/* Begin the database scan
|
||||||
*/
|
*/
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
|
||||||
if( pWInfo==0 ) goto update_cleanup;
|
if( pWInfo==0 ) goto update_cleanup;
|
||||||
|
|
||||||
/* Remember the rowid of every item to be updated.
|
/* Remember the rowid of every item to be updated.
|
||||||
|
|||||||
75
src/where.c
75
src/where.c
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.275 2008/01/05 05:38:21 drh Exp $
|
** $Id: where.c,v 1.276 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -1969,7 +1969,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
SrcList *pTabList, /* A list of all tables to be scanned */
|
SrcList *pTabList, /* A list of all tables to be scanned */
|
||||||
Expr *pWhere, /* The WHERE clause */
|
Expr *pWhere, /* The WHERE clause */
|
||||||
ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
|
ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
|
||||||
|
u8 obflag /* One of ORDERBY_MIN, ORDERBY_MAX or ORDERBY_NORMAL */
|
||||||
){
|
){
|
||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
WhereInfo *pWInfo; /* Will become the return value of this function */
|
WhereInfo *pWInfo; /* Will become the return value of this function */
|
||||||
@@ -1984,6 +1985,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
int iFrom; /* First unused FROM clause element */
|
int iFrom; /* First unused FROM clause element */
|
||||||
int andFlags; /* AND-ed combination of all wc.a[].flags */
|
int andFlags; /* AND-ed combination of all wc.a[].flags */
|
||||||
sqlite3 *db; /* Database connection */
|
sqlite3 *db; /* Database connection */
|
||||||
|
ExprList *pOrderBy = 0;
|
||||||
|
|
||||||
/* The number of tables in the FROM clause is limited by the number of
|
/* The number of tables in the FROM clause is limited by the number of
|
||||||
** bits in a Bitmask
|
** bits in a Bitmask
|
||||||
@@ -1993,6 +1995,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( ppOrderBy ){
|
||||||
|
pOrderBy = *ppOrderBy;
|
||||||
|
}
|
||||||
|
|
||||||
/* Split the WHERE clause into separate subexpressions where each
|
/* Split the WHERE clause into separate subexpressions where each
|
||||||
** subexpression is separated by an AND operator.
|
** subexpression is separated by an AND operator.
|
||||||
*/
|
*/
|
||||||
@@ -2400,6 +2406,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
int testOp;
|
int testOp;
|
||||||
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
|
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
|
||||||
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
|
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
|
||||||
|
int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
|
||||||
|
|
||||||
/* Generate code to evaluate all constraint terms using == or IN
|
/* Generate code to evaluate all constraint terms using == or IN
|
||||||
** and level the values of those terms on the stack.
|
** and level the values of those terms on the stack.
|
||||||
@@ -2428,6 +2435,22 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
SWAP(int, topLimit, btmLimit);
|
SWAP(int, topLimit, btmLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this loop satisfies a sort order (pOrderBy) request that
|
||||||
|
** was passed to this function to implement a "SELECT min(x) ..."
|
||||||
|
** query, then the caller will only allow the loop to run for
|
||||||
|
** a single iteration. This means that the first row returned
|
||||||
|
** should not have a NULL value stored in 'x'. If column 'x' is
|
||||||
|
** the first one after the nEq equality constraints in the index,
|
||||||
|
** this requires some special handling.
|
||||||
|
*/
|
||||||
|
if( (obflag==ORDERBY_MIN)
|
||||||
|
&& (pLevel->flags&WHERE_ORDERBY)
|
||||||
|
&& (pIdx->nColumn>nEq)
|
||||||
|
&& (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
|
||||||
|
){
|
||||||
|
isMinQuery = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate the termination key. This is the key value that
|
/* Generate the termination key. This is the key value that
|
||||||
** will end the search. There is no termination key if there
|
** will end the search. There is no termination key if there
|
||||||
** are no equality terms and no "X<..." term.
|
** are no equality terms and no "X<..." term.
|
||||||
@@ -2452,9 +2475,14 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
|
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
|
||||||
topEq = 1;
|
topEq = 1;
|
||||||
}
|
}
|
||||||
if( testOp!=OP_Noop ){
|
if( testOp!=OP_Noop || (isMinQuery&&bRev) ){
|
||||||
int nCol = nEq + topLimit;
|
int nCol = nEq + topLimit;
|
||||||
pLevel->iMem = ++pParse->nMem;
|
pLevel->iMem = ++pParse->nMem;
|
||||||
|
if( isMinQuery && !topLimit ){
|
||||||
|
nCol++;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||||
|
topEq = 0;
|
||||||
|
}
|
||||||
buildIndexProbe(v, nCol, pIdx);
|
buildIndexProbe(v, nCol, pIdx);
|
||||||
if( bRev ){
|
if( bRev ){
|
||||||
int op = topEq ? OP_MoveLe : OP_MoveLt;
|
int op = topEq ? OP_MoveLe : OP_MoveLt;
|
||||||
@@ -2465,7 +2493,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
}else if( bRev ){
|
}else if( bRev ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk);
|
sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the start key. This is the key that defines the lower
|
/* Generate the start key. This is the key that defines the lower
|
||||||
** bound on the search. There is no start key if there are no
|
** bound on the search. There is no start key if there are no
|
||||||
** equality terms and if there is no "X>..." term. In
|
** equality terms and if there is no "X>..." term. In
|
||||||
@@ -2489,8 +2517,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
}else{
|
}else{
|
||||||
btmEq = 1;
|
btmEq = 1;
|
||||||
}
|
}
|
||||||
if( nEq>0 || btmLimit ){
|
if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){
|
||||||
int nCol = nEq + btmLimit;
|
int nCol = nEq + btmLimit;
|
||||||
|
if( isMinQuery && !btmLimit ){
|
||||||
|
nCol++;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||||
|
btmEq = 0;
|
||||||
|
}
|
||||||
buildIndexProbe(v, nCol, pIdx);
|
buildIndexProbe(v, nCol, pIdx);
|
||||||
if( bRev ){
|
if( bRev ){
|
||||||
pLevel->iMem = ++pParse->nMem;
|
pLevel->iMem = ++pParse->nMem;
|
||||||
@@ -2538,6 +2571,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
*/
|
*/
|
||||||
int start;
|
int start;
|
||||||
int nEq = pLevel->nEq;
|
int nEq = pLevel->nEq;
|
||||||
|
int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
|
||||||
|
|
||||||
/* Generate code to evaluate all constraint terms using == or IN
|
/* Generate code to evaluate all constraint terms using == or IN
|
||||||
** and leave the values of those terms on the stack.
|
** and leave the values of those terms on the stack.
|
||||||
@@ -2545,11 +2579,28 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
|
codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
|
||||||
nxt = pLevel->nxt;
|
nxt = pLevel->nxt;
|
||||||
|
|
||||||
/* Generate a single key that will be used to both start and terminate
|
if( (obflag==ORDERBY_MIN)
|
||||||
** the search
|
&& (pLevel->flags&WHERE_ORDERBY)
|
||||||
*/
|
&& (pIdx->nColumn>nEq)
|
||||||
buildIndexProbe(v, nEq, pIdx);
|
&& (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem);
|
){
|
||||||
|
int h;
|
||||||
|
isMinQuery = 1;
|
||||||
|
for(h=0; h<nEq; h++){
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Copy, 1-nEq);
|
||||||
|
}
|
||||||
|
buildIndexProbe(v, nEq, pIdx);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||||
|
buildIndexProbe(v, nEq+1, pIdx);
|
||||||
|
}else{
|
||||||
|
/* Generate a single key that will be used to both start and
|
||||||
|
** terminate the search
|
||||||
|
*/
|
||||||
|
buildIndexProbe(v, nEq, pIdx);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem);
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate code (1) to move to the first matching element of the table.
|
/* Generate code (1) to move to the first matching element of the table.
|
||||||
** Then generate code (2) that jumps to "nxt" after the cursor is past
|
** Then generate code (2) that jumps to "nxt" after the cursor is past
|
||||||
@@ -2558,13 +2609,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
** iteration of the scan to see if the scan has finished. */
|
** iteration of the scan to see if the scan has finished. */
|
||||||
if( bRev ){
|
if( bRev ){
|
||||||
/* Scan in reverse order */
|
/* Scan in reverse order */
|
||||||
sqlite3VdbeAddOp2(v, OP_MoveLe, iIdxCur, nxt);
|
sqlite3VdbeAddOp2(v, (isMinQuery?OP_MoveLt:OP_MoveLe), iIdxCur, nxt);
|
||||||
start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0);
|
start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxLT, iIdxCur, nxt);
|
sqlite3VdbeAddOp2(v, OP_IdxLT, iIdxCur, nxt);
|
||||||
pLevel->op = OP_Prev;
|
pLevel->op = OP_Prev;
|
||||||
}else{
|
}else{
|
||||||
/* Scan in the forward order */
|
/* Scan in the forward order */
|
||||||
sqlite3VdbeAddOp2(v, OP_MoveGe, iIdxCur, nxt);
|
sqlite3VdbeAddOp2(v, (isMinQuery?OP_MoveGt:OP_MoveGe), iIdxCur, nxt);
|
||||||
start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0);
|
start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0);
|
||||||
sqlite3VdbeAddOp4(v, OP_IdxGE, iIdxCur, nxt, 0, "+", P4_STATIC);
|
sqlite3VdbeAddOp4(v, OP_IdxGE, iIdxCur, nxt, 0, "+", P4_STATIC);
|
||||||
pLevel->op = OP_Next;
|
pLevel->op = OP_Next;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is page cache subsystem.
|
# focus of this script is page cache subsystem.
|
||||||
#
|
#
|
||||||
# $Id: collate4.test,v 1.8 2005/04/01 10:47:40 drh Exp $
|
# $Id: collate4.test,v 1.9 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -591,12 +591,12 @@ do_test collate4-4.3 {
|
|||||||
count {
|
count {
|
||||||
SELECT min(a) FROM collate4t1;
|
SELECT min(a) FROM collate4t1;
|
||||||
}
|
}
|
||||||
} {10 2}
|
} {10 1}
|
||||||
do_test collate4-4.4 {
|
do_test collate4-4.4 {
|
||||||
count {
|
count {
|
||||||
SELECT max(a) FROM collate4t1;
|
SELECT max(a) FROM collate4t1;
|
||||||
}
|
}
|
||||||
} {20 1}
|
} {20 0}
|
||||||
do_test collate4-4.5 {
|
do_test collate4-4.5 {
|
||||||
# Test that the index with collation type NUMERIC is not used.
|
# Test that the index with collation type NUMERIC is not used.
|
||||||
execsql {
|
execsql {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
# aggregate min() and max() functions and which are handled as
|
# aggregate min() and max() functions and which are handled as
|
||||||
# as a special case.
|
# as a special case.
|
||||||
#
|
#
|
||||||
# $Id: minmax.test,v 1.19 2006/03/26 01:21:23 drh Exp $
|
# $Id: minmax.test,v 1.20 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -68,14 +68,14 @@ do_test minmax-1.5 {
|
|||||||
} {1}
|
} {1}
|
||||||
do_test minmax-1.6 {
|
do_test minmax-1.6 {
|
||||||
set sqlite_search_count
|
set sqlite_search_count
|
||||||
} {2}
|
} {1}
|
||||||
do_test minmax-1.7 {
|
do_test minmax-1.7 {
|
||||||
set sqlite_search_count 0
|
set sqlite_search_count 0
|
||||||
execsql {SELECT max(x) FROM t1}
|
execsql {SELECT max(x) FROM t1}
|
||||||
} {20}
|
} {20}
|
||||||
do_test minmax-1.8 {
|
do_test minmax-1.8 {
|
||||||
set sqlite_search_count
|
set sqlite_search_count
|
||||||
} {1}
|
} {0}
|
||||||
do_test minmax-1.9 {
|
do_test minmax-1.9 {
|
||||||
set sqlite_search_count 0
|
set sqlite_search_count 0
|
||||||
execsql {SELECT max(y) FROM t1}
|
execsql {SELECT max(y) FROM t1}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# optimization works right in the presence of descending
|
# optimization works right in the presence of descending
|
||||||
# indices. Ticket #2514.
|
# indices. Ticket #2514.
|
||||||
#
|
#
|
||||||
# $Id: minmax2.test,v 1.1 2007/07/18 18:17:12 drh Exp $
|
# $Id: minmax2.test,v 1.2 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -71,14 +71,14 @@ do_test minmax2-1.5 {
|
|||||||
} {1}
|
} {1}
|
||||||
do_test minmax2-1.6 {
|
do_test minmax2-1.6 {
|
||||||
set sqlite_search_count
|
set sqlite_search_count
|
||||||
} {2}
|
} {1}
|
||||||
do_test minmax2-1.7 {
|
do_test minmax2-1.7 {
|
||||||
set sqlite_search_count 0
|
set sqlite_search_count 0
|
||||||
execsql {SELECT max(x) FROM t1}
|
execsql {SELECT max(x) FROM t1}
|
||||||
} {20}
|
} {20}
|
||||||
do_test minmax2-1.8 {
|
do_test minmax2-1.8 {
|
||||||
set sqlite_search_count
|
set sqlite_search_count
|
||||||
} {1}
|
} {0}
|
||||||
do_test minmax2-1.9 {
|
do_test minmax2-1.9 {
|
||||||
set sqlite_search_count 0
|
set sqlite_search_count 0
|
||||||
execsql {SELECT max(y) FROM t1}
|
execsql {SELECT max(y) FROM t1}
|
||||||
|
|||||||
144
test/minmax3.test
Normal file
144
test/minmax3.test
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# 2008 January 5
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# $Id: minmax3.test,v 1.1 2008/01/05 17:39:30 danielk1977 Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# Do an SQL statement. Append the search count to the end of the result.
|
||||||
|
#
|
||||||
|
proc count sql {
|
||||||
|
set ::sqlite_search_count 0
|
||||||
|
return [concat [execsql $sql] $::sqlite_search_count]
|
||||||
|
}
|
||||||
|
|
||||||
|
# This procedure sets the value of the file-format in file 'test.db'
|
||||||
|
# to $newval. Also, the schema cookie is incremented.
|
||||||
|
#
|
||||||
|
proc set_file_format {newval} {
|
||||||
|
set bt [btree_open test.db 10 0]
|
||||||
|
btree_begin_transaction $bt
|
||||||
|
set meta [btree_get_meta $bt]
|
||||||
|
lset meta 2 $newval ;# File format
|
||||||
|
lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie
|
||||||
|
eval "btree_update_meta $bt $meta"
|
||||||
|
btree_commit $bt
|
||||||
|
btree_close $bt
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the file as file-format 4 (DESC index support). This is
|
||||||
|
# required to exercise a few cases in where.c.
|
||||||
|
#
|
||||||
|
execsql { select * from sqlite_master }
|
||||||
|
set_file_format 4
|
||||||
|
|
||||||
|
do_test minmax3-1.0 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE t1(x, y, z);
|
||||||
|
INSERT INTO t1 VALUES('1', 'I', 'one');
|
||||||
|
INSERT INTO t1 VALUES('2', 'IV', 'four');
|
||||||
|
INSERT INTO t1 VALUES('2', NULL, 'three');
|
||||||
|
INSERT INTO t1 VALUES('2', 'II', 'two');
|
||||||
|
INSERT INTO t1 VALUES('2', 'V', 'five');
|
||||||
|
INSERT INTO t1 VALUES('3', 'VI', 'six');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test minmax3-1.1.1 {
|
||||||
|
# Linear scan.
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {V 5}
|
||||||
|
do_test minmax3-1.1.2 {
|
||||||
|
# Index optimizes the WHERE x='2' constraint.
|
||||||
|
execsql { CREATE INDEX i1 ON t1(x) }
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {V 9}
|
||||||
|
do_test minmax3-1.1.3 {
|
||||||
|
# Index optimizes the WHERE x='2' constraint and the MAX(y).
|
||||||
|
execsql { CREATE INDEX i2 ON t1(x,y) }
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {V 1}
|
||||||
|
do_test minmax3-1.1.4 {
|
||||||
|
# Index optimizes the WHERE x='2' constraint and the MAX(y).
|
||||||
|
execsql { DROP INDEX i2 ; CREATE INDEX i2 ON t1(x, y DESC) }
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {V 1}
|
||||||
|
do_test minmax3-1.1.5 {
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2' AND y != 'V'; }
|
||||||
|
} {IV 2}
|
||||||
|
do_test minmax3-1.1.6 {
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2' AND y < 'V'; }
|
||||||
|
} {IV 1}
|
||||||
|
do_test minmax3-1.1.6 {
|
||||||
|
count { SELECT max(y) FROM t1 WHERE x = '2' AND z != 'five'; }
|
||||||
|
} {IV 4}
|
||||||
|
|
||||||
|
do_test minmax3-1.2.1 {
|
||||||
|
# Linear scan of t1.
|
||||||
|
execsql { DROP INDEX i1 ; DROP INDEX i2 }
|
||||||
|
count { SELECT min(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {II 5}
|
||||||
|
do_test minmax3-1.2.2 {
|
||||||
|
# Index i1 optimizes the WHERE x='2' constraint.
|
||||||
|
execsql { CREATE INDEX i1 ON t1(x) }
|
||||||
|
count { SELECT min(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {II 9}
|
||||||
|
do_test minmax3-1.2.3 {
|
||||||
|
# Index i2 optimizes the WHERE x='2' constraint and the min(y).
|
||||||
|
execsql { CREATE INDEX i2 ON t1(x,y) }
|
||||||
|
count { SELECT min(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {II 1}
|
||||||
|
do_test minmax3-1.2.4 {
|
||||||
|
# Index optimizes the WHERE x='2' constraint and the MAX(y).
|
||||||
|
execsql { DROP INDEX i2 ; CREATE INDEX i2 ON t1(x, y DESC) }
|
||||||
|
count { SELECT min(y) FROM t1 WHERE x = '2'; }
|
||||||
|
} {II 1}
|
||||||
|
|
||||||
|
do_test minmax3-1.3.1 {
|
||||||
|
# Linear scan
|
||||||
|
execsql { DROP INDEX i1 ; DROP INDEX i2 }
|
||||||
|
count { SELECT min(y) FROM t1; }
|
||||||
|
} {I 5}
|
||||||
|
do_test minmax3-1.3.2 {
|
||||||
|
# Index i1 optimizes the min(y)
|
||||||
|
execsql { CREATE INDEX i1 ON t1(y) }
|
||||||
|
count { SELECT min(y) FROM t1; }
|
||||||
|
} {I 1}
|
||||||
|
do_test minmax3-1.3.3 {
|
||||||
|
# Index i1 optimizes the min(y)
|
||||||
|
execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(y DESC) }
|
||||||
|
count { SELECT min(y) FROM t1; }
|
||||||
|
} {I 1}
|
||||||
|
|
||||||
|
do_test minmax3-1.4.1 {
|
||||||
|
# Linear scan
|
||||||
|
execsql { DROP INDEX i1 }
|
||||||
|
count { SELECT max(y) FROM t1; }
|
||||||
|
} {VI 5}
|
||||||
|
do_test minmax3-1.4.2 {
|
||||||
|
# Index i1 optimizes the max(y)
|
||||||
|
execsql { CREATE INDEX i1 ON t1(y) }
|
||||||
|
count { SELECT max(y) FROM t1; }
|
||||||
|
} {VI 0}
|
||||||
|
do_test minmax3-1.4.3 {
|
||||||
|
# Index i1 optimizes the max(y)
|
||||||
|
execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(y DESC) }
|
||||||
|
execsql { SELECT y from t1}
|
||||||
|
count { SELECT max(y) FROM t1; }
|
||||||
|
} {VI 0}
|
||||||
|
do_test minmax3-1.4.4 {
|
||||||
|
execsql { DROP INDEX i1 }
|
||||||
|
} {}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
||||||
Reference in New Issue
Block a user