mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
Continuing improvements to the multi-index OR-clause optimizer. Added a
few simple test cases. (CVS 6062) FossilOrigin-Name: 55d4f493e7df8515574a75caec9967d6c71b6012
This commit is contained in:
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\sproblem\swith\sthe\ssavepoint\scode\sand\sin-memory\sjournals.\s(CVS\s6061)
|
C Continuing\simprovements\sto\sthe\smulti-index\sOR-clause\soptimizer.\s\sAdded\sa\nfew\ssimple\stest\scases.\s(CVS\s6062)
|
||||||
D 2008-12-23T19:15:57
|
D 2008-12-23T23:56:22
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
|
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -110,7 +110,7 @@ F src/build.c 92335a6c6a7c119580be605c5dd1439602d6cf5d
|
|||||||
F src/callback.c bee8949d619b1b7b1e4dfac8a19c5116ae1dd12a
|
F src/callback.c bee8949d619b1b7b1e4dfac8a19c5116ae1dd12a
|
||||||
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
||||||
F src/date.c e010095d85c895761627bb1d0d61d021aea930a9
|
F src/date.c e010095d85c895761627bb1d0d61d021aea930a9
|
||||||
F src/delete.c e2392b6808496fc0a7f54662af3ba677a3e8e44a
|
F src/delete.c 6249005bdd8f85db6ec5f31ddb5c07de023693cc
|
||||||
F src/expr.c a385202af56d622b11d05e8d386def256155152b
|
F src/expr.c a385202af56d622b11d05e8d386def256155152b
|
||||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||||
F src/func.c b0e1c61301f33d67b72ab15d85c80ed76e7c98ac
|
F src/func.c b0e1c61301f33d67b72ab15d85c80ed76e7c98ac
|
||||||
@@ -154,11 +154,11 @@ F src/printf.c 9866a9a9c4a90f6d4147407f373df3fd5d5f9b6f
|
|||||||
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
||||||
F src/resolve.c 18dc9f0df1d60048e012ce6632251063e0dd356a
|
F src/resolve.c 18dc9f0df1d60048e012ce6632251063e0dd356a
|
||||||
F src/rowset.c 2256fa4a928f750e2f3d6fc733523034beceb1d6
|
F src/rowset.c 2256fa4a928f750e2f3d6fc733523034beceb1d6
|
||||||
F src/select.c a4316c5e8a417687e159b3d3ae689363d1dec5df
|
F src/select.c 6c2a5675c21bef11d8160f3dc97e1adfbf26bbb9
|
||||||
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
|
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
|
||||||
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
|
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
|
||||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||||
F src/sqliteInt.h 9411acda2959c3494bafb1ac98048a53ee920ea3
|
F src/sqliteInt.h 2362e805d375c547f6d91d4732da8f93e1e668af
|
||||||
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
||||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||||
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
|
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
|
||||||
@@ -194,7 +194,7 @@ F src/test_thread.c d74fc445e0dba0e00806117eb449b307c0b146bf
|
|||||||
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
|
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
|
||||||
F src/tokenize.c aaa5fa6a4536a9dd7c855a3f66f32508f1612138
|
F src/tokenize.c aaa5fa6a4536a9dd7c855a3f66f32508f1612138
|
||||||
F src/trigger.c 5a669d8fc9197db393ff85fa95ec882282162bb5
|
F src/trigger.c 5a669d8fc9197db393ff85fa95ec882282162bb5
|
||||||
F src/update.c 080889d241e4dcd1c545c8051eb6de86f4939295
|
F src/update.c 8c4925f9ca664effc8a1faaad67449d2074567b1
|
||||||
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
|
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
|
||||||
F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f
|
F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f
|
||||||
F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9
|
F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9
|
||||||
@@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
|
|||||||
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
|
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
|
||||||
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
||||||
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
|
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
|
||||||
F src/where.c 3f4e8020d605b06139b877a9714a10cc3ba63906
|
F src/where.c ef69833cdf0e19a91ec1b305b506d100ac3f648f
|
||||||
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
||||||
@@ -654,6 +654,7 @@ F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
|
|||||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||||
F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
|
F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
|
||||||
|
F test/where7.test b04da5cee08a573c120c95781d7413a7e25ac8d5
|
||||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||||
F test/zeroblob.test 792124852ec61458a2eb527b5091791215e0be95
|
F test/zeroblob.test 792124852ec61458a2eb527b5091791215e0be95
|
||||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||||
@@ -684,7 +685,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P d2105f617eeb04c8177546c45bf6c63e72757f91
|
P 26ceebf38e7ae7bbda3284995b03f829a2d2493f
|
||||||
R 62a2a7b3ecef75a74f7c0626bd24ccb4
|
R 7db5298c8cbec76d68072c3747b105ad
|
||||||
U danielk1977
|
U drh
|
||||||
Z 52a2a6db5bd35226b01afc59433c7e60
|
Z 555ee7a0ef7229cf7451a3a18c0b778e
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
26ceebf38e7ae7bbda3284995b03f829a2d2493f
|
55d4f493e7df8515574a75caec9967d6c71b6012
|
||||||
16
src/delete.c
16
src/delete.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
|
||||||
** in order to generate code for DELETE FROM statements.
|
** in order to generate code for DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.190 2008/12/10 21:19:57 drh Exp $
|
** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -392,21 +392,15 @@ void sqlite3DeleteFrom(
|
|||||||
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
|
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
|
||||||
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
|
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
|
||||||
|
|
||||||
/* Begin the database scan
|
/* Collect rowids of every row to be deleted.
|
||||||
*/
|
*/
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||||
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
|
||||||
|
WHERE_FILL_ROWSET, iRowSet);
|
||||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||||
|
|
||||||
/* Remember the rowid of every item to be deleted.
|
|
||||||
*/
|
|
||||||
sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iRowid);
|
|
||||||
if( db->flags & SQLITE_CountRows ){
|
if( db->flags & SQLITE_CountRows ){
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End the database scan loop.
|
|
||||||
*/
|
|
||||||
sqlite3WhereEnd(pWInfo);
|
sqlite3WhereEnd(pWInfo);
|
||||||
|
|
||||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||||
|
|||||||
@@ -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.494 2008/12/10 22:15:00 drh Exp $
|
** $Id: select.c,v 1.495 2008/12/23 23:56:22 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -3705,7 +3705,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, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0, 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
|
||||||
@@ -3826,7 +3826,7 @@ int sqlite3Select(
|
|||||||
** in the right order to begin with.
|
** in the right order to begin with.
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 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
|
||||||
@@ -4024,7 +4024,7 @@ int sqlite3Select(
|
|||||||
** of output.
|
** of output.
|
||||||
*/
|
*/
|
||||||
resetAccumulator(pParse, &sAggInfo);
|
resetAccumulator(pParse, &sAggInfo);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
|
||||||
if( pWInfo==0 ){
|
if( pWInfo==0 ){
|
||||||
sqlite3ExprListDelete(db, pDel);
|
sqlite3ExprListDelete(db, pDel);
|
||||||
goto select_end;
|
goto select_end;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.814 2008/12/23 13:35:23 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.815 2008/12/23 23:56:22 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1595,10 +1595,11 @@ struct WhereLevel {
|
|||||||
/*
|
/*
|
||||||
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
|
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
|
||||||
*/
|
*/
|
||||||
#define WHERE_ORDERBY_NORMAL 0 /* No-op */
|
#define WHERE_ORDERBY_NORMAL 0x000 /* No-op */
|
||||||
#define WHERE_ORDERBY_MIN 1 /* ORDER BY processing for min() func */
|
#define WHERE_ORDERBY_MIN 0x001 /* ORDER BY processing for min() func */
|
||||||
#define WHERE_ORDERBY_MAX 2 /* ORDER BY processing for max() func */
|
#define WHERE_ORDERBY_MAX 0x002 /* ORDER BY processing for max() func */
|
||||||
#define WHERE_ONEPASS_DESIRED 4 /* Want to do one-pass UPDATE/DELETE */
|
#define WHERE_ONEPASS_DESIRED 0x004 /* Want to do one-pass UPDATE/DELETE */
|
||||||
|
#define WHERE_FILL_ROWSET 0x008 /* Save results in a RowSet object */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The WHERE clause processing routine has two halves. The
|
** The WHERE clause processing routine has two halves. The
|
||||||
@@ -1610,13 +1611,13 @@ struct WhereLevel {
|
|||||||
struct WhereInfo {
|
struct WhereInfo {
|
||||||
Parse *pParse; /* Parsing and code generating context */
|
Parse *pParse; /* Parsing and code generating context */
|
||||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
||||||
|
int regRowSet; /* Store rowids in this rowset if >=0 */
|
||||||
SrcList *pTabList; /* List of tables in the join */
|
SrcList *pTabList; /* List of tables in the join */
|
||||||
int iTop; /* The very beginning of the WHERE loop */
|
int iTop; /* The very beginning of the WHERE loop */
|
||||||
int iContinue; /* Jump here to continue with next record */
|
int iContinue; /* Jump here to continue with next record */
|
||||||
int iBreak; /* Jump here to break out of the loop */
|
int iBreak; /* Jump here to break out of the loop */
|
||||||
int nLevel; /* Number of nested loop */
|
int nLevel; /* Number of nested loop */
|
||||||
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
|
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
|
||||||
sqlite3_index_info **apInfo; /* Array of pointers to index info objects */
|
|
||||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2260,7 +2261,7 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
|
|||||||
#endif
|
#endif
|
||||||
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**, u8);
|
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8, int);
|
||||||
void sqlite3WhereEnd(WhereInfo*);
|
void sqlite3WhereEnd(WhereInfo*);
|
||||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
||||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
void sqlite3ExprCodeMove(Parse*, int, int, 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.190 2008/12/10 22:15:00 drh Exp $
|
** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ void sqlite3Update(
|
|||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
|
||||||
WHERE_ONEPASS_DESIRED);
|
WHERE_ONEPASS_DESIRED, 0);
|
||||||
if( pWInfo==0 ) goto update_cleanup;
|
if( pWInfo==0 ) goto update_cleanup;
|
||||||
okOnePass = pWInfo->okOnePass;
|
okOnePass = pWInfo->okOnePass;
|
||||||
|
|
||||||
|
|||||||
133
src/where.c
133
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.342 2008/12/23 16:23:05 drh Exp $
|
** $Id: where.c,v 1.343 2008/12/23 23:56:22 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -1814,7 +1814,7 @@ static void bestIndex(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SQLITE_ENABLE_MULTI_OR
|
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||||
/* Search for an OR-clause that can be used to look up the table.
|
/* Search for an OR-clause that can be used to look up the table.
|
||||||
*/
|
*/
|
||||||
maskSrc = getMask(pWC->pMaskSet, iCur);
|
maskSrc = getMask(pWC->pMaskSet, iCur);
|
||||||
@@ -1850,7 +1850,7 @@ static void bestIndex(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||||
|
|
||||||
/* If the pSrc table is the right table of a LEFT JOIN then we may not
|
/* If the pSrc table is the right table of a LEFT JOIN then we may not
|
||||||
** use an index to satisfy IS NULL constraints on that table. This is
|
** use an index to satisfy IS NULL constraints on that table. This is
|
||||||
@@ -2174,6 +2174,25 @@ static int codeAllEqualityTerms(
|
|||||||
return regBase;
|
return regBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return TRUE if the WhereClause pWC contains no terms that
|
||||||
|
** are not virtual and which have not been coded.
|
||||||
|
**
|
||||||
|
** To put it another way, return TRUE if no additional WHERE clauses
|
||||||
|
** tests are required in order to establish that the current row
|
||||||
|
** should go to output and return FALSE if there are some terms of
|
||||||
|
** the WHERE clause that need to be validated before outputing the row.
|
||||||
|
*/
|
||||||
|
static int whereRowReadyForOutput(WhereClause *pWC){
|
||||||
|
WhereTerm *pTerm;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||||
|
if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED))==0 ) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
||||||
** implementation described by pWInfo.
|
** implementation described by pWInfo.
|
||||||
@@ -2195,8 +2214,10 @@ static Bitmask codeOneLoopStart(
|
|||||||
Parse *pParse; /* Parsing context */
|
Parse *pParse; /* Parsing context */
|
||||||
Vdbe *v; /* The prepared stmt under constructions */
|
Vdbe *v; /* The prepared stmt under constructions */
|
||||||
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
||||||
int addrBrk;
|
int addrBrk; /* Jump here to break out of the loop */
|
||||||
int addrCont;
|
int addrCont; /* Jump here to continue with next cycle */
|
||||||
|
int regRowSet; /* Write rowids to this RowSet if non-negative */
|
||||||
|
int codeRowSetEarly; /* True if index fully constrains the search */
|
||||||
|
|
||||||
|
|
||||||
pParse = pWInfo->pParse;
|
pParse = pWInfo->pParse;
|
||||||
@@ -2207,6 +2228,8 @@ static Bitmask codeOneLoopStart(
|
|||||||
iCur = pTabItem->iCursor;
|
iCur = pTabItem->iCursor;
|
||||||
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
|
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
|
||||||
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0;
|
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0;
|
||||||
|
regRowSet = pWInfo->regRowSet;
|
||||||
|
codeRowSetEarly = 0;
|
||||||
|
|
||||||
/* Create labels for the "break" and "continue" instructions
|
/* Create labels for the "break" and "continue" instructions
|
||||||
** for the current loop. Jump to addrBrk to break out of a loop.
|
** for the current loop. Jump to addrBrk to break out of a loop.
|
||||||
@@ -2263,7 +2286,6 @@ static Bitmask codeOneLoopStart(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
|
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
|
||||||
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
|
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
|
||||||
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
|
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
|
||||||
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
|
||||||
pVtabIdx->needToFreeIdxStr = 0;
|
pVtabIdx->needToFreeIdxStr = 0;
|
||||||
for(j=0; j<nConstraint; j++){
|
for(j=0; j<nConstraint; j++){
|
||||||
if( aUsage[j].omit ){
|
if( aUsage[j].omit ){
|
||||||
@@ -2274,6 +2296,12 @@ static Bitmask codeOneLoopStart(
|
|||||||
pLevel->op = OP_VNext;
|
pLevel->op = OP_VNext;
|
||||||
pLevel->p1 = iCur;
|
pLevel->p1 = iCur;
|
||||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||||
|
codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
|
||||||
|
if( codeRowSetEarly ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_VRowid, iCur, iReg);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, iReg);
|
||||||
|
}
|
||||||
|
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
||||||
}else
|
}else
|
||||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||||
|
|
||||||
@@ -2294,6 +2322,10 @@ static Bitmask codeOneLoopStart(
|
|||||||
addrNxt = pLevel->addrNxt;
|
addrNxt = pLevel->addrNxt;
|
||||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, addrNxt);
|
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, addrNxt);
|
||||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, r1);
|
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, r1);
|
||||||
|
codeRowSetEarly = (pWC->nTerm==1 && regRowSet>=0) ?1:0;
|
||||||
|
if( codeRowSetEarly ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
|
||||||
|
}
|
||||||
sqlite3ReleaseTempReg(pParse, rtmp);
|
sqlite3ReleaseTempReg(pParse, rtmp);
|
||||||
VdbeComment((v, "pk"));
|
VdbeComment((v, "pk"));
|
||||||
pLevel->op = OP_Noop;
|
pLevel->op = OP_Noop;
|
||||||
@@ -2360,11 +2392,17 @@ static Bitmask codeOneLoopStart(
|
|||||||
pLevel->op = bRev ? OP_Prev : OP_Next;
|
pLevel->op = bRev ? OP_Prev : OP_Next;
|
||||||
pLevel->p1 = iCur;
|
pLevel->p1 = iCur;
|
||||||
pLevel->p2 = start;
|
pLevel->p2 = start;
|
||||||
if( testOp!=OP_Noop ){
|
codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
|
||||||
|
if( codeRowSetEarly || testOp!=OP_Noop ){
|
||||||
int r1 = sqlite3GetTempReg(pParse);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
|
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
|
||||||
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, r1);
|
if( testOp!=OP_Noop ){
|
||||||
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
|
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, r1);
|
||||||
|
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
|
||||||
|
}
|
||||||
|
if( codeRowSetEarly ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
|
||||||
|
}
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}
|
}
|
||||||
}else if( pLevel->plan.wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
|
}else if( pLevel->plan.wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
|
||||||
@@ -2547,9 +2585,16 @@ static Bitmask codeOneLoopStart(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Seek the table cursor, if required */
|
/* Seek the table cursor, if required */
|
||||||
if( !omitTable ){
|
disableTerm(pLevel, pRangeStart);
|
||||||
|
disableTerm(pLevel, pRangeEnd);
|
||||||
|
codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
|
||||||
|
if( !omitTable || codeRowSetEarly ){
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
|
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Seek, iCur, r1); /* Deferred seek */
|
if( codeRowSetEarly ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Seek, iCur, r1); /* Deferred seek */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
|
|
||||||
@@ -2558,11 +2603,9 @@ static Bitmask codeOneLoopStart(
|
|||||||
*/
|
*/
|
||||||
pLevel->op = bRev ? OP_Prev : OP_Next;
|
pLevel->op = bRev ? OP_Prev : OP_Next;
|
||||||
pLevel->p1 = iIdxCur;
|
pLevel->p1 = iIdxCur;
|
||||||
disableTerm(pLevel, pRangeStart);
|
|
||||||
disableTerm(pLevel, pRangeEnd);
|
|
||||||
}else
|
}else
|
||||||
|
|
||||||
#if SQLITE_ENABLE_MULTI_OR
|
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||||
if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
|
if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
|
||||||
/* Case 4: Two or more separately indexed terms connected by OR
|
/* Case 4: Two or more separately indexed terms connected by OR
|
||||||
**
|
**
|
||||||
@@ -2591,7 +2634,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
** Goto 0, A
|
** Goto 0, A
|
||||||
** B:
|
** B:
|
||||||
*/
|
*/
|
||||||
int regRowset; /* Register holding the RowSet object */
|
int regOrRowset; /* Register holding the RowSet object */
|
||||||
int regNextRowid; /* Register holding next rowid */
|
int regNextRowid; /* Register holding next rowid */
|
||||||
WhereTerm *pTerm; /* The complete OR-clause */
|
WhereTerm *pTerm; /* The complete OR-clause */
|
||||||
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
||||||
@@ -2603,33 +2646,41 @@ static Bitmask codeOneLoopStart(
|
|||||||
assert( pTerm->eOperator==WO_OR );
|
assert( pTerm->eOperator==WO_OR );
|
||||||
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
||||||
pOrWc = &pTerm->u.pOrInfo->wc;
|
pOrWc = &pTerm->u.pOrInfo->wc;
|
||||||
|
codeRowSetEarly = (regRowSet>=0 && pWC->nTerm==1) ?1:0;
|
||||||
regRowset = sqlite3GetTempReg(pParse);
|
|
||||||
regNextRowid = sqlite3GetTempReg(pParse);
|
if( codeRowSetEarly ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
|
regOrRowset = regRowSet;
|
||||||
|
}else{
|
||||||
|
regOrRowset = sqlite3GetTempReg(pParse);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Null, 0, regOrRowset);
|
||||||
|
}
|
||||||
oneTab.nSrc = 1;
|
oneTab.nSrc = 1;
|
||||||
oneTab.nAlloc = 1;
|
oneTab.nAlloc = 1;
|
||||||
oneTab.a[0] = *pTabItem;
|
oneTab.a[0] = *pTabItem;
|
||||||
for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
|
for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
|
||||||
WhereInfo *pSubWInfo;
|
WhereInfo *pSubWInfo;
|
||||||
if( pOrTerm->leftCursor!=iCur ) continue;
|
if( pOrTerm->leftCursor!=iCur ) continue;
|
||||||
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0, 0);
|
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
|
||||||
|
WHERE_FILL_ROWSET, regOrRowset);
|
||||||
if( pSubWInfo ){
|
if( pSubWInfo ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Rowid, oneTab.a[0].iCursor, regNextRowid);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowset, regNextRowid);
|
|
||||||
pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY;
|
pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY;
|
||||||
sqlite3WhereEnd(pSubWInfo);
|
sqlite3WhereEnd(pSubWInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeResolveLabel(v, addrCont);
|
sqlite3VdbeResolveLabel(v, addrCont);
|
||||||
addrCont =
|
if( !codeRowSetEarly ){
|
||||||
sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowset, addrBrk, regNextRowid);
|
regNextRowid = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Seek, iCur, regNextRowid);
|
addrCont =
|
||||||
sqlite3ReleaseTempReg(pParse, regNextRowid);
|
sqlite3VdbeAddOp3(v, OP_RowSetRead, regOrRowset,addrBrk,regNextRowid);
|
||||||
pLevel->op = OP_Goto;
|
sqlite3VdbeAddOp2(v, OP_Seek, iCur, regNextRowid);
|
||||||
pLevel->p2 = addrCont;
|
sqlite3ReleaseTempReg(pParse, regNextRowid);
|
||||||
|
/* sqlite3ReleaseTempReg(pParse, regOrRowset); // Preserve the RowSet */
|
||||||
|
pLevel->op = OP_Goto;
|
||||||
|
pLevel->p2 = addrCont;
|
||||||
|
}
|
||||||
|
disableTerm(pLevel, pTerm);
|
||||||
}else
|
}else
|
||||||
#endif /* SQLITE_ENABLE_MULTI_OR */
|
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Case 5: There is no usable index. We must do a complete
|
/* Case 5: There is no usable index. We must do a complete
|
||||||
@@ -2641,6 +2692,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
pLevel->p1 = iCur;
|
pLevel->p1 = iCur;
|
||||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addrBrk);
|
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addrBrk);
|
||||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||||
|
codeRowSetEarly = 0;
|
||||||
}
|
}
|
||||||
notReady &= ~getMask(pWC->pMaskSet, iCur);
|
notReady &= ~getMask(pWC->pMaskSet, iCur);
|
||||||
|
|
||||||
@@ -2685,6 +2737,25 @@ static Bitmask codeOneLoopStart(
|
|||||||
pTerm->wtFlags |= TERM_CODED;
|
pTerm->wtFlags |= TERM_CODED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If it was requested to store the results in a rowset and that has
|
||||||
|
** not already been do, then do so now.
|
||||||
|
*/
|
||||||
|
if( regRowSet>=0 && !codeRowSetEarly ){
|
||||||
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
|
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_VRowid, iCur, r1);
|
||||||
|
}else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
|
||||||
|
}
|
||||||
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
|
}
|
||||||
|
|
||||||
return notReady;
|
return notReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2813,7 +2884,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
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 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */
|
u8 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
|
||||||
|
int regRowSet /* Register hold RowSet if WHERE_FILL_ROWSET is set */
|
||||||
){
|
){
|
||||||
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 */
|
||||||
@@ -2858,6 +2930,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pWInfo->pParse = pParse;
|
pWInfo->pParse = pParse;
|
||||||
pWInfo->pTabList = pTabList;
|
pWInfo->pTabList = pTabList;
|
||||||
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
||||||
|
pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
|
||||||
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
|
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
|
||||||
pMaskSet = (WhereMaskSet*)&pWC[1];
|
pMaskSet = (WhereMaskSet*)&pWC[1];
|
||||||
|
|
||||||
|
|||||||
94
test/where7.test
Normal file
94
test/where7.test
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# 2008 December 23
|
||||||
|
#
|
||||||
|
# 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. The
|
||||||
|
# focus of this file is testing the multi-index OR clause optimizer.
|
||||||
|
#
|
||||||
|
# $Id: where7.test,v 1.1 2008/12/23 23:56:22 drh Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
ifcapable !or_opt {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Evaluate SQL. Return the result set followed by the
|
||||||
|
# and the number of full-scan steps.
|
||||||
|
#
|
||||||
|
proc count_steps {sql} {
|
||||||
|
set r [db eval $sql]
|
||||||
|
lappend r scan [db status step]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build some test data
|
||||||
|
#
|
||||||
|
do_test where7-1.1 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d);
|
||||||
|
INSERT INTO t1 VALUES(1,2,3,4);
|
||||||
|
INSERT INTO t1 VALUES(2,3,4,5);
|
||||||
|
INSERT INTO t1 VALUES(3,4,6,8);
|
||||||
|
INSERT INTO t1 VALUES(4,5,10,15);
|
||||||
|
INSERT INTO t1 VALUES(5,10,100,1000);
|
||||||
|
CREATE INDEX t1b ON t1(b);
|
||||||
|
CREATE INDEX t1c ON t1(c);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {1 2 3 4 2 3 4 5 3 4 6 8 4 5 10 15 5 10 100 1000}
|
||||||
|
do_test where7-1.2 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE b=3 OR c=6
|
||||||
|
}
|
||||||
|
} {2 3 scan 0}
|
||||||
|
do_test where7-1.3 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE b=3 OR +c=6
|
||||||
|
}
|
||||||
|
} {2 3 scan 4}
|
||||||
|
do_test where7-1.4 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE +b=3 OR c=6
|
||||||
|
}
|
||||||
|
} {2 3 scan 4}
|
||||||
|
do_test where7-1.5 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE 3=b OR c=6
|
||||||
|
}
|
||||||
|
} {2 3 scan 0}
|
||||||
|
do_test where7-1.6 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE (3=b OR c=6) AND +a>0
|
||||||
|
}
|
||||||
|
} {2 3 scan 0}
|
||||||
|
do_test where7-1.7 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE (b=3 OR c>10)
|
||||||
|
}
|
||||||
|
} {2 5 scan 0}
|
||||||
|
do_test where7-1.8 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE (b=3 OR c>=10)
|
||||||
|
}
|
||||||
|
} {2 4 5 scan 0}
|
||||||
|
do_test where7-1.9 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4)
|
||||||
|
}
|
||||||
|
} {2 4 5 scan 0}
|
||||||
|
do_test where7-1.10 {
|
||||||
|
count_steps {
|
||||||
|
SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10)
|
||||||
|
}
|
||||||
|
} {2 4 5 scan 0}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
Reference in New Issue
Block a user