-C Employ\sdeliberate_fall_through\smacro\sto\squiet\ssome\scompilers.
-D 2023-01-04T16:54:55.789
+C Ensure\sthat\sLIMIT\sclauses\smay\sbe\spassed\sthrough\sto\svirtual\stable\simplementations\seven\sif\sthe\sWHERE\sclause\suses\soperators\sthat\smay\sonly\sbe\soptimized\sby\svirtual,\snot\sbuilt-in,\stables\s(!=,\sfunctions,\sMATCH\setc.).
+D 2023-01-04T17:46:29.753
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
-F src/test_bestindex.c 8294d8223b7f18a3ddb7f9a0e30815dcca4e61681f78b538c870f7d934f88b81
+F src/test_bestindex.c 1627f782e866a3f4b5ecd01cb46813686bf36612afc9755f26058717fe90b24e
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c 8264637b06a3c1f0727c88d1ea32dcf7986b9e7e358a970cae87cdac8a5b2708
F src/where.c d0d8e3cb2c11e77ba0f8f9ed8eada9d84dbd377167cdcf387b8eeb824c35a3ad
F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c
F src/wherecode.c 76bca3379219880d2527493b71a3be49e696f75396d3481e4de5d4ceec7886b2
-F src/whereexpr.c 05295b44b54eea76d1ba766f0908928d0e20e990c249344c9521454d3d09c7ae
+F src/whereexpr.c 7c5671a04b00c876bec5e99fd4e6f688065feb4773160fbf76fd7900d2901777
F src/window.c 14836767adb26573b50f528eb37f8b1336f2c430ab38de7cead1e5c546bb4d8c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/bestindex7.test f094c669a6400777f4d2ddc3ed28e39169f1adb5be3d59b55f22ccf8c414b71e
F test/bestindex8.test 333ad8c6a554b885a49b68c019166eda92b05f493a92b36b0acdf7f766d04dad
F test/bestindex9.test bf2eb8556e8d5c00ef3ee18c521751cd03c1b55454b6e7683b4c6742e3131b23
+F test/bestindexA.test dd7b7439a46169b45d0305c4cbbb14fc20c7044acc2055c767d2f838b3479c3f
F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9302e4bfdce5905576b8f0af7d6b3a864e1dcd58ed89bb303010a1c4f826e915
-R e73248a148e8d456f99341cdbea50943
-U larrybr
-Z 81e81086d972c0e31b16fcba3d0f3fea
+P 869635fb81e0868dee80ce77653a2c1d2af41b3ffbf0a3f7b788ac99dc808887
+R 09b79d8dee52dbbaabe508a6440984a8
+U dan
+Z 3297969a556ae071bd8b9f4bfdf478f8
# Remove this line to create a well-formed Fossil manifest.
-869635fb81e0868dee80ce77653a2c1d2af41b3ffbf0a3f7b788ac99dc808887
\ No newline at end of file
+f38caab23bcef1df02618376de22d208a3333d023628cde310345505933329f1
\ No newline at end of file
#ifndef SQLITE_OMIT_VIRTUALTABLE
+
typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
+typedef struct TestFindFunction TestFindFunction;
/*
** A fs virtual-table object
sqlite3_vtab base;
Tcl_Interp *interp;
Tcl_Obj *pCmd;
+ TestFindFunction *pFindFunctionList;
sqlite3 *db;
};
sqlite3_stmt *pStmt; /* Read data from here */
};
+struct TestFindFunction {
+ tcl_vtab *pTab;
+ const char *zName;
+ TestFindFunction *pNext;
+};
+
+
/*
** Dequote string z in place.
*/
/* The xDisconnect and xDestroy methods are also the same */
static int tclDisconnect(sqlite3_vtab *pVtab){
tcl_vtab *pTab = (tcl_vtab*)pVtab;
+ while( pTab->pFindFunctionList ){
+ TestFindFunction *p = pTab->pFindFunctionList;
+ pTab->pFindFunctionList = p->pNext;
+ sqlite3_free(p);
+ }
Tcl_DecrRefCount(pTab->pCmd);
sqlite3_free(pTab);
return SQLITE_OK;
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
Tcl_Obj *pElem = Tcl_NewObj();
- const char *zOp = "?";
+ const char *zOp = 0;
Tcl_IncrRefCount(pElem);
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
- Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
+ if( zOp ){
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
+ }else{
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->op));
+ }
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1));
return rc;
}
+static void tclFunction(sqlite3_context *pCtx, int nArg, sqlite3_value **apArg){
+ TestFindFunction *p = (TestFindFunction*)sqlite3_user_data(pCtx);
+ Tcl_Interp *interp = p->pTab->interp;
+ Tcl_Obj *pScript = 0;
+ Tcl_Obj *pRet = 0;
+ int ii;
+
+ pScript = Tcl_DuplicateObj(p->pTab->pCmd);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("function", -1));
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(p->zName, -1));
+
+ for(ii=0; ii<nArg; ii++){
+ const char *zArg = (const char*)sqlite3_value_text(apArg[ii]);
+ Tcl_ListObjAppendElement(interp, pScript,
+ (zArg ? Tcl_NewStringObj(zArg, -1) : Tcl_NewObj())
+ );
+ }
+ Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(pScript);
+
+ pRet = Tcl_GetObjResult(interp);
+ sqlite3_result_text(pCtx, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
+}
+
+static int tclFindFunction(
+ sqlite3_vtab *tab,
+ int nArg,
+ const char *zName,
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT */
+ void **ppArg /* OUT */
+){
+ int iRet = 0;
+ tcl_vtab *pTab = (tcl_vtab*)tab;
+ Tcl_Interp *interp = pTab->interp;
+ Tcl_Obj *pScript = 0;
+ int rc = SQLITE_OK;
+
+ pScript = Tcl_DuplicateObj(pTab->pCmd);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(
+ interp, pScript, Tcl_NewStringObj("xFindFunction", -1)
+ );
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(nArg));
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zName, -1));
+ rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(pScript);
+
+ if( rc==SQLITE_OK ){
+ Tcl_Obj *pObj = Tcl_GetObjResult(interp);
+
+ if( Tcl_GetIntFromObj(interp, pObj, &iRet) ){
+ rc = SQLITE_ERROR;
+ }else if( iRet>0 ){
+ int nName = strlen(zName);
+ int nByte = nName + 1 + sizeof(TestFindFunction);
+ TestFindFunction *pNew = 0;
+
+ pNew = (TestFindFunction*)sqlite3_malloc(nByte);
+ if( pNew==0 ){
+ iRet = 0;
+ }else{
+ memset(pNew, 0, nByte);
+ pNew->zName = (const char*)&pNew[1];
+ memcpy((char*)pNew->zName, zName, nName);
+ pNew->pTab = pTab;
+ pNew->pNext = pTab->pFindFunctionList;
+ pTab->pFindFunctionList = pNew;
+ *ppArg = (void*)pNew;
+ *pxFunc = tclFunction;
+ }
+ }
+ }
+
+ return iRet;
+}
+
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
- 0, /* xFindMethod */
+ tclFindFunction, /* xFindFunction */
0, /* xRename */
};
assert( pWC->a[ii].eOperator==WO_ROWVAL );
continue;
}
+ if( pWC->a[ii].nChild ){
+ /* If this term has child terms, then they are also part of the
+ ** pWC->a[] array. So this term can be ignored, as a LIMIT clause
+ ** will only be added if each of the child terms passes the
+ ** (leftCursor==iCsr) test below. */
+ continue;
+ }
if( pWC->a[ii].leftCursor!=iCsr ) return;
}
--- /dev/null
+# 2020-01-29
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix bestindexA
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+
+proc vtab_command {method args} {
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE x(a, b, c)"
+ }
+
+ xBestIndex {
+ set hdl [lindex $args 0]
+ set clist [$hdl constraints]
+ foreach c $clist {
+ array set C $c
+ lappend ::vtab_constraints [list $C(op) $C(column)]
+ }
+ return [list]
+ }
+
+ xFilter {
+ return ""
+ }
+
+ xFindFunction {
+ foreach {nArg name} $args {}
+ if {$nArg==2 && $name=="even"} {
+ return 152
+ }
+ return 0
+ }
+
+ }
+
+ return {}
+}
+
+register_tcl_module db
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING tcl(vtab_command);
+}
+
+proc do_xbestindex_test {tn sql res} {
+ set script [subst {
+ execsql "$sql"
+ set ::vtab_constraints
+ }]
+
+ uplevel [list do_test $tn $script [list {*}$res]]
+ set ::vtab_constraints [list]
+}
+
+do_xbestindex_test 1.1 {
+ SELECT * FROM t1 WHERE a=?
+} {
+ {eq 0}
+}
+
+do_xbestindex_test 1.2 {
+ SELECT * FROM t1 WHERE a=? LIMIT 10
+} {
+ {eq 0}
+ {limit 0}
+}
+
+do_xbestindex_test 1.3 {
+ SELECT * FROM t1 WHERE a=? AND (b+1)=? LIMIT 10
+} {
+ {eq 0}
+}
+
+proc error_function {args} { error "not a function!" }
+db function even error_function
+
+do_xbestindex_test 1.4 {
+ SELECT * FROM t1 WHERE even(a, ?)
+} {
+ {152 0}
+}
+
+do_xbestindex_test 1.5 {
+ SELECT * FROM t1 WHERE b=10 AND even(a, ?)
+} {
+ {eq 1}
+ {152 0}
+}
+
+do_xbestindex_test 1.6 {
+ SELECT * FROM t1 WHERE b=10 LIMIT 10
+} {
+ {eq 1}
+ {limit 0}
+}
+
+do_xbestindex_test 1.7 {
+ SELECT * FROM t1 WHERE even(b,?) LIMIT 10
+} {
+ {152 1}
+ {limit 0}
+}
+
+do_xbestindex_test 1.8 {
+ SELECT * FROM t1 WHERE b!=? LIMIT 10
+} {
+ {ne 1}
+ {limit 0}
+}
+
+do_xbestindex_test 1.9 {
+ SELECT * FROM t1 WHERE ?=a LIMIT 10
+} {
+ {eq 0}
+ {limit 0}
+}
+
+
+finish_test
+
+
+