$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
-sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
+sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TOP)/src/shell_indexes.c
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
$(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
-C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
-D 2016-02-09T15:10:56.225
+C Experimental\sintegration\sof\sschemalint\sfunctionality\swith\sthe\sshell\stool.\sDoes\snot\swork\syet.
+D 2016-02-11T21:01:16.253
F Makefile.in dac2776c84e0d533b158a9af6e57e05c4a6b19f3
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc b0493f10caddb8adf992a4e6f1943141fc7c6816
F autoconf/Makefile.am 1c1657650775960804945dc392e14d9e43c5ed84
F autoconf/Makefile.msc a35b2aab24d1603f3f0ae65cf01686c2578d319c
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
-F autoconf/README.txt e9757a381e5ce2553dbaa6247bb8ad00eb8d87aa w autoconf/README
+F autoconf/README.txt e9757a381e5ce2553dbaa6247bb8ad00eb8d87aa
F autoconf/configure.ac 72a5e42beb090b32bca580285dc0ab3c4670adb8
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk cd48a5d8a6dc59229f4f3fe40771104f2918f789
+F main.mk eeff3d12ebe5945dac88147c641407c22a731131
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c b1b0880fc474abfab89e737b0ecfde0bd7a60902
F src/loadext.c 84996d7d70a605597d79c1f1d7b2012a5fd34f2b
-F src/main.c b67a45397b93b7ba8fbd6bfcb03423d245baed05
+F src/main.c 816b9a98a6aca0fd643e77f3610d6a4a1a4c7e24
F src/malloc.c 337e9808b5231855fe28857950f4f60ae42c417f
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
F src/pcache.c 73895411fa6b7bd6f0091212feabbe833b358d23
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
-F src/pragma.c 80ee77226d0008d9188356a6cbbe6010866e1bee
+F src/pragma.c cfd521558fccd3864ec664af09a061e9e692583f
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
F src/prepare.c c12b786713df3e8270c0f85f988c5359d8b4d87c
F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26
F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
-F src/shell.c dcd7a83645ef2a58ee9c6d0ea4714d877d7835c4
-F src/sqlite.h.in cf22ad1d52dca2c9862d63833e581028119aab7e
+F src/shell.c 2cde87e03712204231167c4a6c61b0eb5129e105
+F src/shell_indexes.c 3cff393ee86d15fbfbe31f30cd752b46d7779b52
+F src/sqlite.h.in c7db059d3b810b70b83d9ed1436fa813eba22462
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
-F src/sqliteInt.h 3aeaff9611acd790c8e76719b33db09ab885d537
+F src/sqliteInt.h a1d0d9613ed7da3657396795e44991fef188c8ee
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F src/wal.c d21b99fd1458159d0b1ecdccc8ee6ada4fdc4c54
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
-F src/where.c 438b89caa0cbe17cd32703a8f93baca9789d0474
+F src/where.c 89d5845353fe6d2e77bce52a2c8bea0781c69dad
F src/whereInt.h 78b6b4de94db84aecbdc07fe3e38f648eb391e9a
F src/wherecode.c 791a784bbf8749d560fdb0b990b607bc4f44a38d
F src/whereexpr.c de117970b29471177a6901d60ad83a194671dc03
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
F test/savepoint7.test db3db281486c925095f305aad09fe806e5188ff3
-F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2 w test/savepoint3.test
+F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/whereI.test eab5b226bbc344ac70d7dc09b963a064860ae6d7
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
-F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 w test/where8m.test
+F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 9341491c3a11d5a66e4f88d2af9b0d3799b4f27a ca72be8618e5d466d6f35819ca8bbd2b84269959
-R c3affb84a750d99cc1d1198e66d07e76
+P 1a4182eedd0143c3f71b3d97f1d1bb25adeba617
+R 6253a80a5a7097c3b24b24ce68900613
U dan
-Z dbcdec085ed65802fe686b0a9369fd51
+Z bddf3d3a7cd183a6a2362ed54e10358b
-1a4182eedd0143c3f71b3d97f1d1bb25adeba617
\ No newline at end of file
+ed49f297bcee86674ed673e195610b8cc1d35647
\ No newline at end of file
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
+#ifdef SQLITE_SCHEMA_LINT
+ case SQLITE_DBCONFIG_WHEREINFO: {
+ db->xWhereInfo = va_arg(ap, void(*)(void*, int, const char*, int, i64));
+ db->pWhereInfoCtx = va_arg(ap, void*);
+ break;
+ }
+#endif
default: {
static const struct {
int op; /* The opcode */
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
+ ** pk: Non-zero for PK fields.
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
# define setTextMode(X)
#endif
+#include "shell_indexes.c"
/* True if the timer is enabled */
static int enableTimer = 0;
struct ShellState {
sqlite3 *db; /* The database */
int echoOn; /* True to echo input commands */
- int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
+ int autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */
+ int bRecommend; /* Instead of sqlite3_exec(), recommend indexes */
int statsOn; /* True to display memory stats before each finalize */
int scanstatsOn; /* True to display scan stats before each finalize */
int countChanges; /* True to display change counts */
p->iIndent = 0;
}
+typedef struct RecCommandCtx RecCommandCtx;
+struct RecCommandCtx {
+ int (*xCallback)(void*,int,char**,char**,int*);
+ ShellState *pArg;
+};
+
+static void recCommandOut(void *pCtx, const char *zLine){
+ const char *zCol = "output";
+ RecCommandCtx *p = (RecCommandCtx*)pCtx;
+ int t = SQLITE_TEXT;
+ p->xCallback(p->pArg, 1, (char**)&zLine, (char**)&zCol, &t);
+}
+
/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
*pzErrMsg = NULL;
}
+ if( pArg->bRecommend ){
+ RecCommandCtx ctx;
+ ctx.xCallback = xCallback;
+ ctx.pArg = pArg;
+ rc = shellIndexesCommand(db, zSql, recCommandOut, &ctx, pzErrMsg);
+ }else
+
while( zSql[0] && (SQLITE_OK == rc) ){
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
if( SQLITE_OK != rc ){
sqlite3_close(pSrc);
}else
+ if( c=='r' && n>=2 && strncmp(azArg[0], "recommend", n)==0 ){
+ if( nArg==2 ){
+ p->bRecommend = booleanValue(azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .recommend on|off\n");
+ rc = 1;
+ }
+ }else
+
if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
if( nArg==2 ){
if( bail_on_error ) return rc;
}
}
+
+ }else if( strcmp(z, "-recommend") ){
+ data.bRecommend = 1;
}else{
utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
raw_printf(stderr,"Use -help for a list of options.\n");
--- /dev/null
+/*
+** 2016 February 10
+**
+** 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.
+**
+*************************************************************************
+*/
+
+typedef sqlite3_int64 i64;
+
+typedef struct IdxConstraint IdxConstraint;
+typedef struct IdxContext IdxContext;
+typedef struct IdxScan IdxScan;
+typedef struct IdxWhere IdxWhere;
+
+/*
+** A single constraint. Equivalent to either "col = ?" or "col < ?".
+**
+** pLink:
+** ... todo ...
+*/
+struct IdxConstraint {
+ char *zColl; /* Collation sequence */
+ int bRange; /* True for range, false for eq */
+ int iCol; /* Constrained table column */
+ i64 depmask; /* Dependency mask */
+ IdxConstraint *pNext; /* Next constraint in pEq or pRange list */
+ IdxConstraint *pLink; /* See above */
+};
+
+/*
+** A WHERE clause. Made up of IdxConstraint objects.
+**
+** a=? AND b=? AND (c=? OR d=?) AND (e=? OR f=?)
+**
+*/
+struct IdxWhere {
+ IdxConstraint *pEq; /* List of == constraints */
+ IdxConstraint *pRange; /* List of < constraints */
+ IdxWhere **apOr; /* Array of OR branches (joined by pNextOr) */
+ IdxWhere *pNextOr; /* Next in OR'd terms */
+ IdxWhere *pParent; /* Parent object (or NULL) */
+};
+
+/*
+** A single scan of a single table.
+*/
+struct IdxScan {
+ char *zTable; /* Name of table to scan */
+ int iDb; /* Database containing table zTable */
+ i64 covering; /* Mask of columns required for cov. index */
+ IdxConstraint *pOrder; /* ORDER BY columns */
+ IdxWhere where; /* WHERE Constraints */
+ IdxScan *pNextScan; /* Next IdxScan object for same query */
+};
+
+/*
+** Context object passed to idxWhereInfo()
+*/
+struct IdxContext {
+ IdxWhere *pCurrent; /* Current where clause */
+ IdxScan *pScan; /* List of scan objects */
+ sqlite3 *dbm; /* In-memory db for this analysis */
+ int rc; /* Error code (if error has occurred) */
+};
+
+typedef struct PragmaTable PragmaTable;
+typedef struct PragmaCursor PragmaCursor;
+
+struct PragmaTable {
+ sqlite3_vtab base;
+ sqlite3 *db;
+};
+
+struct PragmaCursor {
+ sqlite3_vtab_cursor base;
+ sqlite3_stmt *pStmt;
+ i64 iRowid;
+};
+
+/*
+** Connect to or create a pragma virtual table.
+*/
+static int pragmaConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ const char *zSchema =
+ "CREATE TABLE a(tbl HIDDEN, cid, name, type, notnull, dflt_value, pk)";
+ PragmaTable *pTab = 0;
+ int rc = SQLITE_OK;
+
+ rc = sqlite3_declare_vtab(db, zSchema);
+ if( rc==SQLITE_OK ){
+ pTab = (PragmaTable *)sqlite3_malloc64(sizeof(PragmaTable));
+ if( pTab==0 ) rc = SQLITE_NOMEM;
+ }
+
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( rc==SQLITE_OK ){
+ memset(pTab, 0, sizeof(PragmaTable));
+ pTab->db = db;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a pragma virtual table.
+*/
+static int pragmaDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** xBestIndex method for pragma virtual tables.
+*/
+static int pragmaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int i;
+
+ pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
+
+ /* Look for a valid tbl=? constraint. */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+ if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pIdxInfo->aConstraint[i].iColumn!=0 ) continue;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->estimatedCost = 1.0;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ break;
+ }
+ if( i==pIdxInfo->nConstraint ){
+ tab->zErrMsg = sqlite3_mprintf("missing required tbl=? constraint");
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new pragma cursor.
+*/
+static int pragmaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ PragmaTable *pTab = (PragmaTable *)pVTab;
+ PragmaCursor *pCsr;
+
+ pCsr = (PragmaCursor*)sqlite3_malloc64(sizeof(PragmaCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ memset(pCsr, 0, sizeof(PragmaCursor));
+ pCsr->base.pVtab = pVTab;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor*)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Move a statvfs cursor to the next entry in the file.
+*/
+static int pragmaNext(sqlite3_vtab_cursor *pCursor){
+ PragmaCursor *pCsr = (PragmaCursor*)pCursor;
+ int rc = SQLITE_OK;
+
+ if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
+ rc = sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ }
+ pCsr->iRowid++;
+ return rc;
+}
+
+static int pragmaEof(sqlite3_vtab_cursor *pCursor){
+ PragmaCursor *pCsr = (PragmaCursor*)pCursor;
+ return pCsr->pStmt==0;
+}
+
+static int pragmaFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ PragmaCursor *pCsr = (PragmaCursor*)pCursor;
+ PragmaTable *pTab = (PragmaTable*)(pCursor->pVtab);
+ char *zSql;
+ const char *zTbl;
+ int rc = SQLITE_OK;
+
+ if( pCsr->pStmt ){
+ sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ }
+ pCsr->iRowid = 0;
+
+ assert( argc==1 );
+ zTbl = (const char*)sqlite3_value_text(argv[0]);
+ zSql = sqlite3_mprintf("PRAGMA table_info(%Q)", zTbl);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ }
+ return pragmaNext(pCursor);;
+}
+
+/*
+** xColumn method.
+*/
+static int pragmaColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int iCol
+){
+ PragmaCursor *pCsr = (PragmaCursor *)pCursor;
+ if( iCol>0 ){
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, iCol-1));
+ }
+ return SQLITE_OK;
+}
+
+static int pragmaRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ PragmaCursor *pCsr = (PragmaCursor *)pCursor;
+ *pRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+static int registerPragmaVtabs(sqlite3 *db){
+ static sqlite3_module pragma_module = {
+ 0, /* iVersion */
+ pragmaConnect, /* xCreate */
+ pragmaConnect, /* xConnect */
+ pragmaBestIndex, /* xBestIndex */
+ pragmaDisconnect, /* xDisconnect */
+ pragmaDisconnect, /* xDestroy */
+ pragmaOpen, /* xOpen - open a cursor */
+ pragmaClose, /* xClose - close a cursor */
+ pragmaFilter, /* xFilter - configure scan constraints */
+ pragmaNext, /* xNext - advance a cursor */
+ pragmaEof, /* xEof - check for end of scan */
+ pragmaColumn, /* xColumn - read data */
+ pragmaRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ };
+ return sqlite3_create_module(db, "pragma_table_info", &pragma_module, 0);
+}
+
+/*
+** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc().
+** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
+*/
+static void *idxMalloc(int *pRc, int nByte){
+ void *pRet;
+ assert( *pRc==SQLITE_OK );
+ assert( nByte>0 );
+ pRet = sqlite3_malloc(nByte);
+ if( pRet ){
+ memset(pRet, 0, nByte);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ return pRet;
+}
+
+/*
+** Allocate and return a new IdxConstraint object. Set the IdxConstraint.zColl
+** variable to point to a copy of nul-terminated string zColl.
+*/
+static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){
+ IdxConstraint *pNew;
+ int nColl = strlen(zColl);
+
+ assert( *pRc==SQLITE_OK );
+ pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1);
+ if( pNew ){
+ pNew->zColl = (char*)&pNew[1];
+ memcpy(pNew->zColl, zColl, nColl+1);
+ }
+ return pNew;
+}
+
+/*
+** SQLITE_DBCONFIG_WHEREINFO callback.
+*/
+static void idxWhereInfo(
+ void *pCtx, /* Pointer to IdxContext structure */
+ int eOp,
+ const char *zVal,
+ int iVal,
+ i64 mask
+){
+ IdxContext *p = (IdxContext*)pCtx;
+
+#if 1
+ const char *zOp =
+ eOp==SQLITE_WHEREINFO_TABLE ? "TABLE" :
+ eOp==SQLITE_WHEREINFO_EQUALS ? "EQUALS" :
+ eOp==SQLITE_WHEREINFO_RANGE ? "RANGE" :
+ eOp==SQLITE_WHEREINFO_ORDERBY ? "ORDERBY" :
+ eOp==SQLITE_WHEREINFO_NEXTOR ? "NEXTOR" :
+ eOp==SQLITE_WHEREINFO_ENDOR ? "ENDOR" :
+ eOp==SQLITE_WHEREINFO_BEGINOR ? "BEGINOR" :
+ "!error!";
+ printf("op=%s zVal=%s iVal=%d mask=%llx\n", zOp, zVal, iVal, mask);
+#endif
+
+ if( p->rc==SQLITE_OK ){
+ assert( eOp==SQLITE_WHEREINFO_TABLE || p->pScan!=0 );
+ switch( eOp ){
+ case SQLITE_WHEREINFO_TABLE: {
+ int nVal = strlen(zVal);
+ IdxScan *pNew = (IdxScan*)idxMalloc(&p->rc, sizeof(IdxScan) + nVal + 1);
+ if( !pNew ) return;
+ pNew->zTable = (char*)&pNew[1];
+ memcpy(pNew->zTable, zVal, nVal+1);
+ pNew->pNextScan = p->pScan;
+ pNew->covering = mask;
+ p->pScan = pNew;
+ p->pCurrent = &pNew->where;
+ break;
+ }
+
+ case SQLITE_WHEREINFO_ORDERBY: {
+ IdxConstraint *pNew = idxNewConstraint(&p->rc, zVal);
+ IdxConstraint **pp;
+ if( pNew==0 ) return;
+ pNew->iCol = iVal;
+ for(pp=&p->pScan->pOrder; *pp; pp=&(*pp)->pNext);
+ *pp = pNew;
+ break;
+ }
+
+ case SQLITE_WHEREINFO_EQUALS:
+ case SQLITE_WHEREINFO_RANGE: {
+ IdxConstraint *pNew = idxNewConstraint(&p->rc, zVal);
+ if( pNew==0 ) return;
+ pNew->iCol = iVal;
+ pNew->depmask = mask;
+
+ if( eOp==SQLITE_WHEREINFO_RANGE ){
+ pNew->pNext = p->pCurrent->pRange;
+ p->pCurrent->pRange = pNew;
+ }else{
+ pNew->pNext = p->pCurrent->pEq;
+ p->pCurrent->pEq = pNew;
+ }
+ break;
+ }
+
+ case SQLITE_WHEREINFO_BEGINOR: {
+ assert( 0 );
+ break;
+ }
+ case SQLITE_WHEREINFO_ENDOR: {
+ assert( 0 );
+ break;
+ }
+ case SQLITE_WHEREINFO_NEXTOR: {
+ assert( 0 );
+ break;
+ }
+ }
+ }
+}
+
+/*
+** An error associated with database handle db has just occurred. Pass
+** the error message to callback function xOut.
+*/
+static void idxDatabaseError(
+ sqlite3 *db, /* Database handle */
+ char **pzErrmsg /* Write error here */
+){
+ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+}
+
+static int idxCreateTables(sqlite3 *db, sqlite3 *dbm, IdxScan *pScan){
+ int rc = SQLITE_OK;
+ IdxScan *pIter;
+ for(pIter=pScan; pIter; pIter=pIter->pNextScan){
+ }
+}
+
+static void idxScanFree(IdxScan *pScan){
+}
+
+/*
+** The xOut callback is invoked to return command output to the user. The
+** second argument is always a nul-terminated string. The first argument is
+** passed zero if the string contains normal output or non-zero if it is an
+** error message.
+*/
+int shellIndexesCommand(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL to find indexes for */
+ void (*xOut)(void*, const char*), /* Output callback */
+ void *pOutCtx, /* Context for xOut() */
+ char **pzErrmsg /* OUT: Error message (sqlite3_malloc) */
+){
+ int rc = SQLITE_OK;
+ sqlite3 *dbm = 0;
+ IdxContext ctx;
+ sqlite3_stmt *pStmt = 0; /* Statement compiled from zSql */
+
+ memset(&ctx, 0, sizeof(IdxContext));
+
+ /* Open an in-memory database to work with. The main in-memory
+ ** database schema contains tables similar to those in the users
+ ** database (handle db). The attached in-memory db (aux) contains
+ ** application tables used by the code in this file. */
+ rc = sqlite3_open(":memory:", &dbm);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(dbm,
+ "ATTACH ':memory:' AS aux;"
+ "CREATE TABLE aux.depmask(mask PRIMARY KEY) WITHOUT ROWID;"
+ , 0, 0, 0
+ );
+ }
+ if( rc!=SQLITE_OK ){
+ idxDatabaseError(dbm, pzErrmsg);
+ goto indexes_out;
+ }
+
+ /* Analyze the SELECT statement in zSql. */
+ ctx.dbm = dbm;
+ sqlite3_db_config(db, SQLITE_DBCONFIG_WHEREINFO, idxWhereInfo, (void*)&ctx);
+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ sqlite3_db_config(db, SQLITE_DBCONFIG_WHEREINFO, (void*)0, (void*)0);
+ if( rc!=SQLITE_OK ){
+ idxDatabaseError(db, pzErrmsg);
+ goto indexes_out;
+ }
+
+ /* Create tables within the main in-memory database. These tables
+ ** have the same names, columns and declared types as the tables in
+ ** the user database. All constraints except for PRIMARY KEY are
+ ** removed. */
+ rc = idxCreateTables(db, dbm, ctx.pScan);
+ if( rc!=SQLITE_OK ){
+ goto indexes_out;
+ }
+
+ /* Create candidate indexes within the in-memory database file */
+
+ indexes_out:
+ idxScanFree(ctx.pScan);
+ sqlite3_close(dbm);
+ return rc;
+}
+
+
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
+#define SQLITE_DBCONFIG_WHEREINFO 1004 /* xWhereInfo void* */
+
+#define SQLITE_WHEREINFO_TABLE 1
+#define SQLITE_WHEREINFO_EQUALS 2
+#define SQLITE_WHEREINFO_RANGE 3
+#define SQLITE_WHEREINFO_ORDERBY 4
+#define SQLITE_WHEREINFO_BEGINOR 5
+#define SQLITE_WHEREINFO_ENDOR 6
+#define SQLITE_WHEREINFO_NEXTOR 7
/*
#ifdef SQLITE_USER_AUTHENTICATION
sqlite3_userauth auth; /* User authentication information */
#endif
+#ifdef SQLITE_SCHEMA_LINT
+ void (*xWhereInfo)(void*, int, const char*, int, i64);
+ void *pWhereInfoCtx;
+#endif
};
/*
}
#ifdef SQLITE_SCHEMA_LINT
-static char *whereAppendPrintf(sqlite3 *db, const char *zFmt, ...){
- va_list ap;
- char *zRes = 0;
- va_start(ap, zFmt);
- zRes = sqlite3_vmprintf(zFmt, ap);
- if( zRes==0 ){
- db->mallocFailed = 1;
- }else if( db->mallocFailed ){
- sqlite3_free(zRes);
- zRes = 0;
- }
- va_end(ap);
- return zRes;
-}
-
-/*
-** Append a representation of term pTerm to the string in zIn and return
-** the result. Or, if an OOM occurs, free zIn and return a NULL pointer.
-*/
-static char *whereAppendSingleTerm(
- Parse *pParse,
- Table *pTab,
- int iCol,
- int bOr,
- char *zIn,
- WhereTerm *pTerm
-){
- char *zBuf;
- sqlite3 *db = pParse->db;
- Expr *pX = pTerm->pExpr;
- CollSeq *pColl;
- const char *zOp = 0;
-
- if( pTerm->eOperator & (WO_IS|WO_EQ|WO_IN) ){
- zOp = "eq";
- }else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GE|WO_GT) ){
- zOp = "range";
- }
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
-
- if( zOp ){
- const char *zFmt = bOr ? "%z{{%s \"%w\" \"%w\" %lld}}" :
- "%z{%s \"%w\" \"%w\" %lld}";
- zBuf = whereAppendPrintf(db, zFmt, zIn,
- zOp, pTab->aCol[iCol].zName,
- (pColl ? pColl->zName : "BINARY"),
- pTerm->prereqRight
- );
- }else{
- zBuf = zIn;
- }
-
- return zBuf;
-}
-
-static char *whereTraceWC(
+static void whereTraceWC(
Parse *pParse,
- int bInitialSpace,
struct SrcList_item *pItem,
- char *zIn,
- WhereClause *pWC
+ WhereClause *pWC,
+ int bOr
){
sqlite3 *db = pParse->db;
Table *pTab = pItem->pTab;
- char *zBuf = zIn;
- int iCol;
+ void (*x)(void*, int, const char*, int, i64) = db->xWhereInfo;
+ void *pCtx = db->pWhereInfoCtx;
+ int bFirst = 1; /* True until first callback is made */
int ii;
- int bFirst = !bInitialSpace;
- int bOr = (pWC->op==TK_OR);
- /* List of WO_SINGLE constraints */
- for(iCol=0; iCol<pTab->nCol; iCol++){
+ /* Issue callbacks for WO_SINGLE constraints */
+ for(ii=0; ii<pTab->nCol; ii++){
int opMask = WO_SINGLE;
WhereScan scan;
WhereTerm *pTerm;
- for(pTerm=whereScanInit(&scan, pWC, pItem->iCursor, iCol, opMask, 0);
+ for(pTerm=whereScanInit(&scan, pWC, pItem->iCursor, ii, opMask, 0);
pTerm;
pTerm=whereScanNext(&scan)
){
- /* assert( iCol==pTerm->u.leftColumn ); */
- if( bFirst==0 ) zBuf = whereAppendPrintf(db, "%z ", zBuf);
- zBuf = whereAppendSingleTerm(pParse, pTab, iCol, bOr, zBuf, pTerm);
+ int eOp;
+ Expr *pX = pTerm->pExpr;
+ CollSeq *pC = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
+ if( pTerm->eOperator & (WO_IS|WO_EQ|WO_IN) ){
+ eOp = SQLITE_WHEREINFO_EQUALS;
+ }else{
+ eOp = SQLITE_WHEREINFO_RANGE;
+ }
+ if( bOr && !bFirst ) x(pCtx, SQLITE_WHEREINFO_NEXTOR, 0, 0, 0);
+ x(pCtx, eOp, (pC ? pC->zName : "BINARY"), ii, pTerm->prereqRight);
bFirst = 0;
}
}
- /* Add composite - (WO_OR|WO_AND) - constraints */
+ /* Callbacks for composite - (WO_OR|WO_AND) - constraints */
for(ii=0; ii<pWC->nTerm; ii++){
WhereTerm *pTerm = &pWC->a[ii];
- if( pTerm->eOperator & (WO_OR|WO_AND) ){
- const char *zFmt = ((pTerm->eOperator&WO_OR) ? "%z%s{or " : "%z%s{");
- zBuf = whereAppendPrintf(db, zFmt, zBuf, bFirst ? "" : " ");
- zBuf = whereTraceWC(pParse, 0, pItem, zBuf, &pTerm->u.pOrInfo->wc);
- zBuf = whereAppendPrintf(db, "%z}", zBuf);
+ if( pTerm->eOperator & WO_OR ){
+ assert( bOr==0 );
+ x(pCtx, SQLITE_WHEREINFO_BEGINOR, 0, 0, 0);
+ whereTraceWC(pParse, pItem, &pTerm->u.pOrInfo->wc, 1);
+ x(pCtx, SQLITE_WHEREINFO_ENDOR, 0, 0, 0);
+ }
+ if( pTerm->eOperator & WO_AND ){
+ if( bOr && !bFirst ) x(pCtx, SQLITE_WHEREINFO_NEXTOR, 0, 0, 0);
+ whereTraceWC(pParse, pItem, &pTerm->u.pAndInfo->wc, 0);
bFirst = 0;
}
}
-
- return zBuf;
}
+
static void whereTraceBuilder(
Parse *pParse,
WhereLoopBuilder *p
){
sqlite3 *db = pParse->db;
- if( db->xTrace ){
- ExprList *pOrderBy = p->pOrderBy;
- WhereInfo *pWInfo = p->pWInfo;
- int nTablist = pWInfo->pTabList->nSrc;
+ if( db->xWhereInfo && db->init.busy==0 ){
+ void (*x)(void*, int, const char*, int, i64) = db->xWhereInfo;
+ void *pCtx = db->pWhereInfoCtx;
int ii;
+ int nTab = p->pWInfo->pTabList->nSrc;
/* Loop through each element of the FROM clause. Ignore any sub-selects
- ** or views. Invoke the xTrace() callback once for each real table. */
- for(ii=0; ii<nTablist; ii++){
- char *zBuf = 0;
- int iCol;
- int nCol;
- Table *pTab;
-
- struct SrcList_item *pItem = &pWInfo->pTabList->a[ii];
- if( pItem->pSelect ) continue;
- pTab = pItem->pTab;
- nCol = pTab->nCol;
-
- /* Append the table name to the buffer. */
- zBuf = whereAppendPrintf(db, "\"%w\"", pTab->zName);
-
- /* Append the list of columns required to create a covering index */
- zBuf = whereAppendPrintf(db, "%z {cols", zBuf);
- if( 0==(pItem->colUsed & ((u64)1 << (sizeof(Bitmask)*8-1))) ){
- for(iCol=0; iCol<nCol; iCol++){
- if( iCol==(sizeof(Bitmask)*8-1) ) break;
- if( pItem->colUsed & ((u64)1 << iCol) ){
- const char *zName = pTab->aCol[iCol].zName;
- zBuf = whereAppendPrintf(db, "%z \"%w\"", zBuf, zName);
- }
- }
- }
- zBuf = whereAppendPrintf(db, "%z}",zBuf);
-
- /* Append the contents of WHERE clause */
- zBuf = whereTraceWC(pParse, 1, pItem, zBuf, p->pWC);
-
- /* Append the ORDER BY clause, if any */
- if( pOrderBy ){
- int i;
- int bFirst = 1;
- for(i=0; i<pOrderBy->nExpr; i++){
- Expr *pExpr = pOrderBy->a[i].pExpr;
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
-
- pExpr = sqlite3ExprSkipCollate(pExpr);
- if( pExpr->op==TK_COLUMN && pExpr->iTable==pItem->iCursor ){
- if( pExpr->iColumn>=0 ){
- const char *zName = pTab->aCol[pExpr->iColumn].zName;
- zBuf = whereAppendPrintf(db, "%z%s\"%w\" \"%w\" %s", zBuf,
- bFirst ? " {orderby " : " ", zName, pColl->zName,
- (pOrderBy->a[i].sortOrder ? "DESC" : "ASC")
- );
- bFirst = 0;
+ ** or views. Invoke the xWhereInfo() callback multiple times for each
+ ** real table. */
+ for(ii=0; ii<p->pWInfo->pTabList->nSrc; ii++){
+ struct SrcList_item *pItem = &p->pWInfo->pTabList->a[ii];
+ if( pItem->pSelect==0 ){
+ Table *pTab = pItem->pTab;
+ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+
+ /* Table name callback */
+ x(pCtx, SQLITE_WHEREINFO_TABLE, pTab->zName, iDb, pItem->colUsed);
+
+ /* ORDER BY callbacks */
+ if( p->pOrderBy ){
+ int i;
+ int bFirst = 1;
+ for(i=0; i<p->pOrderBy->nExpr; i++){
+ Expr *pExpr = p->pOrderBy->a[i].pExpr;
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
+ pExpr = sqlite3ExprSkipCollate(pExpr);
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==pItem->iCursor ){
+ int iCol = pExpr->iColumn;
+ if( iCol>=0 ){
+ x(pCtx, SQLITE_WHEREINFO_ORDERBY, pColl->zName, iCol, 0);
+ }
}
}
}
- if( bFirst==0 ) zBuf = whereAppendPrintf(db, "%z}", zBuf);
- }
- /* Pass the buffer to the xTrace() callback, then free it */
- db->xTrace(db->pTraceArg, zBuf);
- sqlite3DbFree(db, zBuf);
+ /* WHERE callbacks */
+ whereTraceWC(pParse, pItem, p->pWC, 0);
+ }
}
}
}