1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge all recent trunk enhancements into the reuse-schema branch.

FossilOrigin-Name: e556f3d3819134022f72e72471976616700c4fe00fc924bfbe713a6132440fdf
This commit is contained in:
drh
2024-04-05 15:04:01 +00:00
18 changed files with 421 additions and 83 deletions

View File

@@ -55,8 +55,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS ** EXTENSION API FUNCTIONS
** **
** xUserData(pFts): ** xUserData(pFts):
** Return a copy of the context pointer the extension function was ** Return a copy of the pUserData pointer passed to the xCreateFunction()
** registered with. ** API when the extension function was registered.
** **
** xColumnTotalSize(pFts, iCol, pnToken): ** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken ** If parameter iCol is less than zero, set output variable *pnToken

View File

@@ -471,7 +471,7 @@ static void icuLoadCollation(
UCollator *pUCollator; /* ICU library collation object */ UCollator *pUCollator; /* ICU library collation object */
int rc; /* Return code from sqlite3_create_collation_x() */ int rc; /* Return code from sqlite3_create_collation_x() */
assert(nArg==2); assert(nArg==2 || nArg==3);
(void)nArg; /* Unused parameter */ (void)nArg; /* Unused parameter */
zLocale = (const char *)sqlite3_value_text(apArg[0]); zLocale = (const char *)sqlite3_value_text(apArg[0]);
zName = (const char *)sqlite3_value_text(apArg[1]); zName = (const char *)sqlite3_value_text(apArg[1]);
@@ -486,7 +486,39 @@ static void icuLoadCollation(
return; return;
} }
assert(p); assert(p);
if(nArg==3){
const char *zOption = (const char*)sqlite3_value_text(apArg[2]);
static const struct {
const char *zName;
UColAttributeValue val;
} aStrength[] = {
{ "PRIMARY", UCOL_PRIMARY },
{ "SECONDARY", UCOL_SECONDARY },
{ "TERTIARY", UCOL_TERTIARY },
{ "DEFAULT", UCOL_DEFAULT_STRENGTH },
{ "QUARTERNARY", UCOL_QUATERNARY },
{ "IDENTICAL", UCOL_IDENTICAL },
};
int i;
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
if( sqlite3_stricmp(zOption,aStrength[i].zName)==0 ){
ucol_setStrength(pUCollator, aStrength[i].val);
break;
}
}
if( i>=sizeof(aStrength)/sizeof(aStrength[0]) ){
sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p));
sqlite3_str_appendf(pStr,
"unknown collation strength \"%s\" - should be one of:",
zOption);
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
sqlite3_str_appendf(pStr, " %s", aStrength[i].zName);
}
sqlite3_result_error(p, sqlite3_str_value(pStr), -1);
sqlite3_free(sqlite3_str_finish(pStr));
return;
}
}
rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
icuCollationColl, icuCollationDel icuCollationColl, icuCollationDel
); );
@@ -509,6 +541,7 @@ int sqlite3IcuInit(sqlite3 *db){
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} scalars[] = { } scalars[] = {
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation}, {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
{"icu_load_collation",3,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc}, {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},

View File

@@ -433,40 +433,56 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
out.returnVal = ()=>opt.resultRows; out.returnVal = ()=>opt.resultRows;
} }
if(opt.callback || opt.resultRows){ if(opt.callback || opt.resultRows){
switch((undefined===opt.rowMode) switch((undefined===opt.rowMode) ? 'array' : opt.rowMode) {
? 'array' : opt.rowMode) { case 'object':
case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break; out.cbArg = (stmt,cache)=>{
case 'array': out.cbArg = (stmt)=>stmt.get([]); break; if( !cache.columnNames ) cache.columnNames = stmt.getColumnNames([]);
case 'stmt': /* https://sqlite.org/forum/forumpost/3632183d2470617d:
if(Array.isArray(opt.resultRows)){ conversion of rows to objects (key/val pairs) is
toss3("exec(): invalid rowMode for a resultRows array: must", somewhat expensive for large data sets because of the
"be one of 'array', 'object',", native-to-JS conversion of the column names. If we
"a result column number, or column name reference."); instead cache the names and build objects from that
} list of strings, it can run twice as fast. The
out.cbArg = (stmt)=>stmt; difference is not noticeable for small data sets but
becomes human-perceivable when enough rows are
involved. */
const row = stmt.get([]);
const rv = Object.create(null);
for( const i in cache.columnNames ) rv[cache.columnNames[i]] = row[i];
return rv;
};
break;
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
case 'stmt':
if(Array.isArray(opt.resultRows)){
toss3("exec(): invalid rowMode for a resultRows array: must",
"be one of 'array', 'object',",
"a result column number, or column name reference.");
}
out.cbArg = (stmt)=>stmt;
break;
default:
if(util.isInt32(opt.rowMode)){
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
break; break;
default: }else if('string'===typeof opt.rowMode
if(util.isInt32(opt.rowMode)){ && opt.rowMode.length>1
out.cbArg = (stmt)=>stmt.get(opt.rowMode); && '$'===opt.rowMode[0]){
break; /* "$X": fetch column named "X" (case-sensitive!). Prior
}else if('string'===typeof opt.rowMode to 2022-12-14 ":X" and "@X" were also permitted, but
&& opt.rowMode.length>1 having so many options is unnecessary and likely to
&& '$'===opt.rowMode[0]){ cause confusion. */
/* "$X": fetch column named "X" (case-sensitive!). Prior const $colName = opt.rowMode.substr(1);
to 2022-12-14 ":X" and "@X" were also permitted, but out.cbArg = (stmt)=>{
having so many options is unnecessary and likely to const rc = stmt.get(Object.create(null))[$colName];
cause confusion. */ return (undefined===rc)
const $colName = opt.rowMode.substr(1); ? toss3(capi.SQLITE_NOTFOUND,
out.cbArg = (stmt)=>{ "exec(): unknown result column:",$colName)
const rc = stmt.get(Object.create(null))[$colName]; : rc;
return (undefined===rc) };
? toss3(capi.SQLITE_NOTFOUND, break;
"exec(): unknown result column:",$colName) }
: rc; toss3("Invalid rowMode:",opt.rowMode);
};
break;
}
toss3("Invalid rowMode:",opt.rowMode);
} }
} }
return out; return out;
@@ -884,10 +900,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
and names. */) ? 0 : 1; and names. */) ? 0 : 1;
evalFirstResult = false; evalFirstResult = false;
if(arg.cbArg || resultRows){ if(arg.cbArg || resultRows){
const cbArgCache = Object.create(null)
/* 2nd arg for arg.cbArg, used by (at least) row-to-object
converter */;
for(; stmt.step(); stmt._lockedByExec = false){ for(; stmt.step(); stmt._lockedByExec = false){
if(0===gotColNames++) stmt.getColumnNames(opt.columnNames); if(0===gotColNames++){
stmt.getColumnNames(cbArgCache.columnNames = (opt.columnNames || []));
}
stmt._lockedByExec = true; stmt._lockedByExec = true;
const row = arg.cbArg(stmt); const row = arg.cbArg(stmt,cbArgCache);
if(resultRows) resultRows.push(row); if(resultRows) resultRows.push(row);
if(callback && false === callback.call(opt, row, stmt)){ if(callback && false === callback.call(opt, row, stmt)){
break; break;

View File

@@ -1272,7 +1272,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return poolUtil; return poolUtil;
}).catch(async (e)=>{ }).catch(async (e)=>{
await thePool.removeVfs().catch(()=>{}); await thePool.removeVfs().catch(()=>{});
return e; throw e;
}); });
}).catch((err)=>{ }).catch((err)=>{
//error("rejecting promise:",err); //error("rejecting promise:",err);

View File

@@ -1,5 +1,5 @@
C Merge\sall\srecent\strunk\senhancements\sinto\sthe\sreuse-schema\sbranch. C Merge\sall\srecent\strunk\senhancements\sinto\sthe\sreuse-schema\sbranch.
D 2024-03-26T10:48:32.013 D 2024-04-05T15:04:01.063
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -93,7 +93,7 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6dbd6348ef0cfc324a7 F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6dbd6348ef0cfc324a7
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl bc3a0ca78be7d3df08e7602c00ca48021ebae40682d75eb001bfdf6e54ffb44e F ext/fts5/extract_api_docs.tcl bc3a0ca78be7d3df08e7602c00ca48021ebae40682d75eb001bfdf6e54ffb44e
F ext/fts5/fts5.h ecba24fed7b359b3a53016bb07e411b3b4c9cdf163aa141006536423a63b611e F ext/fts5/fts5.h 8856e11a5f0269cd346754cea0765efe8089635b80cad3222e8bfdb08cd5348a
F ext/fts5/fts5Int.h defa43c0932265138ee910ca416e6baccf8b774e0f3d610e74be1ab2880e9834 F ext/fts5/fts5Int.h defa43c0932265138ee910ca416e6baccf8b774e0f3d610e74be1ab2880e9834
F ext/fts5/fts5_aux.c 4584e88878e54828bf7d4d0d83deedd232ec60628b7731be02bad6adb62304b1 F ext/fts5/fts5_aux.c 4584e88878e54828bf7d4d0d83deedd232ec60628b7731be02bad6adb62304b1
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09 F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
@@ -249,7 +249,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
F ext/fts5/tool/mkfts5c.tcl 3eba8e9bee4221ed165f3304b51b2a74a705f4ec5df3d044573a2be539534af8 F ext/fts5/tool/mkfts5c.tcl 3eba8e9bee4221ed165f3304b51b2a74a705f4ec5df3d044573a2be539534af8
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/icu.c 5c858611fd11d65caf8a04acd836af9193880a724ba75cee63f9da75ce4a469d
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/intck/intck1.test f3a3cba14b6aeff145ffa5515546dd22f7510dad91512e519f43b92b56514012 F ext/intck/intck1.test f3a3cba14b6aeff145ffa5515546dd22f7510dad91512e519f43b92b56514012
F ext/intck/intck2.test d2457c7e5e5b688046d15ebe08a1e1427cc5e7a6dc8d6af215f42e8bcaf67304 F ext/intck/intck2.test d2457c7e5e5b688046d15ebe08a1e1427cc5e7a6dc8d6af215f42e8bcaf67304
@@ -607,13 +607,13 @@ F ext/wasm/api/post-js-header.js 04dc12c3edd666b64a1b4ef3b6690c88dcc653f26451fd4
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219 F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
F ext/wasm/api/sqlite3-api-glue.js 2d35660c52dcb4bb16d00c56553d34e7caa6ad30083938b515e6f9aa0b312fbb F ext/wasm/api/sqlite3-api-glue.js 2d35660c52dcb4bb16d00c56553d34e7caa6ad30083938b515e6f9aa0b312fbb
F ext/wasm/api/sqlite3-api-oo1.js 7f3bcf0549ac44cde4b9da0b642d771916738d3f6781fb8a1757c50a91e506c0 F ext/wasm/api/sqlite3-api-oo1.js 365b3ae01a461dc974796823652ef1ecb1a9fac5df295ee1a78002cc77afb0d8
F ext/wasm/api/sqlite3-api-prologue.js 93a72b07b2a5d964d2edc76a90b439ece49298bd7ba60a1c6ae5d4878213701e F ext/wasm/api/sqlite3-api-prologue.js 93a72b07b2a5d964d2edc76a90b439ece49298bd7ba60a1c6ae5d4878213701e
F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b5985e309b69bf71187b525cf F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b5985e309b69bf71187b525cf
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 196ad83d36ca794e564044788c9d21b964679d63cad865f604da37c4afc9a285 F ext/wasm/api/sqlite3-opfs-async-proxy.js 196ad83d36ca794e564044788c9d21b964679d63cad865f604da37c4afc9a285
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 5a430874906ff3f4a6ca69aadf0c2aaedc1bb45489b8365bff7e955a83a8d42a F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 8433ee332d5f5e39fb19427fccb7bad7f44aa99b5504daad3343fc128c311e78
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3c72f1a0e6a7343c8c882d29d01bb440f10be12c844651605b486e76f3d6cc8c F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3c72f1a0e6a7343c8c882d29d01bb440f10be12c844651605b486e76f3d6cc8c
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js a2fcbc3fecdd0eea229283584ebc122f29d98194083675dbe5cb2cf3a17fe309 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js a2fcbc3fecdd0eea229283584ebc122f29d98194083675dbe5cb2cf3a17fe309
F ext/wasm/api/sqlite3-wasm.c afba6827a49151b564af5cf588a6bbd0401b16ef5cbe3269c66f676fee9ca92c F ext/wasm/api/sqlite3-wasm.c afba6827a49151b564af5cf588a6bbd0401b16ef5cbe3269c66f676fee9ca92c
@@ -683,7 +683,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2 F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
F src/alter.c 47253323822cc2ad54d5fe5695db683fae2f904242e9df55a1bc5406b1293e3a F src/alter.c 8fd1f87dbf8b49f4e037817640d62d5e28661ad194d68fa10455fe5aada79ee9
F src/analyze.c d4147664724ed16e86e974e1714f893105a8d124bad3acebd30a3c0051553f50 F src/analyze.c d4147664724ed16e86e974e1714f893105a8d124bad3acebd30a3c0051553f50
F src/attach.c 2af98700f1a3867a78475aa164571a2fbacce09c681076b01b119ef31b8ef4ac F src/attach.c 2af98700f1a3867a78475aa164571a2fbacce09c681076b01b119ef31b8ef4ac
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4 F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
@@ -753,10 +753,10 @@ F src/resolve.c eb1860b134fb044fd819c4347105c148d5aac7c6498032be2829e5cc95619b28
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 15a221347789e393b39e7d2d2bd102167979c95a1ce0675bb870b86a24ca6cf4 F src/select.c 15a221347789e393b39e7d2d2bd102167979c95a1ce0675bb870b86a24ca6cf4
F src/shell.c.in 95d92c0162bcfea8a9d9610acbd8a0a861c5e24c15272c957acbe4f39382ddae F src/shell.c.in 95d92c0162bcfea8a9d9610acbd8a0a861c5e24c15272c957acbe4f39382ddae
F src/sqlite.h.in f0f8f0d2a73dd926f41e38bd44fcfac313a40f91373eced4f96333c6c2d4bec3 F src/sqlite.h.in 6a187bd8f031cdf4045d13f3b6bc5675183dc2eb826b08404d2c540bfa40e28f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 13c2178e80eb068397dffe6ae659cbc95af34ee69ceeeca0ad709615796db471 F src/sqliteInt.h f02109c375e41bc0df376ac16502e0127099aec4c43224380e8cc5ca9cd86854
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728 F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c 5028a0afee355aa492f26f0b6a3ec23145caa9261a93164d96cd0b9bf1b2318f F src/status.c 5028a0afee355aa492f26f0b6a3ec23145caa9261a93164d96cd0b9bf1b2318f
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -772,7 +772,7 @@ F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871 F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0 F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
F src/test_bestindex.c f6af1e41cb7901edafb065a8198e4a0192dd42432b642d038965be5e628dec12 F src/test_bestindex.c 1ee3d64b49ca06a9cb8195fab04f1a0585cafc90d25a2a817caa14e7caab22e7
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274 F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c 7f2b70b7259fb9f6418a6d266a035acf24842e3528745a2bed4dd252bddf1a32 F src/test_config.c 7f2b70b7259fb9f6418a6d266a035acf24842e3528745a2bed4dd252bddf1a32
@@ -817,7 +817,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68 F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
F src/trigger.c fce5a48596e30c9517357f533b5726120906e446e9d0ddaa180c8c60b9e14c01 F src/trigger.c fce5a48596e30c9517357f533b5726120906e446e9d0ddaa180c8c60b9e14c01
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92 F src/update.c 732404a04d1737ef14bb6ec6b84f74edf28b3c102a92ae46b4855438a710efe7
F src/upsert.c 2e60567a0e9e8520c18671b30712a88dc73534474304af94f32bb5f3ef65ac65 F src/upsert.c 2e60567a0e9e8520c18671b30712a88dc73534474304af94f32bb5f3ef65ac65
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
F src/util.c 4d6d7ebfe6772a1b950c97bbb1d1a72ad4874617ec498ab8aa73b7f5a43e44bb F src/util.c 4d6d7ebfe6772a1b950c97bbb1d1a72ad4874617ec498ab8aa73b7f5a43e44bb
@@ -837,7 +837,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
F src/where.c 203c385e42ac53642bf54c7a5d99d289fa4e0b2fef2763f6365656a6dfaf551d F src/where.c aa2f7b6cffc918e078e0187ab9e1c208b2878f682f37d09e3ef441f535336563
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435 F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435
@@ -869,7 +869,7 @@ F test/altermalloc3.test 8040e486368403f2fdd6fc3998258b499bd4cc2f3ddbb5f8f874cd4
F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27 F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0 F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
F test/altertab3.test e167ce3b8e243b52306c1e40b13eb868f402a969513c063998593862cc643b44 F test/altertab3.test b331ae34e69594e19605e3297805202d6156fcc8f75379dfd972a2e51cae8721
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
@@ -1059,7 +1059,7 @@ F test/dbpagefault.test 35f06cfb2ef100a9b19d25754e8141b9cba9b7daabd4c60fa5af93fc
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759 F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
F test/decimal.test ef731887b43ee32ef86e1c8fddb61a40789f988332c029c601dcf2c319277e9e F test/decimal.test ef731887b43ee32ef86e1c8fddb61a40789f988332c029c601dcf2c319277e9e
F test/default.test 830fad7180cdf0e6a06e93acc0403bf73762314a639363314db5674c631b6127 F test/default.test c7124864cded213a3f118bc7e2e26f34b7c36dfa26cf6945cc8b7f5db1191277
F test/delete.test 2686e1c98d552ef37d79ad55b17b93fe96fad9737786917ce3839767f734c48f F test/delete.test 2686e1c98d552ef37d79ad55b17b93fe96fad9737786917ce3839767f734c48f
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
@@ -1269,7 +1269,7 @@ F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711 F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
F test/hook.test 18cae9140fa7f9a6f346e892a3fe3e31b2ca0be1494cd01b918adb74281016a6 F test/hook.test 18cae9140fa7f9a6f346e892a3fe3e31b2ca0be1494cd01b918adb74281016a6
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1 F test/icu.test 8da7d52cd9722c82f33b0466ed915460cb03c23a38f18a9a2d3ff97da9a4a8c0
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6 F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6
@@ -1340,7 +1340,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28 F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
F test/joinH.test d5054173442fdf98260eeb6bb9751daa733b0ae6842fe50dcbd5469945b86985 F test/joinH.test 55f69e64da74d4eca2235237f3acb657aef181e22e45daa228e35bba865e0255
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
@@ -1961,7 +1961,7 @@ F test/vtabH.test 2efb5a24b0bb50796b21eca23032cfb77abfa4b0c03938e38ce5897abac404
F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f
F test/vtabJ.test a6aef49d558af90fae10565b29501f82a95781cb4f797f2d13e2d19f9b6bc77b F test/vtabJ.test a6aef49d558af90fae10565b29501f82a95781cb4f797f2d13e2d19f9b6bc77b
F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3afbf F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3afbf
F test/vtabL.test 040b9f782a3b41844f2a5c660e6a0bfd298492980c6b4e126d82113c9785cec3 F test/vtabL.test 49ec7342e8bfcb0d6c3d2443c619f430c609c042d5d7e6ddf52def65d6d1812f
F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783 F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
@@ -2027,6 +2027,7 @@ F test/whereJ.test fc05e374cc9f2dc204148d6c06822c380ad388895fe97a6d335b94a26a08a
F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a
F test/whereL.test 438a397fa883b77bb6361c08a8befa41b52e9cfbe15a2a43715d122f8cfa8649 F test/whereL.test 438a397fa883b77bb6361c08a8befa41b52e9cfbe15a2a43715d122f8cfa8649
F test/whereM.test 0dbc9998783458ddcf3cc078ca7c2951d8b2677d472ecf0028f449ed327c0250 F test/whereM.test 0dbc9998783458ddcf3cc078ca7c2951d8b2677d472ecf0028f449ed327c0250
F test/whereN.test 63a3584b71acfb6963416de82f26c6b1644abc5ca6080c76546b9246734c8803
F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7 F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
F test/wherelimit.test afb46397c6d7e964e6e294ba3569864a0c570fe3807afc634236c2b752372f31 F test/wherelimit.test afb46397c6d7e964e6e294ba3569864a0c570fe3807afc634236c2b752372f31
@@ -2193,8 +2194,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P c2d4adabb929b6088808b05a2f031d045eb4839b44548a66006dc21e358e71f4 6a06dc73847716c88d65651d1bf0e002002303881df1389beac884d0032eae08 P e469b02205a4f3923c93ec9c4825045aba1cc9e053d6e341efaa850993bc155e 4484ec6d26b31305e31de89bdbae26344d8083a7e7de20861430d31737d9979c
R 3b0652db047bafda6f9442911e1fb947 R f4dbba28f9c4664c8d96ddb5bc531b37
U drh U drh
Z 2f230d22a67b67fa1a728aa4b3497b01 Z ff6215cb807d646da0d3d7fb004c0cec
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
e469b02205a4f3923c93ec9c4825045aba1cc9e053d6e341efaa850993bc155e e556f3d3819134022f72e72471976616700c4fe00fc924bfbe713a6132440fdf

View File

@@ -2262,7 +2262,12 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){
if( i==pTab->iPKey ){ if( i==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); sqlite3VdbeAddOp2(v, OP_Null, 0, regOut);
}else{ }else{
char aff = pTab->aCol[i].affinity;
if( aff==SQLITE_AFF_REAL ){
pTab->aCol[i].affinity = SQLITE_AFF_NUMERIC;
}
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
pTab->aCol[i].affinity = aff;
} }
nField++; nField++;
} }

View File

@@ -6888,6 +6888,12 @@ int sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future ** The exceptions defined in this paragraph might change in a future
** release of SQLite. ** release of SQLite.
** **
** Whether the update hook is invoked before or after the
** corresponding change is currently unspecified and may differ
** depending on the type of change. Do not rely on the order of the
** hook call with regards to the final result of the operation which
** triggers the hook.
**
** The update hook implementation must not do anything that will modify ** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions ** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the ** to modify the database connection must be deferred until after the
@@ -8358,7 +8364,7 @@ int sqlite3_test_control(int op, ...);
** The sqlite3_keyword_count() interface returns the number of distinct ** The sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite. ** keywords understood by SQLite.
** **
** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and ** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number ** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not ** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns

View File

@@ -1156,7 +1156,7 @@ extern u32 sqlite3WhereTrace;
** 0x00000010 Display sqlite3_index_info xBestIndex calls ** 0x00000010 Display sqlite3_index_info xBestIndex calls
** 0x00000020 Range an equality scan metrics ** 0x00000020 Range an equality scan metrics
** 0x00000040 IN operator decisions ** 0x00000040 IN operator decisions
** 0x00000080 WhereLoop cost adjustements ** 0x00000080 WhereLoop cost adjustments
** 0x00000100 ** 0x00000100
** 0x00000200 Covering index decisions ** 0x00000200 Covering index decisions
** 0x00000400 OR optimization ** 0x00000400 OR optimization

View File

@@ -226,7 +226,7 @@ static int tclConnect(
} }
sqlite3_free(zCmd); sqlite3_free(zCmd);
*ppVtab = &pTab->base; *ppVtab = pTab ? &pTab->base : 0;
return rc; return rc;
} }

View File

@@ -921,6 +921,9 @@ void sqlite3Update(
} }
} }
if( chngRowid==0 && pPk==0 ){ if( chngRowid==0 && pPk==0 ){
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
if( isView ) sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
#endif
sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
} }
} }

View File

@@ -3252,10 +3252,13 @@ static int whereLoopAddBtreeIndex(
} }
} }
/* Set rCostIdx to the cost of visiting selected rows in index. Add /* Set rCostIdx to the estimated cost of visiting selected rows in the
** it to pNew->rRun, which is currently set to the cost of the index ** index. The estimate is the sum of two values:
** seek only. Then, if this is a non-covering index, add the cost of ** 1. The cost of doing one search-by-key to find the first matching
** visiting the rows in the main table. */ ** entry
** 2. Stepping forward in the index pNew->nOut times to find all
** additional matching entries.
*/
assert( pSrc->pTab->szTabRow>0 ); assert( pSrc->pTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior /* The pProbe->szIdxRow is low for an IPK table since the interior
@@ -3266,7 +3269,15 @@ static int whereLoopAddBtreeIndex(
}else{ }else{
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
} }
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
/* Estimate the cost of running the loop. If all data is coming
** from the index, then this is just the cost of doing the index
** lookup and scan. But if some data is coming out of the main table,
** we also have to add in the cost of doing pNew->nOut searches to
** locate the row in the main table that corresponds to the index entry.
*/
pNew->rRun = rCostIdx;
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){ if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
} }
@@ -5519,7 +5530,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
} }
} }
pWInfo->nRowOut = pFrom->nRow; pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */ /* Free temporary memory and return success */
@@ -5527,6 +5537,83 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** This routine implements a heuristic designed to improve query planning.
** This routine is called in between the first and second call to
** wherePathSolver(). Hence the name "Interstage" "Heuristic".
**
** The first call to wherePathSolver() (hereafter just "solver()") computes
** the best path without regard to the order of the outputs. The second call
** to the solver() builds upon the first call to try to find an alternative
** path that satisfies the ORDER BY clause.
**
** This routine looks at the results of the first solver() run, and for
** every FROM clause term in the resulting query plan that uses an equality
** constraint against an index, disable other WhereLoops for that same
** FROM clause term that would try to do a full-table scan. This prevents
** an index search from being converted into a full-table scan in order to
** satisfy an ORDER BY clause, since even though we might get slightly better
** performance using the full-scan without sorting if the output size
** estimates are very precise, we might also get severe performance
** degradation using the full-scan if the output size estimate is too large.
** It is better to err on the side of caution.
**
** Except, if the first solver() call generated a full-table scan in an outer
** loop then stop this analysis at the first full-scan, since the second
** solver() run might try to swap that full-scan for another in order to
** get the output into the correct order. In other words, we allow a
** rewrite like this:
**
** First Solver() Second Solver()
** |-- SCAN t1 |-- SCAN t2
** |-- SEARCH t2 `-- SEARCH t1
** `-- SORT USING B-TREE
**
** The purpose of this routine is to disallow rewrites such as:
**
** First Solver() Second Solver()
** |-- SEARCH t1 |-- SCAN t2 <--- bad!
** |-- SEARCH t2 `-- SEARCH t1
** `-- SORT USING B-TREE
**
** See test cases in test/whereN.test for the real-world query that
** originally provoked this heuristic.
*/
static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){
int i;
#ifdef WHERETRACE_ENABLED
int once = 0;
#endif
for(i=0; i<pWInfo->nLevel; i++){
WhereLoop *p = pWInfo->a[i].pWLoop;
if( p==0 ) break;
if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue;
if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){
u8 iTab = p->iTab;
WhereLoop *pLoop;
for(pLoop=pWInfo->pLoops; pLoop; pLoop=pLoop->pNextLoop){
if( pLoop->iTab!=iTab ) continue;
if( (pLoop->wsFlags & (WHERE_CONSTRAINT|WHERE_AUTO_INDEX))!=0 ){
/* Auto-index and index-constrained loops allowed to remain */
continue;
}
#ifdef WHERETRACE_ENABLED
if( sqlite3WhereTrace & 0x80 ){
if( once==0 ){
sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n");
once = 1;
}
sqlite3WhereLoopPrint(pLoop, &pWInfo->sWC);
}
#endif /* WHERETRACE_ENABLED */
pLoop->prereq = ALLBITS; /* Prevent 2nd solver() from using this one */
}
}else{
break;
}
}
}
/* /*
** Most queries use only a single table (they are not joins) and have ** Most queries use only a single table (they are not joins) and have
** simple == constraints against indexed fields. This routine attempts ** simple == constraints against indexed fields. This routine attempts
@@ -5861,16 +5948,10 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
Expr *pExpr; Expr *pExpr;
int j = pIdx->aiColumn[i]; int j = pIdx->aiColumn[i];
int bMaybeNullRow;
if( j==XN_EXPR ){ if( j==XN_EXPR ){
pExpr = pIdx->aColExpr->a[i].pExpr; pExpr = pIdx->aColExpr->a[i].pExpr;
testcase( pTabItem->fg.jointype & JT_LEFT );
testcase( pTabItem->fg.jointype & JT_RIGHT );
testcase( pTabItem->fg.jointype & JT_LTORJ );
bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
}else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){ }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]); pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
bMaybeNullRow = 0;
}else{ }else{
continue; continue;
} }
@@ -5902,7 +5983,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
p->iDataCur = pTabItem->iCursor; p->iDataCur = pTabItem->iCursor;
p->iIdxCur = iIdxCur; p->iIdxCur = iIdxCur;
p->iIdxCol = i; p->iIdxCol = i;
p->bMaybeNullRow = bMaybeNullRow; p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){
p->aff = pIdx->zColAff[i]; p->aff = pIdx->zColAff[i];
} }
@@ -6309,6 +6390,7 @@ WhereInfo *sqlite3WhereBegin(
wherePathSolver(pWInfo, 0); wherePathSolver(pWInfo, 0);
if( db->mallocFailed ) goto whereBeginError; if( db->mallocFailed ) goto whereBeginError;
if( pWInfo->pOrderBy ){ if( pWInfo->pOrderBy ){
whereInterstageHeuristic(pWInfo);
wherePathSolver(pWInfo, pWInfo->nRowOut+1); wherePathSolver(pWInfo, pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError; if( db->mallocFailed ) goto whereBeginError;
} }

View File

@@ -763,4 +763,27 @@ do_execsql_test 30.2 {
)} )}
} }
#-------------------------------------------------------------------------
reset_db
do_execsql_test 31.0 {
CREATE TABLE t1(ii INTEGER PRIMARY KEY, tt INTEGER, rr REAL);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000
)
INSERT INTO t1 SELECT NULL, i, 5.0 FROM s;
}
do_test 31.1 {
set pg [db one {PRAGMA page_count}]
execsql {
ALTER TABLE t1 DROP COLUMN tt;
}
set pg2 [db one {PRAGMA page_count}]
expr $pg==$pg2
} {1}
do_execsql_test 31.2 {
SELECT rr FROM t1 LIMIT 1
} {5.0}
finish_test finish_test

View File

@@ -135,10 +135,10 @@ reset_db
do_catchsql_test default-5.1 { do_catchsql_test default-5.1 {
CREATE TABLE t1 (a,b DEFAULT(random() NOTNULL IN (RAISE(IGNORE),2,3))); CREATE TABLE t1 (a,b DEFAULT(random() NOTNULL IN (RAISE(IGNORE),2,3)));
INSERT INTO t1(a) VALUES(1); INSERT INTO t1(a) VALUES(1);
} {1 {RAISE() may only be used within a trigger-program}} } {1 {default value of column [b] is not constant}}
do_catchsql_test default-5.2 { do_catchsql_test default-5.2 {
CREATE TABLE Table0 (Col0 DEFAULT (RAISE(IGNORE) ) ) ; CREATE TABLE Table0 (Col0 DEFAULT (RAISE(IGNORE) ) ) ;
INSERT INTO Table0 DEFAULT VALUES ; INSERT INTO Table0 DEFAULT VALUES ;
} {1 {RAISE() may only be used within a trigger-program}} } {1 {default value of column [Col0] is not constant}}
finish_test finish_test

View File

@@ -149,7 +149,7 @@ ifcapable icu {
# 2020-03-19 # 2020-03-19
# The ESCAPE clause on LIKE takes precedence over wildcards # The ESCAPE clause on LIKE takes precedence over wildcards
# #
do_execsql_test idu-6.0 { do_execsql_test icu-6.0 {
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
CREATE TABLE t1(id INTEGER PRIMARY KEY, x TEXT); CREATE TABLE t1(id INTEGER PRIMARY KEY, x TEXT);
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
@@ -164,4 +164,20 @@ do_execsql_test icu-6.1 {
SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_'; SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_';
} {2} } {2}
# 2024-04-02
# Optional 3rd argument to icu_load_collation() that specifies
# the "strength" of comparison.
#
reset_db
do_catchsql_test icu-7.1 {
SELECT icu_load_collation('en_US','error','xyzzy');
} {1 {unknown collation strength "xyzzy" - should be one of: PRIMARY SECONDARY TERTIARY DEFAULT QUARTERNARY IDENTICAL}}
do_execsql_test icu-7.2 {
SELECT icu_load_collation('en_US','prim','PRIMARY'),
icu_load_collation('en_US','dflt','DEFAULT');
} {{} {}}
do_execsql_test icu-7.3 {
SELECT char(0x100)=='a', char(0x100)=='a' COLLATE dflt, char(0x100)=='a' COLLATE prim;
} {0 0 1}
finish_test finish_test

View File

@@ -309,4 +309,36 @@ do_execsql_test 12.3 {
SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1; SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1;
} }
#-------------------------------------------------------------------------
# 2024-04-05 dbsqlfuzz b9e65e2f110df998f1306571fae7af6c01e4d92b
reset_db
do_execsql_test 13.1 {
CREATE TABLE t1(a INT AS (b), b INT);
INSERT INTO t1(b) VALUES(123);
CREATE TABLE t2(a INT, c INT);
SELECT a FROM t2 NATURAL RIGHT JOIN t1;
} {123}
do_execsql_test 13.2 {
CREATE INDEX t1a ON t1(a);
SELECT a FROM t2 NATURAL RIGHT JOIN t1;
} {123}
# Further tests of the same logic (indexes on expressions
# used by RIGHT JOIN) from check-in ffe23af73fcb324d and
# forum post https://sqlite.org/forum/forumpost/9b491e1debf0b67a.
db null NULL
do_execsql_test 13.3 {
CREATE TABLE t3(a INT, b INT);
CREATE UNIQUE INDEX t3x ON t3(a, a+b);
INSERT INTO t3(a,b) VALUES(1,2),(4,8),(16,32),(4,80),(1,-300);
CREATE TABLE t4(x INT, y INT);
INSERT INTO t4(x,y) SELECT a, b FROM t3;
INSERT INTO t4(x,y) VALUES(99,99);
SELECT a1.a, sum( a1.a+a1.b ) FROM t3 AS a1 RIGHT JOIN t4 ON a=x
GROUP BY a1.a ORDER BY 1;
} {NULL NULL 1 -592 4 192 16 48}
do_execsql_test 13.4 {
SELECT sum( a1.a+a1.b ) FROM t3 AS a1 RIGHT JOIN t3 ON true
GROUP BY a1.a ORDER BY 1;
} {-1480 240 480}
finish_test finish_test

View File

@@ -31,10 +31,7 @@ proc vtab_command {method args} {
return {} return {}
} }
do_execsql_test 1.0 { breakpoint
CREATE TABLE t1(a, b);
}
foreach {tn cts} { foreach {tn cts} {
1 {SELECT 123} 1 {SELECT 123}
2 {SELECT 123, 456} 2 {SELECT 123, 456}
@@ -44,6 +41,8 @@ foreach {tn cts} {
6 {DROP TABLE nosuchtable} 6 {DROP TABLE nosuchtable}
7 {DROP TABLE x1} 7 {DROP TABLE x1}
8 {DROP TABLE t1} 8 {DROP TABLE t1}
9 {CREATE TABLE xyz AS SELECT * FROM sqlite_schema}
10 {CREATE TABLE xyz AS SELECT 1 AS 'col'}
} { } {
set ::create_table_sql $cts set ::create_table_sql $cts
do_catchsql_test 1.$tn { do_catchsql_test 1.$tn {
@@ -51,5 +50,19 @@ foreach {tn cts} {
} {1 {vtable constructor failed: x1}} } {1 {vtable constructor failed: x1}}
} }
foreach {tn cts} {
1 {CREATE TABLE IF NOT EXISTS t1(a, b)}
2 {CREATE TABLE ""(a, b PRIMARY KEY) WITHOUT ROWID}
} {
set ::create_table_sql $cts
execsql { DROP TABLE IF EXISTS x1 }
do_execsql_test 2.$tn.1 {
CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
}
do_execsql_test 2.$tn.2 {
SELECT a, b FROM x1
}
}
finish_test finish_test

103
test/whereN.test Normal file
View File

@@ -0,0 +1,103 @@
# 2024-04-02
#
# 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.
#
#***********************************************************************
# Tests for the whereInterstageHeuristic() routine in the query planner.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix whereN
# The following is a simplified and "sanitized" version of the original
# real-world query that brought the problem to light.
#
# The issue is a slow query. The answer is correct, but it was taking too
# much time, because it was doing a full table scan rather than an indexed
# lookup.
#
# The problem was that the query planner was overestimating the number of
# output rows. The estimated number of output rows is accurate if the
# DSNAME parameter is "ds-one". In that case, a large fraction of the rows
# in "violation" end up being output. The query planner correctly deduces
# that it is faster to do a full table scan of the large "violation" table
# to avoid the after-query sort that implements the ORDER BY clause. However,
# if the DSNAME is "ds-two", then only a few rows (about 6) are generated,
# and it is much much faster to do an indexed lookup of "violation" followed
# by a sort operation to implement ORDER BY
#
# The problem, of course, is that the query planner has no way of knowing
# in advance how many rows will be generated. The query planner tries to
# estimate a worst case, which is a large number of output rows, and it picks
# the best plan for that case. However, the plan choosen is very inefficient
# when the number of output rows is small.
#
# The whereInterstageHeuristic() routine in the query planner attempts to
# correct this by adjusting the query plan such that it avoids the very bad
# query plan for a small number of rows, at the expense of a slightly less
# efficient plan for a large number of rows. The large number of rows case
# is perhaps 5% slower with the revised plan, but the small number of
# rows case is around 100 times faster. That seems like a good tradeoff.
#
do_execsql_test 1.0 {
CREATE TABLE datasource(dsid INT, name TEXT);
INSERT INTO datasource VALUES(1,'ds-one'),(2,'ds-two'),(3,'ds-three');
CREATE INDEX ds1 ON datasource(name, dsid);
CREATE TABLE rule(rid INT, team_id INT, dsid INT);
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<9)
INSERT INTO rule(rid,team_id,dsid) SELECT n, 1, 1 FROM c;
WITH RECURSIVE c(n) AS (VALUES(10) UNION ALL SELECT n+1 FROM c WHERE n<24)
INSERT INTO rule(rid,team_id,dsid) SELECT n, 2, 2 FROM c;
CREATE INDEX rule2 ON rule(dsid, rid);
CREATE TABLE violation(vid INT, rid INT, vx BLOB);
/*** Uncomment to insert actual data
WITH src(rid, cnt) AS (VALUES(1,3586),(2,1343),(3,6505),(5,76230),
(6,740),(7,287794),(8,457),(12,1),
(14,1),(16,1),(17,1),(18,1),(19,1))
INSERT INTO violation(vid, rid, vx)
SELECT rid*1000000+value, rid, randomblob(15)
FROM src, generate_series(1,cnt);
***/
CREATE INDEX v1 ON violation(rid, vid);
CREATE INDEX v2 ON violation(vid);
ANALYZE;
DELETE FROM sqlite_stat1;
DROP TABLE IF EXISTS sqlite_stat4;
INSERT INTO sqlite_stat1 VALUES
('violation','v2','376661 1'),
('violation','v1','376661 28974 1'),
('rule','rule2','24 12 1'),
('datasource','ds1','3 1 1');
ANALYZE sqlite_schema;
}
set DSNAME ds-two ;# Only a few rows. Change to "ds-one" for many rows.
do_eqp_test 1.1 {
SELECT count(*), length(group_concat(vx)) FROM (
SELECT V.*
FROM datasource DS, rule R, violation V
WHERE V.rid=R.rid
AND R.dsid=DS.dsid
AND DS.name=$DSNAME
ORDER BY V.vid desc
);
} {
QUERY PLAN
|--CO-ROUTINE (subquery-xxxxxx)
| |--SEARCH DS USING COVERING INDEX ds1 (name=?)
| |--SEARCH R USING COVERING INDEX rule2 (dsid=?)
| |--SEARCH V USING INDEX v1 (rid=?)
| `--USE TEMP B-TREE FOR ORDER BY
`--SCAN (subquery-xxxxxx)
}
# ^^^^---- We want to see three SEARCH terms. No SCAN terms.
# The ORDER BY is implemented by a separate sorter pass.
finish_test