From 4c7729af99a9fbf54c812cbd6b14572ec8680963 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 10 Oct 2026 17:40:46 +0000 Subject: [PATCH] New extension ext/misc/optname.c provides the canonical mapping between optimization bitmaps and optimization names. This gives a single point of edit when there are changes. Used by the CLI, by testfixture, and by TH3. FossilOrigin-Name: 135ed9e2cc9bd37c3e158a488e37f4ce14ffeca44ff12e31f25a6686a2622ca1 --- Makefile.msc | 1 + ext/misc/optname.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ main.mk | 2 + manifest | 23 +++++----- manifest.uuid | 2 +- src/shell.c.in | 87 ++++++++++------------------------- src/sqliteInt.h | 78 +++++++++++++++---------------- src/test1.c | 73 +++++++++++++---------------- 8 files changed, 223 insertions(+), 155 deletions(-) create mode 100644 ext/misc/optname.c diff --git a/Makefile.msc b/Makefile.msc index 02e740aeb9..8c60802d82 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1594,6 +1594,7 @@ TESTEXT = \ $(TOP)\ext\misc\mmapwarm.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\normalize.c \ + $(TOP)\ext\misc\optname.c \ $(TOP)\ext\misc\prefixes.c \ $(TOP)\ext\misc\qpvtab.c \ $(TOP)\ext\misc\randomjson.c \ diff --git a/ext/misc/optname.c b/ext/misc/optname.c new file mode 100644 index 0000000000..35eb56571d --- /dev/null +++ b/ext/misc/optname.c @@ -0,0 +1,112 @@ +/* +** 2026-10-10 +** +** 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. +** +************************************************************************* +** +** The sqlite3_test_control() interface with SQLITE_TESTCTRL_OPTIMIZATIONS +** and SQLITE_TESTCTRL_GETOPT are used to enable and/or disable various +** optimizations within SQLite. Optimizations are identified by a bitmask. +** This file contains external code that will map symbolic names into +** bitmask values, and bitmask values into symbolic names. +** +** This code is not part of the SQLite core because we don't want to use +** code space to store all the symbolic names. +*/ +#include "sqlite3.h" + +/* +** Convert an optimization number (as recorded in sqliteInt.h) into +** a mask for that optimization. +*/ +#define OPT_MASK(N) ((1ull)<<((N)-1)) + + +/* +** This is the mapping between bits and names. +** +** Some bit values have multiple names. The preferred name always +** comes first. +*/ +static const struct OptName { + sqlite3_uint64 uMask; + const char *zName; +} aOpt[] = { + { OPT_MASK(1), "QueryFlattener" }, + { OPT_MASK(1), "Flatten" }, /* Alias for prior */ + { OPT_MASK(2), "WindowFunc" }, + { OPT_MASK(3), "GroupByOrder" }, + { OPT_MASK(4), "JoinMiss" }, + { OPT_MASK(5), "DistinctOpt" }, + { OPT_MASK(6), "CoverIdxScan" }, + { OPT_MASK(7), "OrderByIdxJoin" }, + { OPT_MASK(8), "Transitive" }, + { OPT_MASK(9), "OmitNoopJoin" }, + { OPT_MASK(10), "CountOfView" }, + { OPT_MASK(11), "CursorHints" }, + { OPT_MASK(12), "Stat4" }, + { OPT_MASK(13), "PushDown" }, + { OPT_MASK(14), "SimplifyJoin" }, + { OPT_MASK(15), "SkipScan" }, + { OPT_MASK(16), "PropagateConst" }, + { OPT_MASK(17), "MinMaxOpt" }, + { OPT_MASK(18), "SeekScan" }, + { OPT_MASK(19), "OmitOrderBy" }, + { OPT_MASK(20), "BloomFilter" }, + /* 21 currently unused */ + { OPT_MASK(22), "BalancedMerge" }, + { OPT_MASK(23), "ReleaseReg" }, + { OPT_MASK(24), "FlttnUnionAll" }, + { OPT_MASK(25), "IndexedExpr" }, + { OPT_MASK(26), "Coroutines" }, + { OPT_MASK(27), "NullUnusedCols" }, + { OPT_MASK(28), "OnePass" }, + { OPT_MASK(29), "OrderBySubq" }, + { OPT_MASK(29), "OrderBySubquery" }, /* Alias for prior */ + { OPT_MASK(30), "StarQuery" }, + { OPT_MASK(31), "ExistsToJoin" }, + { OPT_MASK(32), "UnionLimit" }, + /* Special names */ + { 0xffffffffffffffffULL, "All" }, + { 0x0000000000000000ULL, "None" }, +}; + +/* +** Given a symbolic name, try to compute the corresponding mask. +** +** The return value is: +** +** SQLITE_OK Successful match +** SQLITE_NOTFOUND No match +** SQLITE_MISUSE Bad arguments +*/ +int sqlite3_optimization_mask(const char *zName, sqlite3_uint64 *pMask){ + int i; + if( zName==0 || pMask==0 ){ return SQLITE_MISUSE; } + for(i=0; idb, &curOpt); newOpt = curOpt; for(ii=2; ii=ArraySize(aLabel) ){ + if( sqlite3_optimization_mask(zLabel,&mm)==SQLITE_NOTFOUND ){ cli_printf(stderr, "Error: no such optimization: \"%s\"\n", zLabel); - cli_puts("Should be one of:", stderr); - for(jj=0; jjout); - for(ii=0; iiout, " -%s", aLabel[ii].zLabel); + for(ii=0, m=1; ii<32; ii++, m <<= 1){ + const char *zName; + if( (newOpt & m)!=0 && (zName = sqlite3_optimization_name(m))!=0 ){ + cli_printf(p->out, " -%s", zName); } } }else{ cli_puts("-All", p->out); - for(ii=0; iiout, " +%s", aLabel[ii].zLabel); + for(ii=0, m=1; ii<32; ii++, m <<= 1){ + if( (newOpt & m)==0 && (zName = sqlite3_optimization_name(m))!=0 ){ + cli_printf(p->out, " +%s", zName); } } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index edaffe8b9b..e119ae6cc2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1713,7 +1713,6 @@ struct sqlite3 { int errByteOffset; /* Byte offset of error in SQL statement */ int errMask; /* & result codes with this before returning */ int iSysErrno; /* Errno value from last system error */ - u32 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ @@ -1732,6 +1731,7 @@ struct sqlite3 { int nextPagesize; /* Pagesize after VACUUM if >0 */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ + u32 dbOptFlags; /* Flags to enable/disable optimizations */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ @@ -1931,51 +1931,49 @@ struct sqlite3 { /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to -** selectively disable various optimizations. +** selectively disable various optimizations. The numbers in each macro +** are the one-based bit position (for improved readability). ** -** Keep these values in sync with the ".testctrl" command of the CLI -** and the th3dbOpt() function of TH3. Note also that TH3 expects the -** STAT4 optimization to always be 0x800. +** Keep these values in sync with the ext/misc/optname.c extension. */ -#define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ -#define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ -#define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */ -#define SQLITE_JoinMiss 0x00000008 /* Unwind join loops on a lookup miss*/ -#define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */ -#define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */ -#define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */ -#define SQLITE_Transitive 0x00000080 /* Transitive constraints */ -#define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */ -#define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ -#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */ -#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */ -#define SQLITE_PushDown 0x00001000 /* WHERE-clause push-down opt */ -#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ -#define SQLITE_SkipScan 0x00004000 /* Skip-scans */ -#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ -#define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ -#define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ -#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ -#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filters */ - /* 0x00100000 -- Available for reuse */ -#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ -#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ -#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ -#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ -#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ -#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ -#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ -#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ -#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */ -#define SQLITE_ExistsToJoin 0x40000000 /* The EXISTS-to-JOIN optimization */ -#define SQLITE_UnionLimit 0x80000000 /* Optimizations for UNION + LIMIT */ -#define SQLITE_AllOpts 0xffffffff /* All optimizations */ +#define SQLITE_QueryFlattener 1 /* Query flattening */ +#define SQLITE_WindowFunc 2 /* Use xInverse for window functions */ +#define SQLITE_GroupByOrder 3 /* GROUPBY cover of ORDERBY */ +#define SQLITE_JoinMiss 4 /* Unwind join loops on a lookup miss*/ +#define SQLITE_DistinctOpt 5 /* DISTINCT using indexes */ +#define SQLITE_CoverIdxScan 6 /* Covering index scans */ +#define SQLITE_OrderByIdxJoin 7 /* ORDER BY of joins via index */ +#define SQLITE_Transitive 8 /* Transitive constraints */ +#define SQLITE_OmitNoopJoin 9 /* Omit unused tables in joins */ +#define SQLITE_CountOfView 10 /* The count-of-view optimization */ +#define SQLITE_CursorHints 11 /* Add OP_CursorHint opcodes */ +#define SQLITE_Stat4 12 /* Use STAT4 data */ +#define SQLITE_PushDown 13 /* WHERE-clause push-down opt */ +#define SQLITE_SimplifyJoin 14 /* Convert LEFT JOIN to JOIN */ +#define SQLITE_SkipScan 15 /* Skip-scans */ +#define SQLITE_PropagateConst 16 /* The constant propagation opt */ +#define SQLITE_MinMaxOpt 17 /* The min/max optimization */ +#define SQLITE_SeekScan 18 /* The OP_SeekScan optimization */ +#define SQLITE_OmitOrderBy 19 /* Omit pointless ORDER BY */ +#define SQLITE_BloomFilter 20 /* Use a Bloom filters */ + /* 21 -- Available for reuse */ +#define SQLITE_BalancedMerge 22 /* Balance multi-way merges */ +#define SQLITE_ReleaseReg 23 /* Use OP_ReleaseReg for testing */ +#define SQLITE_FlttnUnionAll 24 /* Disable the UNION ALL flattener */ +#define SQLITE_IndexedExpr 25 /* Pull exprs from index when able */ +#define SQLITE_Coroutines 26 /* Co-routines for subqueries */ +#define SQLITE_NullUnusedCols 27 /* NULL unused columns in subqueries */ +#define SQLITE_OnePass 28 /* Single-pass DELETE and UPDATE */ +#define SQLITE_OrderBySubq 29 /* ORDER BY in subquery helps outer */ +#define SQLITE_StarQuery 30 /* Heurists for star queries */ +#define SQLITE_ExistsToJoin 31 /* The EXISTS-to-JOIN optimization */ +#define SQLITE_UnionLimit 32 /* Optimizations for UNION + LIMIT */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ -#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) -#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) +#define OptimizationDisabled(D,M) (((D)->dbOptFlags&(1ul<<((M)-1)))!=0) +#define OptimizationEnabled(D,M) (((D)->dbOptFlags&(1ul<<((M)-1)))==0) /* ** Return true if it OK to factor constant expressions into the initialization diff --git a/src/test1.c b/src/test1.c index fa2651571b..f46b3cf997 100644 --- a/src/test1.c +++ b/src/test1.c @@ -8539,35 +8539,15 @@ static int SQLITE_TCLAPI optimization_control( int objc, Tcl_Obj *CONST objv[] ){ - int i; + size_t i, j, k; sqlite3 *db; const char *zOpt; int onoff; - int mask = 0; - int cnt = 0; - static const struct { - const char *zOptName; - int mask; - } aOpt[] = { - { "all", SQLITE_AllOpts }, - { "none", 0 }, - { "query-flattener", SQLITE_QueryFlattener }, - { "groupby-order", SQLITE_GroupByOrder }, - { "distinct-opt", SQLITE_DistinctOpt }, - { "cover-idx-scan", SQLITE_CoverIdxScan }, - { "order-by-idx-join", SQLITE_OrderByIdxJoin }, - { "order-by-subquery", SQLITE_OrderBySubq }, - { "transitive", SQLITE_Transitive }, - { "omit-noop-join", SQLITE_OmitNoopJoin }, - { "stat4", SQLITE_Stat4 }, - { "skip-scan", SQLITE_SkipScan }, - { "push-down", SQLITE_PushDown }, - { "balanced-merge", SQLITE_BalancedMerge }, - { "propagate-const", SQLITE_PropagateConst }, - { "one-pass", SQLITE_OnePass }, - { "exists-to-join", SQLITE_ExistsToJoin }, - { "count-of-view", SQLITE_CountOfView }, - }; + u64 m = 0, mask = 0; + int m32; + char zBuf[50]; + extern int sqlite3_optimization_mask(const char*,sqlite3_uint64*); + extern const char *sqlite3_optimization_name(sqlite3_uint64); if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); @@ -8576,23 +8556,36 @@ static int SQLITE_TCLAPI optimization_control( if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; zOpt = Tcl_GetString(objv[2]); - for(i=0; i