aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <dan@noemail.net>2015-11-23 21:09:54 +0000
committerdan <dan@noemail.net>2015-11-23 21:09:54 +0000
commit07bdba86d55b298c44cacdf92f164c1a5953504c (patch)
tree27cc582e9bf008035a2280f2142e2e0a23ec97d6 /src
parent8836cbbcb4924f5b78f5749dffc9857acf9b684f (diff)
downloadsqlite-07bdba86d55b298c44cacdf92f164c1a5953504c.tar.gz
sqlite-07bdba86d55b298c44cacdf92f164c1a5953504c.zip
Add experimental support for LIKE, GLOB and REGEXP to the virtual table interface.
FossilOrigin-Name: 277a5b4027d4c2caba8143228a4f7d6df899dbb4
Diffstat (limited to 'src')
-rw-r--r--src/sqlite.h.in15
-rw-r--r--src/test8.c6
-rw-r--r--src/where.c3
-rw-r--r--src/whereInt.h1
-rw-r--r--src/whereexpr.c28
5 files changed, 41 insertions, 12 deletions
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 13c97d8d4..42652061f 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -5709,12 +5709,15 @@ struct sqlite3_index_info {
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+#define SQLITE_INDEX_CONSTRAINT_LIKE 65
+#define SQLITE_INDEX_CONSTRAINT_GLOB 66
+#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
/*
** CAPI3REF: Register A Virtual Table Implementation
diff --git a/src/test8.c b/src/test8.c
index 2107710a9..6d70c3042 100644
--- a/src/test8.c
+++ b/src/test8.c
@@ -849,6 +849,12 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zOp = ">="; break;
case SQLITE_INDEX_CONSTRAINT_MATCH:
zOp = "LIKE"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIKE:
+ zOp = "like"; break;
+ case SQLITE_INDEX_CONSTRAINT_GLOB:
+ zOp = "glob"; break;
+ case SQLITE_INDEX_CONSTRAINT_REGEXP:
+ zOp = "regexp"; break;
}
if( zOp[0]=='L' ){
zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
diff --git a/src/where.c b/src/where.c
index 1c87706ea..737bfc4e6 100644
--- a/src/where.c
+++ b/src/where.c
@@ -893,6 +893,9 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxCons[j].iTermOffset = i;
op = (u8)pTerm->eOperator & WO_ALL;
if( op==WO_IN ) op = WO_EQ;
+ if( op==WO_MATCH ){
+ op = pTerm->eMatchOp;
+ }
pIdxCons[j].op = op;
/* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
diff --git a/src/whereInt.h b/src/whereInt.h
index cae09acc8..86164d8c1 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -253,6 +253,7 @@ struct WhereTerm {
u16 eOperator; /* A WO_xx value describing <op> */
u16 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
+ u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 21301ac04..0cc2fd720 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -282,16 +282,24 @@ static int isLikeOrGlob(
** If it is then return TRUE. If not, return FALSE.
*/
static int isMatchOfColumn(
- Expr *pExpr /* Test this expression */
+ Expr *pExpr, /* Test this expression */
+ unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
){
+ struct Op2 {
+ const char *zOp;
+ unsigned char eOp2;
+ } aOp[] = {
+ { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
+ { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
+ { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
+ { "regex", SQLITE_INDEX_CONSTRAINT_REGEXP }
+ };
ExprList *pList;
+ int i;
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
- if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
- return 0;
- }
pList = pExpr->x.pList;
if( pList->nExpr!=2 ){
return 0;
@@ -299,7 +307,13 @@ static int isMatchOfColumn(
if( pList->a[1].pExpr->op != TK_COLUMN ){
return 0;
}
- return 1;
+ for(i=0; i<ArraySize(aOp); i++){
+ if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
+ *peOp2 = aOp[i].eOp2;
+ return 1;
+ }
+ }
+ return 0;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -876,6 +890,7 @@ static void exprAnalyze(
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
+ unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */
if( db->mallocFailed ){
return;
@@ -1099,7 +1114,7 @@ static void exprAnalyze(
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
- if( isMatchOfColumn(pExpr) ){
+ if( isMatchOfColumn(pExpr, &eOp2) ){
int idxNew;
Expr *pRight, *pLeft;
WhereTerm *pNewTerm;
@@ -1120,6 +1135,7 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
+ pNewTerm->eMatchOp = eOp2;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;