Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 282b14c9c6 | |||
| ac2fa465e9 |
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
** 2019-04-26
|
||||
**
|
||||
** 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 a virtual-table that can be used to access a
|
||||
** sharded table implemented as the UNION ALL of various separate tables.
|
||||
*/
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* shardvtab_vtab is a subclass of sqlite3_vtab which is
|
||||
** underlying representation of the virtual table
|
||||
*/
|
||||
typedef struct shardvtab_vtab shardvtab_vtab;
|
||||
struct shardvtab_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* The database connection */
|
||||
char *zView; /* Name of view that implements the shard */
|
||||
int nCol; /* Number of columns in the view */
|
||||
char **azCol; /* Names of the columns, individually malloced */
|
||||
};
|
||||
|
||||
/* shardvtab_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct shardvtab_cursor shardvtab_cursor;
|
||||
struct shardvtab_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_stmt *pStmt; /* Prepared statement to access the shard */
|
||||
int rcLastStep; /* Last return from sqlite3_step() */
|
||||
};
|
||||
|
||||
/*
|
||||
** The shardvtabConnect() method is invoked to create a new
|
||||
** shard virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for shardvtab_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the shardvtab_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against the virtual table will look like.
|
||||
*/
|
||||
static int shardvtabConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
shardvtab_vtab *pNew;
|
||||
int rc;
|
||||
char *zSql;
|
||||
sqlite3_str *pSchema;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
const char *zView = 0;
|
||||
char **azCol = 0;
|
||||
int nCol = 0;
|
||||
char cSep;
|
||||
int i;
|
||||
|
||||
if( argc!=4 || argv[0]==0 ){
|
||||
*pzErr = sqlite3_mprintf("one argument requires: the name of a view");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
zView = argv[3];
|
||||
zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zView);
|
||||
if( zSql==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
*pzErr = sqlite3_mprintf("not a valid view: \"%w\"", zView);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pSchema = sqlite3_str_new(db);
|
||||
if( pSchema==0 ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3_str_appendall(pSchema, "CREATE TABLE x");
|
||||
cSep = '(';
|
||||
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
||||
const char *zName = sqlite3_column_name(pStmt,i);
|
||||
char **azNew = sqlite3_realloc64(azCol, sizeof(azCol[0])*(i+1));
|
||||
if( azNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shardvtab_connect_error;
|
||||
}
|
||||
sqlite3_str_appendf(pSchema, "%c\"%w\"", cSep, zName);
|
||||
cSep = ',';
|
||||
azCol = azNew;
|
||||
azCol[nCol] = sqlite3_mprintf("%s", zName);
|
||||
if( azCol[nCol]==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shardvtab_connect_error;
|
||||
}
|
||||
nCol++;
|
||||
}
|
||||
sqlite3_str_appendall(pSchema, ")");
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
zSql = sqlite3_str_finish(pSchema);
|
||||
pSchema = 0;
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shardvtab_connect_error;
|
||||
}
|
||||
rc = sqlite3_declare_vtab(db, zSql);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto shardvtab_connect_error;
|
||||
}else{
|
||||
size_t n = strlen(zView) + 1;
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) + n );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shardvtab_connect_error;
|
||||
}
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
pNew->zView = (char*)&pNew[1];
|
||||
memcpy(pNew->zView, zView, n);
|
||||
pNew->nCol = nCol;
|
||||
pNew->azCol = azCol;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
shardvtab_connect_error:
|
||||
sqlite3_finalize(pStmt);
|
||||
for(i=0; i<nCol; i++) sqlite3_free(azCol[i]);
|
||||
sqlite3_free(azCol);
|
||||
sqlite3_free(sqlite3_str_finish(pSchema));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for shardvtab_vtab objects.
|
||||
*/
|
||||
static int shardvtabDisconnect(sqlite3_vtab *pVtab){
|
||||
int i;
|
||||
shardvtab_vtab *p = (shardvtab_vtab*)pVtab;
|
||||
for(i=0; i<p->nCol; i++) sqlite3_free(p->azCol[i]);
|
||||
sqlite3_free(p->azCol);
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new shardvtab_cursor object.
|
||||
*/
|
||||
static int shardvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
shardvtab_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a shardvtab_cursor.
|
||||
*/
|
||||
static int shardvtabClose(sqlite3_vtab_cursor *cur){
|
||||
shardvtab_cursor *pCur = (shardvtab_cursor*)cur;
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a shardvtab_cursor to its next row of output.
|
||||
*/
|
||||
static int shardvtabNext(sqlite3_vtab_cursor *cur){
|
||||
shardvtab_cursor *pCur = (shardvtab_cursor*)cur;
|
||||
int rc;
|
||||
rc = pCur->rcLastStep = sqlite3_step(pCur->pStmt);
|
||||
if( rc==SQLITE_ROW || rc==SQLITE_DONE ) return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the shardvtab_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int shardvtabColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
shardvtab_cursor *pCur = (shardvtab_cursor*)cur;
|
||||
sqlite3_result_value(ctx, sqlite3_column_value(pCur->pStmt, i));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int shardvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
*pRowid = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int shardvtabEof(sqlite3_vtab_cursor *cur){
|
||||
shardvtab_cursor *pCur = (shardvtab_cursor*)cur;
|
||||
return pCur->rcLastStep!=SQLITE_ROW;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the shardvtab_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to shardvtabColumn() or shardvtabRowid() or
|
||||
** shardvtabEof().
|
||||
*/
|
||||
static int shardvtabFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
shardvtab_cursor *pCur = (shardvtab_cursor *)pVtabCursor;
|
||||
shardvtab_vtab *pTab = (shardvtab_vtab *)pVtabCursor->pVtab;
|
||||
int rc;
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
pCur->pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(pTab->db, idxStr, -1, &pCur->pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int i;
|
||||
for(i=0; i<argc; i++){
|
||||
sqlite3_bind_value(pCur->pStmt, i+1, argv[i]);
|
||||
}
|
||||
}else{
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
pCur->pStmt = 0;
|
||||
}
|
||||
pCur->rcLastStep = rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
*/
|
||||
static int shardvtabBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *p
|
||||
){
|
||||
shardvtab_vtab *pTab = (shardvtab_vtab*)tab;
|
||||
int i;
|
||||
int n;
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
sqlite3_str *pSql;
|
||||
char *zSep = "WHERE";
|
||||
char *zSql;
|
||||
pSql = sqlite3_str_new(pTab->db);
|
||||
if( pSql==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_str_appendf(pSql, "SELECT * FROM \"%w\"", pTab->zView);
|
||||
for(i=n=0; i<p->nConstraint; i++){
|
||||
const char *zOp;
|
||||
int iCol;
|
||||
if( p->aConstraint[i].usable==0 ) continue;
|
||||
iCol = p->aConstraint[i].iColumn;
|
||||
if( iCol<0 ) continue;
|
||||
zOp = 0;
|
||||
switch( p->aConstraint[i].op ){
|
||||
case SQLITE_INDEX_CONSTRAINT_EQ: zOp = "=="; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GT: zOp = ">"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LE: zOp = "<="; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LT: zOp = "<"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GE: zOp = ">="; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_MATCH: zOp = "MATCH"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LIKE: zOp = "LIKE"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GLOB: zOp = "GLOB"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_REGEXP: zOp = "REGEXP"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_NE: zOp = "<>"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_IS: zOp = "IS"; break;
|
||||
}
|
||||
if( zOp ){
|
||||
n++;
|
||||
p->aConstraintUsage[i].argvIndex = n;
|
||||
sqlite3_str_appendf(pSql, " %s (\"%w\" %s ?%d)",
|
||||
zSep, pTab->azCol[iCol], zOp, n);
|
||||
zSep = "AND";
|
||||
}
|
||||
}
|
||||
zSql = sqlite3_str_finish(pSql);
|
||||
if( zSql==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int x = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_EST_COST, 0);
|
||||
p->estimatedCost = pow(2.0, 0.1*x);
|
||||
p->estimatedRows =
|
||||
sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_EST_ROWS, 0);
|
||||
p->idxStr = zSql;
|
||||
p->needToFreeIdxStr = 1;
|
||||
}else{
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** virtual table.
|
||||
*/
|
||||
static sqlite3_module shardvtabModule = {
|
||||
/* iVersion */ 0,
|
||||
/* xCreate */ shardvtabConnect,
|
||||
/* xConnect */ shardvtabConnect,
|
||||
/* xBestIndex */ shardvtabBestIndex,
|
||||
/* xDisconnect */ shardvtabDisconnect,
|
||||
/* xDestroy */ shardvtabDisconnect,
|
||||
/* xOpen */ shardvtabOpen,
|
||||
/* xClose */ shardvtabClose,
|
||||
/* xFilter */ shardvtabFilter,
|
||||
/* xNext */ shardvtabNext,
|
||||
/* xEof */ shardvtabEof,
|
||||
/* xColumn */ shardvtabColumn,
|
||||
/* xRowid */ shardvtabRowid,
|
||||
/* xUpdate */ 0,
|
||||
/* xBegin */ 0,
|
||||
/* xSync */ 0,
|
||||
/* xCommit */ 0,
|
||||
/* xRollback */ 0,
|
||||
/* xFindMethod */ 0,
|
||||
/* xRename */ 0,
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_shardvtab_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_module(db, "shardvtab", &shardvtabModule, 0);
|
||||
return rc;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
C New\stest\scases\sin\stest/fuzzdata8.db.
|
||||
D 2019-04-24T17:04:02.548
|
||||
C Add\sthe\sshardvtab\svirtual\stable\sthat\suses\sthe\snew\scost\sestimation\sfunctions.
|
||||
D 2019-04-27T20:39:38.045
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -306,6 +306,7 @@ F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8d
|
||||
F ext/misc/scrub.c db9fff56fed322ca587d73727c6021b11ae79ce3f31b389e1d82891d144f22ad
|
||||
F ext/misc/series.c 0c97f63378fddc9f425e82ba139b9aaf902211f24ced115c2b6ae12b425f7334
|
||||
F ext/misc/sha1.c df0a667211baa2c0612d8486acbf6331b9f8633fd4d605c17c7cccd26d59c6bd
|
||||
F ext/misc/shardvtab.c 5ff824125e1cbb4040ac2646f3ab3444fdc867a617c263f04f2f4d4da6ef4667
|
||||
F ext/misc/shathree.c 22ba7ca84a433d6466a7d05dcc876910b435a715da8cc462517db9351412b8c8
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c f88ecb2c0294453ce8b7704b211f5350c41b085b38c8e056852e3a08b0f5e484
|
||||
@@ -519,8 +520,8 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 567888ee3faec14dae06519b4306201771058364a37560186a3e0e755ebc4cb8
|
||||
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
|
||||
F src/select.c b7304d2f491c11a03a7fbdf34bc218282ac54052377809d4dc3b4b1e7f4bfc93
|
||||
F src/shell.c.in bcfa17eb257bf8dc2359e99ba7e6bdfab7901705db013bc47a5be6d7fa7a037e
|
||||
F src/sqlite.h.in 38390767acc1914d58930e03149595ee4710afa4e3c43ab6c3a8aea3f1a6b8cd
|
||||
F src/shell.c.in 7544d68921f2c3919da2150c1f7b53a4942c212dd59e68b7926fd903101c3cab
|
||||
F src/sqlite.h.in 0c4ec0ea145005e2a458b892a8e6778d980efcd2ad36a68565b8774712eb79c1
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
|
||||
F src/sqliteInt.h 866311ac436c0c2039fccc7ea976fbc79d40c1c2ea687161fa4ba64379b53ae6
|
||||
@@ -591,10 +592,10 @@ F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
|
||||
F src/util.c 5061987401c2e8003177fa30d73196aa036727c8f04bf36a2df0c82b1904a236
|
||||
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
|
||||
F src/vdbe.c 711ef421b3bb3db3b2476067b2dc3c71ef5844d9b1a723026578f89f6da621e8
|
||||
F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
|
||||
F src/vdbeInt.h 2c12704db9740c8e899786ecfc7a5797a9d067563496eb1b6ed03c592d7b8d90
|
||||
F src/vdbeapi.c 2ddd60f4a351f15ee98d841e346af16111ad59dfa4d25d2dd4012e9875bf7d92
|
||||
F src/vdbeaux.c f873b5c2efcf8a4d6ecfc5b1a5b06fd810419198f3bd882175d371cc03801873
|
||||
F src/vdbe.h f99dbc42943d945f2aa61377dc67e571688310be51dbc9b3e4299bd0124fdd70
|
||||
F src/vdbeInt.h a9089cdf0d5f4a1f076d5b22e5690b6ee2f70b1db0a4814ae1a6397c497c838b
|
||||
F src/vdbeapi.c 69fae8eb6e1e762e04bfce308f8180294f98a95f7b346f6cb3a1364fd8095cdd
|
||||
F src/vdbeaux.c cf9159eaf4b2ac4d0c0daa61544055d9db924989d433c1f77e2af61ebdcb6a05
|
||||
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
||||
F src/vdbemem.c dd2ee49255c4c5450f2b0887ef44cea8faa1cd7a46501b39a1a82b113ae418e3
|
||||
F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47
|
||||
@@ -604,8 +605,8 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b09a2a9cab50efa08451a8c81d47052120ad5da174048c6d0b08d405384abdf2
|
||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||
F src/walker.c 7607f1a68130c028255d8d56094ea602fc402c79e1e35a46e6282849d90d5fe4
|
||||
F src/where.c 99c7b718ef846ac952016083aaf4e22ede2290beceaf4730a2df55c023251369
|
||||
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
|
||||
F src/where.c 3e9689df25c0410dc60ee28d81ca21ea4dcdbdd925bff764afea95ef6c105975
|
||||
F src/whereInt.h 50e1ddaae281e056eb71d8209ffc194e730745fb521fa8f22d0867cc34e9f3d7
|
||||
F src/wherecode.c 0e76672930bea322eb3606d891a4744be55c09bcd3a995bfd501af62a46e0625
|
||||
F src/whereexpr.c 90859652920f153d2c03f075488744be2926625ebd36911bcbcb17d0d29c891c
|
||||
F src/window.c 038c248267e74ff70a2bb9b1884d40fd145c5183b017823ecb6cbb14bc781478
|
||||
@@ -1818,7 +1819,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P e1724f1d618cfbcfd1e495d8965a395656cfc1114e1bffd4bc3be0bd5cdb6550
|
||||
R 3e1175ca2cd3d699a0989ce182ed2c32
|
||||
P 1b25fa108ab2c4ada75935abf919de2b4c3b39553b2a0ab2a485645a02352e7e
|
||||
R d379d98b062e48bddb17018fbaab4555
|
||||
U drh
|
||||
Z b7a4bb53a6677ebeb4f1be668326c373
|
||||
Z d532b28c8391dbdee92daa0c2fe6ec79
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
7be6222c9ec44596e4eddd906c831eb1272b90fbdf68641d791f216264feb7cf
|
||||
9404300ac1dd0ef4e4b42f618901c6120b15a158c230f76e47c4c6346f6f4f58
|
||||
+8
-5
@@ -1772,7 +1772,7 @@ static void eqp_render_level(ShellState *p, int iEqpId){
|
||||
/*
|
||||
** Display and reset the EXPLAIN QUERY PLAN data
|
||||
*/
|
||||
static void eqp_render(ShellState *p){
|
||||
static void eqp_render(ShellState *p, sqlite3_stmt *pStmt){
|
||||
EQPGraphRow *pRow = p->sGraph.pRow;
|
||||
if( pRow ){
|
||||
if( pRow->zText[0]=='-' ){
|
||||
@@ -1784,7 +1784,10 @@ static void eqp_render(ShellState *p){
|
||||
p->sGraph.pRow = pRow->pNext;
|
||||
sqlite3_free(pRow);
|
||||
}else{
|
||||
utf8_printf(p->out, "QUERY PLAN\n");
|
||||
int iCost, nRow;
|
||||
iCost = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_EST_COST, 0);
|
||||
nRow = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_EST_ROWS, 0);
|
||||
utf8_printf(p->out, "QUERY PLAN (log est cost=%d rows=%d)\n", iCost, nRow);
|
||||
}
|
||||
p->sGraph.zPrefix[0] = 0;
|
||||
eqp_render_level(p, 0);
|
||||
@@ -3075,10 +3078,10 @@ static int shell_exec(
|
||||
const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
|
||||
int iEqpId = sqlite3_column_int(pExplain, 0);
|
||||
int iParentId = sqlite3_column_int(pExplain, 1);
|
||||
if( zEQPLine[0]=='-' ) eqp_render(pArg);
|
||||
if( zEQPLine[0]=='-' ) eqp_render(pArg, pExplain);
|
||||
eqp_append(pArg, iEqpId, iParentId, zEQPLine);
|
||||
}
|
||||
eqp_render(pArg);
|
||||
eqp_render(pArg, pExplain);
|
||||
}
|
||||
sqlite3_finalize(pExplain);
|
||||
sqlite3_free(zEQP);
|
||||
@@ -3126,7 +3129,7 @@ static int shell_exec(
|
||||
bind_prepared_stmt(pArg, pStmt);
|
||||
exec_prepared_stmt(pArg, pStmt);
|
||||
explain_data_delete(pArg);
|
||||
eqp_render(pArg);
|
||||
eqp_render(pArg, pStmt);
|
||||
|
||||
/* print usage stats if stats on */
|
||||
if( pArg && pArg->statsOn ){
|
||||
|
||||
@@ -7847,6 +7847,15 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** used to store the prepared statement. ^This value is not actually
|
||||
** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
|
||||
** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_EST_ROWS]] <dt>SQLITE_STMTSTATUS_EST_ROWS</dt>
|
||||
** <dd>^A return value of X indicates that the query planner estimated
|
||||
** that the query will return pow(2,X/10.0) rows.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_EST_COST]] <dt>SQLITE_STMTSTATUS_EST_COST</dt>
|
||||
** <dd>^A return value of X indicates that the query planner estimated
|
||||
** the relative cost of running this statement to completion is
|
||||
** pow(2,X/10.0).
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
@@ -7857,6 +7866,8 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
#define SQLITE_STMTSTATUS_REPREPARE 5
|
||||
#define SQLITE_STMTSTATUS_RUN 6
|
||||
#define SQLITE_STMTSTATUS_MEMUSED 99
|
||||
#define SQLITE_STMTSTATUS_EST_ROWS 100
|
||||
#define SQLITE_STMTSTATUS_EST_COST 101
|
||||
|
||||
/*
|
||||
** CAPI3REF: Custom Page Cache Object
|
||||
|
||||
@@ -264,6 +264,7 @@ void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
|
||||
sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
|
||||
void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
void sqlite3VdbeUpdateCostEstimates(Parse*, LogEst, LogEst);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
char *sqlite3VdbeExpandSql(Vdbe*, const char*);
|
||||
#endif
|
||||
|
||||
@@ -425,6 +425,8 @@ struct Vdbe {
|
||||
bft usesStmtJournal:1; /* True if uses a statement journal */
|
||||
bft readOnly:1; /* True for statements that do not write */
|
||||
bft bIsReader:1; /* True for statements that read */
|
||||
LogEst nRowEst; /* Query planner of estimated number of output rows */
|
||||
LogEst iCostEst; /* Query planner cost estimate */
|
||||
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
||||
u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
|
||||
|
||||
+30
-18
@@ -1658,27 +1658,39 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
|
||||
*/
|
||||
int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
||||
Vdbe *pVdbe = (Vdbe*)pStmt;
|
||||
u32 v;
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !pStmt
|
||||
|| (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
|
||||
){
|
||||
u32 v = 0;
|
||||
if( !pStmt ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if( op==SQLITE_STMTSTATUS_MEMUSED ){
|
||||
sqlite3 *db = pVdbe->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = 0;
|
||||
db->pnBytesFreed = (int*)&v;
|
||||
sqlite3VdbeClearObject(db, pVdbe);
|
||||
sqlite3DbFree(db, pVdbe);
|
||||
db->pnBytesFreed = 0;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}else{
|
||||
v = pVdbe->aCounter[op];
|
||||
if( resetFlag ) pVdbe->aCounter[op] = 0;
|
||||
switch( op ){
|
||||
case SQLITE_STMTSTATUS_MEMUSED: {
|
||||
sqlite3 *db = pVdbe->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = 0;
|
||||
db->pnBytesFreed = (int*)&v;
|
||||
sqlite3VdbeClearObject(db, pVdbe);
|
||||
sqlite3DbFree(db, pVdbe);
|
||||
db->pnBytesFreed = 0;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
break;
|
||||
}
|
||||
case SQLITE_STMTSTATUS_EST_ROWS: {
|
||||
v = pVdbe->nRowEst;
|
||||
break;
|
||||
}
|
||||
case SQLITE_STMTSTATUS_EST_COST: {
|
||||
v = pVdbe->iCostEst;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( op>=0 && op<ArraySize(pVdbe->aCounter) ){
|
||||
v = pVdbe->aCounter[op];
|
||||
if( resetFlag ) pVdbe->aCounter[op] = 0;
|
||||
}else{
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
@@ -4848,6 +4848,20 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Update the estimated cost fields
|
||||
*/
|
||||
void sqlite3VdbeUpdateCostEstimates(Parse *pParse, LogEst iCost, LogEst nRow){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v->iCostEst ){
|
||||
v->iCostEst = sqlite3LogEstAdd(v->iCostEst, iCost+pParse->nQueryLoop) + 1;
|
||||
if( nRow > v->nRowEst ) v->nRowEst = nRow;
|
||||
}else{
|
||||
v->nRowEst = nRow;
|
||||
v->iCostEst = iCost + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Cause a function to throw an error if it was call from OP_PureFunc
|
||||
** rather than OP_Function.
|
||||
|
||||
@@ -4363,6 +4363,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
|
||||
|
||||
pWInfo->nRowOut = pFrom->nRow;
|
||||
pWInfo->iTotalCost = pFrom->rCost;
|
||||
|
||||
/* Free temporary memory and return success */
|
||||
sqlite3DbFreeNN(db, pSpace);
|
||||
@@ -5145,6 +5146,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Generate loop termination code.
|
||||
*/
|
||||
sqlite3VdbeUpdateCostEstimates(pParse, pWInfo->iTotalCost, pWInfo->nRowOut);
|
||||
VdbeModuleComment((v, "End WHERE-core"));
|
||||
for(i=pWInfo->nLevel-1; i>=0; i--){
|
||||
int addr;
|
||||
|
||||
@@ -462,6 +462,7 @@ struct WhereInfo {
|
||||
WhereLoop *pLoops; /* List of all WhereLoop objects */
|
||||
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
||||
LogEst nRowOut; /* Estimated number of output rows */
|
||||
LogEst iTotalCost; /* Cost estimate for the whole plan */
|
||||
WhereClause sWC; /* Decomposition of the WHERE clause */
|
||||
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||
|
||||
Reference in New Issue
Block a user