$(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 \
$(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 \
--- /dev/null
+/*
+** 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;
+}
$(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 \
-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
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
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
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
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
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
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.
-71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80
\ No newline at end of file
+0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5
\ No newline at end of file
sqlite3_autovacuum_pages,
/* Version 3.38.0 and later */
sqlite3_error_offset,
+ sqlite3_vtab_rhs_value,
};
/* True if x is the directory separator character
*/
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}
void*, void(*)(void*));
/* Version 3.38.0 and later */
int (*error_offset)(sqlite3*);
+ int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
};
/*
#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)
#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*);
#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 },
*/
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 */
/*
** 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 */
*/
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;
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()
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.
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;
}
}
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;
}