mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Initial implementation of the sqlite3_vtab_rhs_value() interface and the
qpvtab extension used for testing the virtual table interface. FossilOrigin-Name: 0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5
This commit is contained in:
@ -460,6 +460,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/qpvtab.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
|
@ -1579,6 +1579,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\normalize.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\prefixes.c \
|
||||
$(TOP)\ext\misc\qpvtab.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\remember.c \
|
||||
$(TOP)\ext\misc\series.c \
|
||||
|
338
ext/misc/qpvtab.c
Normal file
338
ext/misc/qpvtab.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
** 2022-01-19
|
||||
**
|
||||
** 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 returns information about
|
||||
** how the query planner called the xBestIndex method. This virtual table
|
||||
** is intended for testing and debugging only.
|
||||
**
|
||||
** The schema of the virtual table is this:
|
||||
**
|
||||
** CREATE TABLE qpvtab(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t);
|
||||
**
|
||||
** There is also a HIDDEN column "flags".
|
||||
**
|
||||
** All columns except column "a" have a value that is either TEXT that
|
||||
** is there name, or INTEGER which is their index (b==1). TEXT is the
|
||||
** default, but INTEGER is used of there is a constraint on flags where the
|
||||
** right-hand side is an integer that includes the 1 bit.
|
||||
**
|
||||
** The "a" column returns text that describes one of the parameters that
|
||||
** xBestIndex was called with. A completely query of the table should
|
||||
** show all details of how xBestIndex was called.
|
||||
*/
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
|
||||
/* qpvtab_vtab is a subclass of sqlite3_vtab which is
|
||||
** underlying representation of the virtual table
|
||||
*/
|
||||
typedef struct qpvtab_vtab qpvtab_vtab;
|
||||
struct qpvtab_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
};
|
||||
|
||||
/* qpvtab_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 qpvtab_cursor qpvtab_cursor;
|
||||
struct qpvtab_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
const char *zData; /* Data to return */
|
||||
int nData; /* Number of bytes of data */
|
||||
int flags; /* Flags value */
|
||||
};
|
||||
|
||||
/*
|
||||
** The qpvtabConnect() method is invoked to create a new
|
||||
** qpvtab virtual table.
|
||||
*/
|
||||
static int qpvtabConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
qpvtab_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t,"
|
||||
" flags HIDDEN)"
|
||||
);
|
||||
#define QPVTAB_A 0
|
||||
#define QPVTAB_B 1
|
||||
#define QPVTAB_T 19
|
||||
#define QPVTAB_FLAGS 20
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for qpvtab_vtab objects.
|
||||
*/
|
||||
static int qpvtabDisconnect(sqlite3_vtab *pVtab){
|
||||
qpvtab_vtab *p = (qpvtab_vtab*)pVtab;
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new qpvtab_cursor object.
|
||||
*/
|
||||
static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
qpvtab_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 qpvtab_cursor.
|
||||
*/
|
||||
static int qpvtabClose(sqlite3_vtab_cursor *cur){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor*)cur;
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a qpvtab_cursor to its next row of output.
|
||||
*/
|
||||
static int qpvtabNext(sqlite3_vtab_cursor *cur){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor*)cur;
|
||||
while( pCur->iRowid<pCur->nData && pCur->zData[pCur->iRowid]!='\n' ){
|
||||
pCur->iRowid++;
|
||||
}
|
||||
if( pCur->zData[pCur->iRowid]=='\n' ) pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the qpvtab_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int qpvtabColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor*)cur;
|
||||
if( i==0 && pCur->iRowid<pCur->nData ){
|
||||
int j;
|
||||
for(j=pCur->iRowid; j<pCur->nData && pCur->zData[j]!='\n'; j++){}
|
||||
sqlite3_result_text64(ctx, &pCur->zData[pCur->iRowid], j-pCur->iRowid,
|
||||
SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
}else if( i>=QPVTAB_B && i<=QPVTAB_T ){
|
||||
if( pCur->flags & 1 ){
|
||||
sqlite3_result_int(ctx, i);
|
||||
}else{
|
||||
char x = 'a'+i;
|
||||
sqlite3_result_text64(ctx, &x, 1, SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
}
|
||||
}else if( i==QPVTAB_FLAGS ){
|
||||
sqlite3_result_int(ctx, pCur->flags);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int qpvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int qpvtabEof(sqlite3_vtab_cursor *cur){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor*)cur;
|
||||
return pCur->iRowid>=pCur->nData;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the qpvtab_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to qpvtabColumn() or qpvtabRowid() or
|
||||
** qpvtabEof().
|
||||
*/
|
||||
static int qpvtabFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
qpvtab_cursor *pCur = (qpvtab_cursor *)pVtabCursor;
|
||||
pCur->iRowid = 0;
|
||||
pCur->zData = idxStr;
|
||||
pCur->nData = (int)strlen(idxStr);
|
||||
pCur->flags = idxNum;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append the text of a value to pStr
|
||||
*/
|
||||
static void qpvtabStrAppendValue(
|
||||
sqlite3_str *pStr,
|
||||
sqlite3_value *pVal
|
||||
){
|
||||
switch( sqlite3_value_type(pVal) ){
|
||||
case SQLITE_NULL:
|
||||
sqlite3_str_appendf(pStr, "NULL");
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pVal));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
sqlite3_str_appendf(pStr, "%f", sqlite3_value_double(pVal));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
sqlite3_str_appendf(pStr, "%Q", sqlite3_value_text(pVal));
|
||||
break;
|
||||
case SQLITE_BLOB: {
|
||||
int i;
|
||||
const unsigned char *a = sqlite3_value_blob(pVal);
|
||||
int n = sqlite3_value_bytes(pVal);
|
||||
sqlite3_str_append(pStr, "x'", 2);
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_str_appendf(pStr, "%02x", a[i]);
|
||||
}
|
||||
sqlite3_str_append(pStr, "'", 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 qpvtabBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
sqlite3_str *pStr = sqlite3_str_new(0);
|
||||
int i, k = 0;
|
||||
sqlite3_str_appendf(pStr, "nConstraint=%d\n", pIdxInfo->nConstraint);
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
sqlite3_value *pVal;
|
||||
int iCol = pIdxInfo->aConstraint[i].iColumn;
|
||||
char zCol[8];
|
||||
if( iCol==QPVTAB_FLAGS ){
|
||||
strcpy(zCol, "flags");
|
||||
if( pIdxInfo->aConstraint[i].usable ){
|
||||
pVal = 0;
|
||||
sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);
|
||||
if( pVal ){
|
||||
pIdxInfo->idxNum = sqlite3_value_int(pVal);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
zCol[0] = iCol+'a';
|
||||
zCol[1] = 0;
|
||||
}
|
||||
sqlite3_str_appendf(pStr,"aConstraint[%d]: iColumn=%s op=%d usable=%d",
|
||||
i,
|
||||
zCol,
|
||||
pIdxInfo->aConstraint[i].op,
|
||||
pIdxInfo->aConstraint[i].usable);
|
||||
pVal = 0;
|
||||
sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);
|
||||
if( pVal ){
|
||||
sqlite3_str_appendf(pStr, " value=");
|
||||
qpvtabStrAppendValue(pStr, pVal);
|
||||
}
|
||||
sqlite3_str_append(pStr, "\n", 1);
|
||||
if( pIdxInfo->aConstraint[i].usable ){
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = ++k;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
}
|
||||
}
|
||||
pIdxInfo->estimatedCost = (double)10;
|
||||
pIdxInfo->estimatedRows = 10;
|
||||
sqlite3_str_appendf(pStr, "idxNum=%d\n", pIdxInfo->idxNum);
|
||||
pIdxInfo->idxStr = sqlite3_str_finish(pStr);
|
||||
pIdxInfo->needToFreeIdxStr = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** virtual table.
|
||||
*/
|
||||
static sqlite3_module qpvtabModule = {
|
||||
/* iVersion */ 0,
|
||||
/* xCreate */ 0,
|
||||
/* xConnect */ qpvtabConnect,
|
||||
/* xBestIndex */ qpvtabBestIndex,
|
||||
/* xDisconnect */ qpvtabDisconnect,
|
||||
/* xDestroy */ 0,
|
||||
/* xOpen */ qpvtabOpen,
|
||||
/* xClose */ qpvtabClose,
|
||||
/* xFilter */ qpvtabFilter,
|
||||
/* xNext */ qpvtabNext,
|
||||
/* xEof */ qpvtabEof,
|
||||
/* xColumn */ qpvtabColumn,
|
||||
/* xRowid */ qpvtabRowid,
|
||||
/* xUpdate */ 0,
|
||||
/* xBegin */ 0,
|
||||
/* xSync */ 0,
|
||||
/* xCommit */ 0,
|
||||
/* xRollback */ 0,
|
||||
/* xFindMethod */ 0,
|
||||
/* xRename */ 0,
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_qpvtab_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "qpvtab", &qpvtabModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
1
main.mk
1
main.mk
@ -377,6 +377,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/qpvtab.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
|
30
manifest
30
manifest
@ -1,11 +1,11 @@
|
||||
C A\sbetter\sand\smore\srobust\sfix\sfor\sthe\sproblem\sof\sreading\sa\sread-only\sWAL\nmode\sdatabase\swith\sexisting\s-wal\sand\s-shm\sfiles,\sreplacing\s[f426874e005e3c23].
|
||||
D 2022-01-20T14:40:34.203
|
||||
C Initial\simplementation\sof\sthe\ssqlite3_vtab_rhs_value()\sinterface\sand\sthe\nqpvtab\sextension\sused\sfor\stesting\sthe\svirtual\stable\sinterface.
|
||||
D 2022-01-20T17:10:59.757
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in fd537743957bfe87997dc5727783d8eec82098921e15eab984d6711cd46f001b
|
||||
F Makefile.in 3271f3cffa0fb1e214816bbffbdb8a367f8d3b8415eda5346839cf427a138c70
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc 22ce0007874c61c8eb51fc22b84f72af175ce2d7431c242253bdffa39c163da4
|
||||
F Makefile.msc eeb45109d245d1bc5d6ce78da818d62848307419f950b0de0a00ab0672b15081
|
||||
F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c
|
||||
F VERSION 392c2f83569705069415a5d98b1c138ec8fe8a56a663a0d94cea019e806537b2
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@ -316,6 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1
|
||||
F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
|
||||
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
|
||||
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
|
||||
F ext/misc/qpvtab.c 0f6e3f4081f6ad0104d016bf6e21de8a7f5e3f14b984a2158940a1809741fd96
|
||||
F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
@ -472,7 +473,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 32e8c752386520016933873a23a9c649f1a9cfd5c75c218614e622f0510b8f42
|
||||
F main.mk 3de4bca45fee4b843aaf74df8ffc639aa8ae3c52af997bbbd6927add30154fda
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -514,7 +515,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743
|
||||
F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d
|
||||
F src/loadext.c 9a693eb89575af5d54b025c1e927b2ea8114bbeee3db346e8abc81676dd82160
|
||||
F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960
|
||||
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
@ -553,15 +554,15 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
|
||||
F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e
|
||||
F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99
|
||||
F src/sqlite.h.in 9257b85dd160fda70e12727881e6c48be0f21ab0d149fa27446505fec5fa4fca
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef
|
||||
F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c
|
||||
F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6
|
||||
F src/test1.c f13fe747afc7d9af189ce0cdaaf641252c5803db2a32bd3525eec2905c7b4f37
|
||||
F src/test1.c 9287559cc1f7c5a25f927aa172e69778237f0e037960dbcdb4257d0bea500114
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
@ -638,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7
|
||||
F src/where.c 9f8a9c1c18ab37bbb32ea82c322b09c72e237a89e9005b30089273c6efa5d406
|
||||
F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be
|
||||
F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6
|
||||
F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3
|
||||
@ -1938,8 +1939,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf
|
||||
R 23c453292071b3de4a1e0dc51f1f1bde
|
||||
P 71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80
|
||||
R 2d7b697c8fff979e242ffc760548c840
|
||||
T *branch * sqlite3_vtab_rhs_value
|
||||
T *sym-sqlite3_vtab_rhs_value *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 048e904f267f4777d2809de2936b5439
|
||||
Z 906d4e9a8d8e3be5e145d8027611963e
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80
|
||||
0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5
|
@ -487,6 +487,7 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_autovacuum_pages,
|
||||
/* Version 3.38.0 and later */
|
||||
sqlite3_error_offset,
|
||||
sqlite3_vtab_rhs_value,
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
@ -9503,6 +9503,29 @@ int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Constraint values in xBestIndex()
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This API may only be used from within an xBestIndex() callback. The
|
||||
** results of calling it from outside of an xBestIndex() callback are
|
||||
** undefined and probably harmful.
|
||||
**
|
||||
** When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
||||
** the [xBestIndex] method of a [virtual table] implementation, with P being
|
||||
** a copy of the sqlite3_index_info object pointer passed into xBestIndex and
|
||||
** J being a 0-based index of one of the constraints, then this routine
|
||||
** attempts to set *V to be the value on the right-hand side of
|
||||
** that constraint if the right-hand side is a known constant. If the
|
||||
** right-hand side of the constraint is not known, then *V is set to a NULL
|
||||
** pointer.
|
||||
**
|
||||
** The sqlite3_value object returned in *V remains valid for the duration of
|
||||
** the xBestIndex method code. When xBestIndex returns, the sqlite3_value
|
||||
** object returned by sqlite3_vtab_rhs_value() is automatically deallocated.
|
||||
*/
|
||||
int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Conflict resolution modes
|
||||
** KEYWORDS: {conflict resolution mode}
|
||||
|
@ -346,6 +346,7 @@ struct sqlite3_api_routines {
|
||||
void*, void(*)(void*));
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -659,6 +660,7 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
@ -7568,6 +7568,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
#endif
|
||||
extern int sqlite3_qpvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@ -7598,6 +7599,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
{ "prefixes", sqlite3_prefixes_init },
|
||||
#endif
|
||||
{ "qpvtab", sqlite3_qpvtab_init },
|
||||
{ "regexp", sqlite3_regexp_init },
|
||||
{ "remember", sqlite3_remember_init },
|
||||
{ "series", sqlite3_series_init },
|
||||
|
66
src/where.c
66
src/where.c
@ -30,8 +30,11 @@
|
||||
*/
|
||||
typedef struct HiddenIndexInfo HiddenIndexInfo;
|
||||
struct HiddenIndexInfo {
|
||||
WhereClause *pWC; /* The Where clause being analyzed */
|
||||
Parse *pParse; /* The parsing context */
|
||||
WhereClause *pWC; /* The Where clause being analyzed */
|
||||
Parse *pParse; /* The parsing context */
|
||||
sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
|
||||
** because extra space is allocated to hold up
|
||||
** to nTerm such values */
|
||||
};
|
||||
|
||||
/* Forward declaration of methods */
|
||||
@ -1095,7 +1098,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
/*
|
||||
** Allocate and populate an sqlite3_index_info structure. It is the
|
||||
** responsibility of the caller to eventually release the structure
|
||||
** by passing the pointer returned by this function to sqlite3_free().
|
||||
** by passing the pointer returned by this function to freeIndexInfo().
|
||||
*/
|
||||
static sqlite3_index_info *allocateIndexInfo(
|
||||
Parse *pParse, /* The parsing context */
|
||||
@ -1207,13 +1210,14 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
*/
|
||||
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
|
||||
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
|
||||
+ sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
|
||||
+ sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden)
|
||||
+ sizeof(sqlite3_value*)*nTerm );
|
||||
if( pIdxInfo==0 ){
|
||||
sqlite3ErrorMsg(pParse, "out of memory");
|
||||
return 0;
|
||||
}
|
||||
pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
|
||||
pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
|
||||
pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm];
|
||||
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
|
||||
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
|
||||
pIdxInfo->aConstraint = pIdxCons;
|
||||
@ -1278,6 +1282,24 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
return pIdxInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free an sqlite3_index_info structure allocated by allocateIndexInfo()
|
||||
** and possibly modified by xBestIndex methods.
|
||||
*/
|
||||
static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){
|
||||
HiddenIndexInfo *pHidden;
|
||||
int i;
|
||||
assert( pIdxInfo!=0 );
|
||||
pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
||||
assert( pHidden->pParse!=0 );
|
||||
assert( pHidden->pParse->db==db );
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
sqlite3ValueFree(pHidden->aRhs[i]);
|
||||
pHidden->aRhs[i] = 0;
|
||||
}
|
||||
sqlite3DbFree(db, pIdxInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
** The table object reference passed as the second argument to this function
|
||||
** must represent a virtual table. This function invokes the xBestIndex()
|
||||
@ -3633,6 +3655,36 @@ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
|
||||
return zRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** This interface is callable from within the xBestIndex callback only.
|
||||
**
|
||||
** If possible, set (*ppVal) to point to an object containing the value
|
||||
** on the right-hand-side of constraint iCons.
|
||||
*/
|
||||
int sqlite3_vtab_rhs_value(
|
||||
sqlite3_index_info *pIdxInfo, /* Copy of first argument to xBestIndex */
|
||||
int iCons, /* Constraint for which RHS is wanted */
|
||||
sqlite3_value **ppVal /* Write value extracted here */
|
||||
){
|
||||
HiddenIndexInfo *pH = (HiddenIndexInfo*)&pIdxInfo[1];
|
||||
sqlite3_value *pVal = 0;
|
||||
int rc = SQLITE_OK;
|
||||
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}else{
|
||||
if( pH->aRhs[iCons]==0 ){
|
||||
WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
|
||||
rc = sqlite3ValueFromExpr(
|
||||
pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db),
|
||||
SQLITE_AFF_BLOB, &pH->aRhs[iCons]
|
||||
);
|
||||
}
|
||||
pVal = pH->aRhs[iCons];
|
||||
}
|
||||
*ppVal = pVal;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for a table of the join identified by
|
||||
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
|
||||
@ -3691,7 +3743,7 @@ static int whereLoopAddVirtual(
|
||||
pNew->u.vtab.needFree = 0;
|
||||
nConstraint = p->nConstraint;
|
||||
if( whereLoopResize(pParse->db, pNew, nConstraint) ){
|
||||
sqlite3DbFree(pParse->db, p);
|
||||
freeIndexInfo(pParse->db, p);
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
@ -3771,7 +3823,7 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
|
||||
sqlite3DbFreeNN(pParse->db, p);
|
||||
freeIndexInfo(pParse->db, p);
|
||||
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
|
||||
return rc;
|
||||
}
|
||||
|
Reference in New Issue
Block a user