From: drh <> Date: Mon, 1 Jan 2024 14:13:59 +0000 (+0000) Subject: Omit the uneven=N argument in sqlite_stat1 and replace it with var=N1,N2,... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=47d1f2759e1c2aca16d5bc4e1b4ca4777e9ff5e9;p=thirdparty%2Fsqlite.git Omit the uneven=N argument in sqlite_stat1 and replace it with var=N1,N2,... so that the variation in each column is reported separately. Omit the "slow" argument from sqlite_stat1, computing that flag internally. PRAGMA stats is enhanced with a new column "est" that shows the aiRowLogEst array for each index after it has been modified by "var=..." and also the "slow" flag. FossilOrigin-Name: 4a8fc17365ccd989cc8050179ac586ca246698c71a64d7209786fb5569ba583a --- diff --git a/manifest b/manifest index 74e81be18d..ff2187a38c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Better\scomments.\s\sSlight\stuning\sof\sparameters. -D 2023-12-31T20:04:32.564 +C Omit\sthe\suneven=N\sargument\sin\ssqlite_stat1\sand\sreplace\sit\swith\svar=N1,N2,...\nso\sthat\sthe\svariation\sin\seach\scolumn\sis\sreported\sseparately.\s\sOmit\sthe\s"slow"\nargument\sfrom\ssqlite_stat1,\scomputing\sthat\sflag\sinternally.\s\sPRAGMA\sstats\sis\nenhanced\swith\sa\snew\scolumn\s"est"\sthat\sshows\sthe\saiRowLogEst\sarray\sfor\seach\nindex\safter\sit\shas\sbeen\smodified\sby\s"var=..."\sand\salso\sthe\s"slow"\sflag. +D 2024-01-01T14:13:59.212 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -670,7 +670,7 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2 F src/alter.c 30c2333b8bb3af71e4eb9adeadee8aa20edb15917ed44b8422e5cd15f3dfcddc -F src/analyze.c 47711a594b1e9784164d32715725f01bdb9fed52fd6cfaa2432730e8c3c2b746 +F src/analyze.c 15eef780c7263f1f5a6b00bc6f2c92a4ac5261b7be95e6ef00263d6c461a5e87 F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39 F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4 F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523 @@ -730,8 +730,8 @@ F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00 -F src/pragma.c b5b4cff830575e6188cd56a295a57448d2b9dbc53f0dae58e22b97354cda3781 -F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 +F src/pragma.c 4b33fdfd0198481f74fa52c91c4583631fbec41615c989fd0fcc51204d9a8450 +F src/pragma.h f95996cd3ab16a1b04b59a70df92d7e4ced1dfd70f18553bb639838d4208b31e F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c @@ -2082,7 +2082,7 @@ F tool/mkmsvcmin.tcl 8897d515ef7f94772322db95a3b6fce6c614d84fe0bdd06ba5a1c786351 F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef F tool/mkopcodeh.tcl 769d9e6a8b462323150dc13a8539d6064664b72974f7894befe2491cc73e05cd F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl 32e359ccb21011958a821955254bd7a5fa7915d01a8c16fed91ffc8b40cb4adf +F tool/mkpragmatab.tcl d014814d2a03f9191d00182c2fb5652f20b3744433eafed128b5192877f310ee F tool/mkshellc.tcl b7adf08b82de60811d2cb6af05ff59fc17e5cd6f3e98743c14eaaa3f8971fed0 F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -2156,8 +2156,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c216921b115169ebfd239267b4ab5ad0fc960ffadce09044b68812f49110d607 -R df3f6be38a64508c745873953ba288dd +P 1cc32eccda8d126264c644df72e308e25c1e41cf4fb68c2f1b6d6d98cbc23ca5 +R 19a9761f2b89c57ab0cba5358f19e101 U drh -Z 151bd3600feff84e5eb2b344bddccb6f +Z 02e04e5291abe3d83162489e3488139a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8594bab577..ddf57a98dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1cc32eccda8d126264c644df72e308e25c1e41cf4fb68c2f1b6d6d98cbc23ca5 \ No newline at end of file +4a8fc17365ccd989cc8050179ac586ca246698c71a64d7209786fb5569ba583a \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 968f162adf..8788d5c804 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -865,7 +865,7 @@ static void statGet( */ sqlite3_str sStat; /* Text of the constructed "stat" line */ int i; /* Loop counter */ - int iUneven = 1; /* max/avg */ + int bUneven = 0; /* True if the uneven=... argument is needed */ u64 nRow; /* Number of rows in the index */ sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); @@ -881,15 +881,16 @@ static void statGet( ** estimated number of rows in the index. */ iVal = p->nEst; }else if( iValnRow*10 <= nDistinct*11 ){ /* If the value is less than or equal to 1.1, round it down to 1.0 */ iVal = 1; @@ -897,29 +898,18 @@ static void statGet( sqlite3_str_appendf(&sStat, " %llu", iVal); assert( p->current.anEq[i] ); - /* Add the "slow" argument if the peak number of rows obtained - ** from a full equality match is so large that a full table scan - ** seems likely to be faster than using the index. The query planner - ** will use the "slow" argument as a hint to avoid using this index - ** for equality lookups. - ** - ** We let ANALYZE determine "slow" rather than the query planner for - ** two reasons: (1) It leaves a visible trace in the sqlite_stat1 table - ** that an index is not useful, and hence serves as a hint to the - ** application developers that the index is a good candidate to be - ** dropped. (2) Being able to use UPDATE to control the presence or - ** absence of the "slow" argument in sqlite_stat1 enables greater - ** control over the query planner during testing. - */ - if( i==p->nKeyCol-1 - && nRow > 1000 && nRow <= iVal*iUneven + sqlite3LogEst(nRow) - 6 - /* ^^^^------------- TUNING ----------------------------^ */ - ){ - sqlite3_str_appendf(&sStat, " slow"); - } } - if( iUneven>1 ){ - sqlite3_str_appendf(&sStat, " uneven=%d", iUneven); + if( bUneven ){ + char cSep = '='; + sqlite3_str_appendf(&sStat, " var"); + for(i=0; inKeyCol; i++){ + u64 nDistinct = p->current.anDLt[i] + 1; + u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; + u64 mx = p->current.amxEq[i]; + int iRatio = mx/iVal; + sqlite3_str_appendf(&sStat, "%c%d", cSep, iRatio); + cSep = ','; + } } sqlite3ResultStrAccum(context, &sStat); } @@ -1601,36 +1591,41 @@ static void decodeIntArray( pIndex->szIdxRow = sqlite3LogEst(sz); }else if( sqlite3_strglob("noskipscan*", z)==0 ){ pIndex->noSkipScan = 1; - }else if( sqlite3_strglob("slow*", z)==0 ){ - pIndex->bSlow = 1; - }else if( sqlite3_strglob("uneven=[0-9]*", z)==0 ){ - /* An argument of "uneven=NNN" means that the maximum length - ** run of the same value is NNN times longer than the average. - ** Go through the iaRowLogEst[] values for the index and increase - ** them by 0.1*NNN, so that so that they are each about 1/10th of - ** of the maximum value. + }else if( sqlite3_strglob("var=[0-9]*", z)==0 ){ + /* An argument like "var=N1,N2,...NN" means that the maximum length + ** run of the same value is Nx times longer than the average for + ** the X-th column of the index. ** - ** The stat column continues to hold the average run length, and - ** then the average is adjusted by the uneven=NNN value. We do this - ** instead of adjusting the run length values in the main body of - ** the stat column for backwards compatibility to older versions of - ** SQLite that expect values in state to be the true the average. - ** Also because the file format specifies that the values in the main - ** body of the stat column should be the true average. + ** For this implementation, go through the iaRowLogEst[] array and + ** increase each value by 1/10th of the average value, to account + ** for the variability of the estimate. ** - ** tag-20231231-02: The 1/10th threshold is tunable. But if changed, - ** one should make a similar adjustment to the uneven=NNN threashold - ** at tag-20231231-01: TUNING ----vv */ - LogEst scale = sqlite3LogEst(sqlite3Atoi(z+7)) - 33; - assert( sqlite3LogEst(10)==33 ); - if( scale>0 ){ - LogEst mx = aLog[0]; - int jj; - for(jj=1; jjnKeyCol; jj++){ - LogEst x = aLog[jj] + scale; - if( x>mx ) x = mx; - aLog[jj] = x; + ** tag-20231231-02: The 1/10th value is tunable. See the tuning + ** comment in the body of the loop. The ANALYZE command only + ** inserts a var=... argument if one or more of the Nx values is + ** within the tuning range, so if changing the tuning factor here, + ** consider also changing it at tag-20232131-01. + ** + ** The stat column continue to hold the average run length for the + ** initial integers, for backwards compatibility. + */ + int jj = 1; + int kk = 4; + LogEst mx = aLog[0]; + while( sqlite3Isdigit(z[kk]) ){ + u64 v = z[kk++] - '0'; + LogEst scale; + while( sqlite3Isdigit(z[kk]) ){ v = v*10 + z[kk++]-'0'; } + scale = sqlite3LogEst(v); + if( scale>33 ){ + /* ^^----- TUNING --------------vv See tag 20231231-02 */ + LogEst adjusted = aLog[jj] + scale - 33; + if( adjusted>mx ) adjusted = mx; + aLog[jj] = adjusted; } + if( jj==pIndex->nKeyCol ) break; + if( z[kk]==',' ) kk++; + jj++; } } #ifdef SQLITE_ENABLE_COSTMULT @@ -1641,6 +1636,16 @@ static void decodeIntArray( while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } + + /* Set the bSlow flag if the peak number of rows obtained + ** from a full equality match is so large that a full table scan + ** seems likely to be faster than using the index. + */ + if( aLog[0] > 66 /* Index has more than 100 rows */ + && aLog[0] <= aLog[pIndex->nKeyCol] /* And only a single value seen */ + ){ + pIndex->bSlow = 1; + } } } diff --git a/src/pragma.c b/src/pragma.c index 4c90574182..dcddabc1e5 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1298,26 +1298,50 @@ void sqlite3Pragma( break; #ifdef SQLITE_DEBUG + /* The output of this pragma is undocumented in the official documentation + ** because it is subject to change, and we don't want people coming to + ** rely on it. + ** + ** Columns: + ** tbl Name of a table that is being described + ** idx Name of an index (belonging to tbl) being described + ** wdth LogEst of the on-disk estimated bytes per row + ** hght LogEst of the estimated number of rows + ** flgs tabFlags for tables + ** est aiRowLogEst[] values for indexes + "slow" flag + */ case PragTyp_STATS: { Index *pIdx; HashElem *i; - pParse->nMem = 5; + sqlite3_str est; + sqlite3StrAccumInit(&est, 0, 0, 0, SQLITE_MAX_LENGTH); + pParse->nMem = 6; sqlite3CodeVerifySchema(pParse, iDb); for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); - sqlite3VdbeMultiLoad(v, 1, "ssiii", + sqlite3VdbeMultiLoad(v, 1, "ssiiis", sqlite3PreferredTableName(pTab->zName), 0, pTab->szTabRow, pTab->nRowLogEst, - pTab->tabFlags); + pTab->tabFlags, + 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeMultiLoad(v, 2, "siiiX", + int j; + est.nChar = 0; + for(j=1; jnKeyCol+1; j++){ + if( j>1 ) sqlite3_str_append(&est, " ", 1); + sqlite3_str_appendf(&est, "%d", pIdx->aiRowLogEst[j]); + } + if( pIdx->bSlow ) sqlite3_str_append(&est, " slow", 5); + sqlite3VdbeMultiLoad(v, 2, "siiisX", pIdx->zName, pIdx->szIdxRow, pIdx->aiRowLogEst[0], - pIdx->hasStat1); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); + pIdx->hasStat1, + sqlite3_str_value(&est)); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); + sqlite3_str_reset(&est); } } } diff --git a/src/pragma.h b/src/pragma.h index 7270db1db4..8c82635e57 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -89,45 +89,46 @@ static const char *const pragCName[] = { /* 18 */ "ncol", /* 19 */ "wr", /* 20 */ "strict", - /* 21 */ "seqno", /* Used by: index_xinfo */ - /* 22 */ "cid", - /* 23 */ "name", - /* 24 */ "desc", - /* 25 */ "coll", - /* 26 */ "key", - /* 27 */ "name", /* Used by: function_list */ - /* 28 */ "builtin", - /* 29 */ "type", - /* 30 */ "enc", - /* 31 */ "narg", - /* 32 */ "flags", - /* 33 */ "tbl", /* Used by: stats */ - /* 34 */ "idx", - /* 35 */ "wdth", - /* 36 */ "hght", - /* 37 */ "flgs", - /* 38 */ "seq", /* Used by: index_list */ - /* 39 */ "name", - /* 40 */ "unique", - /* 41 */ "origin", - /* 42 */ "partial", - /* 43 */ "table", /* Used by: foreign_key_check */ - /* 44 */ "rowid", - /* 45 */ "parent", - /* 46 */ "fkid", - /* index_info reuses 21 */ - /* 47 */ "seq", /* Used by: database_list */ - /* 48 */ "name", - /* 49 */ "file", - /* 50 */ "busy", /* Used by: wal_checkpoint */ - /* 51 */ "log", - /* 52 */ "checkpointed", - /* collation_list reuses 38 */ - /* 53 */ "database", /* Used by: lock_status */ - /* 54 */ "status", - /* 55 */ "cache_size", /* Used by: default_cache_size */ + /* 21 */ "tbl", /* Used by: stats */ + /* 22 */ "idx", + /* 23 */ "wdth", + /* 24 */ "hght", + /* 25 */ "flgs", + /* 26 */ "est", + /* 27 */ "seqno", /* Used by: index_xinfo */ + /* 28 */ "cid", + /* 29 */ "name", + /* 30 */ "desc", + /* 31 */ "coll", + /* 32 */ "key", + /* 33 */ "name", /* Used by: function_list */ + /* 34 */ "builtin", + /* 35 */ "type", + /* 36 */ "enc", + /* 37 */ "narg", + /* 38 */ "flags", + /* 39 */ "seq", /* Used by: index_list */ + /* 40 */ "name", + /* 41 */ "unique", + /* 42 */ "origin", + /* 43 */ "partial", + /* 44 */ "table", /* Used by: foreign_key_check */ + /* 45 */ "rowid", + /* 46 */ "parent", + /* 47 */ "fkid", + /* index_info reuses 27 */ + /* 48 */ "seq", /* Used by: database_list */ + /* 49 */ "name", + /* 50 */ "file", + /* 51 */ "busy", /* Used by: wal_checkpoint */ + /* 52 */ "log", + /* 53 */ "checkpointed", + /* collation_list reuses 39 */ + /* 54 */ "database", /* Used by: lock_status */ + /* 55 */ "status", + /* 56 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ - /* 56 */ "timeout", /* Used by: busy_timeout */ + /* 57 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ @@ -178,7 +179,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 56, 1, + /* ColNames: */ 57, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -217,7 +218,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 2, + /* ColNames: */ 39, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -252,14 +253,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 3, + /* ColNames: */ 48, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, - /* ColNames: */ 55, 1, + /* ColNames: */ 56, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -289,7 +290,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 43, 4, + /* ColNames: */ 44, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) @@ -332,7 +333,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 27, 6, + /* ColNames: */ 33, 6, /* iArg: */ 0 }, #endif #endif @@ -361,17 +362,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 3, + /* ColNames: */ 27, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 38, 5, + /* ColNames: */ 39, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 6, + /* ColNames: */ 27, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -411,7 +412,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 53, 2, + /* ColNames: */ 54, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -550,7 +551,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 33, 5, + /* ColNames: */ 21, 6, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -646,7 +647,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 50, 3, + /* ColNames: */ 51, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 2b5b6fdcdb..1043b01483 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -247,7 +247,7 @@ set pragma_def { NAME: stats FLAG: NeedSchema Result0 SchemaReq - COLS: tbl idx wdth hght flgs + COLS: tbl idx wdth hght flgs est IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) NAME: index_info