The optimizer recognizes MATCH operators and allows virtual-tables to make

use of them. (CVS 3232)

FossilOrigin-Name: 136bed496b89943522310ec511199b78198d0844
This commit is contained in:
drh 2006-06-13 17:38:59 +00:00
parent 03bea70cd8
commit 7f3759015a
5 changed files with 157 additions and 18 deletions

View File

@ -1,5 +1,5 @@
C Add\ssupport\sfor\sthe\sMATCH\soperator.\s(CVS\s3231)
D 2006-06-13T15:37:26
C The\soptimizer\srecognizes\sMATCH\soperators\sand\sallows\svirtual-tables\sto\smake\nuse\sof\sthem.\s(CVS\s3232)
D 2006-06-13T17:39:00
F Makefile.in 56fd6261e83f60724e6dcd764e06ab68cbd53909
F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -43,7 +43,7 @@ F src/date.c cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e
F src/delete.c f9a8c7837adb4bb4810a698a041a88d5ec7bfa9a
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c 8c873e05436ca8ee0ac4c7825d35ff898abb9c89
F src/func.c acbbf533b55221f26760798d99b37de3ac5678fe
F src/func.c 16eaca47b4d5c66f750e0b2d8814387d70f0d5b2
F src/hash.c 449f3d6620193aa557f5d86cbc5cc6b87702b185
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
F src/insert.c 2c3eeb4bcde13c1006824ef14953c2fdad31cf36
@ -102,7 +102,7 @@ F src/vdbeaux.c 0168d770d03f9815511780a49cd8360d9a5f1ec5
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3
F src/vtab.c 12d83f7de893d06592d6d37c285defefebbd2d48
F src/where.c 0b1fcf590040175e20c6d8f2e13485b683d3d03c
F src/where.c 7e614b0278c688aec94c79d42f602b24e9e4119f
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4
@ -171,7 +171,7 @@ F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
F test/expr.test 7b4b349abdb05ab1862c1cfcf7607e3731efc5d2
F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
F test/format4.test 9f31d41d4f926cab97b2ebe6be00a6ab12dece87
F test/func.test 27d02fd00b7c2a6b5c8c302d02f9f20876ce5cc8
F test/func.test 7d8dd2e7d92fb17974d84c0cf02dfb7f9885b5b2
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
F test/index.test e65df12bed94b2903ee89987115e1578687e9266
@ -363,7 +363,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P ea4bc5a0be6cfc81ef1e9405f396c43205fe9cd8
R 3c35da63c52751c585cf9cb6b2473575
P 815b84d5273b42978edcee0d4afe7f91a7933f4e
R fa210e05061370c7e0ab1d80526752c9
U drh
Z a4bc00b43637d2bd30e6651aa4a937df
Z 0393cac6dbaee2c659fa623848ca0a40

View File

@ -1 +1 @@
815b84d5273b42978edcee0d4afe7f91a7933f4e
136bed496b89943522310ec511199b78198d0844

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.128 2006/05/11 13:25:39 drh Exp $
** $Id: func.c,v 1.129 2006/06/13 17:39:00 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -548,6 +548,19 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
}
/*
** The MATCH() function is unimplemented. If anybody tries to use it,
** return an error.
*/
static void matchStub(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
static const char zErr[] = "MATCH is not implemented";
sqlite3_result_error(context, zErr, sizeof(zErr)-1);
}
/*
** EXPERIMENTAL - This is not an official function. The interface may
@ -1003,6 +1016,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "changes", 0, 1, SQLITE_UTF8, 0, changes },
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
{ "match", 2, 0, SQLITE_UTF8, 0, matchStub },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif

View File

@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.214 2006/06/13 15:00:55 danielk1977 Exp $
** $Id: where.c,v 1.215 2006/06/13 17:39:01 drh Exp $
*/
#include "sqliteInt.h"
@ -156,6 +156,7 @@ struct ExprMaskSet {
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 64
/*
** Value for flags returned by bestIndex()
@ -523,6 +524,34 @@ static int isLikeOrGlob(
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
/*
** Check to see if the given expression is of the form
**
** column MATCH expr
**
** If it is then return TRUE. If not, return FALSE.
*/
static int isMatchOfColumn(
Expr *pExpr /* Test this expression */
){
ExprList *pList;
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
if( pExpr->token.n!=5 || sqlite3StrNICmp(pExpr->token.z,"match",5)!=0 ){
return 0;
}
pList = pExpr->pList;
if( pList->nExpr!=2 ){
return 0;
}
if( pList->a[1].pExpr->op != TK_COLUMN ){
return 0;
}
return 1;
}
/*
** If the pBase expression originated in the ON or USING clause of
** a join, then transfer the appropriate markings over to derived.
@ -747,6 +776,39 @@ or_not_possible:
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Add a WO_MATCH auxiliary term to the constraint set if the
** current expression is of the form: column MATCH expr.
** This information is used by the xBestIndex methods of
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
if( isMatchOfColumn(pExpr) ){
int idxNew;
Expr *pRight, *pLeft;
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
pRight = pExpr->pList->a[0].pExpr;
pLeft = pExpr->pList->a[1].pExpr;
prereqExpr = exprTableUsage(pMaskSet, pRight);
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
pNewTerm = &pWC->a[idxNew];
pNewTerm->prereqRight = prereqExpr;
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
pNewTerm->iParent = idxTerm;
pTerm = &pWC->a[idxNew];
pTerm->nChild = 1;
pTerm->flags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
@ -887,7 +949,20 @@ static double estLog(double N){
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Compute the best index for a virtual table
** Compute the best index for a virtual table.
**
** The best index is computed by the xBestIndex method of the virtual
** table module. This routine is really just a wrapper that sets up
** the sqlite3_index_info structure that is used to communicate with
** xBestIndex.
**
** In a join, this routine might be called multiple times for the
** same virtual table. The sqlite3_index_info structure is created
** and initialized on the first invocation and reused on all subsequent
** invocations. The sqlite3_index_info structure is also used when
** code is generated to access the virtual table. The whereInfoDelete()
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
static double bestVirtualIndex(
Parse *pParse, /* The parsing context */
@ -971,12 +1046,16 @@ static double bestVirtualIndex(
pIdxCons[j].iColumn = pTerm->leftColumn;
pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = pTerm->eOperator;
/* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
** following asserts verify this fact. */
assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE) );
assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
j++;
}
for(i=0; i<nOrderBy; i++){
@ -986,6 +1065,13 @@ static double bestVirtualIndex(
}
}
/* At this point, the sqlite3_index_info structure that pIdxInfo points
** to will have been initialized, either during the current invocation or
** during some prior invocation. Now we just have to customize the
** details of pIdxInfo for the current invocation and pass it to
** xBestIndex.
*/
/* The module name must be defined */
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
if( pTab->pVtab==0 ){
@ -995,7 +1081,24 @@ static double bestVirtualIndex(
}
/* Set the aConstraint[].usable fields and initialize all
** output variables
** output variables to zero.
**
** aConstraint[].usable is true for constraints where the right-hand
** side contains only references to tables to the left of the current
** table. In other words, if the constraint is of the form:
**
** column = expr
**
** and we are evaluating a join, then the constraint on column is
** only valid if all tables referenced in expr occur to the left
** of the table containing column.
**
** The aConstraints[] array contains entries for all constraints
** on the current table. That way we only have to compute it once
** even though we might try to pick the best index multiple times.
** For each attempt at picking an index, the order of tables in the
** join might be different so we have to recompute the usable flag
** each time.
*/
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
pUsage = pIdxInfo->aConstraintUsage;
@ -1846,10 +1949,11 @@ WhereInfo *sqlite3WhereBegin(
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pLevel->pIdxInfo ){
/* Case 0: The table is a virtual-table. Use the VFilter and VNext
** to access the data.
*/
char *zSpace; /* Space for OP_VFilter to marshall it's arguments */
/* Case 0: That table is a virtual-table. Use the VFilter and VNext.
*/
sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
for(i=1; i<=pIdxInfo->nConstraint; i++){
int j;

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.51 2006/03/26 01:21:23 drh Exp $
# $Id: func.test,v 1.52 2006/06/13 17:39:01 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -643,6 +643,27 @@ do_test func-18.32 {
}
} {1 {integer overflow}}
# The MATCH function exists but is only a stub and always throws an error.
#
do_test func-19.1 {
execsql {
SELECT match(a,b) FROM t1 WHERE 0;
}
} {}
do_test func-19.2 {
catchsql {
SELECT 'abc' MATCH 'xyz';
}
} {1 {MATCH is not implemented}}
do_test func-19.3 {
catchsql {
SELECT 'abc' NOT MATCH 'xyz';
}
} {1 {MATCH is not implemented}}
do_test func-19.4 {
catchsql {
SELECT match(1,2,3);
}
} {1 {wrong number of arguments to function match()}}
finish_test