You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-20 23:30:05 +02:00
CLI v1.0.168
This commit is contained in:
322
ReactNativeClient/lib/sql-extensions/sqlite/ext/misc/explain.c
Normal file
322
ReactNativeClient/lib/sql-extensions/sqlite/ext/misc/explain.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
** 2018-09-16
|
||||
**
|
||||
** 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 demonstrates an eponymous virtual table that returns the
|
||||
** EXPLAIN output from an SQL statement.
|
||||
**
|
||||
** Usage example:
|
||||
**
|
||||
** .load ./explain
|
||||
** SELECT p2 FROM explain('SELECT * FROM sqlite_schema')
|
||||
** WHERE opcode='OpenRead';
|
||||
**
|
||||
** This module was originally written to help simplify SQLite testing,
|
||||
** by providing an easier means of verifying certain patterns in the
|
||||
** generated bytecode.
|
||||
*/
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/* explain_vtab is a subclass of sqlite3_vtab which will
|
||||
** serve as the underlying representation of a explain virtual table
|
||||
*/
|
||||
typedef struct explain_vtab explain_vtab;
|
||||
struct explain_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this explain vtab */
|
||||
};
|
||||
|
||||
/* explain_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 from an EXPLAIN operation.
|
||||
*/
|
||||
typedef struct explain_cursor explain_cursor;
|
||||
struct explain_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this cursor */
|
||||
char *zSql; /* Value for the EXPLN_COLUMN_SQL column */
|
||||
sqlite3_stmt *pExplain; /* Statement being explained */
|
||||
int rc; /* Result of last sqlite3_step() on pExplain */
|
||||
};
|
||||
|
||||
/*
|
||||
** The explainConnect() method is invoked to create a new
|
||||
** explain_vtab that describes the explain virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for explain_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the explain_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against explain will look like.
|
||||
*/
|
||||
static int explainConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
explain_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define EXPLN_COLUMN_ADDR 0 /* Instruction address */
|
||||
#define EXPLN_COLUMN_OPCODE 1 /* Opcode */
|
||||
#define EXPLN_COLUMN_P1 2 /* Operand 1 */
|
||||
#define EXPLN_COLUMN_P2 3 /* Operand 2 */
|
||||
#define EXPLN_COLUMN_P3 4 /* Operand 3 */
|
||||
#define EXPLN_COLUMN_P4 5 /* Operand 4 */
|
||||
#define EXPLN_COLUMN_P5 6 /* Operand 5 */
|
||||
#define EXPLN_COLUMN_COMMENT 7 /* Comment */
|
||||
#define EXPLN_COLUMN_SQL 8 /* SQL that is being explained */
|
||||
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for explain_cursor objects.
|
||||
*/
|
||||
static int explainDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new explain_cursor object.
|
||||
*/
|
||||
static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
explain_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((explain_vtab*)p)->db;
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a explain_cursor.
|
||||
*/
|
||||
static int explainClose(sqlite3_vtab_cursor *cur){
|
||||
explain_cursor *pCur = (explain_cursor*)cur;
|
||||
sqlite3_finalize(pCur->pExplain);
|
||||
sqlite3_free(pCur->zSql);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a explain_cursor to its next row of output.
|
||||
*/
|
||||
static int explainNext(sqlite3_vtab_cursor *cur){
|
||||
explain_cursor *pCur = (explain_cursor*)cur;
|
||||
pCur->rc = sqlite3_step(pCur->pExplain);
|
||||
if( pCur->rc!=SQLITE_DONE && pCur->rc!=SQLITE_ROW ) return pCur->rc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the explain_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int explainColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
explain_cursor *pCur = (explain_cursor*)cur;
|
||||
if( i==EXPLN_COLUMN_SQL ){
|
||||
sqlite3_result_text(ctx, pCur->zSql, -1, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
sqlite3_result_value(ctx, sqlite3_column_value(pCur->pExplain, 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 explainRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
explain_cursor *pCur = (explain_cursor*)cur;
|
||||
*pRowid = sqlite3_column_int64(pCur->pExplain, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int explainEof(sqlite3_vtab_cursor *cur){
|
||||
explain_cursor *pCur = (explain_cursor*)cur;
|
||||
return pCur->rc!=SQLITE_ROW;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the explain_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to explainColumn() or explainRowid() or
|
||||
** explainEof().
|
||||
**
|
||||
** The argv[0] is the SQL statement that is to be explained.
|
||||
*/
|
||||
static int explainFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
explain_cursor *pCur = (explain_cursor *)pVtabCursor;
|
||||
char *zSql = 0;
|
||||
int rc;
|
||||
sqlite3_finalize(pCur->pExplain);
|
||||
pCur->pExplain = 0;
|
||||
if( sqlite3_value_type(argv[0])!=SQLITE_TEXT ){
|
||||
pCur->rc = SQLITE_DONE;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
sqlite3_free(pCur->zSql);
|
||||
pCur->zSql = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
|
||||
if( pCur->zSql ){
|
||||
zSql = sqlite3_mprintf("EXPLAIN %s", pCur->zSql);
|
||||
}
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pExplain, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc ){
|
||||
sqlite3_finalize(pCur->pExplain);
|
||||
pCur->pExplain = 0;
|
||||
sqlite3_free(pCur->zSql);
|
||||
pCur->zSql = 0;
|
||||
}else{
|
||||
pCur->rc = sqlite3_step(pCur->pExplain);
|
||||
rc = (pCur->rc==SQLITE_DONE || pCur->rc==SQLITE_ROW) ? SQLITE_OK : pCur->rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the explain virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
*/
|
||||
static int explainBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
int idx = -1; /* Index of a usable == constraint against SQL */
|
||||
int unusable = 0; /* True if there are unusable constraints on SQL */
|
||||
|
||||
pIdxInfo->estimatedRows = 500;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
|
||||
if( p->iColumn!=EXPLN_COLUMN_SQL ) continue;
|
||||
if( !p->usable ){
|
||||
unusable = 1;
|
||||
}else if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if( idx>=0 ){
|
||||
/* There exists a usable == constraint against the SQL column */
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].omit = 1;
|
||||
}else if( unusable ){
|
||||
/* There are unusable constraints against the SQL column. Do not allow
|
||||
** this plan to continue forward. */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** explain virtual table.
|
||||
*/
|
||||
static sqlite3_module explainModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
explainConnect, /* xConnect */
|
||||
explainBestIndex, /* xBestIndex */
|
||||
explainDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
explainOpen, /* xOpen - open a cursor */
|
||||
explainClose, /* xClose - close a cursor */
|
||||
explainFilter, /* xFilter - configure scan constraints */
|
||||
explainNext, /* xNext - advance a cursor */
|
||||
explainEof, /* xEof - check for end of scan */
|
||||
explainColumn, /* xColumn - read data */
|
||||
explainRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
int sqlite3ExplainVtabInit(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "explain", &explainModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_explain_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3ExplainVtabInit(db);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user