From 9fe27de6514a3e217a4b82c92b3a7f07b5e921a1 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 9 Jan 2013 15:44:23 +0000 Subject: [PATCH 01/17] Check in an extra test for the fts4 "content=" option. No code changes. FossilOrigin-Name: 0d0e5ab8f16c890629ec1120c78168ef6be9e419 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/fts4content.test | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d43d6d923f..10fec36728 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sover-aggressive\soptimization\sof\sORDER\sBY\son\sa\sthree-way\sjoin\swhere\sthe\nsecond\stable\sis\sUNIQUE\sand\sthe\sORDER\sBY\soccurs\son\sthe\sthird\stable.\nTicket\s[598f5f7596b0557]. -D 2013-01-09T11:31:17.442 +C Check\sin\san\sextra\stest\sfor\sthe\sfts4\s"content="\soption.\sNo\scode\schanges. +D 2013-01-09T15:44:23.023 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -500,7 +500,7 @@ F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659 F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8 -F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f +F test/fts4content.test b8032a15a6cd91df41cf6f335167e02b4a037ed5 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 @@ -1032,7 +1032,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7249bfc2ca57624d73f2be0197a9807c58463c48 -R fcfe7ea587f64ef92e6849f97c544ccd -U drh -Z 6e8a59f9682c67ec0cee9fce08b8ae23 +P 5774f2175ce621dfc4b6b93f7ee13fd66f3ec2b9 +R 55e61a393f7fda758ca2247ac64f35c5 +U dan +Z 742a4d1e5d57ee15d6514285ba4dd6df diff --git a/manifest.uuid b/manifest.uuid index 104853bdda..562f951683 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5774f2175ce621dfc4b6b93f7ee13fd66f3ec2b9 \ No newline at end of file +0d0e5ab8f16c890629ec1120c78168ef6be9e419 \ No newline at end of file diff --git a/test/fts4content.test b/test/fts4content.test index 59c4199fa2..1b25e0818f 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -46,6 +46,8 @@ ifcapable !fts3 { # 8.* - Test that if the content=xxx and prefix options are used together, # the 'rebuild' command still works. # +# 9.* - Test using content=xxx where xxx is a virtual table. +# do_execsql_test 1.1.1 { CREATE TABLE t1(a, b, c); @@ -522,4 +524,42 @@ do_execsql_test 8.4 { SELECT rowid FROM ft10 WHERE a MATCH 'ab*'; } {1 2 3} do_execsql_test 8.5 { SELECT rowid FROM ft10 WHERE b MATCH 'abav*'; } {3} do_execsql_test 8.6 { SELECT rowid FROM ft10 WHERE ft10 MATCH 'abas*'; } {1} +#------------------------------------------------------------------------- +# Test cases 9.* +# +reset_db +register_echo_module [sqlite3_connection_pointer db] + +do_execsql_test 9.1 { + CREATE TABLE tbl1(a, b); + INSERT INTO tbl1 VALUES('a b', 'c d'); + INSERT INTO tbl1 VALUES('e f', 'a b'); + CREATE VIRTUAL TABLE e1 USING echo(tbl1); + CREATE VIRTUAL TABLE ft1 USING fts4(content=e1); + INSERT INTO ft1(ft1) VALUES('rebuild'); +} + +do_execsql_test 9.2 { + SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'e' +} {2 {e f} {a b}} + +do_execsql_test 9.3 { + SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' +} {1 {a b} {c d} 2 {e f} {a b}} + +do_execsql_test 9.4 { + DELETE FROM ft1 WHERE docid=1; +} + +do_execsql_test 9.5 { + SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' +} {2 {e f} {a b}} + +do_execsql_test 9.6 { + INSERT INTO ft1(ft1) VALUES('rebuild'); + SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' +} {1 {a b} {c d} 2 {e f} {a b}} + + + finish_test From 9f5ff3712080db39d3ecf2bef0afe36d01326498 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 11 Jan 2013 09:58:54 +0000 Subject: [PATCH 02/17] Add another test for the fts4 content= option. FossilOrigin-Name: 7e6007a0002f6989bd489abeba8db52acb4a6854 --- main.mk | 1 + manifest | 17 +-- manifest.uuid | 2 +- src/tclsqlite.c | 2 + src/test_fs.c | 327 ++++++++++++++++++++++++++++++++++++++++++ test/fts4content.test | 61 ++++++++ 6 files changed, 401 insertions(+), 9 deletions(-) create mode 100644 src/test_fs.c diff --git a/main.mk b/main.mk index fdabcb4636..2430d3ffe9 100644 --- a/main.mk +++ b/main.mk @@ -240,6 +240,7 @@ TESTSRC = \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ + $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ diff --git a/manifest b/manifest index 10fec36728..e4306e9a89 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Check\sin\san\sextra\stest\sfor\sthe\sfts4\s"content="\soption.\sNo\scode\schanges. -D 2013-01-09T15:44:23.023 +C Add\sanother\stest\sfor\sthe\sfts4\scontent=\soption. +D 2013-01-11T09:58:54.381 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -103,7 +103,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F main.mk 718265bbf49a846c6898b4da09593eef4068fa39 +F main.mk 404cd38114d1a94ef6ad5aa01a1c8bb46da36161 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -183,7 +183,7 @@ F src/sqliteInt.h e998703742455b2241731424c6ec142fd8d0258f F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 5203bb7b71a302bea8896f176cd178e38d7803a4 +F src/tclsqlite.c 3213f3101e3b85f047d6e389da5a53d76d3d7540 F src/test1.c f62769c989146149590662ab02de4a813813a9c5 F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d @@ -200,6 +200,7 @@ F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16 F src/test_config.c 09781397ccc24268cb895be0d4c21b4aad651486 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc +F src/test_fs.c 7d3337933e92c198d06dd600375cc39259cc66b3 F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170 F src/test_fuzzer.c 1d26aa965120420bc14807da29d4d4541bfa6148 F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd @@ -500,7 +501,7 @@ F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659 F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8 -F test/fts4content.test b8032a15a6cd91df41cf6f335167e02b4a037ed5 +F test/fts4content.test 6efc53b4fd03cab167e6998d2b0b7d4b7d419ee6 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 @@ -1032,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 5774f2175ce621dfc4b6b93f7ee13fd66f3ec2b9 -R 55e61a393f7fda758ca2247ac64f35c5 +P 0d0e5ab8f16c890629ec1120c78168ef6be9e419 +R 8314e970c84b41ce51cf4e3af788943a U dan -Z 742a4d1e5d57ee15d6514285ba4dd6df +Z af1374dc5de33897a8a4ab326451d45f diff --git a/manifest.uuid b/manifest.uuid index 562f951683..909c82e7f3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d0e5ab8f16c890629ec1120c78168ef6be9e419 \ No newline at end of file +7e6007a0002f6989bd489abeba8db52acb4a6854 \ No newline at end of file diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 267f759701..2777d2f9f8 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3671,6 +3671,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*); + extern int Sqlitetestfs_Init(Tcl_Interp*); extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); @@ -3715,6 +3716,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); + Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(interp); SqlitetestOsinst_Init(interp); diff --git a/src/test_fs.c b/src/test_fs.c new file mode 100644 index 0000000000..9678005c8d --- /dev/null +++ b/src/test_fs.c @@ -0,0 +1,327 @@ +/* +** 2013 Jan 11 +** +** 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. +** +************************************************************************* +** Code for testing the virtual table interfaces. This code +** is not included in the SQLite library. It is used for automated +** testing of the SQLite library. +** +** The FS virtual table is created as follows: +** +** CREATE VIRTUAL TABLE tbl USING fs(idx); +** +** where idx is the name of a table in the db with 2 columns. The virtual +** table also has two columns - file path and file contents. +** +** The first column of table idx must be an IPK, and the second contains file +** paths. For example: +** +** CREATE TABLE idx(id INTEGER PRIMARY KEY, path TEXT); +** INSERT INTO idx VALUES(4, '/etc/passwd'); +** +** Adding the row to the idx table automatically creates a row in the +** virtual table with rowid=4, path=/etc/passwd and a text field that +** contains data read from file /etc/passwd on disk. +*/ +#include "sqliteInt.h" +#include "tcl.h" + +#include +#include +#include +#include +#include +#include + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +typedef struct fs_vtab fs_vtab; +typedef struct fs_cursor fs_cursor; + +/* +** A fs virtual-table object +*/ +struct fs_vtab { + sqlite3_vtab base; + sqlite3 *db; + char *zDb; /* Name of db containing zTbl */ + char *zTbl; /* Name of docid->file map table */ +}; + +/* A fs cursor object */ +struct fs_cursor { + sqlite3_vtab_cursor base; + sqlite3_stmt *pStmt; + char *zBuf; + int nBuf; + int nAlloc; +}; + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the fs virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fs") +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> other module argument fields. +*/ +static int fsConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + fs_vtab *pVtab; + int nByte; + const char *zTbl; + const char *zDb = argv[1]; + + if( argc!=4 ){ + *pzErr = sqlite3_mprintf("wrong number of arguments"); + return SQLITE_ERROR; + } + zTbl = argv[3]; + + nByte = sizeof(fs_vtab) + strlen(zTbl) + 1 + strlen(zDb) + 1; + pVtab = (fs_vtab *)sqlite3MallocZero( nByte ); + if( !pVtab ) return SQLITE_NOMEM; + + pVtab->zTbl = (char *)&pVtab[1]; + pVtab->zDb = &pVtab->zTbl[strlen(zTbl)+1]; + pVtab->db = db; + memcpy(pVtab->zTbl, zTbl, strlen(zTbl)); + memcpy(pVtab->zDb, zDb, strlen(zDb)); + *ppVtab = &pVtab->base; + sqlite3_declare_vtab(db, "CREATE TABLE xyz(path TEXT, data TEXT)"); + + return SQLITE_OK; +} +/* Note that for this virtual table, the xCreate and xConnect +** methods are identical. */ + +static int fsDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} +/* The xDisconnect and xDestroy methods are also the same */ + +/* +** Open a new fs cursor. +*/ +static int fsOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + fs_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(fs_cursor)); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Close a fs cursor. +*/ +static int fsClose(sqlite3_vtab_cursor *cur){ + fs_cursor *pCur = (fs_cursor *)cur; + sqlite3_finalize(pCur->pStmt); + sqlite3_free(pCur->zBuf); + sqlite3_free(pCur); + return SQLITE_OK; +} + +static int fsNext(sqlite3_vtab_cursor *cur){ + fs_cursor *pCur = (fs_cursor *)cur; + int rc; + + rc = sqlite3_step(pCur->pStmt); + if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK; + + return rc; +} + +static int fsFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + int rc; + fs_cursor *pCur = (fs_cursor *)pVtabCursor; + fs_vtab *p = (fs_vtab *)(pVtabCursor->pVtab); + + assert( (idxNum==0 && argc==0) || (idxNum==1 && argc==1) ); + if( idxNum==1 ){ + char *zStmt = sqlite3_mprintf( + "SELECT * FROM %Q.%Q WHERE rowid=?", p->zDb, p->zTbl); + if( !zStmt ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); + sqlite3_free(zStmt); + if( rc==SQLITE_OK ){ + sqlite3_bind_value(pCur->pStmt, 1, argv[0]); + } + }else{ + char *zStmt = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zTbl); + if( !zStmt ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); + sqlite3_free(zStmt); + } + + if( rc==SQLITE_OK ){ + rc = fsNext(pVtabCursor); + } + return rc; +} + +static int fsColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + fs_cursor *pCur = (fs_cursor*)cur; + + assert( i==0 || i==1 ); + if( i==0 ){ + sqlite3_result_value(ctx, sqlite3_column_value(pCur->pStmt, 0)); + }else{ + const char *zFile = (const char *)sqlite3_column_text(pCur->pStmt, 1); + struct stat sbuf; + int fd; + + fd = open(zFile, O_RDONLY); + if( fd<0 ) return SQLITE_IOERR; + fstat(fd, &sbuf); + + if( sbuf.st_size>=pCur->nAlloc ){ + int nNew = sbuf.st_size*2; + char *zNew; + if( nNew<1024 ) nNew = 1024; + + zNew = sqlite3Realloc(pCur->zBuf, nNew); + if( zNew==0 ){ + close(fd); + return SQLITE_NOMEM; + } + pCur->zBuf = zNew; + pCur->nAlloc = nNew; + } + + read(fd, pCur->zBuf, sbuf.st_size); + close(fd); + pCur->nBuf = sbuf.st_size; + pCur->zBuf[pCur->nBuf] = '\0'; + + sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT); + } + return SQLITE_OK; +} + +static int fsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + fs_cursor *pCur = (fs_cursor*)cur; + *pRowid = sqlite3_column_int64(pCur->pStmt, 0); + return SQLITE_OK; +} + +static int fsEof(sqlite3_vtab_cursor *cur){ + fs_cursor *pCur = (fs_cursor*)cur; + return (sqlite3_data_count(pCur->pStmt)==0); +} + +static int fsBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int ii; + + for(ii=0; iinConstraint; ii++){ + struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii]; + if( pCons->iColumn<0 && pCons->usable + && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + struct sqlite3_index_constraint_usage *pUsage; + pUsage = &pIdxInfo->aConstraintUsage[ii]; + pUsage->omit = 0; + pUsage->argvIndex = 1; + pIdxInfo->idxNum = 1; + pIdxInfo->estimatedCost = 1.0; + break; + } + } + + return SQLITE_OK; +} + +/* +** A virtual table module that provides read-only access to a +** Tcl global variable namespace. +*/ +static sqlite3_module fsModule = { + 0, /* iVersion */ + fsConnect, + fsConnect, + fsBestIndex, + fsDisconnect, + fsDisconnect, + fsOpen, /* xOpen - open a cursor */ + fsClose, /* xClose - close a cursor */ + fsFilter, /* xFilter - configure scan constraints */ + fsNext, /* xNext - advance a cursor */ + fsEof, /* xEof - check for end of scan */ + fsColumn, /* xColumn - read data */ + fsRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ +}; + +/* +** Decode a pointer to an sqlite3 object. +*/ +extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); + +/* +** Register the echo virtual table module. +*/ +static int register_fs_module( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_create_module(db, "fs", &fsModule, (void *)interp); +#endif + return TCL_OK; +} + +#endif + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetestfs_Init(Tcl_Interp *interp){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + void *clientData; + } aObjCmd[] = { + { "register_fs_module", register_fs_module, 0 }, + }; + int i; + for(i=0; i Date: Tue, 15 Jan 2013 16:15:28 +0000 Subject: [PATCH 03/17] Clarification to a comment in where.c. No code changes. FossilOrigin-Name: 04507c176330a06b09dcafa35ec0ca7498f5ace7 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 6 ++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index e4306e9a89..09415e5207 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sanother\stest\sfor\sthe\sfts4\scontent=\soption. -D 2013-01-11T09:58:54.381 +C Clarification\sto\sa\scomment\sin\swhere.c.\s\sNo\scode\schanges. +D 2013-01-15T16:15:28.864 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 4c7fec9cfa3af06597ae039e5f0ec03cbee34c58 +F src/where.c 9df0419ef7210a531a4fda890ab88f2baeea9755 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0d0e5ab8f16c890629ec1120c78168ef6be9e419 -R 8314e970c84b41ce51cf4e3af788943a -U dan -Z af1374dc5de33897a8a4ab326451d45f +P 7e6007a0002f6989bd489abeba8db52acb4a6854 +R d0bbf16dad26659cda0048aa7cd24d37 +U drh +Z e1bea2ae72c72e050882322d94f05fc5 diff --git a/manifest.uuid b/manifest.uuid index 909c82e7f3..7c207cf6d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7e6007a0002f6989bd489abeba8db52acb4a6854 \ No newline at end of file +04507c176330a06b09dcafa35ec0ca7498f5ace7 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 6e096e5c64..31ddb5eecd 100644 --- a/src/where.c +++ b/src/where.c @@ -5105,10 +5105,8 @@ WhereInfo *sqlite3WhereBegin( ** strategies were found by the first iteration. This second iteration ** is used to search for the lowest cost scan overall. ** - ** Previous versions of SQLite performed only the second iteration - - ** the next outermost loop was always that with the lowest overall - ** cost. However, this meant that SQLite could select the wrong plan - ** for scripts such as the following: + ** Without the optimal scan step (the first iteration) a suboptimal + ** plan might be chosen for queries like this: ** ** CREATE TABLE t1(a, b); ** CREATE TABLE t2(c, d); From ea84a65e4e11b6e62efddc28e8b75d67a2694a2b Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 15 Jan 2013 18:49:07 +0000 Subject: [PATCH 04/17] Fix a missing word in a comment. Enhance the "wheretrace" debugging output to show the estimated cost of each table option while planning the join order. FossilOrigin-Name: ac4e119a87497f2e422ff1cb711112ed8594bfa9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 7 ++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 09415e5207..b7881441e1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clarification\sto\sa\scomment\sin\swhere.c.\s\sNo\scode\schanges. -D 2013-01-15T16:15:28.864 +C Fix\sa\smissing\sword\sin\sa\scomment.\s\sEnhance\sthe\s"wheretrace"\sdebugging\soutput\nto\sshow\sthe\sestimated\scost\sof\seach\stable\soption\swhile\splanning\sthe\sjoin\sorder. +D 2013-01-15T18:49:07.627 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 9df0419ef7210a531a4fda890ab88f2baeea9755 +F src/where.c b2a827f2b3fa23a3245a4e6093827e359c1e8054 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7e6007a0002f6989bd489abeba8db52acb4a6854 -R d0bbf16dad26659cda0048aa7cd24d37 +P 04507c176330a06b09dcafa35ec0ca7498f5ace7 +R f5ddb099282326d8029eed3fa99d47e6 U drh -Z e1bea2ae72c72e050882322d94f05fc5 +Z f7bf9c2b2fa73cf7872c5f7a932db154 diff --git a/manifest.uuid b/manifest.uuid index 7c207cf6d9..a55b102705 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -04507c176330a06b09dcafa35ec0ca7498f5ace7 \ No newline at end of file +ac4e119a87497f2e422ff1cb711112ed8594bfa9 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 31ddb5eecd..84d79c811d 100644 --- a/src/where.c +++ b/src/where.c @@ -3569,8 +3569,9 @@ static void bestBtreeIndex(WhereBestIdx *p){ || p->cost.plan.u.pIdx==pSrc->pIndex ); - WHERETRACE((" best index is: %s\n", - p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk")); + WHERETRACE((" best index is %s cost=%.1f\n", + p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk", + p->cost.rCost)); bestOrClauseIndex(p); bestAutomaticIndex(p); @@ -5161,7 +5162,7 @@ WhereInfo *sqlite3WhereBegin( if( isOptimal ){ pWInfo->a[j].rOptCost = sWBI.cost.rCost; }else if( iFrom Date: Wed, 16 Jan 2013 00:46:09 +0000 Subject: [PATCH 05/17] Improvements to query planning for joins: Avoid unnecessary calls to "optimal scan" checks in cases where table reordering is not possible. Make sure optimal scan checks are carried out for CROSS JOINs and LEFT JOINs. FossilOrigin-Name: d5ebb7877885839e93eee3b322624d4c4215c1c4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index b7881441e1..a878fe5539 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smissing\sword\sin\sa\scomment.\s\sEnhance\sthe\s"wheretrace"\sdebugging\soutput\nto\sshow\sthe\sestimated\scost\sof\seach\stable\soption\swhile\splanning\sthe\sjoin\sorder. -D 2013-01-15T18:49:07.627 +C Improvements\sto\squery\splanning\sfor\sjoins:\s\sAvoid\sunnecessary\scalls\sto\n"optimal\sscan"\schecks\sin\scases\swhere\stable\sreordering\sis\snot\spossible.\nMake\ssure\soptimal\sscan\schecks\sare\scarried\sout\sfor\sCROSS\sJOINs\sand\sLEFT\nJOINs. +D 2013-01-16T00:46:09.175 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c b2a827f2b3fa23a3245a4e6093827e359c1e8054 +F src/where.c d48a57d8afd97c51f1b772ebd72431a43a0e48b3 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 04507c176330a06b09dcafa35ec0ca7498f5ace7 -R f5ddb099282326d8029eed3fa99d47e6 +P ac4e119a87497f2e422ff1cb711112ed8594bfa9 +R 604db48c0336d28f8c2561951db4000b U drh -Z f7bf9c2b2fa73cf7872c5f7a932db154 +Z 14d78037173bf002814299854e4b798b diff --git a/manifest.uuid b/manifest.uuid index a55b102705..536565f198 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac4e119a87497f2e422ff1cb711112ed8594bfa9 \ No newline at end of file +d5ebb7877885839e93eee3b322624d4c4215c1c4 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 84d79c811d..ba39fe9a5d 100644 --- a/src/where.c +++ b/src/where.c @@ -5072,6 +5072,7 @@ WhereInfo *sqlite3WhereBegin( int bestJ = -1; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ int isOptimal; /* Iterator for optimal/non-optimal search */ + int ckOptimal; /* Do the optimal scan check */ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ @@ -5122,17 +5123,41 @@ WhereInfo *sqlite3WhereBegin( */ nUnconstrained = 0; notIndexed = 0; - for(isOptimal=(iFrom=0 && bestJ<0; isOptimal--){ + + /* The optimal scan check only occurs if there are two or more tables + ** available to be reordered */ + if( iFrom==nTabList-1 ){ + ckOptimal = 0; /* Common case of just one table in the FROM clause */ + }else{ + ckOptimal = -1; for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jjointype & (JT_LEFT|JT_CROSS))!=0; - if( j!=iFrom && doNotReorder ) break; m = getMask(pMaskSet, sWBI.pSrc->iCursor); if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } + if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break; + if( ++ckOptimal ) break; + if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; + } + } + assert( ckOptimal==0 || ckOptimal==1 ); + + for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){ + for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jiFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + /* This break and one like it in the ckOptimal computation loop + ** above prevent table reordering across LEFT and CROSS JOINs. + ** The LEFT JOIN case is necessary for correctness. The prohibition + ** against reordering across a CROSS JOIN is an SQLite feature that + ** allows the developer to control table reordering */ + break; + } + m = getMask(pMaskSet, sWBI.pSrc->iCursor); + if( (m & sWBI.notValid)==0 ){ + assert( j>iFrom ); + continue; + } sWBI.notReady = (isOptimal ? m : sWBI.notValid); if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; @@ -5161,7 +5186,7 @@ WhereInfo *sqlite3WhereBegin( } if( isOptimal ){ pWInfo->a[j].rOptCost = sWBI.cost.rCost; - }else if( iFromjointype & JT_LEFT)!=0 ) break; } } assert( bestJ>=0 ); assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); + assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 ); + testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); + testcase( bestJ>iFrom && bestJa[bestJ+1].jointype & JT_LEFT)!=0 ); WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", bestJ, pTabList->a[bestJ].pTab->zName, From 7a5bcc0f08d1b8b45adb9870c31e4c1b68c644bd Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Jan 2013 17:08:58 +0000 Subject: [PATCH 06/17] Enhance the query planner to exploit transitivity of join constraints in a multi-way join. FossilOrigin-Name: 13171eb5dc19733276fbfd5515d75b70a9f5f5d7 --- manifest | 17 +++-- manifest.uuid | 2 +- src/sqliteInt.h | 5 ++ src/where.c | 189 +++++++++++++++++++++++++++++++----------------- 4 files changed, 140 insertions(+), 73 deletions(-) diff --git a/manifest b/manifest index a878fe5539..63208c395f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\squery\splanning\sfor\sjoins:\s\sAvoid\sunnecessary\scalls\sto\n"optimal\sscan"\schecks\sin\scases\swhere\stable\sreordering\sis\snot\spossible.\nMake\ssure\soptimal\sscan\schecks\sare\scarried\sout\sfor\sCROSS\sJOINs\sand\sLEFT\nJOINs. -D 2013-01-16T00:46:09.175 +C Enhance\sthe\squery\splanner\sto\sexploit\stransitivity\sof\sjoin\sconstraints\sin\na\smulti-way\sjoin. +D 2013-01-16T17:08:58.150 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,7 +179,7 @@ F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843 F src/sqlite.h.in 39cc33bb08897c748fe3383c29ccf56585704177 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 -F src/sqliteInt.h e998703742455b2241731424c6ec142fd8d0258f +F src/sqliteInt.h a6b3f816df7abd24bbb62b13867b47c2255b11a4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c d48a57d8afd97c51f1b772ebd72431a43a0e48b3 +F src/where.c eb1e1dfc17ff26ba9dc35d6df097e0ecc41d9880 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1033,7 +1033,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ac4e119a87497f2e422ff1cb711112ed8594bfa9 -R 604db48c0336d28f8c2561951db4000b +P d5ebb7877885839e93eee3b322624d4c4215c1c4 +R 3bb8dbee120cecd828508038284032c9 +T *branch * transitive-constraints +T *sym-transitive-constraints * +T -sym-trunk * U drh -Z 14d78037173bf002814299854e4b798b +Z 258dff7809c25174ed1f5fdd919be15b diff --git a/manifest.uuid b/manifest.uuid index 536565f198..7571bed4cb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5ebb7877885839e93eee3b322624d4c4215c1c4 \ No newline at end of file +13171eb5dc19733276fbfd5515d75b70a9f5f5d7 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 74fa0b31ca..d5cb69732f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -575,6 +575,11 @@ struct BusyHandler { */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) +/* +** Determine if the argument is a power of two +*/ +#define IsPowerOfTwo(X) (((X)&((X)-1))==0) + /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the diff --git a/src/where.c b/src/where.c index ba39fe9a5d..873aaaf18b 100644 --- a/src/where.c +++ b/src/where.c @@ -98,8 +98,8 @@ struct WhereTerm { int leftCursor; /* Cursor number of X in "X " */ union { int leftColumn; /* Column number of X in "X " */ - WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */ - WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */ + WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ + WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; u16 eOperator; /* A WO_xx value describing */ u8 wtFlags; /* TERM_xxx bit flags. See below */ @@ -227,6 +227,7 @@ struct WhereCost { #define WO_ISNULL 0x080 #define WO_OR 0x100 /* Two or more OR-connected terms */ #define WO_AND 0x200 /* Two or more AND-connected terms */ +#define WO_EQUIV 0x400 /* Of the form A==B, both columns */ #define WO_NOOP 0x800 /* This term does not restrict search space */ #define WO_ALL 0xfff /* Mask of all possible WO_* values */ @@ -639,44 +640,76 @@ static WhereTerm *findTerm( Index *pIdx /* Must be compatible with this index, if not NULL */ ){ WhereTerm *pTerm; - int k; + WhereTerm *pResult = 0; + WhereClause *pWCOrig = pWC; + int j, k; + int aEquiv[8]; + int nEquiv = 2; + int iEquiv = 2; + Expr *pX; + Parse *pParse; + assert( iCur>=0 ); - op &= WO_ALL; - for(; pWC; pWC=pWC->pOuter){ - for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ - if( pTerm->leftCursor==iCur - && (pTerm->prereqRight & notReady)==0 - && pTerm->u.leftColumn==iColumn - && (pTerm->eOperator & op)!=0 - ){ - if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){ - Expr *pX = pTerm->pExpr; - CollSeq *pColl; - char idxaff; - int j; - Parse *pParse = pWC->pParse; - - idxaff = pIdx->pTable->aCol[iColumn].affinity; - if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; - - /* Figure out the collation sequence required from an index for - ** it to be useful for optimising expression pX. Store this - ** value in variable pColl. - */ - assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); - if( pColl==0 ) pColl = pParse->db->pDfltColl; - - for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ - if( NEVER(j>=pIdx->nColumn) ) return 0; + aEquiv[0] = iCur; + aEquiv[1] = iColumn; + for(;;){ + for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){ + for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ + if( pTerm->leftCursor==iCur + && pTerm->u.leftColumn==iColumn + && (pTerm->eOperator & op & WO_ALL)!=0 + ){ + if( (pTerm->prereqRight & notReady)==0 ){ + if( iColumn>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ + CollSeq *pColl; + char idxaff; + + pX = pTerm->pExpr; + pParse = pWC->pParse; + idxaff = pIdx->pTable->aCol[iColumn].affinity; + if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; + + /* Figure out the collation sequence required from an index for + ** it to be useful for optimising expression pX. Store this + ** value in variable pColl. + */ + assert(pX->pLeft); + pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight); + if( pColl==0 ) pColl = pParse->db->pDfltColl; + + for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + if( NEVER(j>=pIdx->nColumn) ) return 0; + } + if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; + } + pResult = pTerm; + if( pTerm->prereqRight==0 ) goto findTerm_success; + } + if( (op&WO_EQ)!=0 + && (pTerm->eOperator & WO_EQUIV)!=0 + && nEquivpExpr->pRight); + assert( pX->op==TK_COLUMN ); + for(j=0; jiTable && aEquiv[j+1]==pX->iColumn ) break; + } + if( j==nEquiv ){ + aEquiv[j] = pX->iTable; + aEquiv[j+1] = pX->iColumn; + nEquiv += 2; + } } - if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; } - return pTerm; } } + if( iEquiv>=nEquiv ) break; + iCur = aEquiv[iEquiv++]; + iColumn = aEquiv[iEquiv++]; + op &= WO_EQ; } - return 0; +findTerm_success: + return pResult; } /* Forward reference */ @@ -993,7 +1026,7 @@ static void exprAnalyzeOrTerm( b |= getMask(pMaskSet, pOther->leftCursor); } indexable &= b; - if( pOrTerm->eOperator!=WO_EQ ){ + if( (pOrTerm->eOperator & WO_EQ)==0 ){ chngToIN = 0; }else{ chngToIN &= b; @@ -1044,7 +1077,7 @@ static void exprAnalyzeOrTerm( for(j=0; j<2 && !okToChngToIN; j++){ pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ - assert( pOrTerm->eOperator==WO_EQ ); + assert( pOrTerm->eOperator & WO_EQ ); pOrTerm->wtFlags &= ~TERM_OR_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and @@ -1070,7 +1103,7 @@ static void exprAnalyzeOrTerm( /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); - assert( (chngToIN&(chngToIN-1))==0 ); + assert( IsPowerOfTwo(chngToIN) ); assert( chngToIN==getMask(pMaskSet, iCursor) ); break; } @@ -1080,7 +1113,7 @@ static void exprAnalyzeOrTerm( ** table and column is common to every term in the OR clause */ okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ - assert( pOrTerm->eOperator==WO_EQ ); + assert( pOrTerm->eOperator & WO_EQ ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.leftColumn!=iColumn ){ @@ -1116,7 +1149,7 @@ static void exprAnalyzeOrTerm( for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; - assert( pOrTerm->eOperator==WO_EQ ); + assert( pOrTerm->eOperator & WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); @@ -1146,6 +1179,27 @@ static void exprAnalyzeOrTerm( } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ +/* +** Check to see if pExpr is an expression of the form A==B where both +** A and B are columns with the same affinity and collating sequence. +** If A and B are equivalent, return true. +*/ +static int isEquivalenceExpr(Parse *pParse, Expr *pExpr){ + const CollSeq *pCLeft, *pCRight; + if( pExpr->op!=TK_EQ ) return 0; + if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; + assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_COLUMN ); + assert( sqlite3ExprSkipCollate(pExpr->pLeft)->op==TK_COLUMN ); + if( sqlite3ExprAffinity(pExpr->pLeft)!=sqlite3ExprAffinity(pExpr->pRight) ){ + return 0; + } + pCLeft = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + if( pCLeft ){ + pCRight = sqlite3ExprCollSeq(pParse, pExpr->pRight); + if( pCRight && pCRight!=pCLeft ) return 0; + } + return 1; +} /* ** The input to this routine is an WhereTerm structure with only the @@ -1226,6 +1280,7 @@ static void exprAnalyze( if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; Expr *pDup; + u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); @@ -1240,6 +1295,10 @@ static void exprAnalyze( pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; + if( isEquivalenceExpr(pParse, pExpr) ){ + pTerm->eOperator |= WO_EQUIV; + eExtraOp = WO_EQUIV; + } }else{ pDup = pExpr; pNew = pTerm; @@ -1251,7 +1310,7 @@ static void exprAnalyze( testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; - pNew->eOperator = operatorMask(pDup->op); + pNew->eOperator = operatorMask(pDup->op) + eExtraOp; } } @@ -1710,7 +1769,7 @@ static void bestOrClauseIndex(WhereBestIdx *p){ /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTermeOperator==WO_OR + if( (pTerm->eOperator & WO_OR)!=0 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 ){ @@ -1731,7 +1790,7 @@ static void bestOrClauseIndex(WhereBestIdx *p){ WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", (pOrTerm - pOrWC->a), (pTerm - pWC->a) )); - if( pOrTerm->eOperator==WO_AND ){ + if( (pOrTerm->eOperator& WO_AND)!=0 ){ sBOI.pWC = &pOrTerm->u.pAndInfo->wc; bestIndex(&sBOI); }else if( pOrTerm->leftCursor==iCur ){ @@ -1792,7 +1851,7 @@ static int termCanDriveIndex( ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; - if( pTerm->eOperator!=WO_EQ ) return 0; + if( (pTerm->eOperator & WO_EQ)==0 ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; @@ -2054,9 +2113,9 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){ ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; - assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); - testcase( pTerm->eOperator==WO_IN ); - testcase( pTerm->eOperator==WO_ISNULL ); + assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); + testcase( pTerm->eOperator & WO_IN ); + testcase( pTerm->eOperator & WO_ISNULL ); if( pTerm->eOperator & (WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; nTerm++; @@ -2107,14 +2166,14 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){ for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ u8 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; - assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); - testcase( pTerm->eOperator==WO_IN ); - testcase( pTerm->eOperator==WO_ISNULL ); + assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); + testcase( pTerm->eOperator & WO_IN ); + testcase( pTerm->eOperator & WO_ISNULL ); if( pTerm->eOperator & (WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator; + op = (u8)pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; pIdxCons[j].op = op; /* The direct assignment in the previous line is possible only because @@ -2284,7 +2343,7 @@ static void bestVirtualIndex(WhereBestIdx *p){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; if( (pTerm->prereqRight&p->notReady)==0 - && (bAllowIN || pTerm->eOperator!=WO_IN) + && (bAllowIN || (pTerm->eOperator & WO_IN)==0) ){ pIdxCons->usable = 1; }else{ @@ -2316,7 +2375,7 @@ static void bestVirtualIndex(WhereBestIdx *p){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; p->cost.used |= pTerm->prereqRight; - if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){ + if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){ /* Do not attempt to use an IN constraint if the virtual table ** says that the equivalent EQ constraint cannot be safely omitted. ** If we do attempt to use such a constraint, some rows might be @@ -2622,24 +2681,24 @@ static int whereRangeScanEst( if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); - assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE ); + assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK ){ iLower = a[0]; - if( pLower->eOperator==WO_GT ) iLower += a[1]; + if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1]; } sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); - assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE ); + assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK ){ iUpper = a[0]; - if( pUpper->eOperator==WO_LE ) iUpper += a[1]; + if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1]; } sqlite3ValueFree(pRangeVal); } @@ -2947,12 +3006,12 @@ static int isSortingIndex( WO_EQ|WO_ISNULL|WO_IN, pIdx); if( pConstraint==0 ){ isEq = 0; - }else if( pConstraint->eOperator==WO_IN ){ + }else if( (pConstraint->eOperator & WO_IN)!=0 ){ /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY ** because we do not know in what order the values on the RHS of the IN ** operator will occur. */ break; - }else if( pConstraint->eOperator==WO_ISNULL ){ + }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){ uniqueNotNull = 0; isEq = 1; /* "X IS NULL" means X has only a single value */ }else if( pConstraint->prereqRight==0 ){ @@ -3365,12 +3424,13 @@ static void bestBtreeIndex(WhereBestIdx *p){ && pFirstTerm!=0 && aiRowEst[1]>1 ){ assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ - testcase( pFirstTerm->eOperator==WO_EQ ); - testcase( pFirstTerm->eOperator==WO_ISNULL ); + testcase( pFirstTerm->eOperator & WO_EQ ); + testcase( pFirstTerm->eOperator & WO_EQUIV ); + testcase( pFirstTerm->eOperator & WO_ISNULL ); whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &pc.plan.nRow); }else if( bInEst==0 ){ - assert( pFirstTerm->eOperator==WO_IN ); + assert( pFirstTerm->eOperator & WO_IN ); whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &pc.plan.nRow); } @@ -3517,7 +3577,7 @@ static void bestBtreeIndex(WhereBestIdx *p){ ** selective in practice, on average. */ pc.plan.nRow /= 3; } - }else if( pTerm->eOperator!=WO_NOOP ){ + }else if( (pTerm->eOperator & WO_NOOP)==0 ){ /* Any other expression lowers the output row count by half */ pc.plan.nRow /= 2; } @@ -4153,7 +4213,6 @@ static Bitmask codeOneLoopStart( pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); - assert( pTerm->leftCursor==iCur ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg); @@ -4544,7 +4603,7 @@ static Bitmask codeOneLoopStart( pTerm = pLevel->plan.u.pTerm; assert( pTerm!=0 ); - assert( pTerm->eOperator==WO_OR ); + assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pLevel->op = OP_Return; @@ -4617,7 +4676,7 @@ static Bitmask codeOneLoopStart( for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; - if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ + if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; if( pAndExpr ){ From 7fe18b41052f11f68d21672f2ec65db0a1f761cf Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Jan 2013 20:33:02 +0000 Subject: [PATCH 07/17] Fix the activate_extensions pragma so that it is a no-op when the required argument is omitted. FossilOrigin-Name: 6195ebd83323eaad92a0aa095cce1094bf8e2ba6 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pragma.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index a878fe5539..45d665a461 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\squery\splanning\sfor\sjoins:\s\sAvoid\sunnecessary\scalls\sto\n"optimal\sscan"\schecks\sin\scases\swhere\stable\sreordering\sis\snot\spossible.\nMake\ssure\soptimal\sscan\schecks\sare\scarried\sout\sfor\sCROSS\sJOINs\sand\sLEFT\nJOINs. -D 2013-01-16T00:46:09.175 +C Fix\sthe\sactivate_extensions\spragma\sso\sthat\sit\sis\sa\sno-op\swhen\sthe\srequired\nargument\sis\somitted. +D 2013-01-16T20:33:02.794 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -168,7 +168,7 @@ F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 -F src/pragma.c 8907c559d3127729d3bcedb1fe5c59fc196d3a17 +F src/pragma.c b7ef175454106000fae966b3948b19e807bffc89 F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ac4e119a87497f2e422ff1cb711112ed8594bfa9 -R 604db48c0336d28f8c2561951db4000b +P d5ebb7877885839e93eee3b322624d4c4215c1c4 +R 7e1018eedcfc760a5a5a61f3eb36bf10 U drh -Z 14d78037173bf002814299854e4b798b +Z cc9e1bb14175b94a3737a5872056637d diff --git a/manifest.uuid b/manifest.uuid index 536565f198..bcd1128fbe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5ebb7877885839e93eee3b322624d4c4215c1c4 \ No newline at end of file +6195ebd83323eaad92a0aa095cce1094bf8e2ba6 \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 7e8b59b8e4..7d116d5bbc 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1733,7 +1733,7 @@ void sqlite3Pragma( }else #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){ + if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){ #ifdef SQLITE_HAS_CODEC if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ sqlite3_activate_see(&zRight[4]); From 58eb1c0af1e6d2494d1851bc508aaca470bdac34 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Jan 2013 00:08:42 +0000 Subject: [PATCH 08/17] Improved comments explaining the operation of the findTerm() utility routine in where.c. Increase the maximum number of levels of transitivity from 4 to 11. FossilOrigin-Name: fe152f8b048c9a18f99fa6096ff0e68dd630c318 --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/where.c | 44 +++++++++++++++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 63208c395f..bf95c9a433 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\squery\splanner\sto\sexploit\stransitivity\sof\sjoin\sconstraints\sin\na\smulti-way\sjoin. -D 2013-01-16T17:08:58.150 +C Improved\scomments\sexplaining\sthe\soperation\sof\sthe\sfindTerm()\sutility\sroutine\nin\swhere.c.\s\sIncrease\sthe\smaximum\snumber\sof\slevels\sof\stransitivity\sfrom\s4\nto\s11. +D 2013-01-17T00:08:42.232 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c eb1e1dfc17ff26ba9dc35d6df097e0ecc41d9880 +F src/where.c 24d74ec54a71e01e0672e0838f7dd5757fb6324d F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1033,10 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d5ebb7877885839e93eee3b322624d4c4215c1c4 -R 3bb8dbee120cecd828508038284032c9 -T *branch * transitive-constraints -T *sym-transitive-constraints * -T -sym-trunk * +P 13171eb5dc19733276fbfd5515d75b70a9f5f5d7 +R 47b8015795abaf8b9e9739389b1b5d3d U drh -Z 258dff7809c25174ed1f5fdd919be15b +Z c72ed7f67d993d6d7e18306e36936017 diff --git a/manifest.uuid b/manifest.uuid index 7571bed4cb..725783fc54 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -13171eb5dc19733276fbfd5515d75b70a9f5f5d7 \ No newline at end of file +fe152f8b048c9a18f99fa6096ff0e68dd630c318 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 873aaaf18b..6635d8eaee 100644 --- a/src/where.c +++ b/src/where.c @@ -630,6 +630,24 @@ static u16 operatorMask(int op){ ** where X is a reference to the iColumn of table iCur and is one of ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. +** +** The term returned might by Y= if there is another constraint in +** the WHERE clause that specifies that X=Y. Any such constraints will be +** identified by the WO_EQUIV bit in the pTerm->eOperator field. The +** aEquiv[] array holds X and all its equivalents, with each SQL variable +** taking up two slots in aEquiv[]. The first slot is for the cursor number +** and the second is for the column number. There are 22 slots in aEquiv[] +** so that means we can look for X plus up to 10 other equivalent values. +** Hence a search for X will return if X=A1 and A1=A2 and A2=A3 +** and ... and A9=A10 and A10=. +** +** If there are multiple terms in the WHERE clause of the form "X " +** then try for the one with no dependencies on - in other words where +** is a constant expression of some kind. Only return entries of +** the form "X Y" where Y is a column in another table if no terms of +** the form "X " exist. Other than this priority, if there +** are two or more terms that match, then the choice of which term to return +** is arbitrary. */ static WhereTerm *findTerm( WhereClause *pWC, /* The WHERE clause to be searched */ @@ -639,15 +657,15 @@ static WhereTerm *findTerm( u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ - WhereTerm *pTerm; - WhereTerm *pResult = 0; - WhereClause *pWCOrig = pWC; - int j, k; - int aEquiv[8]; - int nEquiv = 2; - int iEquiv = 2; - Expr *pX; - Parse *pParse; + WhereTerm *pTerm; /* Term being examined as possible result */ + WhereTerm *pResult = 0; /* The answer to return */ + WhereClause *pWCOrig = pWC; /* Original pWC value */ + int j, k; /* Loop counters */ + Expr *pX; /* Pointer to an expression */ + Parse *pParse; /* Parsing context */ + int nEquiv = 2; /* Number of entires in aEquiv[] */ + int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */ + int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */ assert( iCur>=0 ); aEquiv[0] = iCur; @@ -1187,7 +1205,9 @@ static void exprAnalyzeOrTerm( static int isEquivalenceExpr(Parse *pParse, Expr *pExpr){ const CollSeq *pCLeft, *pCRight; if( pExpr->op!=TK_EQ ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + return 0; + } assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_COLUMN ); assert( sqlite3ExprSkipCollate(pExpr->pLeft)->op==TK_COLUMN ); if( sqlite3ExprAffinity(pExpr->pLeft)!=sqlite3ExprAffinity(pExpr->pRight) ){ @@ -1196,7 +1216,9 @@ static int isEquivalenceExpr(Parse *pParse, Expr *pExpr){ pCLeft = sqlite3ExprCollSeq(pParse, pExpr->pLeft); if( pCLeft ){ pCRight = sqlite3ExprCollSeq(pParse, pExpr->pRight); - if( pCRight && pCRight!=pCLeft ) return 0; + if( pCRight && pCRight!=pCLeft ){ + return 0; + } } return 1; } From 413c63ba81122f7bb67cf05115c5534f9cb4b5a0 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 17 Jan 2013 03:18:14 +0000 Subject: [PATCH 09/17] Make the 'fs' virtual table module portable to Windows. FossilOrigin-Name: dd473cae5b6ea02b73168b30365f0af5556ee24d --- Makefile.msc | 1 + manifest | 19 +++++++++++-------- manifest.uuid | 2 +- src/test_fs.c | 8 +++++++- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Makefile.msc b/Makefile.msc index 631e9edcbf..2fb9687655 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -678,6 +678,7 @@ TESTSRC = \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ $(TOP)\src\test_devsym.c \ + $(TOP)\src\test_fs.c \ $(TOP)\src\test_func.c \ $(TOP)\src\test_fuzzer.c \ $(TOP)\src\test_hexio.c \ diff --git a/manifest b/manifest index 45d665a461..6aa81d2aeb 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Fix\sthe\sactivate_extensions\spragma\sso\sthat\sit\sis\sa\sno-op\swhen\sthe\srequired\nargument\sis\somitted. -D 2013-01-16T20:33:02.794 +C Make\sthe\s'fs'\svirtual\stable\smodule\sportable\sto\sWindows. +D 2013-01-17T03:18:14.519 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 2b8371775ea8df029d1acf0c3d4c3782d3bd5711 +F Makefile.msc 1bed3bca025ee90441bb0c9f95f36f42b70bd839 F Makefile.vxworks b18ad88e9a8c6a001f5cf4a389116a4f1a7ab45f F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F VERSION 6d4f66eaebabc42ef8c2a4d2d0caf4ce7ee81137 @@ -200,7 +200,7 @@ F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16 F src/test_config.c 09781397ccc24268cb895be0d4c21b4aad651486 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc -F src/test_fs.c 7d3337933e92c198d06dd600375cc39259cc66b3 +F src/test_fs.c 1c51e203b2c20235d8c3739f8c1fb13a7502915b F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170 F src/test_fuzzer.c 1d26aa965120420bc14807da29d4d4541bfa6148 F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd @@ -1033,7 +1033,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d5ebb7877885839e93eee3b322624d4c4215c1c4 -R 7e1018eedcfc760a5a5a61f3eb36bf10 -U drh -Z cc9e1bb14175b94a3737a5872056637d +P 6195ebd83323eaad92a0aa095cce1094bf8e2ba6 +R 391d1ca86287065efd5d1c0418e3ba47 +T *branch * fsVfsWin +T *sym-fsVfsWin * +T -sym-trunk * +U mistachkin +Z 13b4bb0aa5332689b2ba5723b1c52e70 diff --git a/manifest.uuid b/manifest.uuid index bcd1128fbe..0134790b17 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6195ebd83323eaad92a0aa095cce1094bf8e2ba6 \ No newline at end of file +dd473cae5b6ea02b73168b30365f0af5556ee24d \ No newline at end of file diff --git a/src/test_fs.c b/src/test_fs.c index 9678005c8d..532f92528b 100644 --- a/src/test_fs.c +++ b/src/test_fs.c @@ -37,9 +37,15 @@ #include #include #include -#include #include +#if SQLITE_OS_UNIX +# include +#endif +#if SQLITE_OS_WIN +# include +#endif + #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct fs_vtab fs_vtab; From 806c00666fd0233a511b2e0d9a1c19ce4ed2b76b Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 17 Jan 2013 03:18:38 +0000 Subject: [PATCH 10/17] Enhance RTree virtual table creation error messages that involve the getNodeSize() function. FossilOrigin-Name: 652233d646236d3fbca629813b20d075f00f3ed6 --- ext/rtree/rtree.c | 10 ++++++++-- manifest | 18 +++++++++--------- manifest.uuid | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 731cb32be0..34dde0e968 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3049,7 +3049,8 @@ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){ static int getNodeSize( sqlite3 *db, /* Database handle */ Rtree *pRtree, /* Rtree handle */ - int isCreate /* True for xCreate, false for xConnect */ + int isCreate, /* True for xCreate, false for xConnect */ + char **pzErr /* OUT: Error message, if any */ ){ int rc; char *zSql; @@ -3062,6 +3063,8 @@ static int getNodeSize( if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; } + }else{ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } }else{ zSql = sqlite3_mprintf( @@ -3069,6 +3072,9 @@ static int getNodeSize( pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); + if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } } sqlite3_free(zSql); @@ -3132,7 +3138,7 @@ static int rtreeInit( memcpy(pRtree->zName, argv[2], nName); /* Figure out the node size to use. */ - rc = getNodeSize(db, pRtree, isCreate); + rc = getNodeSize(db, pRtree, isCreate, pzErr); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure diff --git a/manifest b/manifest index 6aa81d2aeb..737bcbe3e6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sthe\s'fs'\svirtual\stable\smodule\sportable\sto\sWindows. -D 2013-01-17T03:18:14.519 +C Enhance\sRTree\svirtual\stable\screation\serror\smessages\sthat\sinvolve\sthe\sgetNodeSize()\sfunction. +D 2013-01-17T03:18:38.278 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -83,7 +83,7 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 47064ee2995a396bfb626337d2b43f12cc0af687 +F ext/rtree/rtree.c ebd07d0f06dc167f1424ff3940a5711a3a039982 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -1033,10 +1033,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 6195ebd83323eaad92a0aa095cce1094bf8e2ba6 -R 391d1ca86287065efd5d1c0418e3ba47 -T *branch * fsVfsWin -T *sym-fsVfsWin * -T -sym-trunk * +P dd473cae5b6ea02b73168b30365f0af5556ee24d +R 6de5433403d98c9088f8c6d2808c6cc6 +T *branch * rtreeErrMsg +T *sym-rtreeErrMsg * +T -sym-fsVfsWin * U mistachkin -Z 13b4bb0aa5332689b2ba5723b1c52e70 +Z f672a1a0e379d040e98c12d6bd28ded3 diff --git a/manifest.uuid b/manifest.uuid index 0134790b17..f95e78f4dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd473cae5b6ea02b73168b30365f0af5556ee24d \ No newline at end of file +652233d646236d3fbca629813b20d075f00f3ed6 \ No newline at end of file From 738fc79dcf388487b8e3c448827a3457db2d6a1a Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Jan 2013 15:05:17 +0000 Subject: [PATCH 11/17] Make more aggressive use of transitivity in optimizing queries. Add a test case. FossilOrigin-Name: d96762841a461e192fb2f317d684d000376350dd --- manifest | 14 ++--- manifest.uuid | 2 +- src/where.c | 24 ++++----- test/autoindex1.test | 124 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index bf95c9a433..fb4188f095 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomments\sexplaining\sthe\soperation\sof\sthe\sfindTerm()\sutility\sroutine\nin\swhere.c.\s\sIncrease\sthe\smaximum\snumber\sof\slevels\sof\stransitivity\sfrom\s4\nto\s11. -D 2013-01-17T00:08:42.232 +C Make\smore\saggressive\suse\sof\stransitivity\sin\soptimizing\squeries.\s\sAdd\sa\stest\ncase. +D 2013-01-17T15:05:17.153 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 24d74ec54a71e01e0672e0838f7dd5757fb6324d +F src/where.c 701c32fecbcf44d749a8fdacb887ffdcec21a3e5 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -285,7 +285,7 @@ F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf -F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991 +F test/autoindex1.test f88146c4c889ea0afbb620e49d83b5fbf5ee4d06 F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 @@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 13171eb5dc19733276fbfd5515d75b70a9f5f5d7 -R 47b8015795abaf8b9e9739389b1b5d3d +P fe152f8b048c9a18f99fa6096ff0e68dd630c318 +R f7b812e14ccd12b59aae7b48f0da1945 U drh -Z c72ed7f67d993d6d7e18306e36936017 +Z eaf427dd060ebdbe2c55df9e5c68a5b1 diff --git a/manifest.uuid b/manifest.uuid index 725783fc54..c667be658b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fe152f8b048c9a18f99fa6096ff0e68dd630c318 \ No newline at end of file +d96762841a461e192fb2f317d684d000376350dd \ No newline at end of file diff --git a/src/where.c b/src/where.c index 6635d8eaee..ca59370352 100644 --- a/src/where.c +++ b/src/where.c @@ -663,6 +663,7 @@ static WhereTerm *findTerm( int j, k; /* Loop counters */ Expr *pX; /* Pointer to an expression */ Parse *pParse; /* Parsing context */ + int iOrigCol = iColumn; /* Original value of iColumn */ int nEquiv = 2; /* Number of entires in aEquiv[] */ int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */ int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */ @@ -675,16 +676,17 @@ static WhereTerm *findTerm( for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn - && (pTerm->eOperator & op & WO_ALL)!=0 ){ - if( (pTerm->prereqRight & notReady)==0 ){ - if( iColumn>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ + if( (pTerm->prereqRight & notReady)==0 + && (pTerm->eOperator & op & WO_ALL)!=0 + ){ + if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ CollSeq *pColl; char idxaff; pX = pTerm->pExpr; pParse = pWC->pParse; - idxaff = pIdx->pTable->aCol[iColumn].affinity; + idxaff = pIdx->pTable->aCol[iOrigCol].affinity; if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; /* Figure out the collation sequence required from an index for @@ -695,7 +697,7 @@ static WhereTerm *findTerm( pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight); if( pColl==0 ) pColl = pParse->db->pDfltColl; - for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; @@ -703,8 +705,7 @@ static WhereTerm *findTerm( pResult = pTerm; if( pTerm->prereqRight==0 ) goto findTerm_success; } - if( (op&WO_EQ)!=0 - && (pTerm->eOperator & WO_EQUIV)!=0 + if( (pTerm->eOperator & WO_EQUIV)!=0 && nEquivpExpr->pRight); @@ -724,7 +725,6 @@ static WhereTerm *findTerm( if( iEquiv>=nEquiv ) break; iCur = aEquiv[iEquiv++]; iColumn = aEquiv[iEquiv++]; - op &= WO_EQ; } findTerm_success: return pResult; @@ -1005,7 +1005,6 @@ static void exprAnalyzeOrTerm( for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ WhereAndInfo *pAndInfo; - assert( pOrTerm->eOperator==0 ); assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); chngToIN = 0; pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); @@ -1291,13 +1290,14 @@ static void exprAnalyze( pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; - if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){ + if( allowedOp(op) ){ Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); + u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( pLeft->op==TK_COLUMN ){ pTerm->leftCursor = pLeft->iTable; pTerm->u.leftColumn = pLeft->iColumn; - pTerm->eOperator = operatorMask(op); + pTerm->eOperator = operatorMask(op) & opMask; } if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; @@ -1332,7 +1332,7 @@ static void exprAnalyze( testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; - pNew->eOperator = operatorMask(pDup->op) + eExtraOp; + pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; } } diff --git a/test/autoindex1.test b/test/autoindex1.test index 6c8d54d125..54ff82a2b0 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -257,5 +257,129 @@ do_execsql_test autoindex1-700 { 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } +# The following checks a performance issue reported on the sqlite-dev +# mailing list on 2013-01-10 +# +do_execsql_test autoindex1-800 { + CREATE TABLE accounts( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + account_name TEXT, + account_type TEXT, + data_set TEXT + ); + CREATE TABLE data( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + package_id INTEGER REFERENCES package(_id), + mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL, + raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL, + is_read_only INTEGER NOT NULL DEFAULT 0, + is_primary INTEGER NOT NULL DEFAULT 0, + is_super_primary INTEGER NOT NULL DEFAULT 0, + data_version INTEGER NOT NULL DEFAULT 0, + data1 TEXT, + data2 TEXT, + data3 TEXT, + data4 TEXT, + data5 TEXT, + data6 TEXT, + data7 TEXT, + data8 TEXT, + data9 TEXT, + data10 TEXT, + data11 TEXT, + data12 TEXT, + data13 TEXT, + data14 TEXT, + data15 TEXT, + data_sync1 TEXT, + data_sync2 TEXT, + data_sync3 TEXT, + data_sync4 TEXT + ); + CREATE TABLE mimetypes( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + mimetype TEXT NOT NULL + ); + CREATE TABLE raw_contacts( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + account_id INTEGER REFERENCES accounts(_id), + sourceid TEXT, + raw_contact_is_read_only INTEGER NOT NULL DEFAULT 0, + version INTEGER NOT NULL DEFAULT 1, + dirty INTEGER NOT NULL DEFAULT 0, + deleted INTEGER NOT NULL DEFAULT 0, + contact_id INTEGER REFERENCES contacts(_id), + aggregation_mode INTEGER NOT NULL DEFAULT 0, + aggregation_needed INTEGER NOT NULL DEFAULT 1, + custom_ringtone TEXT, + send_to_voicemail INTEGER NOT NULL DEFAULT 0, + times_contacted INTEGER NOT NULL DEFAULT 0, + last_time_contacted INTEGER, + starred INTEGER NOT NULL DEFAULT 0, + display_name TEXT, + display_name_alt TEXT, + display_name_source INTEGER NOT NULL DEFAULT 0, + phonetic_name TEXT, + phonetic_name_style TEXT, + sort_key TEXT, + sort_key_alt TEXT, + name_verified INTEGER NOT NULL DEFAULT 0, + sync1 TEXT, + sync2 TEXT, + sync3 TEXT, + sync4 TEXT, + sync_uid TEXT, + sync_version INTEGER NOT NULL DEFAULT 1, + has_calendar_event INTEGER NOT NULL DEFAULT 0, + modified_time INTEGER, + is_restricted INTEGER DEFAULT 0, + yp_source TEXT, + method_selected INTEGER DEFAULT 0, + custom_vibration_type INTEGER DEFAULT 0, + custom_ringtone_path TEXT, + message_notification TEXT, + message_notification_path TEXT + ); + CREATE INDEX data_mimetype_data1_index ON data (mimetype_id,data1); + CREATE INDEX data_raw_contact_id ON data (raw_contact_id); + CREATE UNIQUE INDEX mime_type ON mimetypes (mimetype); + CREATE INDEX raw_contact_sort_key1_index ON raw_contacts (sort_key); + CREATE INDEX raw_contact_sort_key2_index ON raw_contacts (sort_key_alt); + CREATE INDEX raw_contacts_contact_id_index ON raw_contacts (contact_id); + CREATE INDEX raw_contacts_source_id_account_id_index + ON raw_contacts (sourceid, account_id); + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 + VALUES('raw_contacts','raw_contact_sort_key2_index','1600 4'); + INSERT INTO sqlite_stat1 + VALUES('raw_contacts','raw_contact_sort_key1_index','1600 4'); + INSERT INTO sqlite_stat1 + VALUES('raw_contacts','raw_contacts_source_id_account_id_index', + '1600 1600 1600'); + INSERT INTO sqlite_stat1 + VALUES('raw_contacts','raw_contacts_contact_id_index','1600 1'); + INSERT INTO sqlite_stat1 VALUES('mimetypes','mime_type','12 1'); + INSERT INTO sqlite_stat1 + VALUES('data','data_mimetype_data1_index','9819 2455 3'); + INSERT INTO sqlite_stat1 VALUES('data','data_raw_contact_id','9819 7'); + INSERT INTO sqlite_stat1 VALUES('accounts',NULL,'1'); + DROP TABLE IF EXISTS sqlite_stat3; + ANALYZE sqlite_master; + + EXPLAIN QUERY PLAN + SELECT * FROM + data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) + JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) + JOIN accounts ON (raw_contacts.account_id=accounts._id) + WHERE mimetype_id=10 AND data14 IS NOT NULL; +} {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/} +do_execsql_test autoindex1-801 { + EXPLAIN QUERY PLAN + SELECT * FROM + data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) + JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) + JOIN accounts ON (raw_contacts.account_id=accounts._id) + WHERE mimetypes._id=10 AND data14 IS NOT NULL; +} {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/} finish_test From 63db0392ae67c0e2d7c188bf8fb6f47e43731663 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Jan 2013 16:18:55 +0000 Subject: [PATCH 12/17] Avoid unnecessary collating sequence and affinity restrictions on the use of transitivity. Add test cases to show that the restrictions are not needed. FossilOrigin-Name: 56549f45666b53876012df5c2bdf813474e10925 --- manifest | 13 +++++------ manifest.uuid | 2 +- src/where.c | 36 ++++++------------------------- test/transitive1.test | 50 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 test/transitive1.test diff --git a/manifest b/manifest index fb4188f095..bdde52fc74 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\smore\saggressive\suse\sof\stransitivity\sin\soptimizing\squeries.\s\sAdd\sa\stest\ncase. -D 2013-01-17T15:05:17.153 +C Avoid\sunnecessary\scollating\ssequence\sand\saffinity\srestrictions\son\sthe\suse\nof\stransitivity.\s\sAdd\stest\scases\sto\sshow\sthat\sthe\srestrictions\sare\snot\s\nneeded. +D 2013-01-17T16:18:55.615 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 701c32fecbcf44d749a8fdacb887ffdcec21a3e5 +F src/where.c 79c257691c5cbe92fae9dc35465392cbd11c3e31 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -896,6 +896,7 @@ F test/trace2.test c1dc104a8d11a347c870cfea6235e3fc6f6cb06d F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22 F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 +F test/transitive1.test d04aa9023e425d6f2d4aa61dd81ee9e102f89062 F test/trigger1.test 30f343f91586765874a28ad539c06f5a5f049931 F test/trigger2.test 834187beafd1db383af0c659cfa49b0576832816 F test/trigger3.test d2c60d8be271c355d61727411e753181e877230a @@ -1033,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P fe152f8b048c9a18f99fa6096ff0e68dd630c318 -R f7b812e14ccd12b59aae7b48f0da1945 +P d96762841a461e192fb2f317d684d000376350dd +R da60dbccb0041de3b6506adfaa629abe U drh -Z eaf427dd060ebdbe2c55df9e5c68a5b1 +Z 92f034648a2e7d96254ca815101088e3 diff --git a/manifest.uuid b/manifest.uuid index c667be658b..3d368975e2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d96762841a461e192fb2f317d684d000376350dd \ No newline at end of file +56549f45666b53876012df5c2bdf813474e10925 \ No newline at end of file diff --git a/src/where.c b/src/where.c index ca59370352..46268bf0f7 100644 --- a/src/where.c +++ b/src/where.c @@ -687,7 +687,9 @@ static WhereTerm *findTerm( pX = pTerm->pExpr; pParse = pWC->pParse; idxaff = pIdx->pTable->aCol[iOrigCol].affinity; - if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; + if( !sqlite3IndexAffinityOk(pX, idxaff) ){ + continue; + } /* Figure out the collation sequence required from an index for ** it to be useful for optimising expression pX. Store this @@ -700,7 +702,9 @@ static WhereTerm *findTerm( for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } - if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; + if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ + continue; + } } pResult = pTerm; if( pTerm->prereqRight==0 ) goto findTerm_success; @@ -1196,32 +1200,6 @@ static void exprAnalyzeOrTerm( } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ -/* -** Check to see if pExpr is an expression of the form A==B where both -** A and B are columns with the same affinity and collating sequence. -** If A and B are equivalent, return true. -*/ -static int isEquivalenceExpr(Parse *pParse, Expr *pExpr){ - const CollSeq *pCLeft, *pCRight; - if( pExpr->op!=TK_EQ ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) ){ - return 0; - } - assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_COLUMN ); - assert( sqlite3ExprSkipCollate(pExpr->pLeft)->op==TK_COLUMN ); - if( sqlite3ExprAffinity(pExpr->pLeft)!=sqlite3ExprAffinity(pExpr->pRight) ){ - return 0; - } - pCLeft = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - if( pCLeft ){ - pCRight = sqlite3ExprCollSeq(pParse, pExpr->pRight); - if( pCRight && pCRight!=pCLeft ){ - return 0; - } - } - return 1; -} - /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the @@ -1317,7 +1295,7 @@ static void exprAnalyze( pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; - if( isEquivalenceExpr(pParse, pExpr) ){ + if( pExpr->op==TK_EQ && !ExprHasProperty(pExpr, EP_FromJoin) ){ pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } diff --git a/test/transitive1.test b/test/transitive1.test new file mode 100644 index 0000000000..ff81af6421 --- /dev/null +++ b/test/transitive1.test @@ -0,0 +1,50 @@ +# 2013 April 17 +# +# 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 script is testing of transitive WHERE clause constraints +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test transitive1-100 { + CREATE TABLE t1(a TEXT, b TEXT, c TEXT COLLATE NOCASE); + INSERT INTO t1 VALUES('abc','abc','Abc'); + INSERT INTO t1 VALUES('def','def','def'); + INSERT INTO t1 VALUES('ghi','ghi','GHI'); + CREATE INDEX t1a1 ON t1(a); + CREATE INDEX t1a2 ON t1(a COLLATE nocase); + + SELECT * FROM t1 WHERE a=b AND c=b AND c='DEF'; +} {def def def} +do_execsql_test transitive1-110 { + SELECT * FROM t1 WHERE a=b AND c=b AND c>='DEF' ORDER BY +a; +} {def def def ghi ghi GHI} +do_execsql_test transitive1-120 { + SELECT * FROM t1 WHERE a=b AND c=b AND c<='DEF' ORDER BY +a; +} {abc abc Abc def def def} + +do_execsql_test transitive1-200 { + CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT); + INSERT INTO t2 VALUES(100,100,100); + INSERT INTO t2 VALUES(20,20,20); + INSERT INTO t2 VALUES(3,3,3); + + SELECT * FROM t2 WHERE a=b AND c=b AND c=20; +} {20 20 20} +do_execsql_test transitive1-210 { + SELECT * FROM t2 WHERE a=b AND c=b AND c>=20 ORDER BY +a; +} {3 3 3 20 20 20} +do_execsql_test transitive1-220 { + SELECT * FROM t2 WHERE a=b AND c=b AND c<=20 ORDER BY +a; +} {20 20 20 100 100 100} + +finish_test From eb5bc9261cd47a5883fba0620775d6f96be43c25 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Jan 2013 16:43:33 +0000 Subject: [PATCH 13/17] Add the ability to disable transitive constraints using the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) interface. FossilOrigin-Name: 593d67c8b0908daf7a70b2a310ed85515d384cbf --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 5 ++++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index bdde52fc74..998cf40129 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sunnecessary\scollating\ssequence\sand\saffinity\srestrictions\son\sthe\suse\nof\stransitivity.\s\sAdd\stest\scases\sto\sshow\sthat\sthe\srestrictions\sare\snot\s\nneeded. -D 2013-01-17T16:18:55.615 +C Add\sthe\sability\sto\sdisable\stransitive\sconstraints\susing\sthe\s\nsqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)\sinterface. +D 2013-01-17T16:43:33.274 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,7 +179,7 @@ F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843 F src/sqlite.h.in 39cc33bb08897c748fe3383c29ccf56585704177 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 -F src/sqliteInt.h a6b3f816df7abd24bbb62b13867b47c2255b11a4 +F src/sqliteInt.h fb4109b7a77d985a39bbd04f1fbc49c940d4e410 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 79c257691c5cbe92fae9dc35465392cbd11c3e31 +F src/where.c 374a6c8190f863b3c69780b441d799e8a6b9e21b F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1034,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d96762841a461e192fb2f317d684d000376350dd -R da60dbccb0041de3b6506adfaa629abe +P 56549f45666b53876012df5c2bdf813474e10925 +R b61f05e227461d8fcbb8f5f454dfcd80 U drh -Z 92f034648a2e7d96254ca815101088e3 +Z 910e0211c204296308c40151d2a7d00a diff --git a/manifest.uuid b/manifest.uuid index 3d368975e2..e5381d6ed1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56549f45666b53876012df5c2bdf813474e10925 \ No newline at end of file +593d67c8b0908daf7a70b2a310ed85515d384cbf \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d5cb69732f..a98eb4b3dd 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -978,6 +978,7 @@ struct sqlite3 { #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ +#define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* diff --git a/src/where.c b/src/where.c index 46268bf0f7..f97bf019c9 100644 --- a/src/where.c +++ b/src/where.c @@ -1295,7 +1295,10 @@ static void exprAnalyze( pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; - if( pExpr->op==TK_EQ && !ExprHasProperty(pExpr, EP_FromJoin) ){ + if( pExpr->op==TK_EQ + && !ExprHasProperty(pExpr, EP_FromJoin) + && OptimizationEnabled(db, SQLITE_Transitive) + ){ pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } From b064dc33bc2fb2163a7a77cbfd830734e9f091ae Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Jan 2013 03:35:14 +0000 Subject: [PATCH 14/17] The \xXX escape in the test_regexp.c must be followed by exactly two hex digits. FossilOrigin-Name: 82957495aa0729468a020c2a0a45ed60019b6e07 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/test_regexp.c | 16 ++++++++-------- test/regexp1.test | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index 2204399b0a..40330a02fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\squery\splanner\sto\sexploit\stransitivity\sof\sjoin\sconstraints. -D 2013-01-17T17:20:49.316 +C The\s\\xXX\sescape\sin\sthe\stest_regexp.c\smust\sbe\sfollowed\sby\sexactly\stwo\shex\ndigits. +D 2013-01-18T03:35:14.887 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -218,7 +218,7 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5 F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb -F src/test_regexp.c 935a1bfb48c7a6857514aa9cedf6df048f8b9928 +F src/test_regexp.c b70fbbf4dca5913fe404ddf909dae92a88488d61 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -669,7 +669,7 @@ F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d -F test/regexp1.test bbcb74e1bbdc20a7c0b9b2360deda14c4df1b46a +F test/regexp1.test 5cbb6e7122ca51260d71079cf9245b63b8f64e1a F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce @@ -1034,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P c0b90d75a86b01f7fafec755cbe046c14d725341 593d67c8b0908daf7a70b2a310ed85515d384cbf -R 19cb0000f7ea18bbcd69f74a26ccdcaa +P 38852f158ab20bb4d7b264af987ec1538052bec3 +R 949bb425bbb85c4c863787918f541c43 U drh -Z bcbd2dcec0eed1962ecdbd3953e8a1f1 +Z f3f2e37133d258307d52a0baf870b3d9 diff --git a/manifest.uuid b/manifest.uuid index 9f3bb32f26..82e8a50f87 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -38852f158ab20bb4d7b264af987ec1538052bec3 \ No newline at end of file +82957495aa0729468a020c2a0a45ed60019b6e07 \ No newline at end of file diff --git a/src/test_regexp.c b/src/test_regexp.c index c0361f17d3..600043e9cd 100644 --- a/src/test_regexp.c +++ b/src/test_regexp.c @@ -26,7 +26,7 @@ ** \c Character c where c is one of \{}()[]|*+?. ** \c C-language escapes for c in afnrtv. ex: \t or \n ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX -** \xXXX Where XXX is any number of hex digits, unicode value XXX +** \xXX Where XX is exactly 2 hex digits, unicode value XX ** [abc] Any single character from the set abc ** [^abc] Any single character not in the set abc ** [a-z] Any single character in the range a-z @@ -387,9 +387,8 @@ static unsigned re_esc_char(ReCompiled *p){ char c; if( p->sIn.i>=p->sIn.mx ) return 0; c = p->sIn.z[p->sIn.i]; - if( c=='u' && p->sIn.i+5sIn.mx ){ + if( c=='u' && p->sIn.i+4sIn.mx ){ const unsigned char *zIn = p->sIn.z + p->sIn.i; - v = 0; if( re_hex(zIn[1],&v) && re_hex(zIn[2],&v) && re_hex(zIn[3],&v) @@ -399,11 +398,12 @@ static unsigned re_esc_char(ReCompiled *p){ return v; } } - if( c=='x' ){ - v = 0; - for(i=1; p->sIn.isIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){} - if( i>1 ){ - p->sIn.i += i; + if( c=='x' && p->sIn.i+2sIn.mx ){ + const unsigned char *zIn = p->sIn.z + p->sIn.i; + if( re_hex(zIn[1],&v) + && re_hex(zIn[2],&v) + ){ + p->sIn.i += 3; return v; } } diff --git a/test/regexp1.test b/test/regexp1.test index 52877f7734..b7ec8fdeab 100644 --- a/test/regexp1.test +++ b/test/regexp1.test @@ -197,12 +197,12 @@ do_execsql_test regexp1-2.15 { do_execsql_test regexp1-2.20 { SELECT 'abc$¢€xyz' REGEXP '^abc\u0024\u00a2\u20acxyz$', 'abc$¢€xyz' REGEXP '^abc\u0024\u00A2\u20ACxyz$', - 'abc$¢€xyz' REGEXP '^abc\x24\xa2\x20acxyz$' + 'abc$¢€xyz' REGEXP '^abc\x24\xa2\u20acxyz$' } {1 1 1} do_execsql_test regexp1-2.21 { SELECT 'abc$¢€xyz' REGEXP '^abc[\u0024][\u00a2][\u20ac]xyz$', 'abc$¢€xyz' REGEXP '^abc[\u0024\u00A2\u20AC]{3}xyz$', - 'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\x20ac]+xyz$' + 'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\u20ac]+xyz$' } {1 1 1} do_execsql_test regexp1-2.22 { SELECT 'abc$¢€xyz' REGEXP '^abc[^\u0025-X][^ -\u007f][^\u20ab]xyz$' From afe1dd84afec84d5b84497b7bfc03fef7d0323ab Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 20 Jan 2013 00:18:49 +0000 Subject: [PATCH 15/17] Fix a typo in a comment in the test_regexp.c test file. FossilOrigin-Name: 68346af70bc43baf791227a381e54f9aca802c72 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test_regexp.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 40330a02fb..d82c1ba727 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\s\\xXX\sescape\sin\sthe\stest_regexp.c\smust\sbe\sfollowed\sby\sexactly\stwo\shex\ndigits. -D 2013-01-18T03:35:14.887 +C Fix\sa\stypo\sin\sa\scomment\sin\sthe\stest_regexp.c\stest\sfile. +D 2013-01-20T00:18:49.354 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -218,7 +218,7 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5 F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb -F src/test_regexp.c b70fbbf4dca5913fe404ddf909dae92a88488d61 +F src/test_regexp.c 58e0349f155bc307dfa209df4b03add0a7749866 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -1034,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 38852f158ab20bb4d7b264af987ec1538052bec3 -R 949bb425bbb85c4c863787918f541c43 +P 82957495aa0729468a020c2a0a45ed60019b6e07 +R 096f4ba1914ea3795c9296fd5f0e033f U drh -Z f3f2e37133d258307d52a0baf870b3d9 +Z 22234c37912a7dbc9b6a20f58b6fea63 diff --git a/manifest.uuid b/manifest.uuid index 82e8a50f87..dfd41645ec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82957495aa0729468a020c2a0a45ed60019b6e07 \ No newline at end of file +68346af70bc43baf791227a381e54f9aca802c72 \ No newline at end of file diff --git a/src/test_regexp.c b/src/test_regexp.c index 600043e9cd..321417b882 100644 --- a/src/test_regexp.c +++ b/src/test_regexp.c @@ -378,7 +378,7 @@ static int re_hex(int c, int *pV){ } /* A backslash character has been seen, read the next character and -** return its intepretation. +** return its interpretation. */ static unsigned re_esc_char(ReCompiled *p){ static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; From 25fe97ae8894b2c78755a03290fb8049b1164252 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Jan 2013 18:44:22 +0000 Subject: [PATCH 16/17] Fix a double-free() call that can occur when SQLITE_ENABLE_TREE_EXPLAIN is defined. FossilOrigin-Name: 5bfb5967d70433bf41d39b57506b7ec167a1b6a0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d82c1ba727..0014395ec3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sa\scomment\sin\sthe\stest_regexp.c\stest\sfile. -D 2013-01-20T00:18:49.354 +C Fix\sa\sdouble-free()\scall\sthat\scan\soccur\nwhen\sSQLITE_ENABLE_TREE_EXPLAIN\sis\sdefined. +D 2013-01-23T18:44:22.359 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -243,7 +243,7 @@ F src/vdbe.c f51eb3207594703d24e91335cb16906e894b48aa F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d F src/vdbeInt.h 79abf9b31be406d35ca77d6999cb2d42aaf91e78 F src/vdbeapi.c 4c2418161cf45392ba76a7ca92f9a5f06b96f89c -F src/vdbeaux.c 7658c5d9db838db5780f6a1c4d1280d0646e3569 +F src/vdbeaux.c 7c3231498470049b6f1ce05d3992c48f615d2b5d F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74 F src/vdbesort.c c61ca318681c0e7267da8be3abfca8469652a7e9 @@ -1034,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 82957495aa0729468a020c2a0a45ed60019b6e07 -R 096f4ba1914ea3795c9296fd5f0e033f +P 68346af70bc43baf791227a381e54f9aca802c72 +R a6ba8189eb28518f1cd4dc399aac4272 U drh -Z 22234c37912a7dbc9b6a20f58b6fea63 +Z e0c36470802c92592f633e73329b9c27 diff --git a/manifest.uuid b/manifest.uuid index dfd41645ec..80ac472d78 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -68346af70bc43baf791227a381e54f9aca802c72 \ No newline at end of file +5bfb5967d70433bf41d39b57506b7ec167a1b6a0 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 3bf8e47148..9949895dc2 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2478,7 +2478,7 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); #if defined(SQLITE_ENABLE_TREE_EXPLAIN) - sqlite3_free(p->zExplain); + sqlite3DbFree(db, p->zExplain); sqlite3DbFree(db, p->pExplain); #endif } From bc46f02c5daf3fe2f7713e03eadb07799c1929d4 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Jan 2013 18:53:23 +0000 Subject: [PATCH 17/17] Improved parsing of the arguments to the ".backup" command in the command-line shell. FossilOrigin-Name: f1127e87b90c7ba049404ec68cb4e99009c22185 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c | 44 +++++++++++++++++++++++++++++++++++--------- test/shell1.test | 4 ++-- 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 0014395ec3..0922ce4694 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sdouble-free()\scall\sthat\scan\soccur\nwhen\sSQLITE_ENABLE_TREE_EXPLAIN\sis\sdefined. -D 2013-01-23T18:44:22.359 +C Improved\sparsing\sof\sthe\sarguments\sto\sthe\s".backup"\scommand\sin\sthe\s\ncommand-line\sshell. +D 2013-01-23T18:53:23.246 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -175,7 +175,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 0bca3bf694f14f96a13873d87f62d6a6f38f913f F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 395e458a6dc611cbe1179f424753f0c344957607 -F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843 +F src/shell.c af0309c2491a0d82ded1c2af3f64fcdb29d26ad5 F src/sqlite.h.in 39cc33bb08897c748fe3383c29ccf56585704177 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 @@ -715,7 +715,7 @@ F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf -F test/shell1.test b7896eb84028f3bc8300caf1fc796a73728aad0b +F test/shell1.test 392a265895e63cff2de1c78554e3b5b1cbbe9b8a F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 @@ -1034,7 +1034,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 68346af70bc43baf791227a381e54f9aca802c72 -R a6ba8189eb28518f1cd4dc399aac4272 +P 5bfb5967d70433bf41d39b57506b7ec167a1b6a0 +R 08c8109626ac00561b249e6640d8f589 U drh -Z e0c36470802c92592f633e73329b9c27 +Z c715715f0fc3823fbef7e95ac29cf308 diff --git a/manifest.uuid b/manifest.uuid index 80ac472d78..60af10143c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5bfb5967d70433bf41d39b57506b7ec167a1b6a0 \ No newline at end of file +f1127e87b90c7ba049404ec68cb4e99009c22185 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 4c50feb466..b333502e13 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1629,24 +1629,50 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; - if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){ - const char *zDestFile; - const char *zDb; + if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){ + const char *zDestFile = 0; + const char *zDb = 0; + const char *zKey = 0; sqlite3 *pDest; sqlite3_backup *pBackup; - if( nArg==2 ){ - zDestFile = azArg[1]; - zDb = "main"; - }else{ - zDestFile = azArg[2]; - zDb = azArg[1]; + int j; + for(j=1; jdb, zDb); if( pBackup==0 ){ diff --git a/test/shell1.test b/test/shell1.test index 50e6c7125c..a3d06ece35 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -253,7 +253,7 @@ do_test shell1-2.4.2 { # .backup ?DB? FILE Backup DB (default "main") to FILE do_test shell1-3.1.1 { catchcmd "test.db" ".backup" -} {1 {Error: unknown command or invalid arguments: "backup". Enter ".help" for help}} +} {1 {missing FILENAME argument on .backup}} do_test shell1-3.1.2 { catchcmd "test.db" ".backup FOO" } {0 {}} @@ -263,7 +263,7 @@ do_test shell1-3.1.3 { do_test shell1-3.1.4 { # too many arguments catchcmd "test.db" ".backup FOO BAR BAD" -} {1 {Error: unknown command or invalid arguments: "backup". Enter ".help" for help}} +} {1 {too many arguments to .backup}} # .bail ON|OFF Stop after hitting an error. Default OFF do_test shell1-3.2.1 {