Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -41,10 +41,11 @@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ +FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile Index: auto.def ================================================================== --- auto.def +++ auto.def @@ -5,10 +5,11 @@ options { with-openssl:path|auto|none => {Look for openssl in the given path, or auto or none} with-zlib:path => {Look for zlib in the given path} with-tcl:path => {Enable Tcl integration, with Tcl in the specified path} + with-tcl-stubs=0 => {Enable Tcl integration via stubs mechanism} internal-sqlite=1 => {Don't use the internal sqlite, use the system one} static=0 => {Link a static executable} lineedit=1 => {Disable line editing} fossil-debug=0 => {Build with fossil debugging enabled} json=0 => {Build with fossil JSON API enabled} @@ -32,11 +33,11 @@ if {![opt-bool internal-sqlite]} { proc find_internal_sqlite {} { # On some systems (slackware), libsqlite3 requires -ldl to link. So # search for the system SQLite once with -ldl, and once without. If - # the library can only be found with $extralibs set to -ldl, then + # the library can only be found with $extralibs set to -ldl, then # the code below will append -ldl to LIBS. # foreach extralibs {{} {-ldl}} { # Locate the system SQLite by searching for sqlite3_open(). Then check @@ -92,35 +93,48 @@ user-error "zlib not found please install it or specify the location with --with-zlib" } set tclpath [opt-val with-tcl] if {$tclpath ne ""} { - # Note parse-tclconfig-sh is in autosetup/local.tcl + # Note parse-tclconfig-sh is in autosetup/local.tcl if {$tclpath eq "1"} { # Use the system Tcl. Look in some likely places. - array set tclconfig [parse-tclconfig-sh /usr /usr/local /usr/share /opt/local] - set msg "on your system" - } else { + array set tclconfig [parse-tclconfig-sh \ + /usr /usr/local /usr/share /opt/local] + set msg "on your system" + } else { array set tclconfig [parse-tclconfig-sh $tclpath] - set msg "at $tclpath" - } - if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} { - user-error "Cannot find Tcl $msg" - } - set cflags $tclconfig(TCL_INCLUDE_SPEC) - set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)" - cc-with [list -cflags $cflags -libs $libs] { - if {![cc-check-functions Tcl_CreateInterp]} { - user-error "Cannot find a usable Tcl $msg" - } - } - set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL) - msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)" - define-append LIBS $libs - define-append EXTRA_CFLAGS $cflags - define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) - + set msg "at $tclpath" + } + if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} { + user-error "Cannot find Tcl $msg" + } + set tclstubs [opt-bool with-tcl-stubs] + if {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} { + set libs "$tclconfig(TCL_STUB_LIB_SPEC)" + define FOSSIL_ENABLE_TCL_STUBS + define USE_TCL_STUBS + } else { + set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)" + } + set cflags $tclconfig(TCL_INCLUDE_SPEC) + cc-with [list -cflags $cflags -libs $libs] { + if {$tclstubs} { + if {![cc-check-functions Tcl_InitStubs]} { + user-error "Cannot find a usable Tcl stubs library $msg" + } + } else { + if {![cc-check-functions Tcl_CreateInterp]} { + user-error "Cannot find a usable Tcl library $msg" + } + } + } + set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL) + msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)" + define-append LIBS $libs + define-append EXTRA_CFLAGS $cflags + define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) define FOSSIL_ENABLE_TCL } # Helper for openssl checking proc check-for-openssl {msg {cflags {}}} { Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -90,10 +90,13 @@ ** "th_tcl.c". */ struct TclContext { int argc; char **argv; + void *library; + void *xFindExecutable; /* see tcl_FindExecutableProc in th_tcl.c */ + void *xCreateInterp; /* see tcl_CreateInterpProc in th_tcl.c */ Tcl_Interp *interp; }; #endif /* Index: src/makemake.tcl ================================================================== --- src/makemake.tcl +++ src/makemake.tcl @@ -375,10 +375,14 @@ # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 + +#### Load Tcl using the stubs mechanism +# +# FOSSIL_ENABLE_TCL_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 @@ -424,11 +428,15 @@ TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # +ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 +else +LIBTCL = -ltcl86 +endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used @@ -464,12 +472,20 @@ RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL -TCC += -DFOSSIL_ENABLE_TCL=1 -DUSE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 +# Either statically linked or via stubs +ifdef FOSSIL_ENABLE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +else +TCC += -DSTATIC_BUILD +RCC += -DSTATIC_BUILD +endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 @@ -499,11 +515,15 @@ #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL +ifdef FOSSIL_ENABLE_TCL_STUBS +LIB += -lkernel32 -lws2_32 +else LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 +endif else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -694,28 +694,33 @@ if( i<ArraySize(p->colWidth) ){ w = p->colWidth[i]; }else{ w = 0; } - if( w<=0 ){ + if( w==0 ){ w = strlen30(azCol[i] ? azCol[i] : ""); if( w<10 ) w = 10; n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue); if( w<n ) w = n; } if( i<ArraySize(p->actualWidth) ){ p->actualWidth[i] = w; } if( p->showHeader ){ - fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); + if( w<0 ){ + fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " "); + }else{ + fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); + } } } if( p->showHeader ){ for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ w = p->actualWidth[i]; + if( w<0 ) w = -w; }else{ w = 10; } fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------" "----------------------------------------------------------", @@ -733,12 +738,17 @@ } if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){ w = strlen30(azArg[i]); } - fprintf(p->out,"%-*.*s%s",w,w, - azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); + if( w<0 ){ + fprintf(p->out,"%*.*s%s",-w,-w, + azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); + }else{ + fprintf(p->out,"%-*.*s%s",w,w, + azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); + } } break; } case MODE_Semi: case MODE_List: { @@ -1414,13 +1424,14 @@ " insert SQL insert statements for TABLE\n" " line One value per line\n" " list Values delimited by .separator string\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" - ".nullvalue STRING Print STRING in place of NULL values\n" + ".nullvalue STRING Use STRING in place of NULL values\n" ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" + ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".schema ?TABLE? Show the CREATE statements\n" @@ -2067,10 +2078,19 @@ } else { sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); } } }else + + if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ + int i; + for(i=1; i<nArg; i++){ + if( i>1 ) fprintf(p->out, " "); + fprintf(p->out, "%s", azArg[i]); + } + fprintf(p->out, "\n"); + }else if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ if( nArg >= 2) { strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); } @@ -2490,10 +2510,17 @@ printf("%s\n", zVfsName); sqlite3_free(zVfsName); } } }else + +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) + if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ + extern int sqlite3WhereTrace; + sqlite3WhereTrace = atoi(azArg[1]); + }else +#endif if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ Index: src/sqlite3.c ================================================================== --- src/sqlite3.c +++ src/sqlite3.c @@ -673,11 +673,11 @@ ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.15" #define SQLITE_VERSION_NUMBER 3007015 -#define SQLITE_SOURCE_ID "2012-09-17 21:24:01 698b2a28004a9a2f0eabaadf36d833da4400b2bf" +#define SQLITE_SOURCE_ID "2012-09-28 00:44:28 1e874629d7cf568368b912b295bd3001147d0b52" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -5315,10 +5315,13 @@ ** successfully. An [error code] is returned otherwise.)^ ** ** ^Shared cache is disabled by default. But this might change in ** future releases of SQLite. Applications that care about shared ** cache setting should set it explicitly. +** +** This interface is threadsafe on processors where writing a +** 32-bit integer is atomic. ** ** See Also: [SQLite Shared-Cache Mode] */ SQLITE_API int sqlite3_enable_shared_cache(int); @@ -8281,10 +8284,11 @@ typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; +typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; @@ -8887,11 +8891,11 @@ #define OPFLG_IN3 0x0010 /* in3: P3 is an input */ #define OPFLG_OUT2 0x0020 /* out2: P2 is an output */ #define OPFLG_OUT3 0x0040 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x01, 0x01, 0x04, 0x04, 0x10, 0x00, 0x02,\ -/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\ +/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x24,\ /* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\ /* 24 */ 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00,\ /* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\ /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\ /* 48 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02,\ @@ -9843,10 +9847,11 @@ int flags; /* Miscellaneous flags. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ + u8 dbOptFlags; /* Flags to enable/disable optimizations */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ @@ -9947,50 +9952,62 @@ #define ENC(db) ((db)->aDb[0].pSchema->enc) /* ** Possible values for the sqlite3.flags. */ -#define SQLITE_VdbeTrace 0x00000100 /* True to trace VDBE execution */ -#define SQLITE_InternChanges 0x00000200 /* Uncommitted Hash table changes */ -#define SQLITE_FullColNames 0x00000400 /* Show full column names on SELECT */ -#define SQLITE_ShortColNames 0x00000800 /* Show short columns names */ -#define SQLITE_CountRows 0x00001000 /* Count rows changed by INSERT, */ +#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ +#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ +#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ +#define SQLITE_ShortColNames 0x00000008 /* Show short columns names */ +#define SQLITE_CountRows 0x00000010 /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ -#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */ +#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */ /* result set is empty */ -#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */ -#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */ - /* 0x00020000 Unused */ -#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */ -#define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */ -#define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */ -#define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */ -#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */ -#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */ -#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */ -#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */ -#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */ -#define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */ -#define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */ - -/* -** Bits of the sqlite3.flags field that are used by the -** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface. -** These must be the low-order bits of the flags field. -*/ -#define SQLITE_QueryFlattener 0x01 /* Disable query flattening */ -#define SQLITE_ColumnCache 0x02 /* Disable the column cache */ -#define SQLITE_GroupByOrder 0x04 /* Disable GROUPBY cover of ORDERBY */ -#define SQLITE_FactorOutConst 0x08 /* Disable factoring out constants */ -#define SQLITE_IdxRealAsInt 0x10 /* Store REAL as INT in indices */ -#define SQLITE_DistinctOpt 0x20 /* DISTINCT using indexes */ -#define SQLITE_CoverIdxScan 0x40 /* Disable covering index scans */ -#define SQLITE_OptMask 0xff /* Mask of all disablable opts */ +#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */ +#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */ + /* 0x00000200 Unused */ +#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */ +#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */ +#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */ +#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */ +#define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */ +#define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00020000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */ +#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */ +#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */ +#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */ + +/* +** Bits of the sqlite3.dbOptFlags field that are used by the +** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to +** selectively disable various optimizations. +*/ +#define SQLITE_QueryFlattener 0x0001 /* Query flattening */ +#define SQLITE_ColumnCache 0x0002 /* Column cache */ +#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ +#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ +#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ +#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ +#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ +#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ +#define SQLITE_AllOpts 0x00ff /* All optimizations */ + +/* +** Macros for testing whether or not optimizations are enabled or disabled. +*/ +#ifndef SQLITE_OMIT_BUILTIN_TEST +#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) +#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) +#else +#define OptimizationDisabled(db, mask) 0 +#define OptimizationEnabled(db, mask) 1 +#endif /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. @@ -10922,11 +10939,12 @@ ** is only used when wsFlags&WHERE_VIRTUALTABLE is true. It is never the ** case that more than one of these conditions is true. */ struct WherePlan { u32 wsFlags; /* WHERE_* flags that describe the strategy */ - u32 nEq; /* Number of == constraints */ + u16 nEq; /* Number of == constraints */ + u16 nOBSat; /* Number of ORDER BY terms satisfied */ double nRow; /* Estimated number of rows (for EQP) */ union { Index *pIdx; /* Index when WHERE_INDEXED is true */ struct WhereTerm *pTerm; /* WHERE clause term for OR-search */ sqlite3_index_info *pVtabIdx; /* Virtual table index to use */ @@ -10998,28 +11016,32 @@ ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. */ struct WhereInfo { - Parse *pParse; /* Parsing and code generating context */ - u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */ - u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; - SrcList *pTabList; /* List of tables in the join */ - int iTop; /* The very beginning of the WHERE loop */ - int iContinue; /* Jump here to continue with next record */ - int iBreak; /* Jump here to break out of the loop */ - int nLevel; /* Number of nested loop */ - struct WhereClause *pWC; /* Decomposition of the WHERE clause */ - double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - double nRowOut; /* Estimated number of output rows */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ + Parse *pParse; /* Parsing and code generating context */ + SrcList *pTabList; /* List of tables in the join */ + u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ + u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + int iTop; /* The very beginning of the WHERE loop */ + int iContinue; /* Jump here to continue with next record */ + int iBreak; /* Jump here to break out of the loop */ + int nLevel; /* Number of nested loop */ + struct WhereClause *pWC; /* Decomposition of the WHERE clause */ + double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + double nRowOut; /* Estimated number of output rows */ + WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; -#define WHERE_DISTINCT_UNIQUE 1 -#define WHERE_DISTINCT_ORDERED 2 +/* Allowed values for WhereInfo.eDistinct and DistinctCtx.eTnctType */ +#define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ +#define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ +#define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ +#define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ /* ** A NameContext defines a context in which to resolve table and column ** names. The context consists of a list of tables (the pSrcList) field and ** a list of named expression (pEList). The named expression list may @@ -11074,17 +11096,16 @@ ** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor ** the number of columns in P2 can be computed at the same time ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences -** for the result set. The KeyInfo for addrOpenTran[2] contains collating +** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ - char affinity; /* MakeRecord with this affinity for SRT_Set */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ double nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ @@ -11131,17 +11152,16 @@ #define SRT_Table 8 /* Store result as data with an automatic rowid */ #define SRT_EphemTab 9 /* Create transient tab and store like SRT_Table */ #define SRT_Coroutine 10 /* Generate a single row of result */ /* -** A structure used to customize the behavior of sqlite3Select(). See -** comments above sqlite3Select() for details. +** An instance of this object describes where to put of the results of +** a SELECT statement. */ -typedef struct SelectDest SelectDest; struct SelectDest { - u8 eDest; /* How to dispose of the results */ - u8 affSdst; /* Affinity used when eDest==SRT_Set */ + u8 eDest; /* How to dispose of the results. On of SRT_* above. */ + char affSdst; /* Affinity used when eDest==SRT_Set */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ }; @@ -11826,17 +11846,15 @@ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *); #endif SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( - Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int); +SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); -SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int); SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); @@ -13178,11 +13196,13 @@ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_RowSet 0x0020 /* Value is a RowSet object */ #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ #define MEM_Invalid 0x0080 /* Value is undefined */ -#define MEM_TypeMask 0x00ff /* Mask of type bits */ +#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ +#define MEM_TypeMask 0x01ff /* Mask of type bits */ + /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated @@ -63693,10 +63713,11 @@ struct OP_Yield_stack_vars { int pcDest; } aa; struct OP_Null_stack_vars { int cnt; + u16 nullFlag; } ab; struct OP_Variable_stack_vars { Mem *pVar; /* Value being transferred */ } ac; struct OP_Move_stack_vars { @@ -63703,60 +63724,63 @@ char *zMalloc; /* Holding variable for allocated memory */ int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ int p2; /* Register to copy to */ } ad; + struct OP_Copy_stack_vars { + int n; + } ae; struct OP_ResultRow_stack_vars { Mem *pMem; int i; - } ae; + } af; struct OP_Concat_stack_vars { i64 nByte; - } af; + } ag; struct OP_Remainder_stack_vars { int flags; /* Combined MEM_* flags from both inputs */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ - } ag; + } ah; struct OP_Function_stack_vars { int i; Mem *pArg; sqlite3_context ctx; sqlite3_value **apVal; int n; - } ah; + } ai; struct OP_ShiftRight_stack_vars { i64 iA; u64 uA; i64 iB; u8 op; - } ai; + } aj; struct OP_Ge_stack_vars { int res; /* Result of the comparison of pIn1 against pIn3 */ char affinity; /* Affinity to use for comparison */ u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ - } aj; + } ak; struct OP_Compare_stack_vars { int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; int idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ - } ak; + } al; struct OP_Or_stack_vars { int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ - } al; + } am; struct OP_IfNot_stack_vars { int c; - } am; + } an; struct OP_Column_stack_vars { u32 payloadSize; /* Number of bytes in the record */ i64 payloadSize64; /* Number of bytes in the record */ int p1; /* P1 value of the opcode */ int p2; /* column number to retrieve */ @@ -63777,15 +63801,15 @@ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ - } an; + } ao; struct OP_Affinity_stack_vars { const char *zAffinity; /* The affinity to be applied */ char cAff; /* A single character of affinity */ - } ao; + } ap; struct OP_MakeRecord_stack_vars { u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ @@ -63798,108 +63822,108 @@ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ int len; /* Length of a field */ - } ap; + } aq; struct OP_Count_stack_vars { i64 nEntry; BtCursor *pCrsr; - } aq; + } ar; struct OP_Savepoint_stack_vars { int p1; /* Value of P1 operand */ char *zName; /* Name of savepoint */ int nName; Savepoint *pNew; Savepoint *pSavepoint; Savepoint *pTmp; int iSavepoint; int ii; - } ar; + } as; struct OP_AutoCommit_stack_vars { int desiredAutoCommit; int iRollback; int turnOnAC; - } as; + } at; struct OP_Transaction_stack_vars { Btree *pBt; - } at; + } au; struct OP_ReadCookie_stack_vars { int iMeta; int iDb; int iCookie; - } au; + } av; struct OP_SetCookie_stack_vars { Db *pDb; - } av; + } aw; struct OP_VerifyCookie_stack_vars { int iMeta; int iGen; Btree *pBt; - } aw; + } ax; struct OP_OpenWrite_stack_vars { int nField; KeyInfo *pKeyInfo; int p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; - } ax; + } ay; struct OP_OpenEphemeral_stack_vars { VdbeCursor *pCx; - } ay; + } az; struct OP_SorterOpen_stack_vars { VdbeCursor *pCx; - } az; + } ba; struct OP_OpenPseudo_stack_vars { VdbeCursor *pCx; - } ba; + } bb; struct OP_SeekGt_stack_vars { int res; int oc; VdbeCursor *pC; UnpackedRecord r; int nField; i64 iKey; /* The rowid we are to seek to */ - } bb; + } bc; struct OP_Seek_stack_vars { VdbeCursor *pC; - } bc; + } bd; struct OP_Found_stack_vars { int alreadyExists; VdbeCursor *pC; int res; char *pFree; UnpackedRecord *pIdxKey; UnpackedRecord r; char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; - } bd; + } be; struct OP_IsUnique_stack_vars { u16 ii; VdbeCursor *pCx; BtCursor *pCrsr; u16 nField; Mem *aMx; UnpackedRecord r; /* B-Tree index search key */ i64 R; /* Rowid stored in register P3 */ - } be; + } bf; struct OP_NotExists_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; - } bf; + } bg; struct OP_NewRowid_stack_vars { i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ - } bg; + } bh; struct OP_InsertInt_stack_vars { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ i64 iKey; /* The integer ROWID or key for the record to be inserted */ VdbeCursor *pC; /* Cursor to table into which insert is written */ @@ -63906,160 +63930,163 @@ int nZero; /* Number of zero-bytes to append */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ const char *zTbl; /* Table name - used by the opdate hook */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ - } bh; + } bi; struct OP_Delete_stack_vars { i64 iKey; VdbeCursor *pC; - } bi; + } bj; struct OP_SorterCompare_stack_vars { VdbeCursor *pC; int res; - } bj; + } bk; struct OP_SorterData_stack_vars { VdbeCursor *pC; - } bk; + } bl; struct OP_RowData_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; u32 n; i64 n64; - } bl; + } bm; struct OP_Rowid_stack_vars { VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; - } bm; + } bn; struct OP_NullRow_stack_vars { VdbeCursor *pC; - } bn; + } bo; struct OP_Last_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; int res; - } bo; + } bp; struct OP_Rewind_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; int res; - } bp; + } bq; struct OP_Next_stack_vars { VdbeCursor *pC; int res; - } bq; + } br; struct OP_IdxInsert_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; int nKey; const char *zKey; - } br; + } bs; struct OP_IdxDelete_stack_vars { VdbeCursor *pC; BtCursor *pCrsr; int res; UnpackedRecord r; - } bs; + } bt; struct OP_IdxRowid_stack_vars { BtCursor *pCrsr; VdbeCursor *pC; i64 rowid; - } bt; + } bu; struct OP_IdxGE_stack_vars { VdbeCursor *pC; int res; UnpackedRecord r; - } bu; + } bv; struct OP_Destroy_stack_vars { int iMoved; int iCnt; Vdbe *pVdbe; int iDb; - } bv; + } bw; struct OP_Clear_stack_vars { int nChange; - } bw; + } bx; struct OP_CreateTable_stack_vars { int pgno; int flags; Db *pDb; - } bx; + } by; struct OP_ParseSchema_stack_vars { int iDb; const char *zMaster; char *zSql; InitData initData; - } by; + } bz; struct OP_IntegrityCk_stack_vars { int nRoot; /* Number of tables to check. (Number of root pages.) */ int *aRoot; /* Array of rootpage numbers for tables to be checked */ int j; /* Loop counter */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ - } bz; + } ca; struct OP_RowSetRead_stack_vars { i64 val; - } ca; + } cb; struct OP_RowSetTest_stack_vars { int iSet; int exists; - } cb; + } cc; struct OP_Program_stack_vars { int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ VdbeFrame *pFrame; /* New vdbe frame to execute in */ SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ - } cc; + } cd; struct OP_Param_stack_vars { VdbeFrame *pFrame; Mem *pIn; - } cd; + } ce; struct OP_MemMax_stack_vars { Mem *pIn1; VdbeFrame *pFrame; - } ce; + } cf; struct OP_AggStep_stack_vars { int n; int i; Mem *pMem; Mem *pRec; sqlite3_context ctx; sqlite3_value **apVal; - } cf; + } cg; struct OP_AggFinal_stack_vars { Mem *pMem; - } cg; + } ch; struct OP_Checkpoint_stack_vars { int i; /* Loop counter */ int aRes[3]; /* Results */ Mem *pMem; /* Write results here */ - } ch; + } ci; struct OP_JournalMode_stack_vars { Btree *pBt; /* Btree to change journal mode of */ Pager *pPager; /* Pager associated with pBt */ int eNew; /* New journal mode */ int eOld; /* The old journal mode */ - } ci; +#ifndef SQLITE_OMIT_WAL + const char *zFilename; /* Name of database file for pPager */ +#endif + } cj; struct OP_IncrVacuum_stack_vars { Btree *pBt; - } cj; + } ck; struct OP_VBegin_stack_vars { VTable *pVTab; - } ck; + } cl; struct OP_VOpen_stack_vars { VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; sqlite3_module *pModule; - } cl; + } cm; struct OP_VFilter_stack_vars { int nArg; int iQuery; const sqlite3_module *pModule; Mem *pQuery; @@ -64068,40 +64095,40 @@ sqlite3_vtab *pVtab; VdbeCursor *pCur; int res; int i; Mem **apArg; - } cm; + } cn; struct OP_VColumn_stack_vars { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; - } cn; + } co; struct OP_VNext_stack_vars { sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; - } co; + } cp; struct OP_VRename_stack_vars { sqlite3_vtab *pVtab; Mem *pName; - } cp; + } cq; struct OP_VUpdate_stack_vars { sqlite3_vtab *pVtab; sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; Mem **apArg; Mem *pX; - } cq; + } cr; struct OP_Trace_stack_vars { char *zTrace; char *z; - } cr; + } cs; } u; /* End automatically generated code ********************************************************************/ assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ @@ -64488,29 +64515,34 @@ pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } -/* Opcode: Null * P2 P3 * * +/* Opcode: Null P1 P2 P3 * * ** ** Write a NULL into registers P2. If P3 greater than P2, then also write -** NULL into register P3 and ever register in between P2 and P3. If P3 +** NULL into register P3 and every register in between P2 and P3. If P3 ** is less than P2 (typically P3 is zero) then only register P2 is -** set to NULL +** set to NULL. +** +** If the P1 value is non-zero, then also set the MEM_Cleared flag so that +** NULL values will not compare equal even if SQLITE_NULLEQ is set on +** OP_Ne or OP_Eq. */ case OP_Null: { /* out2-prerelease */ #if 0 /* local variables moved into u.ab */ int cnt; + u16 nullFlag; #endif /* local variables moved into u.ab */ u.ab.cnt = pOp->p3-pOp->p2; assert( pOp->p3<=p->nMem ); - pOut->flags = MEM_Null; + pOut->flags = u.ab.nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; while( u.ab.cnt>0 ){ pOut++; memAboutToChange(p, pOut); VdbeMemRelease(pOut); - pOut->flags = MEM_Null; + pOut->flags = u.ab.nullFlag; u.ab.cnt--; } break; } @@ -64551,24 +64583,24 @@ break; } /* Opcode: Move P1 P2 P3 * * ** -** Move the values in register P1..P1+P3-1 over into -** registers P2..P2+P3-1. Registers P1..P1+P1-1 are +** Move the values in register P1..P1+P3 over into +** registers P2..P2+P3. Registers P1..P1+P3 are ** left holding a NULL. It is an error for register ranges -** P1..P1+P3-1 and P2..P2+P3-1 to overlap. +** P1..P1+P3 and P2..P2+P3 to overlap. */ case OP_Move: { #if 0 /* local variables moved into u.ad */ char *zMalloc; /* Holding variable for allocated memory */ int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ int p2; /* Register to copy to */ #endif /* local variables moved into u.ad */ - u.ad.n = pOp->p3; + u.ad.n = pOp->p3 + 1; u.ad.p1 = pOp->p1; u.ad.p2 = pOp->p2; assert( u.ad.n>0 && u.ad.p1>0 && u.ad.p2>0 ); assert( u.ad.p1+u.ad.n<=u.ad.p2 || u.ad.p2+u.ad.n<=u.ad.p1 ); @@ -64593,24 +64625,34 @@ pOut++; } break; } -/* Opcode: Copy P1 P2 * * * +/* Opcode: Copy P1 P2 P3 * * ** -** Make a copy of register P1 into register P2. +** Make a copy of registers P1..P1+P3 into registers P2..P2+P3. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ -case OP_Copy: { /* in1, out2 */ +case OP_Copy: { +#if 0 /* local variables moved into u.ae */ + int n; +#endif /* local variables moved into u.ae */ + + u.ae.n = pOp->p3; pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); - sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); - Deephemeralize(pOut); - REGISTER_TRACE(pOp->p2, pOut); + while( 1 ){ + sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); + Deephemeralize(pOut); + REGISTER_TRACE(pOp->p2+pOp->p3-u.ae.n, pOut); + if( (u.ae.n--)==0 ) break; + pOut++; + pIn1++; + } break; } /* Opcode: SCopy P1 P2 * * * ** @@ -64643,14 +64685,14 @@ ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt ** structure to provide access to the top P1 values as the result ** row. */ case OP_ResultRow: { -#if 0 /* local variables moved into u.ae */ +#if 0 /* local variables moved into u.af */ Mem *pMem; int i; -#endif /* local variables moved into u.ae */ +#endif /* local variables moved into u.af */ assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=p->nMem+1 ); /* If this statement has violated immediate foreign key constraints, do @@ -64688,19 +64730,19 @@ /* Make sure the results of the current row are \000 terminated ** and have an assigned type. The results are de-ephemeralized as ** a side effect. */ - u.ae.pMem = p->pResultSet = &aMem[pOp->p1]; - for(u.ae.i=0; u.ae.i<pOp->p2; u.ae.i++){ - assert( memIsValid(&u.ae.pMem[u.ae.i]) ); - Deephemeralize(&u.ae.pMem[u.ae.i]); - assert( (u.ae.pMem[u.ae.i].flags & MEM_Ephem)==0 - || (u.ae.pMem[u.ae.i].flags & (MEM_Str|MEM_Blob))==0 ); - sqlite3VdbeMemNulTerminate(&u.ae.pMem[u.ae.i]); - sqlite3VdbeMemStoreType(&u.ae.pMem[u.ae.i]); - REGISTER_TRACE(pOp->p1+u.ae.i, &u.ae.pMem[u.ae.i]); + u.af.pMem = p->pResultSet = &aMem[pOp->p1]; + for(u.af.i=0; u.af.i<pOp->p2; u.af.i++){ + assert( memIsValid(&u.af.pMem[u.af.i]) ); + Deephemeralize(&u.af.pMem[u.af.i]); + assert( (u.af.pMem[u.af.i].flags & MEM_Ephem)==0 + || (u.af.pMem[u.af.i].flags & (MEM_Str|MEM_Blob))==0 ); + sqlite3VdbeMemNulTerminate(&u.af.pMem[u.af.i]); + sqlite3VdbeMemStoreType(&u.af.pMem[u.af.i]); + REGISTER_TRACE(pOp->p1+u.af.i, &u.af.pMem[u.af.i]); } if( db->mallocFailed ) goto no_mem; /* Return SQLITE_ROW */ @@ -64720,13 +64762,13 @@ ** It is illegal for P1 and P3 to be the same register. Sometimes, ** if P3 is the same register as P2, the implementation is able ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ -#if 0 /* local variables moved into u.af */ +#if 0 /* local variables moved into u.ag */ i64 nByte; -#endif /* local variables moved into u.af */ +#endif /* local variables moved into u.ag */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; assert( pIn1!=pOut ); @@ -64735,26 +64777,26 @@ break; } if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; Stringify(pIn1, encoding); Stringify(pIn2, encoding); - u.af.nByte = pIn1->n + pIn2->n; - if( u.af.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + u.ag.nByte = pIn1->n + pIn2->n; + if( u.ag.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } MemSetTypeFlag(pOut, MEM_Str); - if( sqlite3VdbeMemGrow(pOut, (int)u.af.nByte+2, pOut==pIn2) ){ + if( sqlite3VdbeMemGrow(pOut, (int)u.ag.nByte+2, pOut==pIn2) ){ goto no_mem; } if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); - pOut->z[u.af.nByte] = 0; - pOut->z[u.af.nByte+1] = 0; + pOut->z[u.ag.nByte] = 0; + pOut->z[u.ag.nByte+1] = 0; pOut->flags |= MEM_Term; - pOut->n = (int)u.af.nByte; + pOut->n = (int)u.ag.nByte; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -64794,80 +64836,80 @@ case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ -#if 0 /* local variables moved into u.ag */ +#if 0 /* local variables moved into u.ah */ int flags; /* Combined MEM_* flags from both inputs */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ -#endif /* local variables moved into u.ag */ +#endif /* local variables moved into u.ah */ pIn1 = &aMem[pOp->p1]; applyNumericAffinity(pIn1); pIn2 = &aMem[pOp->p2]; applyNumericAffinity(pIn2); pOut = &aMem[pOp->p3]; - u.ag.flags = pIn1->flags | pIn2->flags; - if( (u.ag.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; + u.ah.flags = pIn1->flags | pIn2->flags; + if( (u.ah.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ - u.ag.iA = pIn1->u.i; - u.ag.iB = pIn2->u.i; + u.ah.iA = pIn1->u.i; + u.ah.iB = pIn2->u.i; switch( pOp->opcode ){ - case OP_Add: if( sqlite3AddInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break; - case OP_Subtract: if( sqlite3SubInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break; - case OP_Multiply: if( sqlite3MulInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break; + case OP_Add: if( sqlite3AddInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break; + case OP_Subtract: if( sqlite3SubInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break; + case OP_Multiply: if( sqlite3MulInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break; case OP_Divide: { - if( u.ag.iA==0 ) goto arithmetic_result_is_null; - if( u.ag.iA==-1 && u.ag.iB==SMALLEST_INT64 ) goto fp_math; - u.ag.iB /= u.ag.iA; + if( u.ah.iA==0 ) goto arithmetic_result_is_null; + if( u.ah.iA==-1 && u.ah.iB==SMALLEST_INT64 ) goto fp_math; + u.ah.iB /= u.ah.iA; break; } default: { - if( u.ag.iA==0 ) goto arithmetic_result_is_null; - if( u.ag.iA==-1 ) u.ag.iA = 1; - u.ag.iB %= u.ag.iA; + if( u.ah.iA==0 ) goto arithmetic_result_is_null; + if( u.ah.iA==-1 ) u.ah.iA = 1; + u.ah.iB %= u.ah.iA; break; } } - pOut->u.i = u.ag.iB; + pOut->u.i = u.ah.iB; MemSetTypeFlag(pOut, MEM_Int); }else{ fp_math: - u.ag.rA = sqlite3VdbeRealValue(pIn1); - u.ag.rB = sqlite3VdbeRealValue(pIn2); + u.ah.rA = sqlite3VdbeRealValue(pIn1); + u.ah.rB = sqlite3VdbeRealValue(pIn2); switch( pOp->opcode ){ - case OP_Add: u.ag.rB += u.ag.rA; break; - case OP_Subtract: u.ag.rB -= u.ag.rA; break; - case OP_Multiply: u.ag.rB *= u.ag.rA; break; + case OP_Add: u.ah.rB += u.ah.rA; break; + case OP_Subtract: u.ah.rB -= u.ah.rA; break; + case OP_Multiply: u.ah.rB *= u.ah.rA; break; case OP_Divide: { /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - if( u.ag.rA==(double)0 ) goto arithmetic_result_is_null; - u.ag.rB /= u.ag.rA; + if( u.ah.rA==(double)0 ) goto arithmetic_result_is_null; + u.ah.rB /= u.ah.rA; break; } default: { - u.ag.iA = (i64)u.ag.rA; - u.ag.iB = (i64)u.ag.rB; - if( u.ag.iA==0 ) goto arithmetic_result_is_null; - if( u.ag.iA==-1 ) u.ag.iA = 1; - u.ag.rB = (double)(u.ag.iB % u.ag.iA); + u.ah.iA = (i64)u.ah.rA; + u.ah.iB = (i64)u.ah.rB; + if( u.ah.iA==0 ) goto arithmetic_result_is_null; + if( u.ah.iA==-1 ) u.ah.iA = 1; + u.ah.rB = (double)(u.ah.iB % u.ah.iA); break; } } #ifdef SQLITE_OMIT_FLOATING_POINT - pOut->u.i = u.ag.rB; + pOut->u.i = u.ah.rB; MemSetTypeFlag(pOut, MEM_Int); #else - if( sqlite3IsNaN(u.ag.rB) ){ + if( sqlite3IsNaN(u.ah.rB) ){ goto arithmetic_result_is_null; } - pOut->r = u.ag.rB; + pOut->r = u.ah.rB; MemSetTypeFlag(pOut, MEM_Real); - if( (u.ag.flags & MEM_Real)==0 ){ + if( (u.ah.flags & MEM_Real)==0 ){ sqlite3VdbeIntegerAffinity(pOut); } #endif } break; @@ -64915,96 +64957,96 @@ ** invocation of this opcode. ** ** See also: AggStep and AggFinal */ case OP_Function: { -#if 0 /* local variables moved into u.ah */ +#if 0 /* local variables moved into u.ai */ int i; Mem *pArg; sqlite3_context ctx; sqlite3_value **apVal; int n; -#endif /* local variables moved into u.ah */ +#endif /* local variables moved into u.ai */ - u.ah.n = pOp->p5; - u.ah.apVal = p->apArg; - assert( u.ah.apVal || u.ah.n==0 ); + u.ai.n = pOp->p5; + u.ai.apVal = p->apArg; + assert( u.ai.apVal || u.ai.n==0 ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); - assert( u.ah.n==0 || (pOp->p2>0 && pOp->p2+u.ah.n<=p->nMem+1) ); - assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ah.n ); - u.ah.pArg = &aMem[pOp->p2]; - for(u.ah.i=0; u.ah.i<u.ah.n; u.ah.i++, u.ah.pArg++){ - assert( memIsValid(u.ah.pArg) ); - u.ah.apVal[u.ah.i] = u.ah.pArg; - Deephemeralize(u.ah.pArg); - sqlite3VdbeMemStoreType(u.ah.pArg); - REGISTER_TRACE(pOp->p2+u.ah.i, u.ah.pArg); + assert( u.ai.n==0 || (pOp->p2>0 && pOp->p2+u.ai.n<=p->nMem+1) ); + assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ai.n ); + u.ai.pArg = &aMem[pOp->p2]; + for(u.ai.i=0; u.ai.i<u.ai.n; u.ai.i++, u.ai.pArg++){ + assert( memIsValid(u.ai.pArg) ); + u.ai.apVal[u.ai.i] = u.ai.pArg; + Deephemeralize(u.ai.pArg); + sqlite3VdbeMemStoreType(u.ai.pArg); + REGISTER_TRACE(pOp->p2+u.ai.i, u.ai.pArg); } assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); if( pOp->p4type==P4_FUNCDEF ){ - u.ah.ctx.pFunc = pOp->p4.pFunc; - u.ah.ctx.pVdbeFunc = 0; + u.ai.ctx.pFunc = pOp->p4.pFunc; + u.ai.ctx.pVdbeFunc = 0; }else{ - u.ah.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; - u.ah.ctx.pFunc = u.ah.ctx.pVdbeFunc->pFunc; + u.ai.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; + u.ai.ctx.pFunc = u.ai.ctx.pVdbeFunc->pFunc; } - u.ah.ctx.s.flags = MEM_Null; - u.ah.ctx.s.db = db; - u.ah.ctx.s.xDel = 0; - u.ah.ctx.s.zMalloc = 0; + u.ai.ctx.s.flags = MEM_Null; + u.ai.ctx.s.db = db; + u.ai.ctx.s.xDel = 0; + u.ai.ctx.s.zMalloc = 0; /* The output cell may already have a buffer allocated. Move - ** the pointer to u.ah.ctx.s so in case the user-function can use + ** the pointer to u.ai.ctx.s so in case the user-function can use ** the already allocated buffer instead of allocating a new one. */ - sqlite3VdbeMemMove(&u.ah.ctx.s, pOut); - MemSetTypeFlag(&u.ah.ctx.s, MEM_Null); + sqlite3VdbeMemMove(&u.ai.ctx.s, pOut); + MemSetTypeFlag(&u.ai.ctx.s, MEM_Null); - u.ah.ctx.isError = 0; - if( u.ah.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ + u.ai.ctx.isError = 0; + if( u.ai.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ assert( pOp>aOp ); assert( pOp[-1].p4type==P4_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); - u.ah.ctx.pColl = pOp[-1].p4.pColl; + u.ai.ctx.pColl = pOp[-1].p4.pColl; } db->lastRowid = lastRowid; - (*u.ah.ctx.pFunc->xFunc)(&u.ah.ctx, u.ah.n, u.ah.apVal); /* IMP: R-24505-23230 */ + (*u.ai.ctx.pFunc->xFunc)(&u.ai.ctx, u.ai.n, u.ai.apVal); /* IMP: R-24505-23230 */ lastRowid = db->lastRowid; /* If any auxiliary data functions have been called by this user function, ** immediately call the destructor for any non-static values. */ - if( u.ah.ctx.pVdbeFunc ){ - sqlite3VdbeDeleteAuxData(u.ah.ctx.pVdbeFunc, pOp->p1); - pOp->p4.pVdbeFunc = u.ah.ctx.pVdbeFunc; + if( u.ai.ctx.pVdbeFunc ){ + sqlite3VdbeDeleteAuxData(u.ai.ctx.pVdbeFunc, pOp->p1); + pOp->p4.pVdbeFunc = u.ai.ctx.pVdbeFunc; pOp->p4type = P4_VDBEFUNC; } if( db->mallocFailed ){ /* Even though a malloc() has failed, the implementation of the ** user function may have called an sqlite3_result_XXX() function ** to return a value. The following call releases any resources ** associated with such a value. */ - sqlite3VdbeMemRelease(&u.ah.ctx.s); + sqlite3VdbeMemRelease(&u.ai.ctx.s); goto no_mem; } /* If the function returned an error, throw an exception */ - if( u.ah.ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ah.ctx.s)); - rc = u.ah.ctx.isError; + if( u.ai.ctx.isError ){ + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ai.ctx.s)); + rc = u.ai.ctx.isError; } /* Copy the result of the function into register P3 */ - sqlite3VdbeChangeEncoding(&u.ah.ctx.s, encoding); - sqlite3VdbeMemMove(pOut, &u.ah.ctx.s); + sqlite3VdbeChangeEncoding(&u.ai.ctx.s, encoding); + sqlite3VdbeMemMove(pOut, &u.ai.ctx.s); if( sqlite3VdbeMemTooBig(pOut) ){ goto too_big; } #if 0 @@ -65048,56 +65090,56 @@ */ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */ case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */ case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ -#if 0 /* local variables moved into u.ai */ +#if 0 /* local variables moved into u.aj */ i64 iA; u64 uA; i64 iB; u8 op; -#endif /* local variables moved into u.ai */ +#endif /* local variables moved into u.aj */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; if( (pIn1->flags | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } - u.ai.iA = sqlite3VdbeIntValue(pIn2); - u.ai.iB = sqlite3VdbeIntValue(pIn1); - u.ai.op = pOp->opcode; - if( u.ai.op==OP_BitAnd ){ - u.ai.iA &= u.ai.iB; - }else if( u.ai.op==OP_BitOr ){ - u.ai.iA |= u.ai.iB; - }else if( u.ai.iB!=0 ){ - assert( u.ai.op==OP_ShiftRight || u.ai.op==OP_ShiftLeft ); + u.aj.iA = sqlite3VdbeIntValue(pIn2); + u.aj.iB = sqlite3VdbeIntValue(pIn1); + u.aj.op = pOp->opcode; + if( u.aj.op==OP_BitAnd ){ + u.aj.iA &= u.aj.iB; + }else if( u.aj.op==OP_BitOr ){ + u.aj.iA |= u.aj.iB; + }else if( u.aj.iB!=0 ){ + assert( u.aj.op==OP_ShiftRight || u.aj.op==OP_ShiftLeft ); /* If shifting by a negative amount, shift in the other direction */ - if( u.ai.iB<0 ){ + if( u.aj.iB<0 ){ assert( OP_ShiftRight==OP_ShiftLeft+1 ); - u.ai.op = 2*OP_ShiftLeft + 1 - u.ai.op; - u.ai.iB = u.ai.iB>(-64) ? -u.ai.iB : 64; + u.aj.op = 2*OP_ShiftLeft + 1 - u.aj.op; + u.aj.iB = u.aj.iB>(-64) ? -u.aj.iB : 64; } - if( u.ai.iB>=64 ){ - u.ai.iA = (u.ai.iA>=0 || u.ai.op==OP_ShiftLeft) ? 0 : -1; + if( u.aj.iB>=64 ){ + u.aj.iA = (u.aj.iA>=0 || u.aj.op==OP_ShiftLeft) ? 0 : -1; }else{ - memcpy(&u.ai.uA, &u.ai.iA, sizeof(u.ai.uA)); - if( u.ai.op==OP_ShiftLeft ){ - u.ai.uA <<= u.ai.iB; + memcpy(&u.aj.uA, &u.aj.iA, sizeof(u.aj.uA)); + if( u.aj.op==OP_ShiftLeft ){ + u.aj.uA <<= u.aj.iB; }else{ - u.ai.uA >>= u.ai.iB; + u.aj.uA >>= u.aj.iB; /* Sign-extend on a right shift of a negative number */ - if( u.ai.iA<0 ) u.ai.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.ai.iB); + if( u.aj.iA<0 ) u.aj.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.aj.iB); } - memcpy(&u.ai.iA, &u.ai.uA, sizeof(u.ai.iA)); + memcpy(&u.aj.iA, &u.aj.uA, sizeof(u.aj.iA)); } } - pOut->u.i = u.ai.iA; + pOut->u.i = u.aj.iA; MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: AddImm P1 P2 * * * @@ -65285,10 +65327,14 @@ ** are of different types, then numbers are considered less than ** strings and strings are considered less than blobs. ** ** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead, ** store a boolean result (either 0, or 1, or NULL) in register P2. +** +** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered +** equal to one another, provided that they do not have their MEM_Cleared +** bit set. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** ** This works just like the Lt opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Lt opcode for @@ -65334,30 +65380,38 @@ case OP_Ne: /* same as TK_NE, jump, in1, in3 */ case OP_Lt: /* same as TK_LT, jump, in1, in3 */ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ -#if 0 /* local variables moved into u.aj */ +#if 0 /* local variables moved into u.ak */ int res; /* Result of the comparison of pIn1 against pIn3 */ char affinity; /* Affinity to use for comparison */ u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ -#endif /* local variables moved into u.aj */ +#endif /* local variables moved into u.ak */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; - u.aj.flags1 = pIn1->flags; - u.aj.flags3 = pIn3->flags; - if( (u.aj.flags1 | u.aj.flags3)&MEM_Null ){ + u.ak.flags1 = pIn1->flags; + u.ak.flags3 = pIn3->flags; + if( (u.ak.flags1 | u.ak.flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ /* If SQLITE_NULLEQ is set (which will only happen if the operator is ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); - u.aj.res = (u.aj.flags1 & u.aj.flags3 & MEM_Null)==0; + assert( (u.ak.flags1 & MEM_Cleared)==0 ); + if( (u.ak.flags1&MEM_Null)!=0 + && (u.ak.flags3&MEM_Null)!=0 + && (u.ak.flags3&MEM_Cleared)==0 + ){ + u.ak.res = 0; /* Results are equal */ + }else{ + u.ak.res = 1; /* Results are not equal */ + } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ @@ -65370,44 +65424,44 @@ } break; } }else{ /* Neither operand is NULL. Do a comparison. */ - u.aj.affinity = pOp->p5 & SQLITE_AFF_MASK; - if( u.aj.affinity ){ - applyAffinity(pIn1, u.aj.affinity, encoding); - applyAffinity(pIn3, u.aj.affinity, encoding); + u.ak.affinity = pOp->p5 & SQLITE_AFF_MASK; + if( u.ak.affinity ){ + applyAffinity(pIn1, u.ak.affinity, encoding); + applyAffinity(pIn3, u.ak.affinity, encoding); if( db->mallocFailed ) goto no_mem; } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); ExpandBlob(pIn1); ExpandBlob(pIn3); - u.aj.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); + u.ak.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } switch( pOp->opcode ){ - case OP_Eq: u.aj.res = u.aj.res==0; break; - case OP_Ne: u.aj.res = u.aj.res!=0; break; - case OP_Lt: u.aj.res = u.aj.res<0; break; - case OP_Le: u.aj.res = u.aj.res<=0; break; - case OP_Gt: u.aj.res = u.aj.res>0; break; - default: u.aj.res = u.aj.res>=0; break; + case OP_Eq: u.ak.res = u.ak.res==0; break; + case OP_Ne: u.ak.res = u.ak.res!=0; break; + case OP_Lt: u.ak.res = u.ak.res<0; break; + case OP_Le: u.ak.res = u.ak.res<=0; break; + case OP_Gt: u.ak.res = u.ak.res>0; break; + default: u.ak.res = u.ak.res>=0; break; } if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Int); - pOut->u.i = u.aj.res; + pOut->u.i = u.ak.res; REGISTER_TRACE(pOp->p2, pOut); - }else if( u.aj.res ){ + }else if( u.ak.res ){ pc = pOp->p2-1; } /* Undo any changes made by applyAffinity() to the input registers. */ - pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.aj.flags1&MEM_TypeMask); - pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.aj.flags3&MEM_TypeMask); + pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.ak.flags1&MEM_TypeMask); + pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.ak.flags3&MEM_TypeMask); break; } /* Opcode: Permutation * * * P4 * ** @@ -65438,50 +65492,50 @@ ** The comparison is a sort comparison, so NULLs compare equal, ** NULLs are less than numbers, numbers are less than strings, ** and strings are less than blobs. */ case OP_Compare: { -#if 0 /* local variables moved into u.ak */ +#if 0 /* local variables moved into u.al */ int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; int idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ -#endif /* local variables moved into u.ak */ +#endif /* local variables moved into u.al */ - u.ak.n = pOp->p3; - u.ak.pKeyInfo = pOp->p4.pKeyInfo; - assert( u.ak.n>0 ); - assert( u.ak.pKeyInfo!=0 ); - u.ak.p1 = pOp->p1; - u.ak.p2 = pOp->p2; + u.al.n = pOp->p3; + u.al.pKeyInfo = pOp->p4.pKeyInfo; + assert( u.al.n>0 ); + assert( u.al.pKeyInfo!=0 ); + u.al.p1 = pOp->p1; + u.al.p2 = pOp->p2; #if SQLITE_DEBUG if( aPermute ){ int k, mx = 0; - for(k=0; k<u.ak.n; k++) if( aPermute[k]>mx ) mx = aPermute[k]; - assert( u.ak.p1>0 && u.ak.p1+mx<=p->nMem+1 ); - assert( u.ak.p2>0 && u.ak.p2+mx<=p->nMem+1 ); + for(k=0; k<u.al.n; k++) if( aPermute[k]>mx ) mx = aPermute[k]; + assert( u.al.p1>0 && u.al.p1+mx<=p->nMem+1 ); + assert( u.al.p2>0 && u.al.p2+mx<=p->nMem+1 ); }else{ - assert( u.ak.p1>0 && u.ak.p1+u.ak.n<=p->nMem+1 ); - assert( u.ak.p2>0 && u.ak.p2+u.ak.n<=p->nMem+1 ); + assert( u.al.p1>0 && u.al.p1+u.al.n<=p->nMem+1 ); + assert( u.al.p2>0 && u.al.p2+u.al.n<=p->nMem+1 ); } #endif /* SQLITE_DEBUG */ - for(u.ak.i=0; u.ak.i<u.ak.n; u.ak.i++){ - u.ak.idx = aPermute ? aPermute[u.ak.i] : u.ak.i; - assert( memIsValid(&aMem[u.ak.p1+u.ak.idx]) ); - assert( memIsValid(&aMem[u.ak.p2+u.ak.idx]) ); - REGISTER_TRACE(u.ak.p1+u.ak.idx, &aMem[u.ak.p1+u.ak.idx]); - REGISTER_TRACE(u.ak.p2+u.ak.idx, &aMem[u.ak.p2+u.ak.idx]); - assert( u.ak.i<u.ak.pKeyInfo->nField ); - u.ak.pColl = u.ak.pKeyInfo->aColl[u.ak.i]; - u.ak.bRev = u.ak.pKeyInfo->aSortOrder[u.ak.i]; - iCompare = sqlite3MemCompare(&aMem[u.ak.p1+u.ak.idx], &aMem[u.ak.p2+u.ak.idx], u.ak.pColl); + for(u.al.i=0; u.al.i<u.al.n; u.al.i++){ + u.al.idx = aPermute ? aPermute[u.al.i] : u.al.i; + assert( memIsValid(&aMem[u.al.p1+u.al.idx]) ); + assert( memIsValid(&aMem[u.al.p2+u.al.idx]) ); + REGISTER_TRACE(u.al.p1+u.al.idx, &aMem[u.al.p1+u.al.idx]); + REGISTER_TRACE(u.al.p2+u.al.idx, &aMem[u.al.p2+u.al.idx]); + assert( u.al.i<u.al.pKeyInfo->nField ); + u.al.pColl = u.al.pKeyInfo->aColl[u.al.i]; + u.al.bRev = u.al.pKeyInfo->aSortOrder[u.al.i]; + iCompare = sqlite3MemCompare(&aMem[u.al.p1+u.al.idx], &aMem[u.al.p2+u.al.idx], u.al.pColl); if( iCompare ){ - if( u.ak.bRev ) iCompare = -iCompare; + if( u.al.bRev ) iCompare = -iCompare; break; } } aPermute = 0; break; @@ -65522,39 +65576,39 @@ ** even if the other input is NULL. A NULL and false or two NULLs ** give a NULL output. */ case OP_And: /* same as TK_AND, in1, in2, out3 */ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ -#if 0 /* local variables moved into u.al */ +#if 0 /* local variables moved into u.am */ int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ -#endif /* local variables moved into u.al */ +#endif /* local variables moved into u.am */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & MEM_Null ){ - u.al.v1 = 2; + u.am.v1 = 2; }else{ - u.al.v1 = sqlite3VdbeIntValue(pIn1)!=0; + u.am.v1 = sqlite3VdbeIntValue(pIn1)!=0; } pIn2 = &aMem[pOp->p2]; if( pIn2->flags & MEM_Null ){ - u.al.v2 = 2; + u.am.v2 = 2; }else{ - u.al.v2 = sqlite3VdbeIntValue(pIn2)!=0; + u.am.v2 = sqlite3VdbeIntValue(pIn2)!=0; } if( pOp->opcode==OP_And ){ static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; - u.al.v1 = and_logic[u.al.v1*3+u.al.v2]; + u.am.v1 = and_logic[u.am.v1*3+u.am.v2]; }else{ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; - u.al.v1 = or_logic[u.al.v1*3+u.al.v2]; + u.am.v1 = or_logic[u.am.v1*3+u.am.v2]; } pOut = &aMem[pOp->p3]; - if( u.al.v1==2 ){ + if( u.am.v1==2 ){ MemSetTypeFlag(pOut, MEM_Null); }else{ - pOut->u.i = u.al.v1; + pOut->u.i = u.am.v1; MemSetTypeFlag(pOut, MEM_Int); } break; } @@ -65621,25 +65675,25 @@ ** is considered false if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if P3 is zero. */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ -#if 0 /* local variables moved into u.am */ +#if 0 /* local variables moved into u.an */ int c; -#endif /* local variables moved into u.am */ +#endif /* local variables moved into u.an */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & MEM_Null ){ - u.am.c = pOp->p3; + u.an.c = pOp->p3; }else{ #ifdef SQLITE_OMIT_FLOATING_POINT - u.am.c = sqlite3VdbeIntValue(pIn1)!=0; + u.an.c = sqlite3VdbeIntValue(pIn1)!=0; #else - u.am.c = sqlite3VdbeRealValue(pIn1)!=0.0; + u.an.c = sqlite3VdbeRealValue(pIn1)!=0.0; #endif - if( pOp->opcode==OP_IfNot ) u.am.c = !u.am.c; + if( pOp->opcode==OP_IfNot ) u.an.c = !u.an.c; } - if( u.am.c ){ + if( u.an.c ){ pc = pOp->p2-1; } break; } @@ -65690,11 +65744,11 @@ ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { -#if 0 /* local variables moved into u.an */ +#if 0 /* local variables moved into u.ao */ u32 payloadSize; /* Number of bytes in the record */ i64 payloadSize64; /* Number of bytes in the record */ int p1; /* P1 value of the opcode */ int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ @@ -65714,130 +65768,130 @@ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ -#endif /* local variables moved into u.an */ +#endif /* local variables moved into u.ao */ - u.an.p1 = pOp->p1; - u.an.p2 = pOp->p2; - u.an.pC = 0; - memset(&u.an.sMem, 0, sizeof(u.an.sMem)); - assert( u.an.p1<p->nCursor ); + u.ao.p1 = pOp->p1; + u.ao.p2 = pOp->p2; + u.ao.pC = 0; + memset(&u.ao.sMem, 0, sizeof(u.ao.sMem)); + assert( u.ao.p1<p->nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); - u.an.pDest = &aMem[pOp->p3]; - memAboutToChange(p, u.an.pDest); - u.an.zRec = 0; + u.ao.pDest = &aMem[pOp->p3]; + memAboutToChange(p, u.ao.pDest); + u.ao.zRec = 0; - /* This block sets the variable u.an.payloadSize to be the total number of + /* This block sets the variable u.ao.payloadSize to be the total number of ** bytes in the record. ** - ** u.an.zRec is set to be the complete text of the record if it is available. + ** u.ao.zRec is set to be the complete text of the record if it is available. ** The complete record text is always available for pseudo-tables ** If the record is stored in a cursor, the complete record text - ** might be available in the u.an.pC->aRow cache. Or it might not be. - ** If the data is unavailable, u.an.zRec is set to NULL. + ** might be available in the u.ao.pC->aRow cache. Or it might not be. + ** If the data is unavailable, u.ao.zRec is set to NULL. ** ** We also compute the number of columns in the record. For cursors, ** the number of columns is stored in the VdbeCursor.nField element. */ - u.an.pC = p->apCsr[u.an.p1]; - assert( u.an.pC!=0 ); + u.ao.pC = p->apCsr[u.ao.p1]; + assert( u.ao.pC!=0 ); #ifndef SQLITE_OMIT_VIRTUALTABLE - assert( u.an.pC->pVtabCursor==0 ); + assert( u.ao.pC->pVtabCursor==0 ); #endif - u.an.pCrsr = u.an.pC->pCursor; - if( u.an.pCrsr!=0 ){ + u.ao.pCrsr = u.ao.pC->pCursor; + if( u.ao.pCrsr!=0 ){ /* The record is stored in a B-Tree */ - rc = sqlite3VdbeCursorMoveto(u.an.pC); + rc = sqlite3VdbeCursorMoveto(u.ao.pC); if( rc ) goto abort_due_to_error; - if( u.an.pC->nullRow ){ - u.an.payloadSize = 0; - }else if( u.an.pC->cacheStatus==p->cacheCtr ){ - u.an.payloadSize = u.an.pC->payloadSize; - u.an.zRec = (char*)u.an.pC->aRow; - }else if( u.an.pC->isIndex ){ - assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(u.an.pCrsr, &u.an.payloadSize64); + if( u.ao.pC->nullRow ){ + u.ao.payloadSize = 0; + }else if( u.ao.pC->cacheStatus==p->cacheCtr ){ + u.ao.payloadSize = u.ao.pC->payloadSize; + u.ao.zRec = (char*)u.ao.pC->aRow; + }else if( u.ao.pC->isIndex ){ + assert( sqlite3BtreeCursorIsValid(u.ao.pCrsr) ); + VVA_ONLY(rc =) sqlite3BtreeKeySize(u.ao.pCrsr, &u.ao.payloadSize64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the - ** payload size, so it is impossible for u.an.payloadSize64 to be + ** payload size, so it is impossible for u.ao.payloadSize64 to be ** larger than 32 bits. */ - assert( (u.an.payloadSize64 & SQLITE_MAX_U32)==(u64)u.an.payloadSize64 ); - u.an.payloadSize = (u32)u.an.payloadSize64; + assert( (u.ao.payloadSize64 & SQLITE_MAX_U32)==(u64)u.ao.payloadSize64 ); + u.ao.payloadSize = (u32)u.ao.payloadSize64; }else{ - assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeDataSize(u.an.pCrsr, &u.an.payloadSize); + assert( sqlite3BtreeCursorIsValid(u.ao.pCrsr) ); + VVA_ONLY(rc =) sqlite3BtreeDataSize(u.ao.pCrsr, &u.ao.payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } - }else if( ALWAYS(u.an.pC->pseudoTableReg>0) ){ - u.an.pReg = &aMem[u.an.pC->pseudoTableReg]; - assert( u.an.pReg->flags & MEM_Blob ); - assert( memIsValid(u.an.pReg) ); - u.an.payloadSize = u.an.pReg->n; - u.an.zRec = u.an.pReg->z; - u.an.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr; - assert( u.an.payloadSize==0 || u.an.zRec!=0 ); + }else if( ALWAYS(u.ao.pC->pseudoTableReg>0) ){ + u.ao.pReg = &aMem[u.ao.pC->pseudoTableReg]; + assert( u.ao.pReg->flags & MEM_Blob ); + assert( memIsValid(u.ao.pReg) ); + u.ao.payloadSize = u.ao.pReg->n; + u.ao.zRec = u.ao.pReg->z; + u.ao.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr; + assert( u.ao.payloadSize==0 || u.ao.zRec!=0 ); }else{ /* Consider the row to be NULL */ - u.an.payloadSize = 0; + u.ao.payloadSize = 0; } - /* If u.an.payloadSize is 0, then just store a NULL. This can happen because of + /* If u.ao.payloadSize is 0, then just store a NULL. This can happen because of ** nullRow or because of a corrupt database. */ - if( u.an.payloadSize==0 ){ - MemSetTypeFlag(u.an.pDest, MEM_Null); + if( u.ao.payloadSize==0 ){ + MemSetTypeFlag(u.ao.pDest, MEM_Null); goto op_column_out; } assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 ); - if( u.an.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( u.ao.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - u.an.nField = u.an.pC->nField; - assert( u.an.p2<u.an.nField ); + u.ao.nField = u.ao.pC->nField; + assert( u.ao.p2<u.ao.nField ); /* Read and parse the table header. Store the results of the parse ** into the record header cache fields of the cursor. */ - u.an.aType = u.an.pC->aType; - if( u.an.pC->cacheStatus==p->cacheCtr ){ - u.an.aOffset = u.an.pC->aOffset; + u.ao.aType = u.ao.pC->aType; + if( u.ao.pC->cacheStatus==p->cacheCtr ){ + u.ao.aOffset = u.ao.pC->aOffset; }else{ - assert(u.an.aType); - u.an.avail = 0; - u.an.pC->aOffset = u.an.aOffset = &u.an.aType[u.an.nField]; - u.an.pC->payloadSize = u.an.payloadSize; - u.an.pC->cacheStatus = p->cacheCtr; + assert(u.ao.aType); + u.ao.avail = 0; + u.ao.pC->aOffset = u.ao.aOffset = &u.ao.aType[u.ao.nField]; + u.ao.pC->payloadSize = u.ao.payloadSize; + u.ao.pC->cacheStatus = p->cacheCtr; /* Figure out how many bytes are in the header */ - if( u.an.zRec ){ - u.an.zData = u.an.zRec; + if( u.ao.zRec ){ + u.ao.zData = u.ao.zRec; }else{ - if( u.an.pC->isIndex ){ - u.an.zData = (char*)sqlite3BtreeKeyFetch(u.an.pCrsr, &u.an.avail); + if( u.ao.pC->isIndex ){ + u.ao.zData = (char*)sqlite3BtreeKeyFetch(u.ao.pCrsr, &u.ao.avail); }else{ - u.an.zData = (char*)sqlite3BtreeDataFetch(u.an.pCrsr, &u.an.avail); + u.ao.zData = (char*)sqlite3BtreeDataFetch(u.ao.pCrsr, &u.ao.avail); } /* If KeyFetch()/DataFetch() managed to get the entire payload, - ** save the payload in the u.an.pC->aRow cache. That will save us from + ** save the payload in the u.ao.pC->aRow cache. That will save us from ** having to make additional calls to fetch the content portion of ** the record. */ - assert( u.an.avail>=0 ); - if( u.an.payloadSize <= (u32)u.an.avail ){ - u.an.zRec = u.an.zData; - u.an.pC->aRow = (u8*)u.an.zData; + assert( u.ao.avail>=0 ); + if( u.ao.payloadSize <= (u32)u.ao.avail ){ + u.ao.zRec = u.ao.zData; + u.ao.pC->aRow = (u8*)u.ao.zData; }else{ - u.an.pC->aRow = 0; + u.ao.pC->aRow = 0; } } /* The following assert is true in all cases except when ** the database file has been corrupted externally. - ** assert( u.an.zRec!=0 || u.an.avail>=u.an.payloadSize || u.an.avail>=9 ); */ - u.an.szHdr = getVarint32((u8*)u.an.zData, u.an.offset); + ** assert( u.ao.zRec!=0 || u.ao.avail>=u.ao.payloadSize || u.ao.avail>=9 ); */ + u.ao.szHdr = getVarint32((u8*)u.ao.zData, u.ao.offset); /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. ** ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte @@ -65844,161 +65898,161 @@ ** types use so much data space that there can only be 4096 and 32 of ** them, respectively. So the maximum header length results from a ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ - if( u.an.offset > 98307 ){ + if( u.ao.offset > 98307 ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_out; } - /* Compute in u.an.len the number of bytes of data we need to read in order - ** to get u.an.nField type values. u.an.offset is an upper bound on this. But - ** u.an.nField might be significantly less than the true number of columns - ** in the table, and in that case, 5*u.an.nField+3 might be smaller than u.an.offset. - ** We want to minimize u.an.len in order to limit the size of the memory - ** allocation, especially if a corrupt database file has caused u.an.offset + /* Compute in u.ao.len the number of bytes of data we need to read in order + ** to get u.ao.nField type values. u.ao.offset is an upper bound on this. But + ** u.ao.nField might be significantly less than the true number of columns + ** in the table, and in that case, 5*u.ao.nField+3 might be smaller than u.ao.offset. + ** We want to minimize u.ao.len in order to limit the size of the memory + ** allocation, especially if a corrupt database file has caused u.ao.offset ** to be oversized. Offset is limited to 98307 above. But 98307 might ** still exceed Robson memory allocation limits on some configurations. - ** On systems that cannot tolerate large memory allocations, u.an.nField*5+3 - ** will likely be much smaller since u.an.nField will likely be less than + ** On systems that cannot tolerate large memory allocations, u.ao.nField*5+3 + ** will likely be much smaller since u.ao.nField will likely be less than ** 20 or so. This insures that Robson memory allocation limits are ** not exceeded even for corrupt database files. */ - u.an.len = u.an.nField*5 + 3; - if( u.an.len > (int)u.an.offset ) u.an.len = (int)u.an.offset; + u.ao.len = u.ao.nField*5 + 3; + if( u.ao.len > (int)u.ao.offset ) u.ao.len = (int)u.ao.offset; /* The KeyFetch() or DataFetch() above are fast and will get the entire ** record header in most cases. But they will fail to get the complete ** record header if the record header does not fit on a single page ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to ** acquire the complete header text. */ - if( !u.an.zRec && u.an.avail<u.an.len ){ - u.an.sMem.flags = 0; - u.an.sMem.db = 0; - rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, 0, u.an.len, u.an.pC->isIndex, &u.an.sMem); + if( !u.ao.zRec && u.ao.avail<u.ao.len ){ + u.ao.sMem.flags = 0; + u.ao.sMem.db = 0; + rc = sqlite3VdbeMemFromBtree(u.ao.pCrsr, 0, u.ao.len, u.ao.pC->isIndex, &u.ao.sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } - u.an.zData = u.an.sMem.z; - } - u.an.zEndHdr = (u8 *)&u.an.zData[u.an.len]; - u.an.zIdx = (u8 *)&u.an.zData[u.an.szHdr]; - - /* Scan the header and use it to fill in the u.an.aType[] and u.an.aOffset[] - ** arrays. u.an.aType[u.an.i] will contain the type integer for the u.an.i-th - ** column and u.an.aOffset[u.an.i] will contain the u.an.offset from the beginning - ** of the record to the start of the data for the u.an.i-th column - */ - for(u.an.i=0; u.an.i<u.an.nField; u.an.i++){ - if( u.an.zIdx<u.an.zEndHdr ){ - u.an.aOffset[u.an.i] = u.an.offset; - if( u.an.zIdx[0]<0x80 ){ - u.an.t = u.an.zIdx[0]; - u.an.zIdx++; - }else{ - u.an.zIdx += sqlite3GetVarint32(u.an.zIdx, &u.an.t); - } - u.an.aType[u.an.i] = u.an.t; - u.an.szField = sqlite3VdbeSerialTypeLen(u.an.t); - u.an.offset += u.an.szField; - if( u.an.offset<u.an.szField ){ /* True if u.an.offset overflows */ - u.an.zIdx = &u.an.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */ - break; - } - }else{ - /* If u.an.i is less that u.an.nField, then there are fewer fields in this + u.ao.zData = u.ao.sMem.z; + } + u.ao.zEndHdr = (u8 *)&u.ao.zData[u.ao.len]; + u.ao.zIdx = (u8 *)&u.ao.zData[u.ao.szHdr]; + + /* Scan the header and use it to fill in the u.ao.aType[] and u.ao.aOffset[] + ** arrays. u.ao.aType[u.ao.i] will contain the type integer for the u.ao.i-th + ** column and u.ao.aOffset[u.ao.i] will contain the u.ao.offset from the beginning + ** of the record to the start of the data for the u.ao.i-th column + */ + for(u.ao.i=0; u.ao.i<u.ao.nField; u.ao.i++){ + if( u.ao.zIdx<u.ao.zEndHdr ){ + u.ao.aOffset[u.ao.i] = u.ao.offset; + if( u.ao.zIdx[0]<0x80 ){ + u.ao.t = u.ao.zIdx[0]; + u.ao.zIdx++; + }else{ + u.ao.zIdx += sqlite3GetVarint32(u.ao.zIdx, &u.ao.t); + } + u.ao.aType[u.ao.i] = u.ao.t; + u.ao.szField = sqlite3VdbeSerialTypeLen(u.ao.t); + u.ao.offset += u.ao.szField; + if( u.ao.offset<u.ao.szField ){ /* True if u.ao.offset overflows */ + u.ao.zIdx = &u.ao.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */ + break; + } + }else{ + /* If u.ao.i is less that u.ao.nField, then there are fewer fields in this ** record than SetNumColumns indicated there are columns in the - ** table. Set the u.an.offset for any extra columns not present in + ** table. Set the u.ao.offset for any extra columns not present in ** the record to 0. This tells code below to store the default value ** for the column instead of deserializing a value from the record. */ - u.an.aOffset[u.an.i] = 0; + u.ao.aOffset[u.ao.i] = 0; } } - sqlite3VdbeMemRelease(&u.an.sMem); - u.an.sMem.flags = MEM_Null; + sqlite3VdbeMemRelease(&u.ao.sMem); + u.ao.sMem.flags = MEM_Null; /* If we have read more header data than was contained in the header, ** or if the end of the last field appears to be past the end of the ** record, or if the end of the last field appears to be before the end ** of the record (when all fields present), then we must be dealing ** with a corrupt database. */ - if( (u.an.zIdx > u.an.zEndHdr) || (u.an.offset > u.an.payloadSize) - || (u.an.zIdx==u.an.zEndHdr && u.an.offset!=u.an.payloadSize) ){ + if( (u.ao.zIdx > u.ao.zEndHdr) || (u.ao.offset > u.ao.payloadSize) + || (u.ao.zIdx==u.ao.zEndHdr && u.ao.offset!=u.ao.payloadSize) ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_out; } } - /* Get the column information. If u.an.aOffset[u.an.p2] is non-zero, then - ** deserialize the value from the record. If u.an.aOffset[u.an.p2] is zero, + /* Get the column information. If u.ao.aOffset[u.ao.p2] is non-zero, then + ** deserialize the value from the record. If u.ao.aOffset[u.ao.p2] is zero, ** then there are not enough fields in the record to satisfy the ** request. In this case, set the value NULL or to P4 if P4 is ** a pointer to a Mem object. */ - if( u.an.aOffset[u.an.p2] ){ + if( u.ao.aOffset[u.ao.p2] ){ assert( rc==SQLITE_OK ); - if( u.an.zRec ){ + if( u.ao.zRec ){ /* This is the common case where the whole row fits on a single page */ - VdbeMemRelease(u.an.pDest); - sqlite3VdbeSerialGet((u8 *)&u.an.zRec[u.an.aOffset[u.an.p2]], u.an.aType[u.an.p2], u.an.pDest); + VdbeMemRelease(u.ao.pDest); + sqlite3VdbeSerialGet((u8 *)&u.ao.zRec[u.ao.aOffset[u.ao.p2]], u.ao.aType[u.ao.p2], u.ao.pDest); }else{ /* This branch happens only when the row overflows onto multiple pages */ - u.an.t = u.an.aType[u.an.p2]; + u.ao.t = u.ao.aType[u.ao.p2]; if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 - && ((u.an.t>=12 && (u.an.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0) + && ((u.ao.t>=12 && (u.ao.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0) ){ /* Content is irrelevant for the typeof() function and for ** the length(X) function if X is a blob. So we might as well use ** bogus content rather than reading content from disk. NULL works - ** for text and blob and whatever is in the u.an.payloadSize64 variable + ** for text and blob and whatever is in the u.ao.payloadSize64 variable ** will work for everything else. */ - u.an.zData = u.an.t<12 ? (char*)&u.an.payloadSize64 : 0; + u.ao.zData = u.ao.t<12 ? (char*)&u.ao.payloadSize64 : 0; }else{ - u.an.len = sqlite3VdbeSerialTypeLen(u.an.t); - sqlite3VdbeMemMove(&u.an.sMem, u.an.pDest); - rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, u.an.aOffset[u.an.p2], u.an.len, u.an.pC->isIndex, - &u.an.sMem); + u.ao.len = sqlite3VdbeSerialTypeLen(u.ao.t); + sqlite3VdbeMemMove(&u.ao.sMem, u.ao.pDest); + rc = sqlite3VdbeMemFromBtree(u.ao.pCrsr, u.ao.aOffset[u.ao.p2], u.ao.len, u.ao.pC->isIndex, + &u.ao.sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } - u.an.zData = u.an.sMem.z; + u.ao.zData = u.ao.sMem.z; } - sqlite3VdbeSerialGet((u8*)u.an.zData, u.an.t, u.an.pDest); + sqlite3VdbeSerialGet((u8*)u.ao.zData, u.ao.t, u.ao.pDest); } - u.an.pDest->enc = encoding; + u.ao.pDest->enc = encoding; }else{ if( pOp->p4type==P4_MEM ){ - sqlite3VdbeMemShallowCopy(u.an.pDest, pOp->p4.pMem, MEM_Static); + sqlite3VdbeMemShallowCopy(u.ao.pDest, pOp->p4.pMem, MEM_Static); }else{ - MemSetTypeFlag(u.an.pDest, MEM_Null); + MemSetTypeFlag(u.ao.pDest, MEM_Null); } } /* If we dynamically allocated space to hold the data (in the ** sqlite3VdbeMemFromBtree() call above) then transfer control of that - ** dynamically allocated space over to the u.an.pDest structure. + ** dynamically allocated space over to the u.ao.pDest structure. ** This prevents a memory copy. */ - if( u.an.sMem.zMalloc ){ - assert( u.an.sMem.z==u.an.sMem.zMalloc ); - assert( !(u.an.pDest->flags & MEM_Dyn) ); - assert( !(u.an.pDest->flags & (MEM_Blob|MEM_Str)) || u.an.pDest->z==u.an.sMem.z ); - u.an.pDest->flags &= ~(MEM_Ephem|MEM_Static); - u.an.pDest->flags |= MEM_Term; - u.an.pDest->z = u.an.sMem.z; - u.an.pDest->zMalloc = u.an.sMem.zMalloc; + if( u.ao.sMem.zMalloc ){ + assert( u.ao.sMem.z==u.ao.sMem.zMalloc ); + assert( !(u.ao.pDest->flags & MEM_Dyn) ); + assert( !(u.ao.pDest->flags & (MEM_Blob|MEM_Str)) || u.ao.pDest->z==u.ao.sMem.z ); + u.ao.pDest->flags &= ~(MEM_Ephem|MEM_Static); + u.ao.pDest->flags |= MEM_Term; + u.ao.pDest->z = u.ao.sMem.z; + u.ao.pDest->zMalloc = u.ao.sMem.zMalloc; } - rc = sqlite3VdbeMemMakeWriteable(u.an.pDest); + rc = sqlite3VdbeMemMakeWriteable(u.ao.pDest); op_column_out: - UPDATE_MAX_BLOBSIZE(u.an.pDest); - REGISTER_TRACE(pOp->p3, u.an.pDest); + UPDATE_MAX_BLOBSIZE(u.ao.pDest); + REGISTER_TRACE(pOp->p3, u.ao.pDest); break; } /* Opcode: Affinity P1 P2 * P4 * ** @@ -66007,24 +66061,24 @@ ** P4 is a string that is P2 characters long. The nth character of the ** string indicates the column affinity that should be used for the nth ** memory cell in the range. */ case OP_Affinity: { -#if 0 /* local variables moved into u.ao */ +#if 0 /* local variables moved into u.ap */ const char *zAffinity; /* The affinity to be applied */ char cAff; /* A single character of affinity */ -#endif /* local variables moved into u.ao */ +#endif /* local variables moved into u.ap */ - u.ao.zAffinity = pOp->p4.z; - assert( u.ao.zAffinity!=0 ); - assert( u.ao.zAffinity[pOp->p2]==0 ); + u.ap.zAffinity = pOp->p4.z; + assert( u.ap.zAffinity!=0 ); + assert( u.ap.zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - while( (u.ao.cAff = *(u.ao.zAffinity++))!=0 ){ + while( (u.ap.cAff = *(u.ap.zAffinity++))!=0 ){ assert( pIn1 <= &p->aMem[p->nMem] ); assert( memIsValid(pIn1) ); ExpandBlob(pIn1); - applyAffinity(pIn1, u.ao.cAff, encoding); + applyAffinity(pIn1, u.ap.cAff, encoding); pIn1++; } break; } @@ -66042,11 +66096,11 @@ ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity NONE. */ case OP_MakeRecord: { -#if 0 /* local variables moved into u.ap */ +#if 0 /* local variables moved into u.aq */ u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ i64 nByte; /* Data space required for this record */ @@ -66058,11 +66112,11 @@ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ int len; /* Length of a field */ -#endif /* local variables moved into u.ap */ +#endif /* local variables moved into u.aq */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ @@ -66075,87 +66129,87 @@ ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. */ - u.ap.nData = 0; /* Number of bytes of data space */ - u.ap.nHdr = 0; /* Number of bytes of header space */ - u.ap.nZero = 0; /* Number of zero bytes at the end of the record */ - u.ap.nField = pOp->p1; - u.ap.zAffinity = pOp->p4.z; - assert( u.ap.nField>0 && pOp->p2>0 && pOp->p2+u.ap.nField<=p->nMem+1 ); - u.ap.pData0 = &aMem[u.ap.nField]; - u.ap.nField = pOp->p2; - u.ap.pLast = &u.ap.pData0[u.ap.nField-1]; - u.ap.file_format = p->minWriteFileFormat; + u.aq.nData = 0; /* Number of bytes of data space */ + u.aq.nHdr = 0; /* Number of bytes of header space */ + u.aq.nZero = 0; /* Number of zero bytes at the end of the record */ + u.aq.nField = pOp->p1; + u.aq.zAffinity = pOp->p4.z; + assert( u.aq.nField>0 && pOp->p2>0 && pOp->p2+u.aq.nField<=p->nMem+1 ); + u.aq.pData0 = &aMem[u.aq.nField]; + u.aq.nField = pOp->p2; + u.aq.pLast = &u.aq.pData0[u.aq.nField-1]; + u.aq.file_format = p->minWriteFileFormat; /* Identify the output register */ assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 ); pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ - for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){ - assert( memIsValid(u.ap.pRec) ); - if( u.ap.zAffinity ){ - applyAffinity(u.ap.pRec, u.ap.zAffinity[u.ap.pRec-u.ap.pData0], encoding); + for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){ + assert( memIsValid(u.aq.pRec) ); + if( u.aq.zAffinity ){ + applyAffinity(u.aq.pRec, u.aq.zAffinity[u.aq.pRec-u.aq.pData0], encoding); } - if( u.ap.pRec->flags&MEM_Zero && u.ap.pRec->n>0 ){ - sqlite3VdbeMemExpandBlob(u.ap.pRec); + if( u.aq.pRec->flags&MEM_Zero && u.aq.pRec->n>0 ){ + sqlite3VdbeMemExpandBlob(u.aq.pRec); } - u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format); - u.ap.len = sqlite3VdbeSerialTypeLen(u.ap.serial_type); - u.ap.nData += u.ap.len; - u.ap.nHdr += sqlite3VarintLen(u.ap.serial_type); - if( u.ap.pRec->flags & MEM_Zero ){ + u.aq.serial_type = sqlite3VdbeSerialType(u.aq.pRec, u.aq.file_format); + u.aq.len = sqlite3VdbeSerialTypeLen(u.aq.serial_type); + u.aq.nData += u.aq.len; + u.aq.nHdr += sqlite3VarintLen(u.aq.serial_type); + if( u.aq.pRec->flags & MEM_Zero ){ /* Only pure zero-filled BLOBs can be input to this Opcode. ** We do not allow blobs with a prefix and a zero-filled tail. */ - u.ap.nZero += u.ap.pRec->u.nZero; - }else if( u.ap.len ){ - u.ap.nZero = 0; + u.aq.nZero += u.aq.pRec->u.nZero; + }else if( u.aq.len ){ + u.aq.nZero = 0; } } /* Add the initial header varint and total the size */ - u.ap.nHdr += u.ap.nVarint = sqlite3VarintLen(u.ap.nHdr); - if( u.ap.nVarint<sqlite3VarintLen(u.ap.nHdr) ){ - u.ap.nHdr++; + u.aq.nHdr += u.aq.nVarint = sqlite3VarintLen(u.aq.nHdr); + if( u.aq.nVarint<sqlite3VarintLen(u.aq.nHdr) ){ + u.aq.nHdr++; } - u.ap.nByte = u.ap.nHdr+u.ap.nData-u.ap.nZero; - if( u.ap.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + u.aq.nByte = u.aq.nHdr+u.aq.nData-u.aq.nZero; + if( u.aq.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemGrow() could clobber the value before it is used). */ - if( sqlite3VdbeMemGrow(pOut, (int)u.ap.nByte, 0) ){ + if( sqlite3VdbeMemGrow(pOut, (int)u.aq.nByte, 0) ){ goto no_mem; } - u.ap.zNewRecord = (u8 *)pOut->z; + u.aq.zNewRecord = (u8 *)pOut->z; /* Write the record */ - u.ap.i = putVarint32(u.ap.zNewRecord, u.ap.nHdr); - for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){ - u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format); - u.ap.i += putVarint32(&u.ap.zNewRecord[u.ap.i], u.ap.serial_type); /* serial type */ + u.aq.i = putVarint32(u.aq.zNewRecord, u.aq.nHdr); + for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){ + u.aq.serial_type = sqlite3VdbeSerialType(u.aq.pRec, u.aq.file_format); + u.aq.i += putVarint32(&u.aq.zNewRecord[u.aq.i], u.aq.serial_type); /* serial type */ } - for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){ /* serial data */ - u.ap.i += sqlite3VdbeSerialPut(&u.ap.zNewRecord[u.ap.i], (int)(u.ap.nByte-u.ap.i), u.ap.pRec,u.ap.file_format); + for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){ /* serial data */ + u.aq.i += sqlite3VdbeSerialPut(&u.aq.zNewRecord[u.aq.i], (int)(u.aq.nByte-u.aq.i), u.aq.pRec,u.aq.file_format); } - assert( u.ap.i==u.ap.nByte ); + assert( u.aq.i==u.aq.nByte ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); - pOut->n = (int)u.ap.nByte; + pOut->n = (int)u.aq.nByte; pOut->flags = MEM_Blob | MEM_Dyn; pOut->xDel = 0; - if( u.ap.nZero ){ - pOut->u.nZero = u.ap.nZero; + if( u.aq.nZero ){ + pOut->u.nZero = u.aq.nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); @@ -66167,22 +66221,22 @@ ** Store the number of entries (an integer value) in the table or index ** opened by cursor P1 in register P2 */ #ifndef SQLITE_OMIT_BTREECOUNT case OP_Count: { /* out2-prerelease */ -#if 0 /* local variables moved into u.aq */ +#if 0 /* local variables moved into u.ar */ i64 nEntry; BtCursor *pCrsr; -#endif /* local variables moved into u.aq */ +#endif /* local variables moved into u.ar */ - u.aq.pCrsr = p->apCsr[pOp->p1]->pCursor; - if( ALWAYS(u.aq.pCrsr) ){ - rc = sqlite3BtreeCount(u.aq.pCrsr, &u.aq.nEntry); + u.ar.pCrsr = p->apCsr[pOp->p1]->pCursor; + if( ALWAYS(u.ar.pCrsr) ){ + rc = sqlite3BtreeCount(u.ar.pCrsr, &u.ar.nEntry); }else{ - u.aq.nEntry = 0; + u.ar.nEntry = 0; } - pOut->u.i = u.aq.nEntry; + pOut->u.i = u.ar.nEntry; break; } #endif /* Opcode: Savepoint P1 * * P4 * @@ -66190,42 +66244,42 @@ ** Open, release or rollback the savepoint named by parameter P4, depending ** on the value of P1. To open a new savepoint, P1==0. To release (commit) an ** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. */ case OP_Savepoint: { -#if 0 /* local variables moved into u.ar */ +#if 0 /* local variables moved into u.as */ int p1; /* Value of P1 operand */ char *zName; /* Name of savepoint */ int nName; Savepoint *pNew; Savepoint *pSavepoint; Savepoint *pTmp; int iSavepoint; int ii; -#endif /* local variables moved into u.ar */ +#endif /* local variables moved into u.as */ - u.ar.p1 = pOp->p1; - u.ar.zName = pOp->p4.z; + u.as.p1 = pOp->p1; + u.as.zName = pOp->p4.z; - /* Assert that the u.ar.p1 parameter is valid. Also that if there is no open + /* Assert that the u.as.p1 parameter is valid. Also that if there is no open ** transaction, then there cannot be any savepoints. */ assert( db->pSavepoint==0 || db->autoCommit==0 ); - assert( u.ar.p1==SAVEPOINT_BEGIN||u.ar.p1==SAVEPOINT_RELEASE||u.ar.p1==SAVEPOINT_ROLLBACK ); + assert( u.as.p1==SAVEPOINT_BEGIN||u.as.p1==SAVEPOINT_RELEASE||u.as.p1==SAVEPOINT_ROLLBACK ); assert( db->pSavepoint || db->isTransactionSavepoint==0 ); assert( checkSavepointCount(db) ); - if( u.ar.p1==SAVEPOINT_BEGIN ){ + if( u.as.p1==SAVEPOINT_BEGIN ){ if( db->writeVdbeCnt>0 ){ /* A new savepoint cannot be created if there are active write ** statements (i.e. open read/write incremental blob handles). */ sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - " "SQL statements in progress"); rc = SQLITE_BUSY; }else{ - u.ar.nName = sqlite3Strlen30(u.ar.zName); + u.as.nName = sqlite3Strlen30(u.as.zName); #ifndef SQLITE_OMIT_VIRTUALTABLE /* This call is Ok even if this savepoint is actually a transaction ** savepoint (and therefore should not prompt xSavepoint()) callbacks. ** If this is a transaction savepoint being opened, it is guaranteed @@ -66235,14 +66289,14 @@ db->nStatement+db->nSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif /* Create a new savepoint structure. */ - u.ar.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.ar.nName+1); - if( u.ar.pNew ){ - u.ar.pNew->zName = (char *)&u.ar.pNew[1]; - memcpy(u.ar.pNew->zName, u.ar.zName, u.ar.nName+1); + u.as.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.as.nName+1); + if( u.as.pNew ){ + u.as.pNew->zName = (char *)&u.as.pNew[1]; + memcpy(u.as.pNew->zName, u.as.zName, u.as.nName+1); /* If there is no open transaction, then mark this as a special ** "transaction savepoint". */ if( db->autoCommit ){ db->autoCommit = 0; @@ -66250,31 +66304,31 @@ }else{ db->nSavepoint++; } /* Link the new savepoint into the database handle's list. */ - u.ar.pNew->pNext = db->pSavepoint; - db->pSavepoint = u.ar.pNew; - u.ar.pNew->nDeferredCons = db->nDeferredCons; + u.as.pNew->pNext = db->pSavepoint; + db->pSavepoint = u.as.pNew; + u.as.pNew->nDeferredCons = db->nDeferredCons; } } }else{ - u.ar.iSavepoint = 0; + u.as.iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ for( - u.ar.pSavepoint = db->pSavepoint; - u.ar.pSavepoint && sqlite3StrICmp(u.ar.pSavepoint->zName, u.ar.zName); - u.ar.pSavepoint = u.ar.pSavepoint->pNext + u.as.pSavepoint = db->pSavepoint; + u.as.pSavepoint && sqlite3StrICmp(u.as.pSavepoint->zName, u.as.zName); + u.as.pSavepoint = u.as.pSavepoint->pNext ){ - u.ar.iSavepoint++; + u.as.iSavepoint++; } - if( !u.ar.pSavepoint ){ - sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.ar.zName); + if( !u.as.pSavepoint ){ + sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.as.zName); rc = SQLITE_ERROR; - }else if( db->writeVdbeCnt>0 && u.ar.p1==SAVEPOINT_RELEASE ){ + }else if( db->writeVdbeCnt>0 && u.as.p1==SAVEPOINT_RELEASE ){ /* It is not possible to release (commit) a savepoint if there are ** active write statements. */ sqlite3SetString(&p->zErrMsg, db, "cannot release savepoint - SQL statements in progress" @@ -66284,12 +66338,12 @@ /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ - int isTransaction = u.ar.pSavepoint->pNext==0 && db->isTransactionSavepoint; - if( isTransaction && u.ar.p1==SAVEPOINT_RELEASE ){ + int isTransaction = u.as.pSavepoint->pNext==0 && db->isTransactionSavepoint; + if( isTransaction && u.as.p1==SAVEPOINT_RELEASE ){ if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; } db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ @@ -66299,55 +66353,55 @@ goto vdbe_return; } db->isTransactionSavepoint = 0; rc = p->rc; }else{ - u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1; - if( u.ar.p1==SAVEPOINT_ROLLBACK ){ - for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){ - sqlite3BtreeTripAllCursors(db->aDb[u.ar.ii].pBt, SQLITE_ABORT); + u.as.iSavepoint = db->nSavepoint - u.as.iSavepoint - 1; + if( u.as.p1==SAVEPOINT_ROLLBACK ){ + for(u.as.ii=0; u.as.ii<db->nDb; u.as.ii++){ + sqlite3BtreeTripAllCursors(db->aDb[u.as.ii].pBt, SQLITE_ABORT); } } - for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){ - rc = sqlite3BtreeSavepoint(db->aDb[u.ar.ii].pBt, u.ar.p1, u.ar.iSavepoint); + for(u.as.ii=0; u.as.ii<db->nDb; u.as.ii++){ + rc = sqlite3BtreeSavepoint(db->aDb[u.as.ii].pBt, u.as.p1, u.as.iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } - if( u.ar.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ + if( u.as.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); } } /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ - while( db->pSavepoint!=u.ar.pSavepoint ){ - u.ar.pTmp = db->pSavepoint; - db->pSavepoint = u.ar.pTmp->pNext; - sqlite3DbFree(db, u.ar.pTmp); + while( db->pSavepoint!=u.as.pSavepoint ){ + u.as.pTmp = db->pSavepoint; + db->pSavepoint = u.as.pTmp->pNext; + sqlite3DbFree(db, u.as.pTmp); db->nSavepoint--; } /* If it is a RELEASE, then destroy the savepoint being operated on ** too. If it is a ROLLBACK TO, then set the number of deferred ** constraint violations present in the database to the value stored ** when the savepoint was created. */ - if( u.ar.p1==SAVEPOINT_RELEASE ){ - assert( u.ar.pSavepoint==db->pSavepoint ); - db->pSavepoint = u.ar.pSavepoint->pNext; - sqlite3DbFree(db, u.ar.pSavepoint); + if( u.as.p1==SAVEPOINT_RELEASE ){ + assert( u.as.pSavepoint==db->pSavepoint ); + db->pSavepoint = u.as.pSavepoint->pNext; + sqlite3DbFree(db, u.as.pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ - db->nDeferredCons = u.ar.pSavepoint->nDeferredCons; + db->nDeferredCons = u.as.pSavepoint->nDeferredCons; } if( !isTransaction ){ - rc = sqlite3VtabSavepoint(db, u.ar.p1, u.ar.iSavepoint); + rc = sqlite3VtabSavepoint(db, u.as.p1, u.as.iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; } } } @@ -66362,53 +66416,53 @@ ** there are active writing VMs or active VMs that use shared cache. ** ** This instruction causes the VM to halt. */ case OP_AutoCommit: { -#if 0 /* local variables moved into u.as */ +#if 0 /* local variables moved into u.at */ int desiredAutoCommit; int iRollback; int turnOnAC; -#endif /* local variables moved into u.as */ +#endif /* local variables moved into u.at */ - u.as.desiredAutoCommit = pOp->p1; - u.as.iRollback = pOp->p2; - u.as.turnOnAC = u.as.desiredAutoCommit && !db->autoCommit; - assert( u.as.desiredAutoCommit==1 || u.as.desiredAutoCommit==0 ); - assert( u.as.desiredAutoCommit==1 || u.as.iRollback==0 ); + u.at.desiredAutoCommit = pOp->p1; + u.at.iRollback = pOp->p2; + u.at.turnOnAC = u.at.desiredAutoCommit && !db->autoCommit; + assert( u.at.desiredAutoCommit==1 || u.at.desiredAutoCommit==0 ); + assert( u.at.desiredAutoCommit==1 || u.at.iRollback==0 ); assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */ #if 0 - if( u.as.turnOnAC && u.as.iRollback && db->activeVdbeCnt>1 ){ + if( u.at.turnOnAC && u.at.iRollback && db->activeVdbeCnt>1 ){ /* If this instruction implements a ROLLBACK and other VMs are ** still running, and a transaction is active, return an error indicating ** that the other VMs must complete first. */ sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - " "SQL statements in progress"); rc = SQLITE_BUSY; }else #endif - if( u.as.turnOnAC && !u.as.iRollback && db->writeVdbeCnt>0 ){ + if( u.at.turnOnAC && !u.at.iRollback && db->writeVdbeCnt>0 ){ /* If this instruction implements a COMMIT and other VMs are writing ** return an error indicating that the other VMs must complete first. */ sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - " "SQL statements in progress"); rc = SQLITE_BUSY; - }else if( u.as.desiredAutoCommit!=db->autoCommit ){ - if( u.as.iRollback ){ - assert( u.as.desiredAutoCommit==1 ); + }else if( u.at.desiredAutoCommit!=db->autoCommit ){ + if( u.at.iRollback ){ + assert( u.at.desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); db->autoCommit = 1; }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ - db->autoCommit = (u8)u.as.desiredAutoCommit; + db->autoCommit = (u8)u.at.desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; - db->autoCommit = (u8)(1-u.as.desiredAutoCommit); + db->autoCommit = (u8)(1-u.at.desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } } assert( db->nStatement==0 ); @@ -66419,12 +66473,12 @@ rc = SQLITE_ERROR; } goto vdbe_return; }else{ sqlite3SetString(&p->zErrMsg, db, - (!u.as.desiredAutoCommit)?"cannot start a transaction within a transaction":( - (u.as.iRollback)?"cannot rollback - no transaction is active": + (!u.at.desiredAutoCommit)?"cannot start a transaction within a transaction":( + (u.at.iRollback)?"cannot rollback - no transaction is active": "cannot commit - no transaction is active")); rc = SQLITE_ERROR; } break; @@ -66460,20 +66514,20 @@ ** will automatically commit when the VDBE halts. ** ** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { -#if 0 /* local variables moved into u.at */ +#if 0 /* local variables moved into u.au */ Btree *pBt; -#endif /* local variables moved into u.at */ +#endif /* local variables moved into u.au */ assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); - u.at.pBt = db->aDb[pOp->p1].pBt; + u.au.pBt = db->aDb[pOp->p1].pBt; - if( u.at.pBt ){ - rc = sqlite3BtreeBeginTrans(u.at.pBt, pOp->p2); + if( u.au.pBt ){ + rc = sqlite3BtreeBeginTrans(u.au.pBt, pOp->p2); if( rc==SQLITE_BUSY ){ p->pc = pc; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } @@ -66482,20 +66536,20 @@ } if( pOp->p2 && p->usesStmtJournal && (db->autoCommit==0 || db->activeVdbeCnt>1) ){ - assert( sqlite3BtreeIsInTrans(u.at.pBt) ); + assert( sqlite3BtreeIsInTrans(u.au.pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginStmt(u.at.pBt, p->iStatement); + rc = sqlite3BtreeBeginStmt(u.au.pBt, p->iStatement); } /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ @@ -66516,25 +66570,25 @@ ** There must be a read-lock on the database (either a transaction ** must be started or there must be an open cursor) before ** executing this instruction. */ case OP_ReadCookie: { /* out2-prerelease */ -#if 0 /* local variables moved into u.au */ +#if 0 /* local variables moved into u.av */ int iMeta; int iDb; int iCookie; -#endif /* local variables moved into u.au */ +#endif /* local variables moved into u.av */ - u.au.iDb = pOp->p1; - u.au.iCookie = pOp->p3; + u.av.iDb = pOp->p1; + u.av.iCookie = pOp->p3; assert( pOp->p3<SQLITE_N_BTREE_META ); - assert( u.au.iDb>=0 && u.au.iDb<db->nDb ); - assert( db->aDb[u.au.iDb].pBt!=0 ); - assert( (p->btreeMask & (((yDbMask)1)<<u.au.iDb))!=0 ); + assert( u.av.iDb>=0 && u.av.iDb<db->nDb ); + assert( db->aDb[u.av.iDb].pBt!=0 ); + assert( (p->btreeMask & (((yDbMask)1)<<u.av.iDb))!=0 ); - sqlite3BtreeGetMeta(db->aDb[u.au.iDb].pBt, u.au.iCookie, (u32 *)&u.au.iMeta); - pOut->u.i = u.au.iMeta; + sqlite3BtreeGetMeta(db->aDb[u.av.iDb].pBt, u.av.iCookie, (u32 *)&u.av.iMeta); + pOut->u.i = u.av.iMeta; break; } /* Opcode: SetCookie P1 P2 P3 * * ** @@ -66545,30 +66599,30 @@ ** database file used to store temporary tables. ** ** A transaction must be started before executing this opcode. */ case OP_SetCookie: { /* in3 */ -#if 0 /* local variables moved into u.av */ +#if 0 /* local variables moved into u.aw */ Db *pDb; -#endif /* local variables moved into u.av */ +#endif /* local variables moved into u.aw */ assert( pOp->p2<SQLITE_N_BTREE_META ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); - u.av.pDb = &db->aDb[pOp->p1]; - assert( u.av.pDb->pBt!=0 ); + u.aw.pDb = &db->aDb[pOp->p1]; + assert( u.aw.pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); pIn3 = &aMem[pOp->p3]; sqlite3VdbeMemIntegerify(pIn3); /* See note about index shifting on OP_ReadCookie */ - rc = sqlite3BtreeUpdateMeta(u.av.pDb->pBt, pOp->p2, (int)pIn3->u.i); + rc = sqlite3BtreeUpdateMeta(u.aw.pDb->pBt, pOp->p2, (int)pIn3->u.i); if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ - u.av.pDb->pSchema->schema_cookie = (int)pIn3->u.i; + u.aw.pDb->pSchema->schema_cookie = (int)pIn3->u.i; db->flags |= SQLITE_InternChanges; }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ - u.av.pDb->pSchema->file_format = (u8)pIn3->u.i; + u.aw.pDb->pSchema->file_format = (u8)pIn3->u.i; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ sqlite3ExpirePreparedStatements(db); @@ -66594,27 +66648,27 @@ ** Either a transaction needs to have been started or an OP_Open needs ** to be executed (to establish a read lock) before this opcode is ** invoked. */ case OP_VerifyCookie: { -#if 0 /* local variables moved into u.aw */ +#if 0 /* local variables moved into u.ax */ int iMeta; int iGen; Btree *pBt; -#endif /* local variables moved into u.aw */ +#endif /* local variables moved into u.ax */ assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); - u.aw.pBt = db->aDb[pOp->p1].pBt; - if( u.aw.pBt ){ - sqlite3BtreeGetMeta(u.aw.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.aw.iMeta); - u.aw.iGen = db->aDb[pOp->p1].pSchema->iGeneration; + u.ax.pBt = db->aDb[pOp->p1].pBt; + if( u.ax.pBt ){ + sqlite3BtreeGetMeta(u.ax.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.ax.iMeta); + u.ax.iGen = db->aDb[pOp->p1].pSchema->iGeneration; }else{ - u.aw.iGen = u.aw.iMeta = 0; + u.ax.iGen = u.ax.iMeta = 0; } - if( u.aw.iMeta!=pOp->p2 || u.aw.iGen!=pOp->p3 ){ + if( u.ax.iMeta!=pOp->p2 || u.ax.iGen!=pOp->p3 ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. @@ -66626,11 +66680,11 @@ ** discard the database schema, as the user code implementing the ** v-table would have to be ready for the sqlite3_vtab structure itself ** to be invalidated whenever sqlite3_step() is called from within ** a v-table method. */ - if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.aw.iMeta ){ + if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.ax.iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } p->expired = 1; rc = SQLITE_SCHEMA; @@ -66687,91 +66741,91 @@ ** ** See also OpenRead. */ case OP_OpenRead: case OP_OpenWrite: { -#if 0 /* local variables moved into u.ax */ +#if 0 /* local variables moved into u.ay */ int nField; KeyInfo *pKeyInfo; int p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; -#endif /* local variables moved into u.ax */ +#endif /* local variables moved into u.ay */ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); if( p->expired ){ rc = SQLITE_ABORT; break; } - u.ax.nField = 0; - u.ax.pKeyInfo = 0; - u.ax.p2 = pOp->p2; - u.ax.iDb = pOp->p3; - assert( u.ax.iDb>=0 && u.ax.iDb<db->nDb ); - assert( (p->btreeMask & (((yDbMask)1)<<u.ax.iDb))!=0 ); - u.ax.pDb = &db->aDb[u.ax.iDb]; - u.ax.pX = u.ax.pDb->pBt; - assert( u.ax.pX!=0 ); + u.ay.nField = 0; + u.ay.pKeyInfo = 0; + u.ay.p2 = pOp->p2; + u.ay.iDb = pOp->p3; + assert( u.ay.iDb>=0 && u.ay.iDb<db->nDb ); + assert( (p->btreeMask & (((yDbMask)1)<<u.ay.iDb))!=0 ); + u.ay.pDb = &db->aDb[u.ay.iDb]; + u.ay.pX = u.ay.pDb->pBt; + assert( u.ay.pX!=0 ); if( pOp->opcode==OP_OpenWrite ){ - u.ax.wrFlag = 1; - assert( sqlite3SchemaMutexHeld(db, u.ax.iDb, 0) ); - if( u.ax.pDb->pSchema->file_format < p->minWriteFileFormat ){ - p->minWriteFileFormat = u.ax.pDb->pSchema->file_format; + u.ay.wrFlag = 1; + assert( sqlite3SchemaMutexHeld(db, u.ay.iDb, 0) ); + if( u.ay.pDb->pSchema->file_format < p->minWriteFileFormat ){ + p->minWriteFileFormat = u.ay.pDb->pSchema->file_format; } }else{ - u.ax.wrFlag = 0; + u.ay.wrFlag = 0; } if( pOp->p5 & OPFLAG_P2ISREG ){ - assert( u.ax.p2>0 ); - assert( u.ax.p2<=p->nMem ); - pIn2 = &aMem[u.ax.p2]; + assert( u.ay.p2>0 ); + assert( u.ay.p2<=p->nMem ); + pIn2 = &aMem[u.ay.p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); - u.ax.p2 = (int)pIn2->u.i; - /* The u.ax.p2 value always comes from a prior OP_CreateTable opcode and - ** that opcode will always set the u.ax.p2 value to 2 or more or else fail. + u.ay.p2 = (int)pIn2->u.i; + /* The u.ay.p2 value always comes from a prior OP_CreateTable opcode and + ** that opcode will always set the u.ay.p2 value to 2 or more or else fail. ** If there were a failure, the prepared statement would have halted ** before reaching this instruction. */ - if( NEVER(u.ax.p2<2) ) { + if( NEVER(u.ay.p2<2) ) { rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } } if( pOp->p4type==P4_KEYINFO ){ - u.ax.pKeyInfo = pOp->p4.pKeyInfo; - u.ax.pKeyInfo->enc = ENC(p->db); - u.ax.nField = u.ax.pKeyInfo->nField+1; + u.ay.pKeyInfo = pOp->p4.pKeyInfo; + u.ay.pKeyInfo->enc = ENC(p->db); + u.ay.nField = u.ay.pKeyInfo->nField+1; }else if( pOp->p4type==P4_INT32 ){ - u.ax.nField = pOp->p4.i; + u.ay.nField = pOp->p4.i; } assert( pOp->p1>=0 ); - u.ax.pCur = allocateCursor(p, pOp->p1, u.ax.nField, u.ax.iDb, 1); - if( u.ax.pCur==0 ) goto no_mem; - u.ax.pCur->nullRow = 1; - u.ax.pCur->isOrdered = 1; - rc = sqlite3BtreeCursor(u.ax.pX, u.ax.p2, u.ax.wrFlag, u.ax.pKeyInfo, u.ax.pCur->pCursor); - u.ax.pCur->pKeyInfo = u.ax.pKeyInfo; + u.ay.pCur = allocateCursor(p, pOp->p1, u.ay.nField, u.ay.iDb, 1); + if( u.ay.pCur==0 ) goto no_mem; + u.ay.pCur->nullRow = 1; + u.ay.pCur->isOrdered = 1; + rc = sqlite3BtreeCursor(u.ay.pX, u.ay.p2, u.ay.wrFlag, u.ay.pKeyInfo, u.ay.pCur->pCursor); + u.ay.pCur->pKeyInfo = u.ay.pKeyInfo; assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); - sqlite3BtreeCursorHints(u.ax.pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); + sqlite3BtreeCursorHints(u.ay.pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); /* Since it performs no memory allocation or IO, the only value that ** sqlite3BtreeCursor() may return is SQLITE_OK. */ assert( rc==SQLITE_OK ); /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has ** since moved into the btree layer. */ - u.ax.pCur->isTable = pOp->p4type!=P4_KEYINFO; - u.ax.pCur->isIndex = !u.ax.pCur->isTable; + u.ay.pCur->isTable = pOp->p4type!=P4_KEYINFO; + u.ay.pCur->isIndex = !u.ay.pCur->isTable; break; } /* Opcode: OpenEphemeral P1 P2 * P4 P5 ** @@ -66803,28 +66857,28 @@ ** by this opcode will be used for automatically created transient ** indices in joins. */ case OP_OpenAutoindex: case OP_OpenEphemeral: { -#if 0 /* local variables moved into u.ay */ +#if 0 /* local variables moved into u.az */ VdbeCursor *pCx; -#endif /* local variables moved into u.ay */ +#endif /* local variables moved into u.az */ static const int vfsFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); - u.ay.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); - if( u.ay.pCx==0 ) goto no_mem; - u.ay.pCx->nullRow = 1; - rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ay.pCx->pBt, + u.az.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); + if( u.az.pCx==0 ) goto no_mem; + u.az.pCx->nullRow = 1; + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.az.pCx->pBt, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(u.ay.pCx->pBt, 1); + rc = sqlite3BtreeBeginTrans(u.az.pCx->pBt, 1); } if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before ** opening it. If a transient table is required, just use the @@ -66831,26 +66885,26 @@ ** automatically created table with root-page 1 (an BLOB_INTKEY table). */ if( pOp->p4.pKeyInfo ){ int pgno; assert( pOp->p4type==P4_KEYINFO ); - rc = sqlite3BtreeCreateTable(u.ay.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); + rc = sqlite3BtreeCreateTable(u.az.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); if( rc==SQLITE_OK ){ assert( pgno==MASTER_ROOT+1 ); - rc = sqlite3BtreeCursor(u.ay.pCx->pBt, pgno, 1, - (KeyInfo*)pOp->p4.z, u.ay.pCx->pCursor); - u.ay.pCx->pKeyInfo = pOp->p4.pKeyInfo; - u.ay.pCx->pKeyInfo->enc = ENC(p->db); + rc = sqlite3BtreeCursor(u.az.pCx->pBt, pgno, 1, + (KeyInfo*)pOp->p4.z, u.az.pCx->pCursor); + u.az.pCx->pKeyInfo = pOp->p4.pKeyInfo; + u.az.pCx->pKeyInfo->enc = ENC(p->db); } - u.ay.pCx->isTable = 0; + u.az.pCx->isTable = 0; }else{ - rc = sqlite3BtreeCursor(u.ay.pCx->pBt, MASTER_ROOT, 1, 0, u.ay.pCx->pCursor); - u.ay.pCx->isTable = 1; + rc = sqlite3BtreeCursor(u.az.pCx->pBt, MASTER_ROOT, 1, 0, u.az.pCx->pCursor); + u.az.pCx->isTable = 1; } } - u.ay.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); - u.ay.pCx->isIndex = !u.ay.pCx->isTable; + u.az.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + u.az.pCx->isIndex = !u.az.pCx->isTable; break; } /* Opcode: OpenSorter P1 P2 * P4 * ** @@ -66857,20 +66911,21 @@ ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. */ case OP_SorterOpen: { -#if 0 /* local variables moved into u.az */ +#if 0 /* local variables moved into u.ba */ VdbeCursor *pCx; -#endif /* local variables moved into u.az */ +#endif /* local variables moved into u.ba */ + #ifndef SQLITE_OMIT_MERGE_SORT - u.az.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); - if( u.az.pCx==0 ) goto no_mem; - u.az.pCx->pKeyInfo = pOp->p4.pKeyInfo; - u.az.pCx->pKeyInfo->enc = ENC(p->db); - u.az.pCx->isSorter = 1; - rc = sqlite3VdbeSorterInit(db, u.az.pCx); + u.ba.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); + if( u.ba.pCx==0 ) goto no_mem; + u.ba.pCx->pKeyInfo = pOp->p4.pKeyInfo; + u.ba.pCx->pKeyInfo->enc = ENC(p->db); + u.ba.pCx->isSorter = 1; + rc = sqlite3VdbeSorterInit(db, u.ba.pCx); #else pOp->opcode = OP_OpenEphemeral; pc--; #endif break; @@ -66890,21 +66945,21 @@ ** ** P3 is the number of fields in the records that will be stored by ** the pseudo-table. */ case OP_OpenPseudo: { -#if 0 /* local variables moved into u.ba */ +#if 0 /* local variables moved into u.bb */ VdbeCursor *pCx; -#endif /* local variables moved into u.ba */ +#endif /* local variables moved into u.bb */ assert( pOp->p1>=0 ); - u.ba.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); - if( u.ba.pCx==0 ) goto no_mem; - u.ba.pCx->nullRow = 1; - u.ba.pCx->pseudoTableReg = pOp->p2; - u.ba.pCx->isTable = 1; - u.ba.pCx->isIndex = 0; + u.bb.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); + if( u.bb.pCx==0 ) goto no_mem; + u.bb.pCx->nullRow = 1; + u.bb.pCx->pseudoTableReg = pOp->p2; + u.bb.pCx->isTable = 1; + u.bb.pCx->isIndex = 0; break; } /* Opcode: Close P1 * * * * ** @@ -66972,39 +67027,39 @@ */ case OP_SeekLt: /* jump, in3 */ case OP_SeekLe: /* jump, in3 */ case OP_SeekGe: /* jump, in3 */ case OP_SeekGt: { /* jump, in3 */ -#if 0 /* local variables moved into u.bb */ +#if 0 /* local variables moved into u.bc */ int res; int oc; VdbeCursor *pC; UnpackedRecord r; int nField; i64 iKey; /* The rowid we are to seek to */ -#endif /* local variables moved into u.bb */ +#endif /* local variables moved into u.bc */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p2!=0 ); - u.bb.pC = p->apCsr[pOp->p1]; - assert( u.bb.pC!=0 ); - assert( u.bb.pC->pseudoTableReg==0 ); + u.bc.pC = p->apCsr[pOp->p1]; + assert( u.bc.pC!=0 ); + assert( u.bc.pC->pseudoTableReg==0 ); assert( OP_SeekLe == OP_SeekLt+1 ); assert( OP_SeekGe == OP_SeekLt+2 ); assert( OP_SeekGt == OP_SeekLt+3 ); - assert( u.bb.pC->isOrdered ); - if( ALWAYS(u.bb.pC->pCursor!=0) ){ - u.bb.oc = pOp->opcode; - u.bb.pC->nullRow = 0; - if( u.bb.pC->isTable ){ + assert( u.bc.pC->isOrdered ); + if( ALWAYS(u.bc.pC->pCursor!=0) ){ + u.bc.oc = pOp->opcode; + u.bc.pC->nullRow = 0; + if( u.bc.pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so covert it. */ pIn3 = &aMem[pOp->p3]; applyNumericAffinity(pIn3); - u.bb.iKey = sqlite3VdbeIntValue(pIn3); - u.bb.pC->rowidIsValid = 0; + u.bc.iKey = sqlite3VdbeIntValue(pIn3); + u.bc.pC->rowidIsValid = 0; /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (pIn3->flags & MEM_Int)==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ @@ -67015,105 +67070,105 @@ } /* If we reach this point, then the P3 value must be a floating ** point number. */ assert( (pIn3->flags & MEM_Real)!=0 ); - if( u.bb.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.bb.iKey || pIn3->r>0) ){ + if( u.bc.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.bc.iKey || pIn3->r>0) ){ /* The P3 value is too large in magnitude to be expressed as an ** integer. */ - u.bb.res = 1; + u.bc.res = 1; if( pIn3->r<0 ){ - if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt ); - rc = sqlite3BtreeFirst(u.bb.pC->pCursor, &u.bb.res); + if( u.bc.oc>=OP_SeekGe ){ assert( u.bc.oc==OP_SeekGe || u.bc.oc==OP_SeekGt ); + rc = sqlite3BtreeFirst(u.bc.pC->pCursor, &u.bc.res); if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ - if( u.bb.oc<=OP_SeekLe ){ assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe ); - rc = sqlite3BtreeLast(u.bb.pC->pCursor, &u.bb.res); + if( u.bc.oc<=OP_SeekLe ){ assert( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekLe ); + rc = sqlite3BtreeLast(u.bc.pC->pCursor, &u.bc.res); if( rc!=SQLITE_OK ) goto abort_due_to_error; } } - if( u.bb.res ){ + if( u.bc.res ){ pc = pOp->p2 - 1; } break; - }else if( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekGe ){ + }else if( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekGe ){ /* Use the ceiling() function to convert real->int */ - if( pIn3->r > (double)u.bb.iKey ) u.bb.iKey++; + if( pIn3->r > (double)u.bc.iKey ) u.bc.iKey++; }else{ /* Use the floor() function to convert real->int */ - assert( u.bb.oc==OP_SeekLe || u.bb.oc==OP_SeekGt ); - if( pIn3->r < (double)u.bb.iKey ) u.bb.iKey--; + assert( u.bc.oc==OP_SeekLe || u.bc.oc==OP_SeekGt ); + if( pIn3->r < (double)u.bc.iKey ) u.bc.iKey--; } } - rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, 0, (u64)u.bb.iKey, 0, &u.bb.res); + rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, 0, (u64)u.bc.iKey, 0, &u.bc.res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( u.bb.res==0 ){ - u.bb.pC->rowidIsValid = 1; - u.bb.pC->lastRowid = u.bb.iKey; + if( u.bc.res==0 ){ + u.bc.pC->rowidIsValid = 1; + u.bc.pC->lastRowid = u.bc.iKey; } }else{ - u.bb.nField = pOp->p4.i; + u.bc.nField = pOp->p4.i; assert( pOp->p4type==P4_INT32 ); - assert( u.bb.nField>0 ); - u.bb.r.pKeyInfo = u.bb.pC->pKeyInfo; - u.bb.r.nField = (u16)u.bb.nField; + assert( u.bc.nField>0 ); + u.bc.r.pKeyInfo = u.bc.pC->pKeyInfo; + u.bc.r.nField = (u16)u.bc.nField; /* The next line of code computes as follows, only faster: - ** if( u.bb.oc==OP_SeekGt || u.bb.oc==OP_SeekLe ){ - ** u.bb.r.flags = UNPACKED_INCRKEY; + ** if( u.bc.oc==OP_SeekGt || u.bc.oc==OP_SeekLe ){ + ** u.bc.r.flags = UNPACKED_INCRKEY; ** }else{ - ** u.bb.r.flags = 0; + ** u.bc.r.flags = 0; ** } */ - u.bb.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.bb.oc - OP_SeekLt))); - assert( u.bb.oc!=OP_SeekGt || u.bb.r.flags==UNPACKED_INCRKEY ); - assert( u.bb.oc!=OP_SeekLe || u.bb.r.flags==UNPACKED_INCRKEY ); - assert( u.bb.oc!=OP_SeekGe || u.bb.r.flags==0 ); - assert( u.bb.oc!=OP_SeekLt || u.bb.r.flags==0 ); + u.bc.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.bc.oc - OP_SeekLt))); + assert( u.bc.oc!=OP_SeekGt || u.bc.r.flags==UNPACKED_INCRKEY ); + assert( u.bc.oc!=OP_SeekLe || u.bc.r.flags==UNPACKED_INCRKEY ); + assert( u.bc.oc!=OP_SeekGe || u.bc.r.flags==0 ); + assert( u.bc.oc!=OP_SeekLt || u.bc.r.flags==0 ); - u.bb.r.aMem = &aMem[pOp->p3]; + u.bc.r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG - { int i; for(i=0; i<u.bb.r.nField; i++) assert( memIsValid(&u.bb.r.aMem[i]) ); } + { int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); } #endif - ExpandBlob(u.bb.r.aMem); - rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, &u.bb.r, 0, 0, &u.bb.res); + ExpandBlob(u.bc.r.aMem); + rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, &u.bc.r, 0, 0, &u.bc.res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - u.bb.pC->rowidIsValid = 0; + u.bc.pC->rowidIsValid = 0; } - u.bb.pC->deferredMoveto = 0; - u.bb.pC->cacheStatus = CACHE_STALE; + u.bc.pC->deferredMoveto = 0; + u.bc.pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST sqlite3_search_count++; #endif - if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt ); - if( u.bb.res<0 || (u.bb.res==0 && u.bb.oc==OP_SeekGt) ){ - rc = sqlite3BtreeNext(u.bb.pC->pCursor, &u.bb.res); + if( u.bc.oc>=OP_SeekGe ){ assert( u.bc.oc==OP_SeekGe || u.bc.oc==OP_SeekGt ); + if( u.bc.res<0 || (u.bc.res==0 && u.bc.oc==OP_SeekGt) ){ + rc = sqlite3BtreeNext(u.bc.pC->pCursor, &u.bc.res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - u.bb.pC->rowidIsValid = 0; + u.bc.pC->rowidIsValid = 0; }else{ - u.bb.res = 0; + u.bc.res = 0; } }else{ - assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe ); - if( u.bb.res>0 || (u.bb.res==0 && u.bb.oc==OP_SeekLt) ){ - rc = sqlite3BtreePrevious(u.bb.pC->pCursor, &u.bb.res); + assert( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekLe ); + if( u.bc.res>0 || (u.bc.res==0 && u.bc.oc==OP_SeekLt) ){ + rc = sqlite3BtreePrevious(u.bc.pC->pCursor, &u.bc.res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - u.bb.pC->rowidIsValid = 0; + u.bc.pC->rowidIsValid = 0; }else{ - /* u.bb.res might be negative because the table is empty. Check to + /* u.bc.res might be negative because the table is empty. Check to ** see if this is the case. */ - u.bb.res = sqlite3BtreeEof(u.bb.pC->pCursor); + u.bc.res = sqlite3BtreeEof(u.bc.pC->pCursor); } } assert( pOp->p2>0 ); - if( u.bb.res ){ + if( u.bc.res ){ pc = pOp->p2 - 1; } }else{ /* This happens when attempting to open the sqlite3_master table ** for read access returns SQLITE_EMPTY. In this case always @@ -67132,24 +67187,24 @@ ** This is actually a deferred seek. Nothing actually happens until ** the cursor is used to read a record. That way, if no reads ** occur, no unnecessary I/O happens. */ case OP_Seek: { /* in2 */ -#if 0 /* local variables moved into u.bc */ +#if 0 /* local variables moved into u.bd */ VdbeCursor *pC; -#endif /* local variables moved into u.bc */ +#endif /* local variables moved into u.bd */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bc.pC = p->apCsr[pOp->p1]; - assert( u.bc.pC!=0 ); - if( ALWAYS(u.bc.pC->pCursor!=0) ){ - assert( u.bc.pC->isTable ); - u.bc.pC->nullRow = 0; + u.bd.pC = p->apCsr[pOp->p1]; + assert( u.bd.pC!=0 ); + if( ALWAYS(u.bd.pC->pCursor!=0) ){ + assert( u.bd.pC->isTable ); + u.bd.pC->nullRow = 0; pIn2 = &aMem[pOp->p2]; - u.bc.pC->movetoTarget = sqlite3VdbeIntValue(pIn2); - u.bc.pC->rowidIsValid = 0; - u.bc.pC->deferredMoveto = 1; + u.bd.pC->movetoTarget = sqlite3VdbeIntValue(pIn2); + u.bd.pC->rowidIsValid = 0; + u.bd.pC->deferredMoveto = 1; } break; } @@ -67177,67 +67232,67 @@ ** ** See also: Found, NotExists, IsUnique */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ -#if 0 /* local variables moved into u.bd */ +#if 0 /* local variables moved into u.be */ int alreadyExists; VdbeCursor *pC; int res; char *pFree; UnpackedRecord *pIdxKey; UnpackedRecord r; char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; -#endif /* local variables moved into u.bd */ +#endif /* local variables moved into u.be */ #ifdef SQLITE_TEST sqlite3_found_count++; #endif - u.bd.alreadyExists = 0; + u.be.alreadyExists = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p4type==P4_INT32 ); - u.bd.pC = p->apCsr[pOp->p1]; - assert( u.bd.pC!=0 ); + u.be.pC = p->apCsr[pOp->p1]; + assert( u.be.pC!=0 ); pIn3 = &aMem[pOp->p3]; - if( ALWAYS(u.bd.pC->pCursor!=0) ){ + if( ALWAYS(u.be.pC->pCursor!=0) ){ - assert( u.bd.pC->isTable==0 ); + assert( u.be.pC->isTable==0 ); if( pOp->p4.i>0 ){ - u.bd.r.pKeyInfo = u.bd.pC->pKeyInfo; - u.bd.r.nField = (u16)pOp->p4.i; - u.bd.r.aMem = pIn3; + u.be.r.pKeyInfo = u.be.pC->pKeyInfo; + u.be.r.nField = (u16)pOp->p4.i; + u.be.r.aMem = pIn3; #ifdef SQLITE_DEBUG - { int i; for(i=0; i<u.bd.r.nField; i++) assert( memIsValid(&u.bd.r.aMem[i]) ); } + { int i; for(i=0; i<u.be.r.nField; i++) assert( memIsValid(&u.be.r.aMem[i]) ); } #endif - u.bd.r.flags = UNPACKED_PREFIX_MATCH; - u.bd.pIdxKey = &u.bd.r; + u.be.r.flags = UNPACKED_PREFIX_MATCH; + u.be.pIdxKey = &u.be.r; }else{ - u.bd.pIdxKey = sqlite3VdbeAllocUnpackedRecord( - u.bd.pC->pKeyInfo, u.bd.aTempRec, sizeof(u.bd.aTempRec), &u.bd.pFree + u.be.pIdxKey = sqlite3VdbeAllocUnpackedRecord( + u.be.pC->pKeyInfo, u.be.aTempRec, sizeof(u.be.aTempRec), &u.be.pFree ); - if( u.bd.pIdxKey==0 ) goto no_mem; + if( u.be.pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ - sqlite3VdbeRecordUnpack(u.bd.pC->pKeyInfo, pIn3->n, pIn3->z, u.bd.pIdxKey); - u.bd.pIdxKey->flags |= UNPACKED_PREFIX_MATCH; + sqlite3VdbeRecordUnpack(u.be.pC->pKeyInfo, pIn3->n, pIn3->z, u.be.pIdxKey); + u.be.pIdxKey->flags |= UNPACKED_PREFIX_MATCH; } - rc = sqlite3BtreeMovetoUnpacked(u.bd.pC->pCursor, u.bd.pIdxKey, 0, 0, &u.bd.res); + rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, u.be.pIdxKey, 0, 0, &u.be.res); if( pOp->p4.i==0 ){ - sqlite3DbFree(db, u.bd.pFree); + sqlite3DbFree(db, u.be.pFree); } if( rc!=SQLITE_OK ){ break; } - u.bd.alreadyExists = (u.bd.res==0); - u.bd.pC->deferredMoveto = 0; - u.bd.pC->cacheStatus = CACHE_STALE; + u.be.alreadyExists = (u.be.res==0); + u.be.pC->deferredMoveto = 0; + u.be.pC->cacheStatus = CACHE_STALE; } if( pOp->opcode==OP_Found ){ - if( u.bd.alreadyExists ) pc = pOp->p2 - 1; + if( u.be.alreadyExists ) pc = pOp->p2 - 1; }else{ - if( !u.bd.alreadyExists ) pc = pOp->p2 - 1; + if( !u.be.alreadyExists ) pc = pOp->p2 - 1; } break; } /* Opcode: IsUnique P1 P2 P3 P4 * @@ -67265,67 +67320,67 @@ ** instruction. ** ** See also: NotFound, NotExists, Found */ case OP_IsUnique: { /* jump, in3 */ -#if 0 /* local variables moved into u.be */ +#if 0 /* local variables moved into u.bf */ u16 ii; VdbeCursor *pCx; BtCursor *pCrsr; u16 nField; Mem *aMx; UnpackedRecord r; /* B-Tree index search key */ i64 R; /* Rowid stored in register P3 */ -#endif /* local variables moved into u.be */ +#endif /* local variables moved into u.bf */ pIn3 = &aMem[pOp->p3]; - u.be.aMx = &aMem[pOp->p4.i]; + u.bf.aMx = &aMem[pOp->p4.i]; /* Assert that the values of parameters P1 and P4 are in range. */ assert( pOp->p4type==P4_INT32 ); assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); /* Find the index cursor. */ - u.be.pCx = p->apCsr[pOp->p1]; - assert( u.be.pCx->deferredMoveto==0 ); - u.be.pCx->seekResult = 0; - u.be.pCx->cacheStatus = CACHE_STALE; - u.be.pCrsr = u.be.pCx->pCursor; + u.bf.pCx = p->apCsr[pOp->p1]; + assert( u.bf.pCx->deferredMoveto==0 ); + u.bf.pCx->seekResult = 0; + u.bf.pCx->cacheStatus = CACHE_STALE; + u.bf.pCrsr = u.bf.pCx->pCursor; /* If any of the values are NULL, take the jump. */ - u.be.nField = u.be.pCx->pKeyInfo->nField; - for(u.be.ii=0; u.be.ii<u.be.nField; u.be.ii++){ - if( u.be.aMx[u.be.ii].flags & MEM_Null ){ + u.bf.nField = u.bf.pCx->pKeyInfo->nField; + for(u.bf.ii=0; u.bf.ii<u.bf.nField; u.bf.ii++){ + if( u.bf.aMx[u.bf.ii].flags & MEM_Null ){ pc = pOp->p2 - 1; - u.be.pCrsr = 0; + u.bf.pCrsr = 0; break; } } - assert( (u.be.aMx[u.be.nField].flags & MEM_Null)==0 ); + assert( (u.bf.aMx[u.bf.nField].flags & MEM_Null)==0 ); - if( u.be.pCrsr!=0 ){ + if( u.bf.pCrsr!=0 ){ /* Populate the index search key. */ - u.be.r.pKeyInfo = u.be.pCx->pKeyInfo; - u.be.r.nField = u.be.nField + 1; - u.be.r.flags = UNPACKED_PREFIX_SEARCH; - u.be.r.aMem = u.be.aMx; + u.bf.r.pKeyInfo = u.bf.pCx->pKeyInfo; + u.bf.r.nField = u.bf.nField + 1; + u.bf.r.flags = UNPACKED_PREFIX_SEARCH; + u.bf.r.aMem = u.bf.aMx; #ifdef SQLITE_DEBUG - { int i; for(i=0; i<u.be.r.nField; i++) assert( memIsValid(&u.be.r.aMem[i]) ); } + { int i; for(i=0; i<u.bf.r.nField; i++) assert( memIsValid(&u.bf.r.aMem[i]) ); } #endif - /* Extract the value of u.be.R from register P3. */ + /* Extract the value of u.bf.R from register P3. */ sqlite3VdbeMemIntegerify(pIn3); - u.be.R = pIn3->u.i; + u.bf.R = pIn3->u.i; /* Search the B-Tree index. If no conflicting record is found, jump ** to P2. Otherwise, copy the rowid of the conflicting record to ** register P3 and fall through to the next instruction. */ - rc = sqlite3BtreeMovetoUnpacked(u.be.pCrsr, &u.be.r, 0, 0, &u.be.pCx->seekResult); - if( (u.be.r.flags & UNPACKED_PREFIX_SEARCH) || u.be.r.rowid==u.be.R ){ + rc = sqlite3BtreeMovetoUnpacked(u.bf.pCrsr, &u.bf.r, 0, 0, &u.bf.pCx->seekResult); + if( (u.bf.r.flags & UNPACKED_PREFIX_SEARCH) || u.bf.r.rowid==u.bf.R ){ pc = pOp->p2 - 1; }else{ - pIn3->u.i = u.be.r.rowid; + pIn3->u.i = u.bf.r.rowid; } } break; } @@ -67342,46 +67397,46 @@ ** P1 is an index. ** ** See also: Found, NotFound, IsUnique */ case OP_NotExists: { /* jump, in3 */ -#if 0 /* local variables moved into u.bf */ +#if 0 /* local variables moved into u.bg */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; -#endif /* local variables moved into u.bf */ +#endif /* local variables moved into u.bg */ pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bf.pC = p->apCsr[pOp->p1]; - assert( u.bf.pC!=0 ); - assert( u.bf.pC->isTable ); - assert( u.bf.pC->pseudoTableReg==0 ); - u.bf.pCrsr = u.bf.pC->pCursor; - if( ALWAYS(u.bf.pCrsr!=0) ){ - u.bf.res = 0; - u.bf.iKey = pIn3->u.i; - rc = sqlite3BtreeMovetoUnpacked(u.bf.pCrsr, 0, u.bf.iKey, 0, &u.bf.res); - u.bf.pC->lastRowid = pIn3->u.i; - u.bf.pC->rowidIsValid = u.bf.res==0 ?1:0; - u.bf.pC->nullRow = 0; - u.bf.pC->cacheStatus = CACHE_STALE; - u.bf.pC->deferredMoveto = 0; - if( u.bf.res!=0 ){ + u.bg.pC = p->apCsr[pOp->p1]; + assert( u.bg.pC!=0 ); + assert( u.bg.pC->isTable ); + assert( u.bg.pC->pseudoTableReg==0 ); + u.bg.pCrsr = u.bg.pC->pCursor; + if( ALWAYS(u.bg.pCrsr!=0) ){ + u.bg.res = 0; + u.bg.iKey = pIn3->u.i; + rc = sqlite3BtreeMovetoUnpacked(u.bg.pCrsr, 0, u.bg.iKey, 0, &u.bg.res); + u.bg.pC->lastRowid = pIn3->u.i; + u.bg.pC->rowidIsValid = u.bg.res==0 ?1:0; + u.bg.pC->nullRow = 0; + u.bg.pC->cacheStatus = CACHE_STALE; + u.bg.pC->deferredMoveto = 0; + if( u.bg.res!=0 ){ pc = pOp->p2 - 1; - assert( u.bf.pC->rowidIsValid==0 ); + assert( u.bg.pC->rowidIsValid==0 ); } - u.bf.pC->seekResult = u.bf.res; + u.bg.pC->seekResult = u.bg.res; }else{ /* This happens when an attempt to open a read cursor on the ** sqlite_master table returns SQLITE_EMPTY. */ pc = pOp->p2 - 1; - assert( u.bf.pC->rowidIsValid==0 ); - u.bf.pC->seekResult = 0; + assert( u.bg.pC->rowidIsValid==0 ); + u.bg.pC->seekResult = 0; } break; } /* Opcode: Sequence P1 P2 * * * @@ -67412,25 +67467,25 @@ ** an SQLITE_FULL error is generated. The P3 register is updated with the ' ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2-prerelease */ -#if 0 /* local variables moved into u.bg */ +#if 0 /* local variables moved into u.bh */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ -#endif /* local variables moved into u.bg */ +#endif /* local variables moved into u.bh */ - u.bg.v = 0; - u.bg.res = 0; + u.bh.v = 0; + u.bh.res = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bg.pC = p->apCsr[pOp->p1]; - assert( u.bg.pC!=0 ); - if( NEVER(u.bg.pC->pCursor==0) ){ + u.bh.pC = p->apCsr[pOp->p1]; + assert( u.bh.pC!=0 ); + if( NEVER(u.bh.pC->pCursor==0) ){ /* The zero initialization above is all that is needed */ }else{ /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. ** @@ -67442,11 +67497,11 @@ ** The second algorithm is to select a rowid at random and see if ** it already exists in the table. If it does not exist, we have ** succeeded. If the random rowid does exist, we select a new one ** and try again, up to 100 times. */ - assert( u.bg.pC->isTable ); + assert( u.bh.pC->isTable ); #ifdef SQLITE_32BIT_ROWID # define MAX_ROWID 0x7fffffff #else /* Some compilers complain about constants of the form 0x7fffffffffffffff. @@ -67454,101 +67509,101 @@ ** to provide the constant while making all compilers happy. */ # define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff ) #endif - if( !u.bg.pC->useRandomRowid ){ - u.bg.v = sqlite3BtreeGetCachedRowid(u.bg.pC->pCursor); - if( u.bg.v==0 ){ - rc = sqlite3BtreeLast(u.bg.pC->pCursor, &u.bg.res); + if( !u.bh.pC->useRandomRowid ){ + u.bh.v = sqlite3BtreeGetCachedRowid(u.bh.pC->pCursor); + if( u.bh.v==0 ){ + rc = sqlite3BtreeLast(u.bh.pC->pCursor, &u.bh.res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( u.bg.res ){ - u.bg.v = 1; /* IMP: R-61914-48074 */ + if( u.bh.res ){ + u.bh.v = 1; /* IMP: R-61914-48074 */ }else{ - assert( sqlite3BtreeCursorIsValid(u.bg.pC->pCursor) ); - rc = sqlite3BtreeKeySize(u.bg.pC->pCursor, &u.bg.v); + assert( sqlite3BtreeCursorIsValid(u.bh.pC->pCursor) ); + rc = sqlite3BtreeKeySize(u.bh.pC->pCursor, &u.bh.v); assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ - if( u.bg.v>=MAX_ROWID ){ - u.bg.pC->useRandomRowid = 1; + if( u.bh.v>=MAX_ROWID ){ + u.bh.pC->useRandomRowid = 1; }else{ - u.bg.v++; /* IMP: R-29538-34987 */ + u.bh.v++; /* IMP: R-29538-34987 */ } } } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pOp->p3 ){ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3>0 ); if( p->pFrame ){ - for(u.bg.pFrame=p->pFrame; u.bg.pFrame->pParent; u.bg.pFrame=u.bg.pFrame->pParent); + for(u.bh.pFrame=p->pFrame; u.bh.pFrame->pParent; u.bh.pFrame=u.bh.pFrame->pParent); /* Assert that P3 is a valid memory cell. */ - assert( pOp->p3<=u.bg.pFrame->nMem ); - u.bg.pMem = &u.bg.pFrame->aMem[pOp->p3]; + assert( pOp->p3<=u.bh.pFrame->nMem ); + u.bh.pMem = &u.bh.pFrame->aMem[pOp->p3]; }else{ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3<=p->nMem ); - u.bg.pMem = &aMem[pOp->p3]; - memAboutToChange(p, u.bg.pMem); + u.bh.pMem = &aMem[pOp->p3]; + memAboutToChange(p, u.bh.pMem); } - assert( memIsValid(u.bg.pMem) ); + assert( memIsValid(u.bh.pMem) ); - REGISTER_TRACE(pOp->p3, u.bg.pMem); - sqlite3VdbeMemIntegerify(u.bg.pMem); - assert( (u.bg.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ - if( u.bg.pMem->u.i==MAX_ROWID || u.bg.pC->useRandomRowid ){ + REGISTER_TRACE(pOp->p3, u.bh.pMem); + sqlite3VdbeMemIntegerify(u.bh.pMem); + assert( (u.bh.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ + if( u.bh.pMem->u.i==MAX_ROWID || u.bh.pC->useRandomRowid ){ rc = SQLITE_FULL; /* IMP: R-12275-61338 */ goto abort_due_to_error; } - if( u.bg.v<u.bg.pMem->u.i+1 ){ - u.bg.v = u.bg.pMem->u.i + 1; + if( u.bh.v<u.bh.pMem->u.i+1 ){ + u.bh.v = u.bh.pMem->u.i + 1; } - u.bg.pMem->u.i = u.bg.v; + u.bh.pMem->u.i = u.bh.v; } #endif - sqlite3BtreeSetCachedRowid(u.bg.pC->pCursor, u.bg.v<MAX_ROWID ? u.bg.v+1 : 0); + sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, u.bh.v<MAX_ROWID ? u.bh.v+1 : 0); } - if( u.bg.pC->useRandomRowid ){ + if( u.bh.pC->useRandomRowid ){ /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the ** largest possible integer (9223372036854775807) then the database ** engine starts picking positive candidate ROWIDs at random until ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ /* on the first attempt, simply do one more than previous */ - u.bg.v = lastRowid; - u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ - u.bg.v++; /* ensure non-zero */ - u.bg.cnt = 0; - while( ((rc = sqlite3BtreeMovetoUnpacked(u.bg.pC->pCursor, 0, (u64)u.bg.v, - 0, &u.bg.res))==SQLITE_OK) - && (u.bg.res==0) - && (++u.bg.cnt<100)){ + u.bh.v = lastRowid; + u.bh.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ + u.bh.v++; /* ensure non-zero */ + u.bh.cnt = 0; + while( ((rc = sqlite3BtreeMovetoUnpacked(u.bh.pC->pCursor, 0, (u64)u.bh.v, + 0, &u.bh.res))==SQLITE_OK) + && (u.bh.res==0) + && (++u.bh.cnt<100)){ /* collision - try another random rowid */ - sqlite3_randomness(sizeof(u.bg.v), &u.bg.v); - if( u.bg.cnt<5 ){ + sqlite3_randomness(sizeof(u.bh.v), &u.bh.v); + if( u.bh.cnt<5 ){ /* try "small" random rowids for the initial attempts */ - u.bg.v &= 0xffffff; + u.bh.v &= 0xffffff; }else{ - u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ + u.bh.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ } - u.bg.v++; /* ensure non-zero */ + u.bh.v++; /* ensure non-zero */ } - if( rc==SQLITE_OK && u.bg.res==0 ){ + if( rc==SQLITE_OK && u.bh.res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } - assert( u.bg.v>0 ); /* EV: R-40812-03570 */ + assert( u.bh.v>0 ); /* EV: R-40812-03570 */ } - u.bg.pC->rowidIsValid = 0; - u.bg.pC->deferredMoveto = 0; - u.bg.pC->cacheStatus = CACHE_STALE; + u.bh.pC->rowidIsValid = 0; + u.bh.pC->deferredMoveto = 0; + u.bh.pC->cacheStatus = CACHE_STALE; } - pOut->u.i = u.bg.v; + pOut->u.i = u.bh.v; break; } /* Opcode: Insert P1 P2 P3 P4 P5 ** @@ -67594,74 +67649,74 @@ ** This works exactly like OP_Insert except that the key is the ** integer value P3, not the value of the integer stored in register P3. */ case OP_Insert: case OP_InsertInt: { -#if 0 /* local variables moved into u.bh */ +#if 0 /* local variables moved into u.bi */ Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ i64 iKey; /* The integer ROWID or key for the record to be inserted */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int nZero; /* Number of zero-bytes to append */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ const char *zTbl; /* Table name - used by the opdate hook */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ -#endif /* local variables moved into u.bh */ +#endif /* local variables moved into u.bi */ - u.bh.pData = &aMem[pOp->p2]; + u.bi.pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - assert( memIsValid(u.bh.pData) ); - u.bh.pC = p->apCsr[pOp->p1]; - assert( u.bh.pC!=0 ); - assert( u.bh.pC->pCursor!=0 ); - assert( u.bh.pC->pseudoTableReg==0 ); - assert( u.bh.pC->isTable ); - REGISTER_TRACE(pOp->p2, u.bh.pData); + assert( memIsValid(u.bi.pData) ); + u.bi.pC = p->apCsr[pOp->p1]; + assert( u.bi.pC!=0 ); + assert( u.bi.pC->pCursor!=0 ); + assert( u.bi.pC->pseudoTableReg==0 ); + assert( u.bi.pC->isTable ); + REGISTER_TRACE(pOp->p2, u.bi.pData); if( pOp->opcode==OP_Insert ){ - u.bh.pKey = &aMem[pOp->p3]; - assert( u.bh.pKey->flags & MEM_Int ); - assert( memIsValid(u.bh.pKey) ); - REGISTER_TRACE(pOp->p3, u.bh.pKey); - u.bh.iKey = u.bh.pKey->u.i; + u.bi.pKey = &aMem[pOp->p3]; + assert( u.bi.pKey->flags & MEM_Int ); + assert( memIsValid(u.bi.pKey) ); + REGISTER_TRACE(pOp->p3, u.bi.pKey); + u.bi.iKey = u.bi.pKey->u.i; }else{ assert( pOp->opcode==OP_InsertInt ); - u.bh.iKey = pOp->p3; + u.bi.iKey = pOp->p3; } if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bh.iKey; - if( u.bh.pData->flags & MEM_Null ){ - u.bh.pData->z = 0; - u.bh.pData->n = 0; - }else{ - assert( u.bh.pData->flags & (MEM_Blob|MEM_Str) ); - } - u.bh.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bh.pC->seekResult : 0); - if( u.bh.pData->flags & MEM_Zero ){ - u.bh.nZero = u.bh.pData->u.nZero; - }else{ - u.bh.nZero = 0; - } - sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, 0); - rc = sqlite3BtreeInsert(u.bh.pC->pCursor, 0, u.bh.iKey, - u.bh.pData->z, u.bh.pData->n, u.bh.nZero, - pOp->p5 & OPFLAG_APPEND, u.bh.seekResult - ); - u.bh.pC->rowidIsValid = 0; - u.bh.pC->deferredMoveto = 0; - u.bh.pC->cacheStatus = CACHE_STALE; + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bi.iKey; + if( u.bi.pData->flags & MEM_Null ){ + u.bi.pData->z = 0; + u.bi.pData->n = 0; + }else{ + assert( u.bi.pData->flags & (MEM_Blob|MEM_Str) ); + } + u.bi.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bi.pC->seekResult : 0); + if( u.bi.pData->flags & MEM_Zero ){ + u.bi.nZero = u.bi.pData->u.nZero; + }else{ + u.bi.nZero = 0; + } + sqlite3BtreeSetCachedRowid(u.bi.pC->pCursor, 0); + rc = sqlite3BtreeInsert(u.bi.pC->pCursor, 0, u.bi.iKey, + u.bi.pData->z, u.bi.pData->n, u.bi.nZero, + pOp->p5 & OPFLAG_APPEND, u.bi.seekResult + ); + u.bi.pC->rowidIsValid = 0; + u.bi.pC->deferredMoveto = 0; + u.bi.pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ - u.bh.zDb = db->aDb[u.bh.pC->iDb].zName; - u.bh.zTbl = pOp->p4.z; - u.bh.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); - assert( u.bh.pC->isTable ); - db->xUpdateCallback(db->pUpdateArg, u.bh.op, u.bh.zDb, u.bh.zTbl, u.bh.iKey); - assert( u.bh.pC->iDb>=0 ); + u.bi.zDb = db->aDb[u.bi.pC->iDb].zName; + u.bi.zTbl = pOp->p4.z; + u.bi.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); + assert( u.bi.pC->isTable ); + db->xUpdateCallback(db->pUpdateArg, u.bi.op, u.bi.zDb, u.bi.zTbl, u.bi.iKey); + assert( u.bi.pC->iDb>=0 ); } break; } /* Opcode: Delete P1 P2 * P4 * @@ -67683,51 +67738,51 @@ ** pointing to. The update hook will be invoked, if it exists. ** If P4 is not NULL then the P1 cursor must have been positioned ** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { -#if 0 /* local variables moved into u.bi */ +#if 0 /* local variables moved into u.bj */ i64 iKey; VdbeCursor *pC; -#endif /* local variables moved into u.bi */ +#endif /* local variables moved into u.bj */ - u.bi.iKey = 0; + u.bj.iKey = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bi.pC = p->apCsr[pOp->p1]; - assert( u.bi.pC!=0 ); - assert( u.bi.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ + u.bj.pC = p->apCsr[pOp->p1]; + assert( u.bj.pC!=0 ); + assert( u.bj.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ - /* If the update-hook will be invoked, set u.bi.iKey to the rowid of the + /* If the update-hook will be invoked, set u.bj.iKey to the rowid of the ** row being deleted. */ if( db->xUpdateCallback && pOp->p4.z ){ - assert( u.bi.pC->isTable ); - assert( u.bi.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */ - u.bi.iKey = u.bi.pC->lastRowid; + assert( u.bj.pC->isTable ); + assert( u.bj.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */ + u.bj.iKey = u.bj.pC->lastRowid; } /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or ** OP_Column on the same table without any intervening operations that - ** might move or invalidate the cursor. Hence cursor u.bi.pC is always pointing + ** might move or invalidate the cursor. Hence cursor u.bj.pC is always pointing ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation ** below is always a no-op and cannot fail. We will run it anyhow, though, ** to guard against future changes to the code generator. **/ - assert( u.bi.pC->deferredMoveto==0 ); - rc = sqlite3VdbeCursorMoveto(u.bi.pC); + assert( u.bj.pC->deferredMoveto==0 ); + rc = sqlite3VdbeCursorMoveto(u.bj.pC); if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; - sqlite3BtreeSetCachedRowid(u.bi.pC->pCursor, 0); - rc = sqlite3BtreeDelete(u.bi.pC->pCursor); - u.bi.pC->cacheStatus = CACHE_STALE; + sqlite3BtreeSetCachedRowid(u.bj.pC->pCursor, 0); + rc = sqlite3BtreeDelete(u.bj.pC->pCursor); + u.bj.pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ - const char *zDb = db->aDb[u.bi.pC->iDb].zName; + const char *zDb = db->aDb[u.bj.pC->iDb].zName; const char *zTbl = pOp->p4.z; - db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bi.iKey); - assert( u.bi.pC->iDb>=0 ); + db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bj.iKey); + assert( u.bj.pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } /* Opcode: ResetCount * * * * * @@ -67749,20 +67804,20 @@ ** register P3 with the entry that the sorter cursor currently points to. ** If, excluding the rowid fields at the end, the two records are a match, ** fall through to the next instruction. Otherwise, jump to instruction P2. */ case OP_SorterCompare: { -#if 0 /* local variables moved into u.bj */ +#if 0 /* local variables moved into u.bk */ VdbeCursor *pC; int res; -#endif /* local variables moved into u.bj */ +#endif /* local variables moved into u.bk */ - u.bj.pC = p->apCsr[pOp->p1]; - assert( isSorter(u.bj.pC) ); + u.bk.pC = p->apCsr[pOp->p1]; + assert( isSorter(u.bk.pC) ); pIn3 = &aMem[pOp->p3]; - rc = sqlite3VdbeSorterCompare(u.bj.pC, pIn3, &u.bj.res); - if( u.bj.res ){ + rc = sqlite3VdbeSorterCompare(u.bk.pC, pIn3, &u.bk.res); + if( u.bk.res ){ pc = pOp->p2-1; } break; }; @@ -67769,18 +67824,19 @@ /* Opcode: SorterData P1 P2 * * * ** ** Write into register P2 the current sorter data for sorter cursor P1. */ case OP_SorterData: { -#if 0 /* local variables moved into u.bk */ +#if 0 /* local variables moved into u.bl */ VdbeCursor *pC; -#endif /* local variables moved into u.bk */ +#endif /* local variables moved into u.bl */ + #ifndef SQLITE_OMIT_MERGE_SORT pOut = &aMem[pOp->p2]; - u.bk.pC = p->apCsr[pOp->p1]; - assert( u.bk.pC->isSorter ); - rc = sqlite3VdbeSorterRowkey(u.bk.pC, pOut); + u.bl.pC = p->apCsr[pOp->p1]; + assert( u.bl.pC->isSorter ); + rc = sqlite3VdbeSorterRowkey(u.bl.pC, pOut); #else pOp->opcode = OP_RowKey; pc--; #endif break; @@ -67806,66 +67862,66 @@ ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. */ case OP_RowKey: case OP_RowData: { -#if 0 /* local variables moved into u.bl */ +#if 0 /* local variables moved into u.bm */ VdbeCursor *pC; BtCursor *pCrsr; u32 n; i64 n64; -#endif /* local variables moved into u.bl */ +#endif /* local variables moved into u.bm */ pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bl.pC = p->apCsr[pOp->p1]; - assert( u.bl.pC->isSorter==0 ); - assert( u.bl.pC->isTable || pOp->opcode!=OP_RowData ); - assert( u.bl.pC->isIndex || pOp->opcode==OP_RowData ); - assert( u.bl.pC!=0 ); - assert( u.bl.pC->nullRow==0 ); - assert( u.bl.pC->pseudoTableReg==0 ); - assert( u.bl.pC->pCursor!=0 ); - u.bl.pCrsr = u.bl.pC->pCursor; - assert( sqlite3BtreeCursorIsValid(u.bl.pCrsr) ); + u.bm.pC = p->apCsr[pOp->p1]; + assert( u.bm.pC->isSorter==0 ); + assert( u.bm.pC->isTable || pOp->opcode!=OP_RowData ); + assert( u.bm.pC->isIndex || pOp->opcode==OP_RowData ); + assert( u.bm.pC!=0 ); + assert( u.bm.pC->nullRow==0 ); + assert( u.bm.pC->pseudoTableReg==0 ); + assert( u.bm.pC->pCursor!=0 ); + u.bm.pCrsr = u.bm.pC->pCursor; + assert( sqlite3BtreeCursorIsValid(u.bm.pCrsr) ); /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_Rewind/Op_Next with no intervening instructions that might invalidate ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always ** a no-op and can never fail. But we leave it in place as a safety. */ - assert( u.bl.pC->deferredMoveto==0 ); - rc = sqlite3VdbeCursorMoveto(u.bl.pC); + assert( u.bm.pC->deferredMoveto==0 ); + rc = sqlite3VdbeCursorMoveto(u.bm.pC); if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; - if( u.bl.pC->isIndex ){ - assert( !u.bl.pC->isTable ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bl.pCrsr, &u.bl.n64); + if( u.bm.pC->isIndex ){ + assert( !u.bm.pC->isTable ); + VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bm.pCrsr, &u.bm.n64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ - if( u.bl.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( u.bm.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - u.bl.n = (u32)u.bl.n64; + u.bm.n = (u32)u.bm.n64; }else{ - VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bl.pCrsr, &u.bl.n); + VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bm.pCrsr, &u.bm.n); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ - if( u.bl.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( u.bm.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } } - if( sqlite3VdbeMemGrow(pOut, u.bl.n, 0) ){ + if( sqlite3VdbeMemGrow(pOut, u.bm.n, 0) ){ goto no_mem; } - pOut->n = u.bl.n; + pOut->n = u.bm.n; MemSetTypeFlag(pOut, MEM_Blob); - if( u.bl.pC->isIndex ){ - rc = sqlite3BtreeKey(u.bl.pCrsr, 0, u.bl.n, pOut->z); + if( u.bm.pC->isIndex ){ + rc = sqlite3BtreeKey(u.bm.pCrsr, 0, u.bm.n, pOut->z); }else{ - rc = sqlite3BtreeData(u.bl.pCrsr, 0, u.bl.n, pOut->z); + rc = sqlite3BtreeData(u.bm.pCrsr, 0, u.bm.n, pOut->z); } pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -67878,46 +67934,46 @@ ** P1 can be either an ordinary table or a virtual table. There used to ** be a separate OP_VRowid opcode for use with virtual tables, but this ** one opcode now works for both table types. */ case OP_Rowid: { /* out2-prerelease */ -#if 0 /* local variables moved into u.bm */ +#if 0 /* local variables moved into u.bn */ VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; -#endif /* local variables moved into u.bm */ +#endif /* local variables moved into u.bn */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bm.pC = p->apCsr[pOp->p1]; - assert( u.bm.pC!=0 ); - assert( u.bm.pC->pseudoTableReg==0 ); - if( u.bm.pC->nullRow ){ + u.bn.pC = p->apCsr[pOp->p1]; + assert( u.bn.pC!=0 ); + assert( u.bn.pC->pseudoTableReg==0 ); + if( u.bn.pC->nullRow ){ pOut->flags = MEM_Null; break; - }else if( u.bm.pC->deferredMoveto ){ - u.bm.v = u.bm.pC->movetoTarget; + }else if( u.bn.pC->deferredMoveto ){ + u.bn.v = u.bn.pC->movetoTarget; #ifndef SQLITE_OMIT_VIRTUALTABLE - }else if( u.bm.pC->pVtabCursor ){ - u.bm.pVtab = u.bm.pC->pVtabCursor->pVtab; - u.bm.pModule = u.bm.pVtab->pModule; - assert( u.bm.pModule->xRowid ); - rc = u.bm.pModule->xRowid(u.bm.pC->pVtabCursor, &u.bm.v); - importVtabErrMsg(p, u.bm.pVtab); + }else if( u.bn.pC->pVtabCursor ){ + u.bn.pVtab = u.bn.pC->pVtabCursor->pVtab; + u.bn.pModule = u.bn.pVtab->pModule; + assert( u.bn.pModule->xRowid ); + rc = u.bn.pModule->xRowid(u.bn.pC->pVtabCursor, &u.bn.v); + importVtabErrMsg(p, u.bn.pVtab); #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ - assert( u.bm.pC->pCursor!=0 ); - rc = sqlite3VdbeCursorMoveto(u.bm.pC); + assert( u.bn.pC->pCursor!=0 ); + rc = sqlite3VdbeCursorMoveto(u.bn.pC); if( rc ) goto abort_due_to_error; - if( u.bm.pC->rowidIsValid ){ - u.bm.v = u.bm.pC->lastRowid; + if( u.bn.pC->rowidIsValid ){ + u.bn.v = u.bn.pC->lastRowid; }else{ - rc = sqlite3BtreeKeySize(u.bm.pC->pCursor, &u.bm.v); + rc = sqlite3BtreeKeySize(u.bn.pC->pCursor, &u.bn.v); assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */ } } - pOut->u.i = u.bm.v; + pOut->u.i = u.bn.v; break; } /* Opcode: NullRow P1 * * * * ** @@ -67924,22 +67980,22 @@ ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. */ case OP_NullRow: { -#if 0 /* local variables moved into u.bn */ +#if 0 /* local variables moved into u.bo */ VdbeCursor *pC; -#endif /* local variables moved into u.bn */ +#endif /* local variables moved into u.bo */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bn.pC = p->apCsr[pOp->p1]; - assert( u.bn.pC!=0 ); - u.bn.pC->nullRow = 1; - u.bn.pC->rowidIsValid = 0; - assert( u.bn.pC->pCursor || u.bn.pC->pVtabCursor ); - if( u.bn.pC->pCursor ){ - sqlite3BtreeClearCursor(u.bn.pC->pCursor); + u.bo.pC = p->apCsr[pOp->p1]; + assert( u.bo.pC!=0 ); + u.bo.pC->nullRow = 1; + u.bo.pC->rowidIsValid = 0; + assert( u.bo.pC->pCursor || u.bo.pC->pVtabCursor ); + if( u.bo.pC->pCursor ){ + sqlite3BtreeClearCursor(u.bo.pC->pCursor); } break; } /* Opcode: Last P1 P2 * * * @@ -67949,29 +68005,29 @@ ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Last: { /* jump */ -#if 0 /* local variables moved into u.bo */ +#if 0 /* local variables moved into u.bp */ VdbeCursor *pC; BtCursor *pCrsr; int res; -#endif /* local variables moved into u.bo */ +#endif /* local variables moved into u.bp */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bo.pC = p->apCsr[pOp->p1]; - assert( u.bo.pC!=0 ); - u.bo.pCrsr = u.bo.pC->pCursor; - u.bo.res = 0; - if( ALWAYS(u.bo.pCrsr!=0) ){ - rc = sqlite3BtreeLast(u.bo.pCrsr, &u.bo.res); + u.bp.pC = p->apCsr[pOp->p1]; + assert( u.bp.pC!=0 ); + u.bp.pCrsr = u.bp.pC->pCursor; + u.bp.res = 0; + if( ALWAYS(u.bp.pCrsr!=0) ){ + rc = sqlite3BtreeLast(u.bp.pCrsr, &u.bp.res); } - u.bo.pC->nullRow = (u8)u.bo.res; - u.bo.pC->deferredMoveto = 0; - u.bo.pC->rowidIsValid = 0; - u.bo.pC->cacheStatus = CACHE_STALE; - if( pOp->p2>0 && u.bo.res ){ + u.bp.pC->nullRow = (u8)u.bp.res; + u.bp.pC->deferredMoveto = 0; + u.bp.pC->rowidIsValid = 0; + u.bp.pC->cacheStatus = CACHE_STALE; + if( pOp->p2>0 && u.bp.res ){ pc = pOp->p2 - 1; } break; } @@ -68007,35 +68063,35 @@ ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Rewind: { /* jump */ -#if 0 /* local variables moved into u.bp */ +#if 0 /* local variables moved into u.bq */ VdbeCursor *pC; BtCursor *pCrsr; int res; -#endif /* local variables moved into u.bp */ +#endif /* local variables moved into u.bq */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bp.pC = p->apCsr[pOp->p1]; - assert( u.bp.pC!=0 ); - assert( u.bp.pC->isSorter==(pOp->opcode==OP_SorterSort) ); - u.bp.res = 1; - if( isSorter(u.bp.pC) ){ - rc = sqlite3VdbeSorterRewind(db, u.bp.pC, &u.bp.res); + u.bq.pC = p->apCsr[pOp->p1]; + assert( u.bq.pC!=0 ); + assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterSort) ); + u.bq.res = 1; + if( isSorter(u.bq.pC) ){ + rc = sqlite3VdbeSorterRewind(db, u.bq.pC, &u.bq.res); }else{ - u.bp.pCrsr = u.bp.pC->pCursor; - assert( u.bp.pCrsr ); - rc = sqlite3BtreeFirst(u.bp.pCrsr, &u.bp.res); - u.bp.pC->atFirst = u.bp.res==0 ?1:0; - u.bp.pC->deferredMoveto = 0; - u.bp.pC->cacheStatus = CACHE_STALE; - u.bp.pC->rowidIsValid = 0; + u.bq.pCrsr = u.bq.pC->pCursor; + assert( u.bq.pCrsr ); + rc = sqlite3BtreeFirst(u.bq.pCrsr, &u.bq.res); + u.bq.pC->atFirst = u.bq.res==0 ?1:0; + u.bq.pC->deferredMoveto = 0; + u.bq.pC->cacheStatus = CACHE_STALE; + u.bq.pC->rowidIsValid = 0; } - u.bp.pC->nullRow = (u8)u.bp.res; + u.bq.pC->nullRow = (u8)u.bq.res; assert( pOp->p2>0 && pOp->p2<p->nOp ); - if( u.bp.res ){ + if( u.bq.res ){ pc = pOp->p2 - 1; } break; } @@ -68075,44 +68131,44 @@ #ifdef SQLITE_OMIT_MERGE_SORT pOp->opcode = OP_Next; #endif case OP_Prev: /* jump */ case OP_Next: { /* jump */ -#if 0 /* local variables moved into u.bq */ +#if 0 /* local variables moved into u.br */ VdbeCursor *pC; int res; -#endif /* local variables moved into u.bq */ +#endif /* local variables moved into u.br */ CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p5<=ArraySize(p->aCounter) ); - u.bq.pC = p->apCsr[pOp->p1]; - if( u.bq.pC==0 ){ + u.br.pC = p->apCsr[pOp->p1]; + if( u.br.pC==0 ){ break; /* See ticket #2273 */ } - assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterNext) ); - if( isSorter(u.bq.pC) ){ + assert( u.br.pC->isSorter==(pOp->opcode==OP_SorterNext) ); + if( isSorter(u.br.pC) ){ assert( pOp->opcode==OP_SorterNext ); - rc = sqlite3VdbeSorterNext(db, u.bq.pC, &u.bq.res); + rc = sqlite3VdbeSorterNext(db, u.br.pC, &u.br.res); }else{ - u.bq.res = 1; - assert( u.bq.pC->deferredMoveto==0 ); - assert( u.bq.pC->pCursor ); + u.br.res = 1; + assert( u.br.pC->deferredMoveto==0 ); + assert( u.br.pC->pCursor ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); - rc = pOp->p4.xAdvance(u.bq.pC->pCursor, &u.bq.res); + rc = pOp->p4.xAdvance(u.br.pC->pCursor, &u.br.res); } - u.bq.pC->nullRow = (u8)u.bq.res; - u.bq.pC->cacheStatus = CACHE_STALE; - if( u.bq.res==0 ){ + u.br.pC->nullRow = (u8)u.br.res; + u.br.pC->cacheStatus = CACHE_STALE; + if( u.br.res==0 ){ pc = pOp->p2 - 1; if( pOp->p5 ) p->aCounter[pOp->p5-1]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif } - u.bq.pC->rowidIsValid = 0; + u.br.pC->rowidIsValid = 0; break; } /* Opcode: IdxInsert P1 P2 P3 * P5 ** @@ -68129,38 +68185,38 @@ case OP_SorterInsert: /* in2 */ #ifdef SQLITE_OMIT_MERGE_SORT pOp->opcode = OP_IdxInsert; #endif case OP_IdxInsert: { /* in2 */ -#if 0 /* local variables moved into u.br */ +#if 0 /* local variables moved into u.bs */ VdbeCursor *pC; BtCursor *pCrsr; int nKey; const char *zKey; -#endif /* local variables moved into u.br */ +#endif /* local variables moved into u.bs */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.br.pC = p->apCsr[pOp->p1]; - assert( u.br.pC!=0 ); - assert( u.br.pC->isSorter==(pOp->opcode==OP_SorterInsert) ); + u.bs.pC = p->apCsr[pOp->p1]; + assert( u.bs.pC!=0 ); + assert( u.bs.pC->isSorter==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); - u.br.pCrsr = u.br.pC->pCursor; - if( ALWAYS(u.br.pCrsr!=0) ){ - assert( u.br.pC->isTable==0 ); + u.bs.pCrsr = u.bs.pC->pCursor; + if( ALWAYS(u.bs.pCrsr!=0) ){ + assert( u.bs.pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ - if( isSorter(u.br.pC) ){ - rc = sqlite3VdbeSorterWrite(db, u.br.pC, pIn2); + if( isSorter(u.bs.pC) ){ + rc = sqlite3VdbeSorterWrite(db, u.bs.pC, pIn2); }else{ - u.br.nKey = pIn2->n; - u.br.zKey = pIn2->z; - rc = sqlite3BtreeInsert(u.br.pCrsr, u.br.zKey, u.br.nKey, "", 0, 0, pOp->p3, - ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.br.pC->seekResult : 0) + u.bs.nKey = pIn2->n; + u.bs.zKey = pIn2->z; + rc = sqlite3BtreeInsert(u.bs.pCrsr, u.bs.zKey, u.bs.nKey, "", 0, 0, pOp->p3, + ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bs.pC->seekResult : 0) ); - assert( u.br.pC->deferredMoveto==0 ); - u.br.pC->cacheStatus = CACHE_STALE; + assert( u.bs.pC->deferredMoveto==0 ); + u.bs.pC->cacheStatus = CACHE_STALE; } } } break; } @@ -68170,37 +68226,37 @@ ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. */ case OP_IdxDelete: { -#if 0 /* local variables moved into u.bs */ +#if 0 /* local variables moved into u.bt */ VdbeCursor *pC; BtCursor *pCrsr; int res; UnpackedRecord r; -#endif /* local variables moved into u.bs */ +#endif /* local variables moved into u.bt */ assert( pOp->p3>0 ); assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bs.pC = p->apCsr[pOp->p1]; - assert( u.bs.pC!=0 ); - u.bs.pCrsr = u.bs.pC->pCursor; - if( ALWAYS(u.bs.pCrsr!=0) ){ - u.bs.r.pKeyInfo = u.bs.pC->pKeyInfo; - u.bs.r.nField = (u16)pOp->p3; - u.bs.r.flags = 0; - u.bs.r.aMem = &aMem[pOp->p2]; + u.bt.pC = p->apCsr[pOp->p1]; + assert( u.bt.pC!=0 ); + u.bt.pCrsr = u.bt.pC->pCursor; + if( ALWAYS(u.bt.pCrsr!=0) ){ + u.bt.r.pKeyInfo = u.bt.pC->pKeyInfo; + u.bt.r.nField = (u16)pOp->p3; + u.bt.r.flags = 0; + u.bt.r.aMem = &aMem[pOp->p2]; #ifdef SQLITE_DEBUG - { int i; for(i=0; i<u.bs.r.nField; i++) assert( memIsValid(&u.bs.r.aMem[i]) ); } + { int i; for(i=0; i<u.bt.r.nField; i++) assert( memIsValid(&u.bt.r.aMem[i]) ); } #endif - rc = sqlite3BtreeMovetoUnpacked(u.bs.pCrsr, &u.bs.r, 0, 0, &u.bs.res); - if( rc==SQLITE_OK && u.bs.res==0 ){ - rc = sqlite3BtreeDelete(u.bs.pCrsr); + rc = sqlite3BtreeMovetoUnpacked(u.bt.pCrsr, &u.bt.r, 0, 0, &u.bt.res); + if( rc==SQLITE_OK && u.bt.res==0 ){ + rc = sqlite3BtreeDelete(u.bt.pCrsr); } - assert( u.bs.pC->deferredMoveto==0 ); - u.bs.pC->cacheStatus = CACHE_STALE; + assert( u.bt.pC->deferredMoveto==0 ); + u.bt.pC->cacheStatus = CACHE_STALE; } break; } /* Opcode: IdxRowid P1 P2 * * * @@ -68210,32 +68266,32 @@ ** the rowid of the table entry to which this index entry points. ** ** See also: Rowid, MakeRecord. */ case OP_IdxRowid: { /* out2-prerelease */ -#if 0 /* local variables moved into u.bt */ +#if 0 /* local variables moved into u.bu */ BtCursor *pCrsr; VdbeCursor *pC; i64 rowid; -#endif /* local variables moved into u.bt */ +#endif /* local variables moved into u.bu */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bt.pC = p->apCsr[pOp->p1]; - assert( u.bt.pC!=0 ); - u.bt.pCrsr = u.bt.pC->pCursor; + u.bu.pC = p->apCsr[pOp->p1]; + assert( u.bu.pC!=0 ); + u.bu.pCrsr = u.bu.pC->pCursor; pOut->flags = MEM_Null; - if( ALWAYS(u.bt.pCrsr!=0) ){ - rc = sqlite3VdbeCursorMoveto(u.bt.pC); + if( ALWAYS(u.bu.pCrsr!=0) ){ + rc = sqlite3VdbeCursorMoveto(u.bu.pC); if( NEVER(rc) ) goto abort_due_to_error; - assert( u.bt.pC->deferredMoveto==0 ); - assert( u.bt.pC->isTable==0 ); - if( !u.bt.pC->nullRow ){ - rc = sqlite3VdbeIdxRowid(db, u.bt.pCrsr, &u.bt.rowid); + assert( u.bu.pC->deferredMoveto==0 ); + assert( u.bu.pC->isTable==0 ); + if( !u.bu.pC->nullRow ){ + rc = sqlite3VdbeIdxRowid(db, u.bu.pCrsr, &u.bu.rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pOut->u.i = u.bt.rowid; + pOut->u.i = u.bu.rowid; pOut->flags = MEM_Int; } } break; } @@ -68266,43 +68322,43 @@ ** If P5 is non-zero then the key value is increased by an epsilon prior ** to the comparison. This makes the opcode work like IdxLE. */ case OP_IdxLT: /* jump */ case OP_IdxGE: { /* jump */ -#if 0 /* local variables moved into u.bu */ +#if 0 /* local variables moved into u.bv */ VdbeCursor *pC; int res; UnpackedRecord r; -#endif /* local variables moved into u.bu */ +#endif /* local variables moved into u.bv */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); - u.bu.pC = p->apCsr[pOp->p1]; - assert( u.bu.pC!=0 ); - assert( u.bu.pC->isOrdered ); - if( ALWAYS(u.bu.pC->pCursor!=0) ){ - assert( u.bu.pC->deferredMoveto==0 ); + u.bv.pC = p->apCsr[pOp->p1]; + assert( u.bv.pC!=0 ); + assert( u.bv.pC->isOrdered ); + if( ALWAYS(u.bv.pC->pCursor!=0) ){ + assert( u.bv.pC->deferredMoveto==0 ); assert( pOp->p5==0 || pOp->p5==1 ); assert( pOp->p4type==P4_INT32 ); - u.bu.r.pKeyInfo = u.bu.pC->pKeyInfo; - u.bu.r.nField = (u16)pOp->p4.i; + u.bv.r.pKeyInfo = u.bv.pC->pKeyInfo; + u.bv.r.nField = (u16)pOp->p4.i; if( pOp->p5 ){ - u.bu.r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH; + u.bv.r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH; }else{ - u.bu.r.flags = UNPACKED_PREFIX_MATCH; + u.bv.r.flags = UNPACKED_PREFIX_MATCH; } - u.bu.r.aMem = &aMem[pOp->p3]; + u.bv.r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG - { int i; for(i=0; i<u.bu.r.nField; i++) assert( memIsValid(&u.bu.r.aMem[i]) ); } + { int i; for(i=0; i<u.bv.r.nField; i++) assert( memIsValid(&u.bv.r.aMem[i]) ); } #endif - rc = sqlite3VdbeIdxKeyCompare(u.bu.pC, &u.bu.r, &u.bu.res); + rc = sqlite3VdbeIdxKeyCompare(u.bv.pC, &u.bv.r, &u.bv.res); if( pOp->opcode==OP_IdxLT ){ - u.bu.res = -u.bu.res; + u.bv.res = -u.bv.res; }else{ assert( pOp->opcode==OP_IdxGE ); - u.bu.res++; + u.bv.res++; } - if( u.bu.res>0 ){ + if( u.bv.res>0 ){ pc = pOp->p2 - 1 ; } } break; } @@ -68326,43 +68382,44 @@ ** If AUTOVACUUM is disabled then a zero is stored in register P2. ** ** See also: Clear */ case OP_Destroy: { /* out2-prerelease */ -#if 0 /* local variables moved into u.bv */ +#if 0 /* local variables moved into u.bw */ int iMoved; int iCnt; Vdbe *pVdbe; int iDb; -#endif /* local variables moved into u.bv */ +#endif /* local variables moved into u.bw */ + #ifndef SQLITE_OMIT_VIRTUALTABLE - u.bv.iCnt = 0; - for(u.bv.pVdbe=db->pVdbe; u.bv.pVdbe; u.bv.pVdbe = u.bv.pVdbe->pNext){ - if( u.bv.pVdbe->magic==VDBE_MAGIC_RUN && u.bv.pVdbe->inVtabMethod<2 && u.bv.pVdbe->pc>=0 ){ - u.bv.iCnt++; + u.bw.iCnt = 0; + for(u.bw.pVdbe=db->pVdbe; u.bw.pVdbe; u.bw.pVdbe = u.bw.pVdbe->pNext){ + if( u.bw.pVdbe->magic==VDBE_MAGIC_RUN && u.bw.pVdbe->inVtabMethod<2 && u.bw.pVdbe->pc>=0 ){ + u.bw.iCnt++; } } #else - u.bv.iCnt = db->activeVdbeCnt; + u.bw.iCnt = db->activeVdbeCnt; #endif pOut->flags = MEM_Null; - if( u.bv.iCnt>1 ){ + if( u.bw.iCnt>1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; }else{ - u.bv.iDb = pOp->p3; - assert( u.bv.iCnt==1 ); - assert( (p->btreeMask & (((yDbMask)1)<<u.bv.iDb))!=0 ); - rc = sqlite3BtreeDropTable(db->aDb[u.bv.iDb].pBt, pOp->p1, &u.bv.iMoved); + u.bw.iDb = pOp->p3; + assert( u.bw.iCnt==1 ); + assert( (p->btreeMask & (((yDbMask)1)<<u.bw.iDb))!=0 ); + rc = sqlite3BtreeDropTable(db->aDb[u.bw.iDb].pBt, pOp->p1, &u.bw.iMoved); pOut->flags = MEM_Int; - pOut->u.i = u.bv.iMoved; + pOut->u.i = u.bw.iMoved; #ifndef SQLITE_OMIT_AUTOVACUUM - if( rc==SQLITE_OK && u.bv.iMoved!=0 ){ - sqlite3RootPageMoved(db, u.bv.iDb, u.bv.iMoved, pOp->p1); + if( rc==SQLITE_OK && u.bw.iMoved!=0 ){ + sqlite3RootPageMoved(db, u.bw.iDb, u.bw.iMoved, pOp->p1); /* All OP_Destroy operations occur on the same btree */ - assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bv.iDb+1 ); - resetSchemaOnFault = u.bv.iDb+1; + assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bw.iDb+1 ); + resetSchemaOnFault = u.bw.iDb+1; } #endif } break; } @@ -68384,25 +68441,25 @@ ** also incremented by the number of rows in the table being cleared. ** ** See also: Destroy */ case OP_Clear: { -#if 0 /* local variables moved into u.bw */ +#if 0 /* local variables moved into u.bx */ int nChange; -#endif /* local variables moved into u.bw */ +#endif /* local variables moved into u.bx */ - u.bw.nChange = 0; + u.bx.nChange = 0; assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 ); rc = sqlite3BtreeClearTable( - db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bw.nChange : 0) + db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bx.nChange : 0) ); if( pOp->p3 ){ - p->nChange += u.bw.nChange; + p->nChange += u.bx.nChange; if( pOp->p3>0 ){ assert( memIsValid(&aMem[pOp->p3]) ); memAboutToChange(p, &aMem[pOp->p3]); - aMem[pOp->p3].u.i += u.bw.nChange; + aMem[pOp->p3].u.i += u.bx.nChange; } } break; } @@ -68428,29 +68485,29 @@ ** ** See documentation on OP_CreateTable for additional information. */ case OP_CreateIndex: /* out2-prerelease */ case OP_CreateTable: { /* out2-prerelease */ -#if 0 /* local variables moved into u.bx */ +#if 0 /* local variables moved into u.by */ int pgno; int flags; Db *pDb; -#endif /* local variables moved into u.bx */ +#endif /* local variables moved into u.by */ - u.bx.pgno = 0; + u.by.pgno = 0; assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); - u.bx.pDb = &db->aDb[pOp->p1]; - assert( u.bx.pDb->pBt!=0 ); + u.by.pDb = &db->aDb[pOp->p1]; + assert( u.by.pDb->pBt!=0 ); if( pOp->opcode==OP_CreateTable ){ - /* u.bx.flags = BTREE_INTKEY; */ - u.bx.flags = BTREE_INTKEY; + /* u.by.flags = BTREE_INTKEY; */ + u.by.flags = BTREE_INTKEY; }else{ - u.bx.flags = BTREE_BLOBKEY; + u.by.flags = BTREE_BLOBKEY; } - rc = sqlite3BtreeCreateTable(u.bx.pDb->pBt, &u.bx.pgno, u.bx.flags); - pOut->u.i = u.bx.pgno; + rc = sqlite3BtreeCreateTable(u.by.pDb->pBt, &u.by.pgno, u.by.flags); + pOut->u.i = u.by.pgno; break; } /* Opcode: ParseSchema P1 * * P4 * ** @@ -68459,48 +68516,48 @@ ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ case OP_ParseSchema: { -#if 0 /* local variables moved into u.by */ +#if 0 /* local variables moved into u.bz */ int iDb; const char *zMaster; char *zSql; InitData initData; -#endif /* local variables moved into u.by */ +#endif /* local variables moved into u.bz */ /* Any prepared statement that invokes this opcode will hold mutexes ** on every btree. This is a prerequisite for invoking ** sqlite3InitCallback(). */ #ifdef SQLITE_DEBUG - for(u.by.iDb=0; u.by.iDb<db->nDb; u.by.iDb++){ - assert( u.by.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.by.iDb].pBt) ); + for(u.bz.iDb=0; u.bz.iDb<db->nDb; u.bz.iDb++){ + assert( u.bz.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.bz.iDb].pBt) ); } #endif - u.by.iDb = pOp->p1; - assert( u.by.iDb>=0 && u.by.iDb<db->nDb ); - assert( DbHasProperty(db, u.by.iDb, DB_SchemaLoaded) ); + u.bz.iDb = pOp->p1; + assert( u.bz.iDb>=0 && u.bz.iDb<db->nDb ); + assert( DbHasProperty(db, u.bz.iDb, DB_SchemaLoaded) ); /* Used to be a conditional */ { - u.by.zMaster = SCHEMA_TABLE(u.by.iDb); - u.by.initData.db = db; - u.by.initData.iDb = pOp->p1; - u.by.initData.pzErrMsg = &p->zErrMsg; - u.by.zSql = sqlite3MPrintf(db, + u.bz.zMaster = SCHEMA_TABLE(u.bz.iDb); + u.bz.initData.db = db; + u.bz.initData.iDb = pOp->p1; + u.bz.initData.pzErrMsg = &p->zErrMsg; + u.bz.zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", - db->aDb[u.by.iDb].zName, u.by.zMaster, pOp->p4.z); - if( u.by.zSql==0 ){ + db->aDb[u.bz.iDb].zName, u.bz.zMaster, pOp->p4.z); + if( u.bz.zSql==0 ){ rc = SQLITE_NOMEM; }else{ assert( db->init.busy==0 ); db->init.busy = 1; - u.by.initData.rc = SQLITE_OK; + u.bz.initData.rc = SQLITE_OK; assert( !db->mallocFailed ); - rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0); - if( rc==SQLITE_OK ) rc = u.by.initData.rc; - sqlite3DbFree(db, u.by.zSql); + rc = sqlite3_exec(db, u.bz.zSql, sqlite3InitCallback, &u.bz.initData, 0); + if( rc==SQLITE_OK ) rc = u.bz.initData.rc; + sqlite3DbFree(db, u.bz.zSql); db->init.busy = 0; } } if( rc ) sqlite3ResetAllSchemasOfConnection(db); if( rc==SQLITE_NOMEM ){ @@ -68580,45 +68637,45 @@ ** file, not the main database file. ** ** This opcode is used to implement the integrity_check pragma. */ case OP_IntegrityCk: { -#if 0 /* local variables moved into u.bz */ +#if 0 /* local variables moved into u.ca */ int nRoot; /* Number of tables to check. (Number of root pages.) */ int *aRoot; /* Array of rootpage numbers for tables to be checked */ int j; /* Loop counter */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ -#endif /* local variables moved into u.bz */ +#endif /* local variables moved into u.ca */ - u.bz.nRoot = pOp->p2; - assert( u.bz.nRoot>0 ); - u.bz.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.bz.nRoot+1) ); - if( u.bz.aRoot==0 ) goto no_mem; + u.ca.nRoot = pOp->p2; + assert( u.ca.nRoot>0 ); + u.ca.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.ca.nRoot+1) ); + if( u.ca.aRoot==0 ) goto no_mem; assert( pOp->p3>0 && pOp->p3<=p->nMem ); - u.bz.pnErr = &aMem[pOp->p3]; - assert( (u.bz.pnErr->flags & MEM_Int)!=0 ); - assert( (u.bz.pnErr->flags & (MEM_Str|MEM_Blob))==0 ); + u.ca.pnErr = &aMem[pOp->p3]; + assert( (u.ca.pnErr->flags & MEM_Int)!=0 ); + assert( (u.ca.pnErr->flags & (MEM_Str|MEM_Blob))==0 ); pIn1 = &aMem[pOp->p1]; - for(u.bz.j=0; u.bz.j<u.bz.nRoot; u.bz.j++){ - u.bz.aRoot[u.bz.j] = (int)sqlite3VdbeIntValue(&pIn1[u.bz.j]); + for(u.ca.j=0; u.ca.j<u.ca.nRoot; u.ca.j++){ + u.ca.aRoot[u.ca.j] = (int)sqlite3VdbeIntValue(&pIn1[u.ca.j]); } - u.bz.aRoot[u.bz.j] = 0; + u.ca.aRoot[u.ca.j] = 0; assert( pOp->p5<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 ); - u.bz.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.bz.aRoot, u.bz.nRoot, - (int)u.bz.pnErr->u.i, &u.bz.nErr); - sqlite3DbFree(db, u.bz.aRoot); - u.bz.pnErr->u.i -= u.bz.nErr; + u.ca.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.ca.aRoot, u.ca.nRoot, + (int)u.ca.pnErr->u.i, &u.ca.nErr); + sqlite3DbFree(db, u.ca.aRoot); + u.ca.pnErr->u.i -= u.ca.nErr; sqlite3VdbeMemSetNull(pIn1); - if( u.bz.nErr==0 ){ - assert( u.bz.z==0 ); - }else if( u.bz.z==0 ){ + if( u.ca.nErr==0 ){ + assert( u.ca.z==0 ); + }else if( u.ca.z==0 ){ goto no_mem; }else{ - sqlite3VdbeMemSetStr(pIn1, u.bz.z, -1, SQLITE_UTF8, sqlite3_free); + sqlite3VdbeMemSetStr(pIn1, u.ca.z, -1, SQLITE_UTF8, sqlite3_free); } UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); break; } @@ -68648,24 +68705,24 @@ ** Extract the smallest value from boolean index P1 and put that value into ** register P3. Or, if boolean index P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ -#if 0 /* local variables moved into u.ca */ +#if 0 /* local variables moved into u.cb */ i64 val; -#endif /* local variables moved into u.ca */ +#endif /* local variables moved into u.cb */ CHECK_FOR_INTERRUPT; pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_RowSet)==0 - || sqlite3RowSetNext(pIn1->u.pRowSet, &u.ca.val)==0 + || sqlite3RowSetNext(pIn1->u.pRowSet, &u.cb.val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); pc = pOp->p2 - 1; }else{ /* A value was pulled from the index */ - sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.ca.val); + sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.cb.val); } break; } /* Opcode: RowSetTest P1 P2 P3 P4 @@ -68690,18 +68747,18 @@ ** inserted, there is no need to search to see if the same value was ** previously inserted as part of set X (only if it was previously ** inserted as part of some other set). */ case OP_RowSetTest: { /* jump, in1, in3 */ -#if 0 /* local variables moved into u.cb */ +#if 0 /* local variables moved into u.cc */ int iSet; int exists; -#endif /* local variables moved into u.cb */ +#endif /* local variables moved into u.cc */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; - u.cb.iSet = pOp->p4.i; + u.cc.iSet = pOp->p4.i; assert( pIn3->flags&MEM_Int ); /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ @@ -68709,21 +68766,21 @@ sqlite3VdbeMemSetRowSet(pIn1); if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; } assert( pOp->p4type==P4_INT32 ); - assert( u.cb.iSet==-1 || u.cb.iSet>=0 ); - if( u.cb.iSet ){ - u.cb.exists = sqlite3RowSetTest(pIn1->u.pRowSet, - (u8)(u.cb.iSet>=0 ? u.cb.iSet & 0xf : 0xff), + assert( u.cc.iSet==-1 || u.cc.iSet>=0 ); + if( u.cc.iSet ){ + u.cc.exists = sqlite3RowSetTest(pIn1->u.pRowSet, + (u8)(u.cc.iSet>=0 ? u.cc.iSet & 0xf : 0xff), pIn3->u.i); - if( u.cb.exists ){ + if( u.cc.exists ){ pc = pOp->p2 - 1; break; } } - if( u.cb.iSet>=0 ){ + if( u.cc.iSet>=0 ){ sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); } break; } @@ -68742,24 +68799,24 @@ ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. */ case OP_Program: { /* jump */ -#if 0 /* local variables moved into u.cc */ +#if 0 /* local variables moved into u.cd */ int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ VdbeFrame *pFrame; /* New vdbe frame to execute in */ SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ -#endif /* local variables moved into u.cc */ +#endif /* local variables moved into u.cd */ - u.cc.pProgram = pOp->p4.pProgram; - u.cc.pRt = &aMem[pOp->p3]; - assert( u.cc.pProgram->nOp>0 ); + u.cd.pProgram = pOp->p4.pProgram; + u.cd.pRt = &aMem[pOp->p3]; + assert( u.cd.pProgram->nOp>0 ); /* If the p5 flag is clear, then recursive invocation of triggers is ** disabled for backwards compatibility (p5 is set if this sub-program ** is really a trigger, not a foreign key action, and the flag set ** and cleared by the "PRAGMA recursive_triggers" command is clear). @@ -68769,84 +68826,84 @@ ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a ** single trigger all have the same value for the SubProgram.token ** variable. */ if( pOp->p5 ){ - u.cc.t = u.cc.pProgram->token; - for(u.cc.pFrame=p->pFrame; u.cc.pFrame && u.cc.pFrame->token!=u.cc.t; u.cc.pFrame=u.cc.pFrame->pParent); - if( u.cc.pFrame ) break; + u.cd.t = u.cd.pProgram->token; + for(u.cd.pFrame=p->pFrame; u.cd.pFrame && u.cd.pFrame->token!=u.cd.t; u.cd.pFrame=u.cd.pFrame->pParent); + if( u.cd.pFrame ) break; } if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "too many levels of trigger recursion"); break; } - /* Register u.cc.pRt is used to store the memory required to save the state + /* Register u.cd.pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute - ** the trigger program. If this trigger has been fired before, then u.cc.pRt + ** the trigger program. If this trigger has been fired before, then u.cd.pRt ** is already allocated. Otherwise, it must be initialized. */ - if( (u.cc.pRt->flags&MEM_Frame)==0 ){ + if( (u.cd.pRt->flags&MEM_Frame)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local - ** variable u.cc.nMem (and later, VdbeFrame.nChildMem) to this value. + ** variable u.cd.nMem (and later, VdbeFrame.nChildMem) to this value. */ - u.cc.nMem = u.cc.pProgram->nMem + u.cc.pProgram->nCsr; - u.cc.nByte = ROUND8(sizeof(VdbeFrame)) - + u.cc.nMem * sizeof(Mem) - + u.cc.pProgram->nCsr * sizeof(VdbeCursor *) - + u.cc.pProgram->nOnce * sizeof(u8); - u.cc.pFrame = sqlite3DbMallocZero(db, u.cc.nByte); - if( !u.cc.pFrame ){ + u.cd.nMem = u.cd.pProgram->nMem + u.cd.pProgram->nCsr; + u.cd.nByte = ROUND8(sizeof(VdbeFrame)) + + u.cd.nMem * sizeof(Mem) + + u.cd.pProgram->nCsr * sizeof(VdbeCursor *) + + u.cd.pProgram->nOnce * sizeof(u8); + u.cd.pFrame = sqlite3DbMallocZero(db, u.cd.nByte); + if( !u.cd.pFrame ){ goto no_mem; } - sqlite3VdbeMemRelease(u.cc.pRt); - u.cc.pRt->flags = MEM_Frame; - u.cc.pRt->u.pFrame = u.cc.pFrame; - - u.cc.pFrame->v = p; - u.cc.pFrame->nChildMem = u.cc.nMem; - u.cc.pFrame->nChildCsr = u.cc.pProgram->nCsr; - u.cc.pFrame->pc = pc; - u.cc.pFrame->aMem = p->aMem; - u.cc.pFrame->nMem = p->nMem; - u.cc.pFrame->apCsr = p->apCsr; - u.cc.pFrame->nCursor = p->nCursor; - u.cc.pFrame->aOp = p->aOp; - u.cc.pFrame->nOp = p->nOp; - u.cc.pFrame->token = u.cc.pProgram->token; - u.cc.pFrame->aOnceFlag = p->aOnceFlag; - u.cc.pFrame->nOnceFlag = p->nOnceFlag; - - u.cc.pEnd = &VdbeFrameMem(u.cc.pFrame)[u.cc.pFrame->nChildMem]; - for(u.cc.pMem=VdbeFrameMem(u.cc.pFrame); u.cc.pMem!=u.cc.pEnd; u.cc.pMem++){ - u.cc.pMem->flags = MEM_Invalid; - u.cc.pMem->db = db; - } - }else{ - u.cc.pFrame = u.cc.pRt->u.pFrame; - assert( u.cc.pProgram->nMem+u.cc.pProgram->nCsr==u.cc.pFrame->nChildMem ); - assert( u.cc.pProgram->nCsr==u.cc.pFrame->nChildCsr ); - assert( pc==u.cc.pFrame->pc ); + sqlite3VdbeMemRelease(u.cd.pRt); + u.cd.pRt->flags = MEM_Frame; + u.cd.pRt->u.pFrame = u.cd.pFrame; + + u.cd.pFrame->v = p; + u.cd.pFrame->nChildMem = u.cd.nMem; + u.cd.pFrame->nChildCsr = u.cd.pProgram->nCsr; + u.cd.pFrame->pc = pc; + u.cd.pFrame->aMem = p->aMem; + u.cd.pFrame->nMem = p->nMem; + u.cd.pFrame->apCsr = p->apCsr; + u.cd.pFrame->nCursor = p->nCursor; + u.cd.pFrame->aOp = p->aOp; + u.cd.pFrame->nOp = p->nOp; + u.cd.pFrame->token = u.cd.pProgram->token; + u.cd.pFrame->aOnceFlag = p->aOnceFlag; + u.cd.pFrame->nOnceFlag = p->nOnceFlag; + + u.cd.pEnd = &VdbeFrameMem(u.cd.pFrame)[u.cd.pFrame->nChildMem]; + for(u.cd.pMem=VdbeFrameMem(u.cd.pFrame); u.cd.pMem!=u.cd.pEnd; u.cd.pMem++){ + u.cd.pMem->flags = MEM_Invalid; + u.cd.pMem->db = db; + } + }else{ + u.cd.pFrame = u.cd.pRt->u.pFrame; + assert( u.cd.pProgram->nMem+u.cd.pProgram->nCsr==u.cd.pFrame->nChildMem ); + assert( u.cd.pProgram->nCsr==u.cd.pFrame->nChildCsr ); + assert( pc==u.cd.pFrame->pc ); } p->nFrame++; - u.cc.pFrame->pParent = p->pFrame; - u.cc.pFrame->lastRowid = lastRowid; - u.cc.pFrame->nChange = p->nChange; + u.cd.pFrame->pParent = p->pFrame; + u.cd.pFrame->lastRowid = lastRowid; + u.cd.pFrame->nChange = p->nChange; p->nChange = 0; - p->pFrame = u.cc.pFrame; - p->aMem = aMem = &VdbeFrameMem(u.cc.pFrame)[-1]; - p->nMem = u.cc.pFrame->nChildMem; - p->nCursor = (u16)u.cc.pFrame->nChildCsr; + p->pFrame = u.cd.pFrame; + p->aMem = aMem = &VdbeFrameMem(u.cd.pFrame)[-1]; + p->nMem = u.cd.pFrame->nChildMem; + p->nCursor = (u16)u.cd.pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; - p->aOp = aOp = u.cc.pProgram->aOp; - p->nOp = u.cc.pProgram->nOp; + p->aOp = aOp = u.cd.pProgram->aOp; + p->nOp = u.cd.pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; - p->nOnceFlag = u.cc.pProgram->nOnce; + p->nOnceFlag = u.cd.pProgram->nOnce; pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); break; } @@ -68862,17 +68919,17 @@ ** The address of the cell in the parent frame is determined by adding ** the value of the P1 argument to the value of the P1 argument to the ** calling OP_Program instruction. */ case OP_Param: { /* out2-prerelease */ -#if 0 /* local variables moved into u.cd */ +#if 0 /* local variables moved into u.ce */ VdbeFrame *pFrame; Mem *pIn; -#endif /* local variables moved into u.cd */ - u.cd.pFrame = p->pFrame; - u.cd.pIn = &u.cd.pFrame->aMem[pOp->p1 + u.cd.pFrame->aOp[u.cd.pFrame->pc].p1]; - sqlite3VdbeMemShallowCopy(pOut, u.cd.pIn, MEM_Ephem); +#endif /* local variables moved into u.ce */ + u.ce.pFrame = p->pFrame; + u.ce.pIn = &u.ce.pFrame->aMem[pOp->p1 + u.ce.pFrame->aOp[u.ce.pFrame->pc].p1]; + sqlite3VdbeMemShallowCopy(pOut, u.ce.pIn, MEM_Ephem); break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ @@ -68924,26 +68981,26 @@ ** ** This instruction throws an error if the memory cell is not initially ** an integer. */ case OP_MemMax: { /* in2 */ -#if 0 /* local variables moved into u.ce */ +#if 0 /* local variables moved into u.cf */ Mem *pIn1; VdbeFrame *pFrame; -#endif /* local variables moved into u.ce */ +#endif /* local variables moved into u.cf */ if( p->pFrame ){ - for(u.ce.pFrame=p->pFrame; u.ce.pFrame->pParent; u.ce.pFrame=u.ce.pFrame->pParent); - u.ce.pIn1 = &u.ce.pFrame->aMem[pOp->p1]; + for(u.cf.pFrame=p->pFrame; u.cf.pFrame->pParent; u.cf.pFrame=u.cf.pFrame->pParent); + u.cf.pIn1 = &u.cf.pFrame->aMem[pOp->p1]; }else{ - u.ce.pIn1 = &aMem[pOp->p1]; + u.cf.pIn1 = &aMem[pOp->p1]; } - assert( memIsValid(u.ce.pIn1) ); - sqlite3VdbeMemIntegerify(u.ce.pIn1); + assert( memIsValid(u.cf.pIn1) ); + sqlite3VdbeMemIntegerify(u.cf.pIn1); pIn2 = &aMem[pOp->p2]; sqlite3VdbeMemIntegerify(pIn2); - if( u.ce.pIn1->u.i<pIn2->u.i){ - u.ce.pIn1->u.i = pIn2->u.i; + if( u.cf.pIn1->u.i<pIn2->u.i){ + u.cf.pIn1->u.i = pIn2->u.i; } break; } #endif /* SQLITE_OMIT_AUTOINCREMENT */ @@ -69006,60 +69063,60 @@ ** ** The P5 arguments are taken from register P2 and its ** successors. */ case OP_AggStep: { -#if 0 /* local variables moved into u.cf */ +#if 0 /* local variables moved into u.cg */ int n; int i; Mem *pMem; Mem *pRec; sqlite3_context ctx; sqlite3_value **apVal; -#endif /* local variables moved into u.cf */ +#endif /* local variables moved into u.cg */ - u.cf.n = pOp->p5; - assert( u.cf.n>=0 ); - u.cf.pRec = &aMem[pOp->p2]; - u.cf.apVal = p->apArg; - assert( u.cf.apVal || u.cf.n==0 ); - for(u.cf.i=0; u.cf.i<u.cf.n; u.cf.i++, u.cf.pRec++){ - assert( memIsValid(u.cf.pRec) ); - u.cf.apVal[u.cf.i] = u.cf.pRec; - memAboutToChange(p, u.cf.pRec); - sqlite3VdbeMemStoreType(u.cf.pRec); + u.cg.n = pOp->p5; + assert( u.cg.n>=0 ); + u.cg.pRec = &aMem[pOp->p2]; + u.cg.apVal = p->apArg; + assert( u.cg.apVal || u.cg.n==0 ); + for(u.cg.i=0; u.cg.i<u.cg.n; u.cg.i++, u.cg.pRec++){ + assert( memIsValid(u.cg.pRec) ); + u.cg.apVal[u.cg.i] = u.cg.pRec; + memAboutToChange(p, u.cg.pRec); + sqlite3VdbeMemStoreType(u.cg.pRec); } - u.cf.ctx.pFunc = pOp->p4.pFunc; + u.cg.ctx.pFunc = pOp->p4.pFunc; assert( pOp->p3>0 && pOp->p3<=p->nMem ); - u.cf.ctx.pMem = u.cf.pMem = &aMem[pOp->p3]; - u.cf.pMem->n++; - u.cf.ctx.s.flags = MEM_Null; - u.cf.ctx.s.z = 0; - u.cf.ctx.s.zMalloc = 0; - u.cf.ctx.s.xDel = 0; - u.cf.ctx.s.db = db; - u.cf.ctx.isError = 0; - u.cf.ctx.pColl = 0; - u.cf.ctx.skipFlag = 0; - if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ + u.cg.ctx.pMem = u.cg.pMem = &aMem[pOp->p3]; + u.cg.pMem->n++; + u.cg.ctx.s.flags = MEM_Null; + u.cg.ctx.s.z = 0; + u.cg.ctx.s.zMalloc = 0; + u.cg.ctx.s.xDel = 0; + u.cg.ctx.s.db = db; + u.cg.ctx.isError = 0; + u.cg.ctx.pColl = 0; + u.cg.ctx.skipFlag = 0; + if( u.cg.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ assert( pOp>p->aOp ); assert( pOp[-1].p4type==P4_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); - u.cf.ctx.pColl = pOp[-1].p4.pColl; + u.cg.ctx.pColl = pOp[-1].p4.pColl; } - (u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */ - if( u.cf.ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s)); - rc = u.cf.ctx.isError; + (u.cg.ctx.pFunc->xStep)(&u.cg.ctx, u.cg.n, u.cg.apVal); /* IMP: R-24505-23230 */ + if( u.cg.ctx.isError ){ + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cg.ctx.s)); + rc = u.cg.ctx.isError; } - if( u.cf.ctx.skipFlag ){ + if( u.cg.ctx.skipFlag ){ assert( pOp[-1].opcode==OP_CollSeq ); - u.cf.i = pOp[-1].p1; - if( u.cf.i ) sqlite3VdbeMemSetInt64(&aMem[u.cf.i], 1); + u.cg.i = pOp[-1].p1; + if( u.cg.i ) sqlite3VdbeMemSetInt64(&aMem[u.cg.i], 1); } - sqlite3VdbeMemRelease(&u.cf.ctx.s); + sqlite3VdbeMemRelease(&u.cg.ctx.s); break; } /* Opcode: AggFinal P1 P2 * P4 * @@ -69073,23 +69130,23 @@ ** functions that can take varying numbers of arguments. The ** P4 argument is only needed for the degenerate case where ** the step function was not previously called. */ case OP_AggFinal: { -#if 0 /* local variables moved into u.cg */ +#if 0 /* local variables moved into u.ch */ Mem *pMem; -#endif /* local variables moved into u.cg */ +#endif /* local variables moved into u.ch */ assert( pOp->p1>0 && pOp->p1<=p->nMem ); - u.cg.pMem = &aMem[pOp->p1]; - assert( (u.cg.pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); - rc = sqlite3VdbeMemFinalize(u.cg.pMem, pOp->p4.pFunc); + u.ch.pMem = &aMem[pOp->p1]; + assert( (u.ch.pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); + rc = sqlite3VdbeMemFinalize(u.ch.pMem, pOp->p4.pFunc); if( rc ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.cg.pMem)); + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.ch.pMem)); } - sqlite3VdbeChangeEncoding(u.cg.pMem, encoding); - UPDATE_MAX_BLOBSIZE(u.cg.pMem); - if( sqlite3VdbeMemTooBig(u.cg.pMem) ){ + sqlite3VdbeChangeEncoding(u.ch.pMem, encoding); + UPDATE_MAX_BLOBSIZE(u.ch.pMem); + if( sqlite3VdbeMemTooBig(u.ch.pMem) ){ goto too_big; } break; } @@ -69104,29 +69161,29 @@ ** in the WAL that have been checkpointed after the checkpoint ** completes into mem[P3+2]. However on an error, mem[P3+1] and ** mem[P3+2] are initialized to -1. */ case OP_Checkpoint: { -#if 0 /* local variables moved into u.ch */ +#if 0 /* local variables moved into u.ci */ int i; /* Loop counter */ int aRes[3]; /* Results */ Mem *pMem; /* Write results here */ -#endif /* local variables moved into u.ch */ +#endif /* local variables moved into u.ci */ - u.ch.aRes[0] = 0; - u.ch.aRes[1] = u.ch.aRes[2] = -1; + u.ci.aRes[0] = 0; + u.ci.aRes[1] = u.ci.aRes[2] = -1; assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE || pOp->p2==SQLITE_CHECKPOINT_FULL || pOp->p2==SQLITE_CHECKPOINT_RESTART ); - rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.ch.aRes[1], &u.ch.aRes[2]); + rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.ci.aRes[1], &u.ci.aRes[2]); if( rc==SQLITE_BUSY ){ rc = SQLITE_OK; - u.ch.aRes[0] = 1; + u.ci.aRes[0] = 1; } - for(u.ch.i=0, u.ch.pMem = &aMem[pOp->p3]; u.ch.i<3; u.ch.i++, u.ch.pMem++){ - sqlite3VdbeMemSetInt64(u.ch.pMem, (i64)u.ch.aRes[u.ch.i]); + for(u.ci.i=0, u.ci.pMem = &aMem[pOp->p3]; u.ci.i<3; u.ci.i++, u.ci.pMem++){ + sqlite3VdbeMemSetInt64(u.ci.pMem, (i64)u.ci.aRes[u.ci.i]); } break; }; #endif @@ -69141,97 +69198,97 @@ ** If changing into or out of WAL mode the procedure is more complicated. ** ** Write a string containing the final journal-mode to register P2. */ case OP_JournalMode: { /* out2-prerelease */ -#if 0 /* local variables moved into u.ci */ +#if 0 /* local variables moved into u.cj */ Btree *pBt; /* Btree to change journal mode of */ Pager *pPager; /* Pager associated with pBt */ int eNew; /* New journal mode */ int eOld; /* The old journal mode */ -#endif /* local variables moved into u.ci */ #ifndef SQLITE_OMIT_WAL - const char *zFilename; /* Name of database file for u.ci.pPager */ + const char *zFilename; /* Name of database file for pPager */ #endif +#endif /* local variables moved into u.cj */ - u.ci.eNew = pOp->p3; - assert( u.ci.eNew==PAGER_JOURNALMODE_DELETE - || u.ci.eNew==PAGER_JOURNALMODE_TRUNCATE - || u.ci.eNew==PAGER_JOURNALMODE_PERSIST - || u.ci.eNew==PAGER_JOURNALMODE_OFF - || u.ci.eNew==PAGER_JOURNALMODE_MEMORY - || u.ci.eNew==PAGER_JOURNALMODE_WAL - || u.ci.eNew==PAGER_JOURNALMODE_QUERY + u.cj.eNew = pOp->p3; + assert( u.cj.eNew==PAGER_JOURNALMODE_DELETE + || u.cj.eNew==PAGER_JOURNALMODE_TRUNCATE + || u.cj.eNew==PAGER_JOURNALMODE_PERSIST + || u.cj.eNew==PAGER_JOURNALMODE_OFF + || u.cj.eNew==PAGER_JOURNALMODE_MEMORY + || u.cj.eNew==PAGER_JOURNALMODE_WAL + || u.cj.eNew==PAGER_JOURNALMODE_QUERY ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); - u.ci.pBt = db->aDb[pOp->p1].pBt; - u.ci.pPager = sqlite3BtreePager(u.ci.pBt); - u.ci.eOld = sqlite3PagerGetJournalMode(u.ci.pPager); - if( u.ci.eNew==PAGER_JOURNALMODE_QUERY ) u.ci.eNew = u.ci.eOld; - if( !sqlite3PagerOkToChangeJournalMode(u.ci.pPager) ) u.ci.eNew = u.ci.eOld; + u.cj.pBt = db->aDb[pOp->p1].pBt; + u.cj.pPager = sqlite3BtreePager(u.cj.pBt); + u.cj.eOld = sqlite3PagerGetJournalMode(u.cj.pPager); + if( u.cj.eNew==PAGER_JOURNALMODE_QUERY ) u.cj.eNew = u.cj.eOld; + if( !sqlite3PagerOkToChangeJournalMode(u.cj.pPager) ) u.cj.eNew = u.cj.eOld; #ifndef SQLITE_OMIT_WAL - zFilename = sqlite3PagerFilename(u.ci.pPager, 1); + u.cj.zFilename = sqlite3PagerFilename(u.cj.pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support shared memory */ - if( u.ci.eNew==PAGER_JOURNALMODE_WAL - && (sqlite3Strlen30(zFilename)==0 /* Temp file */ - || !sqlite3PagerWalSupported(u.ci.pPager)) /* No shared-memory support */ + if( u.cj.eNew==PAGER_JOURNALMODE_WAL + && (sqlite3Strlen30(u.cj.zFilename)==0 /* Temp file */ + || !sqlite3PagerWalSupported(u.cj.pPager)) /* No shared-memory support */ ){ - u.ci.eNew = u.ci.eOld; + u.cj.eNew = u.cj.eOld; } - if( (u.ci.eNew!=u.ci.eOld) - && (u.ci.eOld==PAGER_JOURNALMODE_WAL || u.ci.eNew==PAGER_JOURNALMODE_WAL) + if( (u.cj.eNew!=u.cj.eOld) + && (u.cj.eOld==PAGER_JOURNALMODE_WAL || u.cj.eNew==PAGER_JOURNALMODE_WAL) ){ if( !db->autoCommit || db->activeVdbeCnt>1 ){ rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "cannot change %s wal mode from within a transaction", - (u.ci.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") + (u.cj.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") ); break; }else{ - if( u.ci.eOld==PAGER_JOURNALMODE_WAL ){ + if( u.cj.eOld==PAGER_JOURNALMODE_WAL ){ /* If leaving WAL mode, close the log file. If successful, the call ** to PagerCloseWal() checkpoints and deletes the write-ahead-log ** file. An EXCLUSIVE lock may still be held on the database file ** after a successful return. */ - rc = sqlite3PagerCloseWal(u.ci.pPager); + rc = sqlite3PagerCloseWal(u.cj.pPager); if( rc==SQLITE_OK ){ - sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew); + sqlite3PagerSetJournalMode(u.cj.pPager, u.cj.eNew); } - }else if( u.ci.eOld==PAGER_JOURNALMODE_MEMORY ){ + }else if( u.cj.eOld==PAGER_JOURNALMODE_MEMORY ){ /* Cannot transition directly from MEMORY to WAL. Use mode OFF ** as an intermediate */ - sqlite3PagerSetJournalMode(u.ci.pPager, PAGER_JOURNALMODE_OFF); + sqlite3PagerSetJournalMode(u.cj.pPager, PAGER_JOURNALMODE_OFF); } /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ - assert( sqlite3BtreeIsInTrans(u.ci.pBt)==0 ); + assert( sqlite3BtreeIsInTrans(u.cj.pBt)==0 ); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeSetVersion(u.ci.pBt, (u.ci.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); + rc = sqlite3BtreeSetVersion(u.cj.pBt, (u.cj.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } } } #endif /* ifndef SQLITE_OMIT_WAL */ if( rc ){ - u.ci.eNew = u.ci.eOld; + u.cj.eNew = u.cj.eOld; } - u.ci.eNew = sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew); + u.cj.eNew = sqlite3PagerSetJournalMode(u.cj.pPager, u.cj.eNew); pOut = &aMem[pOp->p2]; pOut->flags = MEM_Str|MEM_Static|MEM_Term; - pOut->z = (char *)sqlite3JournalModename(u.ci.eNew); + pOut->z = (char *)sqlite3JournalModename(u.cj.eNew); pOut->n = sqlite3Strlen30(pOut->z); pOut->enc = SQLITE_UTF8; sqlite3VdbeChangeEncoding(pOut, encoding); break; }; @@ -69256,18 +69313,18 @@ ** Perform a single step of the incremental vacuum procedure on ** the P1 database. If the vacuum has finished, jump to instruction ** P2. Otherwise, fall through to the next instruction. */ case OP_IncrVacuum: { /* jump */ -#if 0 /* local variables moved into u.cj */ +#if 0 /* local variables moved into u.ck */ Btree *pBt; -#endif /* local variables moved into u.cj */ +#endif /* local variables moved into u.ck */ assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); - u.cj.pBt = db->aDb[pOp->p1].pBt; - rc = sqlite3BtreeIncrVacuum(u.cj.pBt); + u.ck.pBt = db->aDb[pOp->p1].pBt; + rc = sqlite3BtreeIncrVacuum(u.ck.pBt); if( rc==SQLITE_DONE ){ pc = pOp->p2 - 1; rc = SQLITE_OK; } break; @@ -69333,16 +69390,16 @@ ** Also, whether or not P4 is set, check that this is not being called from ** within a callback to a virtual table xSync() method. If it is, the error ** code will be set to SQLITE_LOCKED. */ case OP_VBegin: { -#if 0 /* local variables moved into u.ck */ +#if 0 /* local variables moved into u.cl */ VTable *pVTab; -#endif /* local variables moved into u.ck */ - u.ck.pVTab = pOp->p4.pVtab; - rc = sqlite3VtabBegin(db, u.ck.pVTab); - if( u.ck.pVTab ) importVtabErrMsg(p, u.ck.pVTab->pVtab); +#endif /* local variables moved into u.cl */ + u.cl.pVTab = pOp->p4.pVtab; + rc = sqlite3VtabBegin(db, u.cl.pVTab); + if( u.cl.pVTab ) importVtabErrMsg(p, u.cl.pVTab->pVtab); break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -69377,36 +69434,36 @@ ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ case OP_VOpen: { -#if 0 /* local variables moved into u.cl */ +#if 0 /* local variables moved into u.cm */ VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; sqlite3_module *pModule; -#endif /* local variables moved into u.cl */ +#endif /* local variables moved into u.cm */ - u.cl.pCur = 0; - u.cl.pVtabCursor = 0; - u.cl.pVtab = pOp->p4.pVtab->pVtab; - u.cl.pModule = (sqlite3_module *)u.cl.pVtab->pModule; - assert(u.cl.pVtab && u.cl.pModule); - rc = u.cl.pModule->xOpen(u.cl.pVtab, &u.cl.pVtabCursor); - importVtabErrMsg(p, u.cl.pVtab); + u.cm.pCur = 0; + u.cm.pVtabCursor = 0; + u.cm.pVtab = pOp->p4.pVtab->pVtab; + u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule; + assert(u.cm.pVtab && u.cm.pModule); + rc = u.cm.pModule->xOpen(u.cm.pVtab, &u.cm.pVtabCursor); + importVtabErrMsg(p, u.cm.pVtab); if( SQLITE_OK==rc ){ /* Initialize sqlite3_vtab_cursor base class */ - u.cl.pVtabCursor->pVtab = u.cl.pVtab; + u.cm.pVtabCursor->pVtab = u.cm.pVtab; /* Initialise vdbe cursor object */ - u.cl.pCur = allocateCursor(p, pOp->p1, 0, -1, 0); - if( u.cl.pCur ){ - u.cl.pCur->pVtabCursor = u.cl.pVtabCursor; - u.cl.pCur->pModule = u.cl.pVtabCursor->pVtab->pModule; + u.cm.pCur = allocateCursor(p, pOp->p1, 0, -1, 0); + if( u.cm.pCur ){ + u.cm.pCur->pVtabCursor = u.cm.pVtabCursor; + u.cm.pCur->pModule = u.cm.pVtabCursor->pVtab->pModule; }else{ db->mallocFailed = 1; - u.cl.pModule->xClose(u.cl.pVtabCursor); + u.cm.pModule->xClose(u.cm.pVtabCursor); } } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -69429,11 +69486,11 @@ ** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter. ** ** A jump is made to P2 if the result set after filtering would be empty. */ case OP_VFilter: { /* jump */ -#if 0 /* local variables moved into u.cm */ +#if 0 /* local variables moved into u.cn */ int nArg; int iQuery; const sqlite3_module *pModule; Mem *pQuery; Mem *pArgc; @@ -69441,49 +69498,49 @@ sqlite3_vtab *pVtab; VdbeCursor *pCur; int res; int i; Mem **apArg; -#endif /* local variables moved into u.cm */ +#endif /* local variables moved into u.cn */ - u.cm.pQuery = &aMem[pOp->p3]; - u.cm.pArgc = &u.cm.pQuery[1]; - u.cm.pCur = p->apCsr[pOp->p1]; - assert( memIsValid(u.cm.pQuery) ); - REGISTER_TRACE(pOp->p3, u.cm.pQuery); - assert( u.cm.pCur->pVtabCursor ); - u.cm.pVtabCursor = u.cm.pCur->pVtabCursor; - u.cm.pVtab = u.cm.pVtabCursor->pVtab; - u.cm.pModule = u.cm.pVtab->pModule; + u.cn.pQuery = &aMem[pOp->p3]; + u.cn.pArgc = &u.cn.pQuery[1]; + u.cn.pCur = p->apCsr[pOp->p1]; + assert( memIsValid(u.cn.pQuery) ); + REGISTER_TRACE(pOp->p3, u.cn.pQuery); + assert( u.cn.pCur->pVtabCursor ); + u.cn.pVtabCursor = u.cn.pCur->pVtabCursor; + u.cn.pVtab = u.cn.pVtabCursor->pVtab; + u.cn.pModule = u.cn.pVtab->pModule; /* Grab the index number and argc parameters */ - assert( (u.cm.pQuery->flags&MEM_Int)!=0 && u.cm.pArgc->flags==MEM_Int ); - u.cm.nArg = (int)u.cm.pArgc->u.i; - u.cm.iQuery = (int)u.cm.pQuery->u.i; + assert( (u.cn.pQuery->flags&MEM_Int)!=0 && u.cn.pArgc->flags==MEM_Int ); + u.cn.nArg = (int)u.cn.pArgc->u.i; + u.cn.iQuery = (int)u.cn.pQuery->u.i; /* Invoke the xFilter method */ { - u.cm.res = 0; - u.cm.apArg = p->apArg; - for(u.cm.i = 0; u.cm.i<u.cm.nArg; u.cm.i++){ - u.cm.apArg[u.cm.i] = &u.cm.pArgc[u.cm.i+1]; - sqlite3VdbeMemStoreType(u.cm.apArg[u.cm.i]); + u.cn.res = 0; + u.cn.apArg = p->apArg; + for(u.cn.i = 0; u.cn.i<u.cn.nArg; u.cn.i++){ + u.cn.apArg[u.cn.i] = &u.cn.pArgc[u.cn.i+1]; + sqlite3VdbeMemStoreType(u.cn.apArg[u.cn.i]); } p->inVtabMethod = 1; - rc = u.cm.pModule->xFilter(u.cm.pVtabCursor, u.cm.iQuery, pOp->p4.z, u.cm.nArg, u.cm.apArg); + rc = u.cn.pModule->xFilter(u.cn.pVtabCursor, u.cn.iQuery, pOp->p4.z, u.cn.nArg, u.cn.apArg); p->inVtabMethod = 0; - importVtabErrMsg(p, u.cm.pVtab); + importVtabErrMsg(p, u.cn.pVtab); if( rc==SQLITE_OK ){ - u.cm.res = u.cm.pModule->xEof(u.cm.pVtabCursor); + u.cn.res = u.cn.pModule->xEof(u.cn.pVtabCursor); } - if( u.cm.res ){ + if( u.cn.res ){ pc = pOp->p2 - 1; } } - u.cm.pCur->nullRow = 0; + u.cn.pCur->nullRow = 0; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -69493,55 +69550,55 @@ ** Store the value of the P2-th column of ** the row of the virtual-table that the ** P1 cursor is pointing to into register P3. */ case OP_VColumn: { -#if 0 /* local variables moved into u.cn */ +#if 0 /* local variables moved into u.co */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; -#endif /* local variables moved into u.cn */ +#endif /* local variables moved into u.co */ VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); - u.cn.pDest = &aMem[pOp->p3]; - memAboutToChange(p, u.cn.pDest); + u.co.pDest = &aMem[pOp->p3]; + memAboutToChange(p, u.co.pDest); if( pCur->nullRow ){ - sqlite3VdbeMemSetNull(u.cn.pDest); + sqlite3VdbeMemSetNull(u.co.pDest); break; } - u.cn.pVtab = pCur->pVtabCursor->pVtab; - u.cn.pModule = u.cn.pVtab->pModule; - assert( u.cn.pModule->xColumn ); - memset(&u.cn.sContext, 0, sizeof(u.cn.sContext)); + u.co.pVtab = pCur->pVtabCursor->pVtab; + u.co.pModule = u.co.pVtab->pModule; + assert( u.co.pModule->xColumn ); + memset(&u.co.sContext, 0, sizeof(u.co.sContext)); /* The output cell may already have a buffer allocated. Move - ** the current contents to u.cn.sContext.s so in case the user-function + ** the current contents to u.co.sContext.s so in case the user-function ** can use the already allocated buffer instead of allocating a ** new one. */ - sqlite3VdbeMemMove(&u.cn.sContext.s, u.cn.pDest); - MemSetTypeFlag(&u.cn.sContext.s, MEM_Null); + sqlite3VdbeMemMove(&u.co.sContext.s, u.co.pDest); + MemSetTypeFlag(&u.co.sContext.s, MEM_Null); - rc = u.cn.pModule->xColumn(pCur->pVtabCursor, &u.cn.sContext, pOp->p2); - importVtabErrMsg(p, u.cn.pVtab); - if( u.cn.sContext.isError ){ - rc = u.cn.sContext.isError; + rc = u.co.pModule->xColumn(pCur->pVtabCursor, &u.co.sContext, pOp->p2); + importVtabErrMsg(p, u.co.pVtab); + if( u.co.sContext.isError ){ + rc = u.co.sContext.isError; } /* Copy the result of the function to the P3 register. We ** do this regardless of whether or not an error occurred to ensure any - ** dynamic allocation in u.cn.sContext.s (a Mem struct) is released. + ** dynamic allocation in u.co.sContext.s (a Mem struct) is released. */ - sqlite3VdbeChangeEncoding(&u.cn.sContext.s, encoding); - sqlite3VdbeMemMove(u.cn.pDest, &u.cn.sContext.s); - REGISTER_TRACE(pOp->p3, u.cn.pDest); - UPDATE_MAX_BLOBSIZE(u.cn.pDest); + sqlite3VdbeChangeEncoding(&u.co.sContext.s, encoding); + sqlite3VdbeMemMove(u.co.pDest, &u.co.sContext.s); + REGISTER_TRACE(pOp->p3, u.co.pDest); + UPDATE_MAX_BLOBSIZE(u.co.pDest); - if( sqlite3VdbeMemTooBig(u.cn.pDest) ){ + if( sqlite3VdbeMemTooBig(u.co.pDest) ){ goto too_big; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -69552,42 +69609,42 @@ ** Advance virtual table P1 to the next row in its result set and ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ case OP_VNext: { /* jump */ -#if 0 /* local variables moved into u.co */ +#if 0 /* local variables moved into u.cp */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; -#endif /* local variables moved into u.co */ +#endif /* local variables moved into u.cp */ - u.co.res = 0; - u.co.pCur = p->apCsr[pOp->p1]; - assert( u.co.pCur->pVtabCursor ); - if( u.co.pCur->nullRow ){ + u.cp.res = 0; + u.cp.pCur = p->apCsr[pOp->p1]; + assert( u.cp.pCur->pVtabCursor ); + if( u.cp.pCur->nullRow ){ break; } - u.co.pVtab = u.co.pCur->pVtabCursor->pVtab; - u.co.pModule = u.co.pVtab->pModule; - assert( u.co.pModule->xNext ); + u.cp.pVtab = u.cp.pCur->pVtabCursor->pVtab; + u.cp.pModule = u.cp.pVtab->pModule; + assert( u.cp.pModule->xNext ); /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ p->inVtabMethod = 1; - rc = u.co.pModule->xNext(u.co.pCur->pVtabCursor); + rc = u.cp.pModule->xNext(u.cp.pCur->pVtabCursor); p->inVtabMethod = 0; - importVtabErrMsg(p, u.co.pVtab); + importVtabErrMsg(p, u.cp.pVtab); if( rc==SQLITE_OK ){ - u.co.res = u.co.pModule->xEof(u.co.pCur->pVtabCursor); + u.cp.res = u.cp.pModule->xEof(u.cp.pCur->pVtabCursor); } - if( !u.co.res ){ + if( !u.cp.res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; } break; } @@ -69599,28 +69656,28 @@ ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { -#if 0 /* local variables moved into u.cp */ +#if 0 /* local variables moved into u.cq */ sqlite3_vtab *pVtab; Mem *pName; -#endif /* local variables moved into u.cp */ +#endif /* local variables moved into u.cq */ - u.cp.pVtab = pOp->p4.pVtab->pVtab; - u.cp.pName = &aMem[pOp->p1]; - assert( u.cp.pVtab->pModule->xRename ); - assert( memIsValid(u.cp.pName) ); - REGISTER_TRACE(pOp->p1, u.cp.pName); - assert( u.cp.pName->flags & MEM_Str ); - testcase( u.cp.pName->enc==SQLITE_UTF8 ); - testcase( u.cp.pName->enc==SQLITE_UTF16BE ); - testcase( u.cp.pName->enc==SQLITE_UTF16LE ); - rc = sqlite3VdbeChangeEncoding(u.cp.pName, SQLITE_UTF8); + u.cq.pVtab = pOp->p4.pVtab->pVtab; + u.cq.pName = &aMem[pOp->p1]; + assert( u.cq.pVtab->pModule->xRename ); + assert( memIsValid(u.cq.pName) ); + REGISTER_TRACE(pOp->p1, u.cq.pName); + assert( u.cq.pName->flags & MEM_Str ); + testcase( u.cq.pName->enc==SQLITE_UTF8 ); + testcase( u.cq.pName->enc==SQLITE_UTF16BE ); + testcase( u.cq.pName->enc==SQLITE_UTF16LE ); + rc = sqlite3VdbeChangeEncoding(u.cq.pName, SQLITE_UTF8); if( rc==SQLITE_OK ){ - rc = u.cp.pVtab->pModule->xRename(u.cp.pVtab, u.cp.pName->z); - importVtabErrMsg(p, u.cp.pVtab); + rc = u.cq.pVtab->pModule->xRename(u.cq.pVtab, u.cq.pName->z); + importVtabErrMsg(p, u.cq.pVtab); p->expired = 0; } break; } #endif @@ -69648,45 +69705,45 @@ ** P1 is a boolean flag. If it is set to true and the xUpdate call ** is successful, then the value returned by sqlite3_last_insert_rowid() ** is set to the value of the rowid for the row just inserted. */ case OP_VUpdate: { -#if 0 /* local variables moved into u.cq */ +#if 0 /* local variables moved into u.cr */ sqlite3_vtab *pVtab; sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; Mem **apArg; Mem *pX; -#endif /* local variables moved into u.cq */ +#endif /* local variables moved into u.cr */ assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); - u.cq.pVtab = pOp->p4.pVtab->pVtab; - u.cq.pModule = (sqlite3_module *)u.cq.pVtab->pModule; - u.cq.nArg = pOp->p2; + u.cr.pVtab = pOp->p4.pVtab->pVtab; + u.cr.pModule = (sqlite3_module *)u.cr.pVtab->pModule; + u.cr.nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); - if( ALWAYS(u.cq.pModule->xUpdate) ){ + if( ALWAYS(u.cr.pModule->xUpdate) ){ u8 vtabOnConflict = db->vtabOnConflict; - u.cq.apArg = p->apArg; - u.cq.pX = &aMem[pOp->p3]; - for(u.cq.i=0; u.cq.i<u.cq.nArg; u.cq.i++){ - assert( memIsValid(u.cq.pX) ); - memAboutToChange(p, u.cq.pX); - sqlite3VdbeMemStoreType(u.cq.pX); - u.cq.apArg[u.cq.i] = u.cq.pX; - u.cq.pX++; + u.cr.apArg = p->apArg; + u.cr.pX = &aMem[pOp->p3]; + for(u.cr.i=0; u.cr.i<u.cr.nArg; u.cr.i++){ + assert( memIsValid(u.cr.pX) ); + memAboutToChange(p, u.cr.pX); + sqlite3VdbeMemStoreType(u.cr.pX); + u.cr.apArg[u.cr.i] = u.cr.pX; + u.cr.pX++; } db->vtabOnConflict = pOp->p5; - rc = u.cq.pModule->xUpdate(u.cq.pVtab, u.cq.nArg, u.cq.apArg, &u.cq.rowid); + rc = u.cr.pModule->xUpdate(u.cr.pVtab, u.cr.nArg, u.cr.apArg, &u.cr.rowid); db->vtabOnConflict = vtabOnConflict; - importVtabErrMsg(p, u.cq.pVtab); + importVtabErrMsg(p, u.cr.pVtab); if( rc==SQLITE_OK && pOp->p1 ){ - assert( u.cq.nArg>1 && u.cq.apArg[0] && (u.cq.apArg[0]->flags&MEM_Null) ); - db->lastRowid = lastRowid = u.cq.rowid; + assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) ); + db->lastRowid = lastRowid = u.cr.rowid; } if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ if( pOp->p5==OE_Ignore ){ rc = SQLITE_OK; }else{ @@ -69742,28 +69799,28 @@ ** ** If tracing is enabled (by the sqlite3_trace()) interface, then ** the UTF-8 string contained in P4 is emitted on the trace callback. */ case OP_Trace: { -#if 0 /* local variables moved into u.cr */ +#if 0 /* local variables moved into u.cs */ char *zTrace; char *z; -#endif /* local variables moved into u.cr */ +#endif /* local variables moved into u.cs */ if( db->xTrace && !p->doingRerun - && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 + && (u.cs.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ - u.cr.z = sqlite3VdbeExpandSql(p, u.cr.zTrace); - db->xTrace(db->pTraceArg, u.cr.z); - sqlite3DbFree(db, u.cr.z); + u.cs.z = sqlite3VdbeExpandSql(p, u.cs.zTrace); + db->xTrace(db->pTraceArg, u.cs.z); + sqlite3DbFree(db, u.cs.z); } #ifdef SQLITE_DEBUG if( (db->flags & SQLITE_SqlTrace)!=0 - && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 + && (u.cs.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ - sqlite3DebugPrintf("SQL-trace: %s\n", u.cr.zTrace); + sqlite3DebugPrintf("SQL-trace: %s\n", u.cs.zTrace); } #endif /* SQLITE_DEBUG */ break; } #endif @@ -74733,27 +74790,36 @@ return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); } /* ** This function is used by the implementation of the IN (...) operator. -** It's job is to find or create a b-tree structure that may be used -** either to test for membership of the (...) set or to iterate through -** its members, skipping duplicates. +** The pX parameter is the expression on the RHS of the IN operator, which +** might be either a list of expressions or a subquery. ** -** The index of the cursor opened on the b-tree (database table, database index -** or ephermal table) is stored in pX->iTable before this function returns. +** The job of this routine is to find or create a b-tree object that can +** be used either to test for membership in the RHS set or to iterate through +** all members of the RHS set, skipping duplicates. +** +** A cursor is opened on the b-tree object that the RHS of the IN operator +** and pX->iTable is set to the index of that cursor. +** ** The returned value of this function indicates the b-tree type, as follows: ** ** IN_INDEX_ROWID - The cursor was opened on a database table. ** IN_INDEX_INDEX - The cursor was opened on a database index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. ** -** An existing b-tree may only be used if the SELECT is of the simple -** form: +** An existing b-tree might be used if the RHS expression pX is a simple +** subquery such as: ** ** SELECT <column> FROM <table> +** +** If the RHS of the IN operator is a list or a more complex subquery, then +** an ephemeral table might need to be generated from the RHS and then +** pX->iTable made to point to the ephermeral table instead of an +** existing table. ** ** If the prNotFound parameter is 0, then the b-tree will be used to iterate ** through the set members, skipping any duplicates. In this case an ** epheremal table must be used unless the selected <column> is guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or it @@ -74846,12 +74912,11 @@ /* Check that the affinity that will be used to perform the ** comparison is the same as the affinity of the column. If ** it is not, it is not possible to use any index. */ - char aff = comparisonAffinity(pX); - int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE); + int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity); for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None)) @@ -75371,11 +75436,11 @@ /* The SQLITE_ColumnCache flag disables the column cache. This is used ** for testing only - to verify that SQLite always gets the same answer ** with and without the column cache. */ - if( pParse->db->flags & SQLITE_ColumnCache ) return; + if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return; /* First replace any existing entry. ** ** Actually, the way the column cache is currently used, we are guaranteed ** that the object will never already be in cache. Verify this guarantee. @@ -75568,32 +75633,20 @@ ** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ int i; struct yColCache *p; - if( NEVER(iFrom==iTo) ) return; - sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); + assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1); for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ int x = p->iReg; if( x>=iFrom && x<iFrom+nReg ){ p->iReg += iTo-iFrom; } } } -/* -** Generate code to copy content from registers iFrom...iFrom+nReg-1 -** over to iTo..iTo+nReg-1. -*/ -SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){ - int i; - if( NEVER(iFrom==iTo) ) return; - for(i=0; i<nReg; i++){ - sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i); - } -} - #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* ** Return true if any register in the range iFrom..iTo (inclusive) ** is used as part of the column cache. ** @@ -76699,11 +76752,11 @@ ** precomputed into registers or if they are inserted in-line. */ SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; - if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return; + if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return; w.xExprCallback = evalConstExpr; w.xSelectCallback = 0; w.pParse = pParse; sqlite3WalkExpr(&w, pExpr); } @@ -85180,11 +85233,13 @@ sqlite3ColumnDefault(v, pTab, idx, -1); } } if( doMakeRec ){ const char *zAff; - if( pTab->pSelect || (pParse->db->flags & SQLITE_IdxRealAsInt)!=0 ){ + if( pTab->pSelect + || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt) + ){ zAff = 0; }else{ zAff = sqlite3IndexAffinityStr(v, pIdx); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); @@ -92422,11 +92477,11 @@ sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); + sqlite3VdbeAddOp2(v, OP_Move, 2, 4); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. @@ -92725,10 +92780,26 @@ */ if( sqlite3StrICmp(zLeft, "shrink_memory")==0 ){ sqlite3_db_release_memory(db); }else + /* + ** PRAGMA busy_timeout + ** PRAGMA busy_timeout = N + ** + ** Call sqlite3_busy_timeout(db, N). Return the current timeout value + ** if one is set. If no busy handler or a different busy handler is set + ** then 0 is returned. Setting the busy_timeout to 0 or negative + ** disables the timeout. + */ + if( sqlite3StrICmp(zLeft, "busy_timeout")==0 ){ + if( zRight ){ + sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); + } + returnSingleInt(pParse, "timeout", db->busyTimeout); + }else + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases */ if( sqlite3StrICmp(zLeft, "lock_status")==0 ){ @@ -92955,11 +93026,13 @@ ** indicate success or failure. */ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ int rc; int i; +#ifndef SQLITE_OMIT_DEPRECATED int size; +#endif Table *pTab; Db *pDb; char const *azArg[4]; int meta[5]; InitData initData; @@ -94210,10 +94283,23 @@ return 0; } } #endif +/* +** An instance of the following object is used to record information about +** how to process the DISTINCT keyword, to simplify passing that information +** into the selectInnerLoop() routine. +*/ +typedef struct DistinctCtx DistinctCtx; +struct DistinctCtx { + u8 isTnct; /* True if the DISTINCT keyword is present */ + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ + int tabTnct; /* Ephemeral table used for DISTINCT processing */ + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ +}; + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** ** If srcTab and nColumn are both zero, then the pEList expressions @@ -94226,11 +94312,11 @@ Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ int nColumn, /* Number of columns in the source table */ ExprList *pOrderBy, /* If not NULL, sort results using this key */ - int distinct, /* If >=0, make sure results are distinct */ + DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ int iContinue, /* Jump here to continue with next row */ int iBreak /* Jump here to break out of the inner loop */ ){ Vdbe *v = pParse->pVdbe; @@ -94242,11 +94328,11 @@ int nResultCol; /* Number of result columns */ assert( v ); if( NEVER(v==0) ) return; assert( pEList!=0 ); - hasDistinct = distinct>=0; + hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pOrderBy==0 && !hasDistinct ){ codeOffset(v, p, iContinue); } /* Pull the requested columns. @@ -94282,11 +94368,59 @@ ** part of the result. */ if( hasDistinct ){ assert( pEList!=0 ); assert( pEList->nExpr==nColumn ); - codeDistinct(pParse, distinct, iContinue, nColumn, regResult); + switch( pDistinct->eTnctType ){ + case WHERE_DISTINCT_ORDERED: { + VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ + int iJump; /* Jump destination */ + int regPrev; /* Previous row content */ + + /* Allocate space for the previous row */ + regPrev = pParse->nMem+1; + pParse->nMem += nColumn; + + /* Change the OP_OpenEphemeral coded earlier to an OP_Null + ** sets the MEM_Cleared bit on the first register of the + ** previous value. This will cause the OP_Ne below to always + ** fail on the first iteration of the loop even if the first + ** row is all NULLs. + */ + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); + pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct); + pOp->opcode = OP_Null; + pOp->p1 = 1; + pOp->p2 = regPrev; + + iJump = sqlite3VdbeCurrentAddr(v) + nColumn; + for(i=0; i<nColumn; i++){ + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr); + if( i<nColumn-1 ){ + sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i); + }else{ + sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i); + } + sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + } + assert( sqlite3VdbeCurrentAddr(v)==iJump ); + sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nColumn-1); + break; + } + + case WHERE_DISTINCT_UNIQUE: { + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); + break; + } + + default: { + assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); + codeDistinct(pParse, pDistinct->tabTnct, iContinue, nColumn, regResult); + break; + } + } if( pOrderBy==0 ){ codeOffset(v, p, iContinue); } } @@ -94340,20 +94474,21 @@ ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { assert( nColumn==1 ); - p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); + pDest->affSdst = + sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter(pParse, pOrderBy, p, regResult); }else{ int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); sqlite3ExprCacheAffinityChange(pParse, regResult, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); } break; @@ -94616,11 +94751,12 @@ break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==1 ); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, + &pDest->affSdst, 1); sqlite3ExprCacheAffinityChange(pParse, regRow, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid); break; } case SRT_Mem: { @@ -95453,11 +95589,11 @@ iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, - 0, -1, &dest, iCont, iBreak); + 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } @@ -95531,11 +95667,11 @@ r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, - 0, -1, &dest, iCont, iBreak); + 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); @@ -95651,11 +95787,11 @@ j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst, (char*)pKeyInfo, p4type); sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); sqlite3VdbeJumpHere(v, j1); - sqlite3ExprCodeCopy(pParse, pIn->iSdst, regPrev+1, pIn->nSdst); + sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1); sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); } if( pParse->db->mallocFailed ) return 0; /* Suppress the first OFFSET entries if there is an OFFSET clause @@ -95686,14 +95822,14 @@ ** item into the set table with bogus data. */ case SRT_Set: { int r1; assert( pIn->nSdst==1 ); - p->affinity = + pDest->affSdst = sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst); r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &p->affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1); sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1); sqlite3ReleaseTempReg(pParse, r1); break; } @@ -96431,11 +96567,11 @@ /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); assert( p->pPrior==0 ); /* Unable to flatten compound queries */ - if( db->flags & SQLITE_QueryFlattener ) return 0; + if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; @@ -97471,15 +97607,13 @@ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ - int isDistinct; /* True if the DISTINCT keyword is present */ - int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ - int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */ + DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ #ifndef SQLITE_OMIT_EXPLAIN @@ -97601,11 +97735,11 @@ pEList = p->pEList; #endif pWhere = p->pWhere; pGroupBy = p->pGroupBy; pHaving = p->pHaving; - isDistinct = (p->selFlags & SF_Distinct)!=0; + sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #ifndef SQLITE_OMIT_COMPOUND_SELECT /* If there is are a sequence of queries, do the earlier ones first. */ if( p->pPrior ){ @@ -97636,11 +97770,11 @@ ** an optimization - the correct answer should result regardless. ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER ** to disable this optimization for testing purposes. */ if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0 - && (db->flags & SQLITE_GroupByOrder)==0 ){ + && OptimizationEnabled(db, SQLITE_GroupByOrder) ){ pOrderBy = 0; } /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query @@ -97662,10 +97796,14 @@ ){ p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; pOrderBy = 0; + /* Notice that even thought SF_Distinct has been cleared from p->selFlags, + ** the sDistinct.isTnct is still set. Hence, isTnct represents the + ** original setting of the SF_Distinct flag, not the current setting */ + assert( sDistinct.isTnct ); } /* If there is an ORDER BY clause, then this sorting ** index might end up being unused if the data can be ** extracted in pre-sorted order. If that is the case, then the @@ -97702,28 +97840,31 @@ } /* Open a virtual index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ - KeyInfo *pKeyInfo; - distinct = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0, - (char*)pKeyInfo, P4_KEYINFO_HANDOFF); + sDistinct.tabTnct = pParse->nTab++; + sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + sDistinct.tabTnct, 0, 0, + (char*)keyInfoFromExprList(pParse, p->pEList), + P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); + sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ - distinct = addrDistinctIndex = -1; + sDistinct.eTnctType = WHERE_DISTINCT_NOOP; } - /* Aggregate and non-aggregate queries are handled differently */ if( !isAgg && pGroupBy==0 ){ - ExprList *pDist = (isDistinct ? p->pEList : 0); + /* No aggregate functions and no GROUP BY clause */ + ExprList *pDist = (sDistinct.isTnct ? p->pEList : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, pDist, 0,0); if( pWInfo==0 ) goto select_end; if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; + if( pWInfo->eDistinct ) sDistinct.eTnctType = pWInfo->eDistinct; + if( pOrderBy && pWInfo->nOBSat==pOrderBy->nExpr ) pOrderBy = 0; /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ @@ -97730,63 +97871,20 @@ if( addrSortIndex>=0 && pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, addrSortIndex); p->addrOpenEphm[2] = -1; } - if( pWInfo->eDistinct ){ - VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ - - assert( addrDistinctIndex>=0 ); - pOp = sqlite3VdbeGetOp(v, addrDistinctIndex); - - assert( isDistinct ); - assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED - || pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE - ); - distinct = -1; - if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){ - int iJump; - int iExpr; - int iFlag = ++pParse->nMem; - int iBase = pParse->nMem+1; - int iBase2 = iBase + pEList->nExpr; - pParse->nMem += (pEList->nExpr*2); - - /* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The - ** OP_Integer initializes the "first row" flag. */ - pOp->opcode = OP_Integer; - pOp->p1 = 1; - pOp->p2 = iFlag; - - sqlite3ExprCodeExprList(pParse, pEList, iBase, 1); - iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1; - sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1); - for(iExpr=0; iExpr<pEList->nExpr; iExpr++){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr); - sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr); - sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - } - sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue); - - sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag); - assert( sqlite3VdbeCurrentAddr(v)==iJump ); - sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr); - }else{ - pOp->opcode = OP_Noop; - } - } - /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest, + selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, &sDistinct, pDest, pWInfo->iContinue, pWInfo->iBreak); /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); }else{ - /* This is the processing for aggregate queries */ + /* This case when there exist aggregate functions or a GROUP BY clause + ** or both */ NameContext sNC; /* Name context for processing aggregate information */ int iAMem; /* First Mem address for storing current GROUP BY */ int iBMem; /* First Mem address for previous GROUP BY */ int iUseFlag; /* Mem address holding flag indicating that at least ** one row of the input to the aggregator has been @@ -97890,18 +97988,17 @@ ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0); if( pWInfo==0 ) goto select_end; - if( pGroupBy==0 ){ + if( pWInfo->nOBSat==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ - pGroupBy = p->pGroupBy; groupBySort = 0; }else{ /* Rows are coming out in undetermined order. We have to push ** each row into a sorting index, terminate the first loop, ** then loop over the sorting index in order to get the output @@ -97911,11 +98008,12 @@ int regRecord; int nCol; int nGroupBy; explainTempTable(pParse, - isDistinct && !(p->selFlags&SF_Distinct)?"DISTINCT":"GROUP BY"); + (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? + "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy + 1; j = nGroupBy+1; @@ -98043,11 +98141,11 @@ VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, - distinct, pDest, + &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); VdbeComment((v, "end groupby result generator")); /* Generate a subroutine that will reset the group-by accumulator @@ -98146,10 +98244,11 @@ */ ExprList *pMinMax = 0; u8 flag = minMaxQuery(p); if( flag ){ assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) ); + assert( p->pEList->a[0].pExpr->x.pList->nExpr==1 ); pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0); pDel = pMinMax; if( pMinMax && !db->mallocFailed ){ pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].pExpr->op = TK_COLUMN; @@ -98159,17 +98258,18 @@ /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. */ resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDel); goto select_end; } updateAccumulator(pParse, &sAggInfo); - if( !pMinMax && flag ){ + assert( pMinMax==0 || pMinMax->nExpr==1 ); + if( pWInfo->nOBSat>0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak); VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); } sqlite3WhereEnd(pWInfo); @@ -98176,19 +98276,19 @@ finalizeAggFunctions(pParse, &sAggInfo); } pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1, + selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, 0, pDest, addrEnd, addrEnd); sqlite3ExprListDelete(db, pDel); } sqlite3VdbeResolveLabel(v, addrEnd); } /* endif aggregate query */ - if( distinct>=0 ){ + if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ explainTempTable(pParse, "DISTINCT"); } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. @@ -101789,13 +101889,14 @@ /* ** Trace output macros */ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) -SQLITE_PRIVATE int sqlite3WhereTrace = 0; +/***/ int sqlite3WhereTrace = 0; #endif -#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) # define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X #else # define WHERETRACE(X) #endif @@ -102031,10 +102132,32 @@ #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */ #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */ #define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ #define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */ + +/* +** This module contains many separate subroutines that work together to +** find the best indices to use for accessing a particular table in a query. +** An instance of the following structure holds context information about the +** index search so that it can be more easily passed between the various +** routines. +*/ +typedef struct WhereBestIdx WhereBestIdx; +struct WhereBestIdx { + Parse *pParse; /* Parser context */ + WhereClause *pWC; /* The WHERE clause */ + struct SrcList_item *pSrc; /* The FROM clause term to search */ + Bitmask notReady; /* Mask of cursors not available */ + Bitmask notValid; /* Cursors not available for any purpose */ + ExprList *pOrderBy; /* The ORDER BY clause */ + ExprList *pDistinct; /* The select-list if query is DISTINCT */ + sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */ + int i, n; /* Which loop is being coded; # of loops */ + WhereLevel *aLevel; /* Info about outer loops */ + WhereCost cost; /* Lowest cost query plan */ +}; /* ** Initialize a preallocated WhereClause structure. */ static void whereClauseInit( @@ -103174,26 +103297,22 @@ */ pTerm->prereqRight |= extraRight; } /* -** Return TRUE if any of the expressions in pList->a[iFirst...] contain -** a reference to any table other than the iBase table. +** Return TRUE if the given index is UNIQUE and all columns past the +** first nSkip columns are NOT NULL. */ -static int referencesOtherTables( - ExprList *pList, /* Search expressions in ths list */ - WhereMaskSet *pMaskSet, /* Mapping from tables to bitmaps */ - int iFirst, /* Be searching with the iFirst-th expression */ - int iBase /* Ignore references to this table */ -){ - Bitmask allowed = ~getMask(pMaskSet, iBase); - while( iFirst<pList->nExpr ){ - if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){ - return 1; - } +static int indexIsUniqueNotNull(Index *pIdx, int nSkip){ + Table *pTab = pIdx->pTable; + int i; + if( pIdx->onError==OE_None ) return 0; + for(i=nSkip; i<pIdx->nColumn; i++){ + int j = pIdx->aiColumn[i]; + if( j>=0 && pTab->aCol[j].notNull==0 ) return 0; } - return 0; + return 1; } /* ** This function searches the expression list passed as the second argument ** for an expression of type TK_COLUMN that refers to the same column and @@ -103355,47 +103474,63 @@ return 0; } /* ** This routine decides if pIdx can be used to satisfy the ORDER BY -** clause. If it can, it returns 1. If pIdx cannot satisfy the -** ORDER BY clause, this routine returns 0. +** clause, either in whole or in part. The return value is the +** cumulative number of terms in the ORDER BY clause that are satisfied +** by the index pIdx and other indices in outer loops. ** -** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the -** left-most table in the FROM clause of that same SELECT statement and -** the table has a cursor number of "base". pIdx is an index on pTab. +** The table being queried has a cursor number of "base". pIdx is the +** index that is postulated for use to access the table. ** ** nEqCol is the number of columns of pIdx that are used as equality -** constraints. Any of these columns may be missing from the ORDER BY -** clause and the match can still be a success. +** constraints and where the other side of the == is an ordered column +** or constant. An "order column" in the previous sentence means a column +** in table from an outer loop whose values will always appear in the +** correct order due to othre index, or because the outer loop generates +** a unique result. Any of the first nEqCol columns of pIdx may be missing +** from the ORDER BY clause and the match can still be a success. ** -** All terms of the ORDER BY that match against the index must be either -** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE -** index do not need to satisfy this constraint.) The *pbRev value is -** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if -** the ORDER BY clause is all ASC. +** The *pbRev value is set to 0 order 1 depending on whether or not +** pIdx should be run in the forward order or in reverse order. */ static int isSortingIndex( - Parse *pParse, /* Parsing context */ - WhereMaskSet *pMaskSet, /* Mapping from table cursor numbers to bitmaps */ - Index *pIdx, /* The index we are testing */ - int base, /* Cursor number for the table to be sorted */ - ExprList *pOrderBy, /* The ORDER BY clause */ - int nEqCol, /* Number of index columns with == constraints */ - int wsFlags, /* Index usages flags */ - int *pbRev /* Set to 1 if ORDER BY is DESC */ -){ - int i, j; /* Loop counters */ - int sortOrder = 0; /* XOR of index and ORDER BY sort direction */ - int nTerm; /* Number of ORDER BY terms */ - struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ - sqlite3 *db = pParse->db; - - if( !pOrderBy ) return 0; - if( wsFlags & WHERE_COLUMN_IN ) return 0; - if( pIdx->bUnordered ) return 0; - + WhereBestIdx *p, /* Best index search context */ + Index *pIdx, /* The index we are testing */ + int base, /* Cursor number for the table to be sorted */ + int nEqCol, /* Number of index columns with ordered == constraints */ + int wsFlags, /* Index usages flags */ + int bOuterRev, /* True if outer loops scan in reverse order */ + int *pbRev /* Set to 1 for reverse-order scan of pIdx */ +){ + int i; /* Number of pIdx terms used */ + int j; /* Number of ORDER BY terms satisfied */ + int sortOrder = 0; /* XOR of index and ORDER BY sort direction */ + int nTerm; /* Number of ORDER BY terms */ + struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ + ExprList *pOrderBy; /* The ORDER BY clause */ + Parse *pParse = p->pParse; /* Parser context */ + sqlite3 *db = pParse->db; /* Database connection */ + int nPriorSat; /* ORDER BY terms satisfied by outer loops */ + int seenRowid = 0; /* True if an ORDER BY rowid term is seen */ + int nEqOneRow; /* Idx columns that ref unique values */ + + if( p->i==0 ){ + nPriorSat = 0; + nEqOneRow = nEqCol; + }else{ + if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; + nPriorSat = p->aLevel[p->i-1].plan.nOBSat; + sortOrder = bOuterRev; + nEqOneRow = 0; + } + if( p->i>0 && nEqCol==0 /*&& !allOuterLoopsUnique(p)*/ ) return nPriorSat; + pOrderBy = p->pOrderBy; + if( !pOrderBy ) return nPriorSat; + if( wsFlags & WHERE_COLUMN_IN ) return nPriorSat; + if( pIdx->bUnordered ) return nPriorSat; nTerm = pOrderBy->nExpr; assert( nTerm>0 ); /* Argument pIdx must either point to a 'real' named index structure, ** or an index structure allocated on the stack by bestBtreeIndex() to @@ -103408,11 +103543,11 @@ ** Note that indices have pIdx->nColumn regular columns plus ** one additional column containing the rowid. The rowid column ** of the index is also allowed to match against the ORDER BY ** clause. */ - for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){ + for(i=0,j=nPriorSat,pTerm=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){ Expr *pExpr; /* The expression of the ORDER BY pTerm */ CollSeq *pColl; /* The collating sequence of pExpr */ int termSortOrder; /* Sort order for this term */ int iColumn; /* The i-th column of the index. -1 for rowid */ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */ @@ -103452,68 +103587,53 @@ break; }else{ /* If an index column fails to match and is not constrained by == ** then the index cannot satisfy the ORDER BY constraint. */ - return 0; + return nPriorSat; } } assert( pIdx->aSortOrder!=0 || iColumn==-1 ); assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 ); assert( iSortOrder==0 || iSortOrder==1 ); termSortOrder = iSortOrder ^ pTerm->sortOrder; - if( i>nEqCol ){ + if( i>nEqOneRow ){ if( termSortOrder!=sortOrder ){ /* Indices can only be used if all ORDER BY terms past the ** equality constraints are all either DESC or ASC. */ - return 0; + break; } }else{ sortOrder = termSortOrder; } j++; pTerm++; - if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ - /* If the indexed column is the primary key and everything matches - ** so far and none of the ORDER BY terms to the right reference other - ** tables in the join, then we are assured that the index can be used - ** to sort because the primary key is unique and so none of the other - ** columns will make any difference - */ - j = nTerm; - } - } - - *pbRev = sortOrder!=0; - if( j>=nTerm ){ - /* All terms of the ORDER BY clause are covered by this index so - ** this index can be used for sorting. */ - return 1; - } - if( pIdx->onError!=OE_None && i==pIdx->nColumn - && (wsFlags & WHERE_COLUMN_NULL)==0 - && !referencesOtherTables(pOrderBy, pMaskSet, j, base) - ){ - Column *aCol = pIdx->pTable->aCol; - - /* All terms of this index match some prefix of the ORDER BY clause, - ** the index is UNIQUE, and no terms on the tail of the ORDER BY - ** refer to other tables in a join. So, assuming that the index entries - ** visited contain no NULL values, then this index delivers rows in - ** the required order. - ** - ** It is not possible for any of the first nEqCol index fields to be - ** NULL (since the corresponding "=" operator in the WHERE clause would - ** not be true). So if all remaining index columns have NOT NULL - ** constaints attached to them, we can be confident that the visited - ** index entries are free of NULLs. */ - for(i=nEqCol; i<pIdx->nColumn; i++){ - if( aCol[pIdx->aiColumn[i]].notNull==0 ) break; - } - return (i==pIdx->nColumn); - } - return 0; + if( iColumn<0 ){ + seenRowid = 1; + break; + } + } + *pbRev = sortOrder; + + /* If there was an "ORDER BY rowid" term that matched, or it is only + ** possible for a single row from this table to match, then skip over + ** any additional ORDER BY terms dealing with this table. + */ + if( seenRowid || + ( (wsFlags & WHERE_COLUMN_NULL)==0 + && i>=pIdx->nColumn + && indexIsUniqueNotNull(pIdx, nEqCol) + ) + ){ + /* Advance j over additional ORDER BY terms associated with base */ + WhereMaskSet *pMS = p->pWC->pMaskSet; + Bitmask m = ~getMask(pMS, base); + while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){ + j++; + } + } + return j; } /* ** Prepare a crude estimate of the logarithm of the input value. ** The results need not be exact. This is only used for estimating @@ -103576,35 +103696,27 @@ #endif /* ** Required because bestIndex() is called by bestOrClauseIndex() */ -static void bestIndex( - Parse*, WhereClause*, struct SrcList_item*, - Bitmask, Bitmask, ExprList*, WhereCost*); +static void bestIndex(WhereBestIdx*); /* ** This routine attempts to find an scanning strategy that can be used ** to optimize an 'OR' expression that is part of a WHERE clause. ** ** The table associated with FROM clause term pSrc may be either a ** regular B-Tree table or a virtual table. */ -static void bestOrClauseIndex( - Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to search */ - Bitmask notReady, /* Mask of cursors not available for indexing */ - Bitmask notValid, /* Cursors not available for any purpose */ - ExprList *pOrderBy, /* The ORDER BY clause */ - WhereCost *pCost /* Lowest cost query plan */ -){ +static void bestOrClauseIndex(WhereBestIdx *p){ #ifndef SQLITE_OMIT_OR_OPTIMIZATION - const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ + WhereClause *pWC = p->pWC; /* The WHERE clause */ + struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ + const int iCur = pSrc->iCursor; /* The cursor of the table */ const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */ WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */ - WhereTerm *pTerm; /* A single term of the WHERE clause */ + WhereTerm *pTerm; /* A single term of the WHERE clause */ /* The OR-clause optimization is disallowed if the INDEXED BY or ** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */ if( pSrc->notIndexed || pSrc->pIndex!=0 ){ return; @@ -103614,66 +103726,71 @@ } /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ if( pTerm->eOperator==WO_OR - && ((pTerm->prereqAll & ~maskSrc) & notReady)==0 + && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int flags = WHERE_MULTI_OR; double rTotal = 0; double nRow = 0; Bitmask used = 0; + WhereBestIdx sBOI; + sBOI = *p; + sBOI.pOrderBy = 0; + sBOI.pDistinct = 0; + sBOI.ppIdxInfo = 0; for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ - WhereCost sTermCost; WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", (pOrTerm - pOrWC->a), (pTerm - pWC->a) )); if( pOrTerm->eOperator==WO_AND ){ - WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc; - bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost); + sBOI.pWC = &pOrTerm->u.pAndInfo->wc; + bestIndex(&sBOI); }else if( pOrTerm->leftCursor==iCur ){ WhereClause tempWC; tempWC.pParse = pWC->pParse; tempWC.pMaskSet = pWC->pMaskSet; tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.a = pOrTerm; tempWC.wctrlFlags = 0; tempWC.nTerm = 1; - bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); + sBOI.pWC = &tempWC; + bestIndex(&sBOI); }else{ continue; } - rTotal += sTermCost.rCost; - nRow += sTermCost.plan.nRow; - used |= sTermCost.used; - if( rTotal>=pCost->rCost ) break; + rTotal += sBOI.cost.rCost; + nRow += sBOI.cost.plan.nRow; + used |= sBOI.cost.used; + if( rTotal>=p->cost.rCost ) break; } /* If there is an ORDER BY clause, increase the scan cost to account ** for the cost of the sort. */ - if( pOrderBy!=0 ){ + if( p->pOrderBy!=0 ){ WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n", rTotal, rTotal+nRow*estLog(nRow))); rTotal += nRow*estLog(nRow); } /* If the cost of scanning using this OR term for optimization is ** less than the current cost stored in pCost, replace the contents ** of pCost. */ WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow)); - if( rTotal<pCost->rCost ){ - pCost->rCost = rTotal; - pCost->used = used; - pCost->plan.nRow = nRow; - pCost->plan.wsFlags = flags; - pCost->plan.u.pTerm = pTerm; + if( rTotal<p->cost.rCost ){ + p->cost.rCost = rTotal; + p->cost.used = used; + p->cost.plan.nRow = nRow; + p->cost.plan.wsFlags = flags; + p->cost.plan.u.pTerm = pTerm; } } } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ } @@ -103706,19 +103823,16 @@ ** possible to construct a transient index that would perform better ** than a full table scan even when the cost of constructing the index ** is taken into account, then alter the query plan to use the ** transient index. */ -static void bestAutomaticIndex( - Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to search */ - Bitmask notReady, /* Mask of cursors that are not available */ - WhereCost *pCost /* Lowest cost query plan */ -){ - double nTableRow; /* Rows in the input table */ - double logN; /* log(nTableRow) */ +static void bestAutomaticIndex(WhereBestIdx *p){ + Parse *pParse = p->pParse; /* The parsing context */ + WhereClause *pWC = p->pWC; /* The WHERE clause */ + struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ + double nTableRow; /* Rows in the input table */ + double logN; /* log(nTableRow) */ double costTempIdx; /* per-query cost of the transient index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pWCEnd; /* End of pWC->a[] */ Table *pTable; /* Table tht might be indexed */ @@ -103728,11 +103842,11 @@ } if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){ /* Automatic indices are disabled at run-time */ return; } - if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){ + if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){ /* We already have some kind of index in use for this query. */ return; } if( pSrc->notIndexed ){ /* The NOT INDEXED clause appears in the SQL. */ @@ -103746,32 +103860,32 @@ assert( pParse->nQueryLoop >= (double)1 ); pTable = pSrc->pTab; nTableRow = pTable->nRowEst; logN = estLog(nTableRow); costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1); - if( costTempIdx>=pCost->rCost ){ + if( costTempIdx>=p->cost.rCost ){ /* The cost of creating the transient table would be greater than ** doing the full table scan */ return; } /* Search for any equality comparison term */ pWCEnd = &pWC->a[pWC->nTerm]; for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ - if( termCanDriveIndex(pTerm, pSrc, notReady) ){ + if( termCanDriveIndex(pTerm, pSrc, p->notReady) ){ WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n", - pCost->rCost, costTempIdx)); - pCost->rCost = costTempIdx; - pCost->plan.nRow = logN + 1; - pCost->plan.wsFlags = WHERE_TEMP_INDEX; - pCost->used = pTerm->prereqRight; + p->cost.rCost, costTempIdx)); + p->cost.rCost = costTempIdx; + p->cost.plan.nRow = logN + 1; + p->cost.plan.wsFlags = WHERE_TEMP_INDEX; + p->cost.used = pTerm->prereqRight; break; } } } #else -# define bestAutomaticIndex(A,B,C,D,E) /* no-op */ +# define bestAutomaticIndex(A) /* no-op */ #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* @@ -103928,16 +104042,15 @@ /* ** 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(). */ -static sqlite3_index_info *allocateIndexInfo( - Parse *pParse, - WhereClause *pWC, - struct SrcList_item *pSrc, - ExprList *pOrderBy -){ +static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){ + Parse *pParse = p->pParse; + WhereClause *pWC = p->pWC; + struct SrcList_item *pSrc = p->pSrc; + ExprList *pOrderBy = p->pOrderBy; int i, j; int nTerm; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; @@ -103963,16 +104076,17 @@ ** virtual table then allocate space for the aOrderBy part of ** the sqlite3_index_info structure. */ nOrderBy = 0; if( pOrderBy ){ - for(i=0; i<pOrderBy->nExpr; i++){ + int n = pOrderBy->nExpr; + for(i=0; i<n; i++){ Expr *pExpr = pOrderBy->a[i].pExpr; if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; } - if( i==pOrderBy->nExpr ){ - nOrderBy = pOrderBy->nExpr; + if( i==n){ + nOrderBy = n; } } /* Allocate the sqlite3_index_info structure */ @@ -104092,20 +104206,14 @@ ** invocations. The sqlite3_index_info structure is also used when ** code is generated to access the virtual table. The whereInfoDelete() ** routine takes care of freeing the sqlite3_index_info structure after ** everybody has finished with it. */ -static void bestVirtualIndex( - Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to search */ - Bitmask notReady, /* Mask of cursors not available for index */ - Bitmask notValid, /* Cursors not valid for any purpose */ - ExprList *pOrderBy, /* The order by clause */ - WhereCost *pCost, /* Lowest cost query plan */ - sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ -){ +static void bestVirtualIndex(WhereBestIdx *p){ + Parse *pParse = p->pParse; /* The parsing context */ + WhereClause *pWC = p->pWC; /* The WHERE clause */ + struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; @@ -104115,19 +104223,19 @@ /* Make sure wsFlags is initialized to some sane value. Otherwise, if the ** malloc in allocateIndexInfo() fails and this function returns leaving ** wsFlags in an uninitialized state, the caller may behave unpredictably. */ - memset(pCost, 0, sizeof(*pCost)); - pCost->plan.wsFlags = WHERE_VIRTUALTABLE; + memset(&p->cost, 0, sizeof(p->cost)); + p->cost.plan.wsFlags = WHERE_VIRTUALTABLE; /* If the sqlite3_index_info structure has not been previously ** allocated and initialized, then allocate and initialize it now. */ - pIdxInfo = *ppIdxInfo; + pIdxInfo = *p->ppIdxInfo; if( pIdxInfo==0 ){ - *ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pOrderBy); + *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p); } if( pIdxInfo==0 ){ return; } @@ -104168,11 +104276,11 @@ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pUsage = pIdxInfo->aConstraintUsage; for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; - pIdxCons->usable = (pTerm->prereqRight¬Ready) ? 0 : 1; + pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1; } memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); if( pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); } @@ -104181,11 +104289,11 @@ pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); nOrderBy = pIdxInfo->nOrderBy; - if( !pOrderBy ){ + if( !p->pOrderBy ){ pIdxInfo->nOrderBy = 0; } if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ return; @@ -104192,20 +104300,20 @@ } pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++){ if( pUsage[i].argvIndex>0 ){ - pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; + p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; } } /* If there is an ORDER BY clause, and the selected virtual table index ** does not satisfy it, increase the cost of the scan accordingly. This ** matches the processing for non-virtual tables in bestBtreeIndex(). */ rCost = pIdxInfo->estimatedCost; - if( pOrderBy && pIdxInfo->orderByConsumed==0 ){ + if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){ rCost += estLog(rCost)*rCost; } /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the ** inital value of lowestCost in this loop. If it is, then the @@ -104213,25 +104321,25 @@ ** ** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT ** is defined. */ if( (SQLITE_BIG_DBL/((double)2))<rCost ){ - pCost->rCost = (SQLITE_BIG_DBL/((double)2)); + p->cost.rCost = (SQLITE_BIG_DBL/((double)2)); }else{ - pCost->rCost = rCost; + p->cost.rCost = rCost; } - pCost->plan.u.pVtabIdx = pIdxInfo; + p->cost.plan.u.pVtabIdx = pIdxInfo; if( pIdxInfo->orderByConsumed ){ - pCost->plan.wsFlags |= WHERE_ORDERBY; + p->cost.plan.wsFlags |= WHERE_ORDERBY; } - pCost->plan.nEq = 0; + p->cost.plan.nEq = 0; pIdxInfo->nOrderBy = nOrderBy; /* Try to find a more efficient access pattern by using multiple indexes ** to optimize an OR expression within the WHERE clause. */ - bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); + bestOrClauseIndex(p); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef SQLITE_ENABLE_STAT3 /* @@ -104626,15 +104734,88 @@ } return rc; } #endif /* defined(SQLITE_ENABLE_STAT3) */ +/* +** Check to see if column iCol of the table with cursor iTab will appear +** in sorted order according to the current query plan. Return true if +** it will and false if not. +** +** If *pbRev is initially 2 (meaning "unknown") then set *pbRev to the +** sort order of iTab.iCol. If *pbRev is 0 or 1 but does not match +** the sort order of iTab.iCol, then consider the column to be unordered. +*/ +static int isOrderedColumn(WhereBestIdx *p, int iTab, int iCol, int *pbRev){ + int i, j; + WhereLevel *pLevel = &p->aLevel[p->i-1]; + Index *pIdx; + u8 sortOrder; + for(i=p->i-1; i>=0; i--, pLevel--){ + if( pLevel->iTabCur!=iTab ) continue; + if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ + pIdx = pLevel->plan.u.pIdx; + if( iCol<0 ){ + sortOrder = 0; + testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); + }else{ + for(j=0; j<pIdx->nColumn; j++){ + if( iCol==pIdx->aiColumn[j] ) break; + } + if( j>=pIdx->nColumn ) return 0; + sortOrder = pIdx->aSortOrder[j]; + testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); + } + }else{ + if( iCol!=(-1) ) return 0; + sortOrder = 0; + testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); + } + if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){ + assert( sortOrder==0 || sortOrder==1 ); + testcase( sortOrder==1 ); + sortOrder = 1 - sortOrder; + } + if( *pbRev==2 ){ + *pbRev = sortOrder; + return 1; + } + return (*pbRev==sortOrder); + } + return 0; +} + +/* +** pTerm is an == constraint. Check to see if the other side of +** the == is a constant or a value that is guaranteed to be ordered +** by outer loops. Return 1 if pTerm is ordered, and 0 if not. +*/ +static int isOrderedTerm(WhereBestIdx *p, WhereTerm *pTerm, int *pbRev){ + Expr *pExpr = pTerm->pExpr; + assert( pExpr->op==TK_EQ ); + assert( pExpr->pLeft!=0 && pExpr->pLeft->op==TK_COLUMN ); + assert( pExpr->pRight!=0 ); + if( p->i==0 ){ + return 1; /* All == are ordered in the outer loop */ + } + if( pTerm->prereqRight==0 ){ + return 1; /* RHS of the == is a constant */ + } + if( pExpr->pRight->op==TK_COLUMN + && isOrderedColumn(p, pExpr->pRight->iTable, pExpr->pRight->iColumn, pbRev) + ){ + return 1; + } + + /* If we cannot prove that the constraint is ordered, assume it is not */ + return 0; +} + /* ** Find the best query plan for accessing a particular table. Write the -** best query plan and its cost into the WhereCost object supplied as the -** last parameter. +** best query plan and its cost into the p->cost. ** ** The lowest cost plan wins. The cost is an estimate of the amount of ** CPU and disk I/O needed to process the requested result. ** Factors that influence cost include: ** @@ -104655,33 +104836,27 @@ ** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table ** in the SELECT statement, then no indexes are considered. However, the ** selected plan may still take advantage of the built-in rowid primary key ** index. */ -static void bestBtreeIndex( - Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to search */ - Bitmask notReady, /* Mask of cursors not available for indexing */ - Bitmask notValid, /* Cursors not available for any purpose */ - ExprList *pOrderBy, /* The ORDER BY clause */ - ExprList *pDistinct, /* The select-list if query is DISTINCT */ - WhereCost *pCost /* Lowest cost query plan */ -){ +static void bestBtreeIndex(WhereBestIdx *p){ + Parse *pParse = p->pParse; /* The parsing context */ + WhereClause *pWC = p->pWC; /* The WHERE clause */ + struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ Index *pProbe; /* An index we are evaluating */ Index *pIdx; /* Copy of pProbe, or zero for IPK index */ int eqTermMask; /* Current mask of valid equality operators */ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ - int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */ + int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */ /* Initialize the cost to a worst-case value */ - memset(pCost, 0, sizeof(*pCost)); - pCost->rCost = SQLITE_BIG_DBL; + memset(&p->cost, 0, sizeof(p->cost)); + p->cost.rCost = SQLITE_BIG_DBL; /* If the pSrc table is the right table of a LEFT JOIN then we may not ** use an index to satisfy IS NULL constraints on that table. This is ** because columns might end up being NULL if the table does not match - ** a circumstance which the index cannot help us discover. Ticket #2177. @@ -104730,11 +104905,11 @@ for(; pProbe; pIdx=pProbe=pProbe->pNext){ const tRowcnt * const aiRowEst = pProbe->aiRowEst; double cost; /* Cost of using pProbe */ double nRow; /* Estimated number of rows in result set */ double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */ - int rev; /* True to scan in reverse order */ + int bRev = 2; /* 0=forward scan. 1=reverse. 2=undecided */ int wsFlags = 0; Bitmask used = 0; /* The following variables are populated based on the properties of ** index being evaluated. They are then used to determine the expected @@ -104763,10 +104938,14 @@ ** ** If there exists a WHERE term of the form "x IN (SELECT ...)", then ** the sub-select is assumed to return 25 rows for the purposes of ** determining nInMul. ** + ** nOrdered: + ** The number of equality terms that are constrainted by outer loop + ** variables that are well-ordered. + ** ** bInEst: ** Set to true if there was at least one "x IN (SELECT ...)" term used ** in determining the value of nInMul. Note that the RHS of the ** IN operator must be a SELECT, not a value list, for this variable ** to be true. @@ -104781,10 +104960,14 @@ ** bSort: ** Boolean. True if there is an ORDER BY clause that will require an ** external sort (i.e. scanning the index being evaluated will not ** correctly order records). ** + ** bDistinct: + ** Boolean. True if there is a DISTINCT clause that will require an + ** external btree. + ** ** bLookup: ** Boolean. True if a table lookup is required for each index entry ** visited. In other words, true if this is not a covering index. ** This is always false for the rowid primary key index of a table. ** For other indexes, it is true unless all the columns of the table @@ -104797,26 +104980,33 @@ ** ** SELECT a, b FROM tbl WHERE a = 1; ** SELECT a, b, c FROM tbl WHERE a = 1; */ int nEq; /* Number of == or IN terms matching index */ + int nOrdered; /* Number of ordered terms matching index */ int bInEst = 0; /* True if "x IN (SELECT...)" seen */ int nInMul = 1; /* Number of distinct equalities to lookup */ double rangeDiv = (double)1; /* Estimated reduction in search space */ int nBound = 0; /* Number of range constraints seen */ - int bSort = !!pOrderBy; /* True if external sort required */ - int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */ + int bSort; /* True if external sort required */ + int bDist; /* True if index cannot help with DISTINCT */ int bLookup = 0; /* True if not a covering index */ + int nOBSat = 0; /* Number of ORDER BY terms satisfied */ + int nOrderBy; /* Number of ORDER BY terms */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE_ENABLE_STAT3 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif + + nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0; + bSort = nOrderBy>0 && (p->i==0 || p->aLevel[p->i-1].plan.nOBSat<nOrderBy); + bDist = p->i==0 && p->pDistinct!=0; /* Determine the values of nEq and nInMul */ - for(nEq=0; nEq<pProbe->nColumn; nEq++){ + for(nEq=nOrdered=0; nEq<pProbe->nColumn; nEq++){ int j = pProbe->aiColumn[nEq]; - pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx); + pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx); if( pTerm==0 ) break; wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ); testcase( pTerm->pWC!=pWC ); if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; @@ -104829,10 +105019,13 @@ /* "x IN (value, value, ...)" */ nInMul *= pExpr->x.pList->nExpr; } }else if( pTerm->eOperator & WO_ISNULL ){ wsFlags |= WHERE_COLUMN_NULL; + if( nEq==nOrdered ) nOrdered++; + }else if( bSort && nEq==nOrdered && isOrderedTerm(p, pTerm, &bRev) ){ + nOrdered++; } #ifdef SQLITE_ENABLE_STAT3 if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm; #endif used |= pTerm->prereqRight; @@ -104853,13 +105046,14 @@ if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ wsFlags |= WHERE_UNIQUE; } }else if( pProbe->bUnordered==0 ){ int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]); - if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ - WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); - WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); + if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ + WhereTerm *pTop, *pBtm; + pTop = findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE, pIdx); + pBtm = findTerm(pWC, iCur, j, p->notReady, WO_GT|WO_GE, pIdx); whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv); if( pTop ){ nBound = 1; wsFlags |= WHERE_TOP_LIMIT; used |= pTop->prereqRight; @@ -104877,22 +105071,29 @@ /* If there is an ORDER BY clause and the index being considered will ** naturally scan rows in the required order, set the appropriate flags ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** will scan rows in a different order, set the bSort variable. */ - if( isSortingIndex( - pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev) - ){ - bSort = 0; - wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; - wsFlags |= (rev ? WHERE_REVERSE : 0); + assert( bRev>=0 && bRev<=2 ); + if( bSort ){ + testcase( bRev==0 ); + testcase( bRev==1 ); + testcase( bRev==2 ); + nOBSat = isSortingIndex(p, pProbe, iCur, nOrdered, + wsFlags, bRev&1, &bRev); + if( nOrderBy==nOBSat ){ + bSort = 0; + wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; + } + if( bRev & 1 ) wsFlags |= WHERE_REVERSE; } /* If there is a DISTINCT qualifier and this index will scan rows in ** order of the DISTINCT expressions, clear bDist and set the appropriate ** flags in wsFlags. */ - if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq) + if( bDist + && isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, nEq) && (wsFlags & WHERE_COLUMN_IN)==0 ){ bDist = 0; wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT; } @@ -104965,16 +105166,14 @@ ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do ** not give us data on the relative sizes of table and index records. ** So this computation assumes table records are about twice as big ** as index records */ - if( wsFlags==WHERE_IDX_ONLY + if( (wsFlags&~WHERE_REVERSE)==WHERE_IDX_ONLY && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis -#ifndef SQLITE_OMIT_BUILTIN_TEST - && (pParse->db->flags & SQLITE_CoverIdxScan)==0 -#endif + && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan) ){ /* This index is not useful for indexing, but it is a covering index. ** A full-scan of the index might be a little faster than a full-scan ** of the table, so give this case a cost slightly less than a table ** scan. */ @@ -105024,11 +105223,11 @@ ** adds C*N*log10(N) to the cost, where N is the number of rows to be ** sorted and C is a factor between 1.95 and 4.3. We will split the ** difference and select C of 3.0. */ if( bSort ){ - cost += nRow*estLog(nRow)*3; + cost += nRow*estLog(nRow*(nOrderBy - nOBSat)/nOrderBy)*3; } if( bDist ){ cost += nRow*estLog(nRow)*3; } @@ -105048,20 +105247,20 @@ ** tables that are not in outer loops. If notReady is used here instead ** of notValid, then a optimal index that depends on inner joins loops ** might be selected even when there exists an optimal index that has ** no such dependency. */ - if( nRow>2 && cost<=pCost->rCost ){ + if( nRow>2 && cost<=p->cost.rCost ){ int k; /* Loop counter */ int nSkipEq = nEq; /* Number of == constraints to skip */ int nSkipRange = nBound; /* Number of < constraints to skip */ Bitmask thisTab; /* Bitmap for pSrc */ thisTab = getMask(pWC->pMaskSet, iCur); for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){ if( pTerm->wtFlags & TERM_VIRTUAL ) continue; - if( (pTerm->prereqAll & notValid)!=thisTab ) continue; + if( (pTerm->prereqAll & p->notValid)!=thisTab ) continue; if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ if( nSkipEq ){ /* Ignore the first nEq equality matches since the index ** has already accounted for these */ nSkipEq--; @@ -105092,29 +105291,32 @@ if( nRow<2 ) nRow = 2; } WHERETRACE(( - "%s(%s): nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%x\n" - " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n", + "%s(%s):\n" + " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n" + " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n" + " used=0x%llx nOrdered=%d nOBSat=%d\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags, - notReady, log10N, nRow, cost, used + p->notReady, log10N, nRow, cost, used, nOrdered, nOBSat )); /* If this index is the best we have seen so far, then record this ** index and its cost in the pCost structure. */ if( (!pIdx || wsFlags) - && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow)) + && (cost<p->cost.rCost || (cost<=p->cost.rCost && nRow<p->cost.plan.nRow)) ){ - pCost->rCost = cost; - pCost->used = used; - pCost->plan.nRow = nRow; - pCost->plan.wsFlags = (wsFlags&wsFlagMask); - pCost->plan.nEq = nEq; - pCost->plan.u.pIdx = pIdx; + p->cost.rCost = cost; + p->cost.used = used; + p->cost.plan.nRow = nRow; + p->cost.plan.wsFlags = (wsFlags&wsFlagMask); + p->cost.plan.nEq = nEq; + p->cost.plan.nOBSat = nOBSat; + p->cost.plan.u.pIdx = pIdx; } /* If there was an INDEXED BY clause, then only that one index is ** considered. */ if( pSrc->pIndex ) break; @@ -105127,58 +105329,57 @@ /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag ** is set, then reverse the order that the index will be scanned ** in. This is used for application testing, to help find cases ** where application behaviour depends on the (undefined) order that ** SQLite outputs rows in in the absence of an ORDER BY clause. */ - if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ - pCost->plan.wsFlags |= WHERE_REVERSE; + if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ + p->cost.plan.wsFlags |= WHERE_REVERSE; } - assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 ); - assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 ); + assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERBY)==0 ); + assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 ); assert( pSrc->pIndex==0 - || pCost->plan.u.pIdx==0 - || pCost->plan.u.pIdx==pSrc->pIndex + || p->cost.plan.u.pIdx==0 + || p->cost.plan.u.pIdx==pSrc->pIndex ); WHERETRACE(("best index is: %s\n", - ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : - pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") + ((p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : + p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk") )); - bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); - bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost); - pCost->plan.wsFlags |= eqTermMask; + bestOrClauseIndex(p); + bestAutomaticIndex(p); + p->cost.plan.wsFlags |= eqTermMask; } /* ** Find the query plan for accessing table pSrc->pTab. Write the ** best query plan and its cost into the WhereCost object supplied ** as the last parameter. This function may calculate the cost of ** both real and virtual table scans. +** +** This function does not take ORDER BY or DISTINCT into account. Nor +** does it remember the virtual table query plan. All it does is compute +** the cost while determining if an OR optimization is applicable. The +** details will be reconsidered later if the optimization is found to be +** applicable. */ -static void bestIndex( - Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to search */ - Bitmask notReady, /* Mask of cursors not available for indexing */ - Bitmask notValid, /* Cursors not available for any purpose */ - ExprList *pOrderBy, /* The ORDER BY clause */ - WhereCost *pCost /* Lowest cost query plan */ -){ +static void bestIndex(WhereBestIdx *p){ #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pSrc->pTab) ){ - sqlite3_index_info *p = 0; - bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p); - if( p->needToFreeIdxStr ){ - sqlite3_free(p->idxStr); + if( IsVirtual(p->pSrc->pTab) ){ + sqlite3_index_info *pIdxInfo = 0; + p->ppIdxInfo = &pIdxInfo; + bestVirtualIndex(p); + if( pIdxInfo->needToFreeIdxStr ){ + sqlite3_free(pIdxInfo->idxStr); } - sqlite3DbFree(pParse->db, p); + sqlite3DbFree(p->pParse->db, pIdxInfo); }else #endif { - bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, 0, pCost); + bestBtreeIndex(p); } } /* ** Disable a term in the WHERE clause. Except, do not disable the term @@ -106432,46 +106633,50 @@ ** fi ** end ** ** ORDER BY CLAUSE PROCESSING ** -** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement, +** pOrderBy is a pointer to the ORDER BY clause of a SELECT statement, ** if there is one. If there is no ORDER BY clause or if this routine -** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL. +** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** If an index can be used so that the natural output order of the table ** scan is correct for the ORDER BY clause, then that index is used and -** *ppOrderBy is set to NULL. This is an optimization that prevents an -** unnecessary sort of the result set if an index appropriate for the -** ORDER BY clause already exists. +** the returned WhereInfo.nOBSat field is set to pOrderBy->nExpr. This +** is an optimization that prevents an unnecessary sort of the result set +** if an index appropriate for the ORDER BY clause already exists. ** ** If the where clause loops cannot be arranged to provide the correct -** output order, then the *ppOrderBy is unchanged. +** output order, then WhereInfo.nOBSat is 0. */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ - ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ + ExprList *pOrderBy, /* An ORDER BY clause, or NULL */ ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ - int i; /* Loop counter */ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ + WhereBestIdx sWBI; /* Best index search context */ WhereMaskSet *pMaskSet; /* The expression mask set */ - WhereClause *pWC; /* Decomposition of the WHERE clause */ - struct SrcList_item *pTabItem; /* A single entry from pTabList */ - WhereLevel *pLevel; /* A single level in the pWInfo list */ - int iFrom; /* First unused FROM clause element */ + WhereLevel *pLevel; /* A single level in pWInfo->a[] */ + int iFrom; /* First unused FROM clause element */ int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */ + int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ + + /* Variable initialization */ + memset(&sWBI, 0, sizeof(sWBI)); + sWBI.pParse = pParse; + /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ @@ -106507,26 +106712,27 @@ } pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); - pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; + pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; - pMaskSet = (WhereMaskSet*)&pWC[1]; + pMaskSet = (WhereMaskSet*)&sWBI.pWC[1]; + sWBI.aLevel = pWInfo->a; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ - if( db->flags & SQLITE_DistinctOpt ) pDistinct = 0; + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ) pDistinct = 0; /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); - whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags); + whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags); sqlite3ExprCodeConstants(pParse, pWhere); - whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ + whereSplit(sWBI.pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ @@ -106553,24 +106759,24 @@ ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_ONETABLE_ONLY flag is set. */ - assert( pWC->vmask==0 && pMaskSet->n==0 ); - for(i=0; i<pTabList->nSrc; i++){ - createMask(pMaskSet, pTabList->a[i].iCursor); + assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 ); + for(ii=0; ii<pTabList->nSrc; ii++){ + createMask(pMaskSet, pTabList->a[ii].iCursor); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){ - pWC->vmask |= ((Bitmask)1 << i); + if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){ + sWBI.pWC->vmask |= ((Bitmask)1 << ii); } #endif } #ifndef NDEBUG { Bitmask toTheLeft = 0; - for(i=0; i<pTabList->nSrc; i++){ - Bitmask m = getMask(pMaskSet, pTabList->a[i].iCursor); + for(ii=0; ii<pTabList->nSrc; ii++){ + Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); toTheLeft |= m; } } #endif @@ -106578,20 +106784,20 @@ /* Analyze all of the subexpressions. Note that exprAnalyze() might ** add new virtual terms onto the end of the WHERE clause. We do not ** want to analyze these virtual terms, so start analyzing at the end ** and work forward so that the added virtual terms are never processed. */ - exprAnalyzeAll(pTabList, pWC); + exprAnalyzeAll(pTabList, sWBI.pWC); if( db->mallocFailed ){ goto whereBeginError; } /* Check if the DISTINCT qualifier, if there is one, is redundant. ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. */ - if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){ + if( pDistinct && isDistinctRedundant(pParse, pTabList, sWBI.pWC, pDistinct) ){ pDistinct = 0; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } /* Chose the best index to use for each table in the FROM clause. @@ -106607,14 +106813,17 @@ ** pWInfo->a[].pTerm When wsFlags==WO_OR, the OR-clause term ** ** This loop also figures out the nesting order of tables in the FROM ** clause. */ - notReady = ~(Bitmask)0; + sWBI.notValid = ~(Bitmask)0; + sWBI.pOrderBy = pOrderBy; + sWBI.n = nTabList; + sWBI.pDistinct = pDistinct; andFlags = ~0; WHERETRACE(("*** Optimizer Start ***\n")); - for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){ + for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.i++, pLevel++){ WhereCost bestPlan; /* Most efficient plan seen so far */ Index *pIdx; /* Index for FROM table at pTabItem */ int j; /* For looping over FROM tables */ int bestJ = -1; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ @@ -106622,11 +106831,11 @@ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ memset(&bestPlan, 0, sizeof(bestPlan)); bestPlan.rCost = SQLITE_BIG_DBL; - WHERETRACE(("*** Begin search for loop %d ***\n", i)); + WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i)); /* Loop through the remaining entries in the FROM clause to find the ** next nested loop. The loop tests all FROM clause entries ** either once or twice. ** @@ -106638,12 +106847,12 @@ ** were used as the innermost nested loop. In other words, a table ** is chosen such that the cost of running that table cannot be reduced ** by waiting for other tables to run first. This "optimal" test works ** by first assuming that the FROM clause is on the inner loop and finding ** its query plan, then checking to see if that query plan uses any - ** other FROM clause terms that are notReady. If no notReady terms are - ** used then the "optimal" query plan works. + ** other FROM clause terms that are sWBI.notValid. If no notValid terms + ** are used then the "optimal" query plan works. ** ** Note that the WhereCost.nRow parameter for an optimal scan might ** not be as small as it would be if the table really were the innermost ** join. The nRow value can be reduced by WHERE clause constraints ** that do not use indices. But this nRow reduction only happens if the @@ -106670,59 +106879,52 @@ ** costlier approach. */ nUnconstrained = 0; notIndexed = 0; for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){ - Bitmask mask; /* Mask of tables not yet ready */ - for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){ + for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){ int doNotReorder; /* True if this table should not be reordered */ - WhereCost sCost; /* Cost information from best[Virtual]Index() */ - ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ - ExprList *pDist; /* DISTINCT clause for index to optimize */ - doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; + doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0; if( j!=iFrom && doNotReorder ) break; - m = getMask(pMaskSet, pTabItem->iCursor); - if( (m & notReady)==0 ){ + m = getMask(pMaskSet, sWBI.pSrc->iCursor); + if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } - mask = (isOptimal ? m : notReady); - pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0); - pDist = (i==0 ? pDistinct : 0); - if( pTabItem->pIndex==0 ) nUnconstrained++; + sWBI.notReady = (isOptimal ? m : sWBI.notValid); + if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; WHERETRACE(("=== trying table %d with isOptimal=%d ===\n", j, isOptimal)); - assert( pTabItem->pTab ); + assert( sWBI.pSrc->pTab ); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pTabItem->pTab) ){ - sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; - bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, - &sCost, pp); + if( IsVirtual(sWBI.pSrc->pTab) ){ + sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo; + bestVirtualIndex(&sWBI); }else #endif { - bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, - pDist, &sCost); + bestBtreeIndex(&sWBI); } - assert( isOptimal || (sCost.used¬Ready)==0 ); + assert( isOptimal || (sWBI.cost.used&sWBI.notValid)==0 ); /* If an INDEXED BY clause is present, then the plan must use that ** index if it uses any index at all */ - assert( pTabItem->pIndex==0 - || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 - || sCost.plan.u.pIdx==pTabItem->pIndex ); + assert( sWBI.pSrc->pIndex==0 + || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 + || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex ); - if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ + if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } /* Conditions under which this table becomes the best so far: ** ** (1) The table must not depend on other tables that have not - ** yet run. + ** yet run. (In other words, it must not depend on tables + ** in inner loops.) ** ** (2) A full-table-scan plan cannot supercede indexed plan unless ** the full-table-scan is an "optimal" plan as defined above. ** ** (3) All tables have an INDEXED BY clause or this table lacks an @@ -106735,37 +106937,38 @@ ** An indexable full-table-scan from reaching rule (3). ** ** (4) The plan cost must be lower than prior plans or else the ** cost must be the same and the number of rows must be lower. */ - if( (sCost.used¬Ready)==0 /* (1) */ - && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ + if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ + && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 - || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) - && (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */ - || NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) - && (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */ - || (sCost.rCost<=bestPlan.rCost - && sCost.plan.nRow<bestPlan.plan.nRow)) + || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) + && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ + || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) + && (bestJ<0 || sWBI.cost.rCost<bestPlan.rCost /* (4) */ + || (sWBI.cost.rCost<=bestPlan.rCost + && sWBI.cost.plan.nRow<bestPlan.plan.nRow)) ){ WHERETRACE(("=== table %d is best so far" - " with cost=%g and nRow=%g\n", - j, sCost.rCost, sCost.plan.nRow)); - bestPlan = sCost; + " with cost=%.1f, nRow=%.1f, nOBSat=%d\n", + j, sWBI.cost.rCost, sWBI.cost.plan.nRow, + sWBI.cost.plan.nOBSat)); + bestPlan = sWBI.cost; bestJ = j; } if( doNotReorder ) break; } } assert( bestJ>=0 ); - assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); - WHERETRACE(("*** Optimizer selects table %d for loop %d" - " with cost=%g and nRow=%g\n", - bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow)); - /* The ALWAYS() that follows was added to hush up clang scan-build */ - if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 && ALWAYS(ppOrderBy) ){ - *ppOrderBy = 0; + assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); + WHERETRACE(("*** Optimizer selects table %d for loop %d with:\n" + " cost=%.1f, nRow=%.1f, nOBSat=%d wsFlags=0x%08x\n", + bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow, + bestPlan.plan.nOBSat, bestPlan.plan.wsFlags)); + if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){ + pWInfo->nOBSat = pOrderBy->nExpr; } if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){ assert( pWInfo->eDistinct==0 ); pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } @@ -106782,11 +106985,11 @@ pLevel->iIdxCur = pParse->nTab++; } }else{ pLevel->iIdxCur = -1; } - notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor); + sWBI.notValid &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor); pLevel->iFrom = (u8)bestJ; if( bestPlan.plan.nRow>=(double)1 ){ pParse->nQueryLoop *= bestPlan.plan.nRow; } @@ -106814,12 +107017,12 @@ } /* If the total query only selects a single row, then the ORDER BY ** clause is irrelevant. */ - if( (andFlags & WHERE_UNIQUE)!=0 && ppOrderBy ){ - *ppOrderBy = 0; + if( (andFlags & WHERE_UNIQUE)!=0 && pOrderBy ){ + pWInfo->nOBSat = pOrderBy->nExpr; } /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** The one-pass algorithm only works if the WHERE clause constraints @@ -106835,13 +107038,14 @@ ** searching those tables. */ sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ notReady = ~(Bitmask)0; pWInfo->nRowOut = (double)1; - for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){ + for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){ Table *pTab; /* Table to open */ int iDb; /* Index of database containing table/index */ + struct SrcList_item *pTabItem; pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; pLevel->iTabCur = pTabItem->iCursor; pWInfo->nRowOut *= pLevel->plan.nRow; @@ -106873,11 +107077,11 @@ }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){ - constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel); + constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel); }else #endif if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ Index *pIx = pLevel->plan.u.pIdx; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); @@ -106887,24 +107091,24 @@ sqlite3VdbeAddOp4(v, OP_OpenRead, iIndexCur, pIx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIx->zName)); } sqlite3CodeVerifySchema(pParse, iDb); - notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor); + notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; - for(i=0; i<nTabList; i++){ - pLevel = &pWInfo->a[i]; - explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags); - notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady); + for(ii=0; ii<nTabList; ii++){ + pLevel = &pWInfo->a[ii]; + explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); + notReady = codeOneLoopStart(pWInfo, ii, wctrlFlags, notReady); pWInfo->iContinue = pLevel->addrCont; } #ifdef SQLITE_TEST /* For testing and debugging use only */ /* Record in the query plan information about the current table @@ -106911,15 +107115,17 @@ ** and the index used to access it (if any). If the table itself ** is not used, its name is just '{}'. If no index is used ** the index is listed as "{}". If the primary key is used the ** index name is '*'. */ - for(i=0; i<nTabList; i++){ + for(ii=0; ii<nTabList; ii++){ char *z; int n; int w; - pLevel = &pWInfo->a[i]; + struct SrcList_item *pTabItem; + + pLevel = &pWInfo->a[ii]; w = pLevel->plan.wsFlags; pTabItem = &pTabList->a[pLevel->iFrom]; z = pTabItem->zAlias; if( z==0 ) z = pTabItem->pTab->zName; n = sqlite3Strlen30(z); @@ -112874,10 +113080,11 @@ ){ sqlite3_mutex_enter(db->mutex); db->busyHandler.xFunc = xBusy; db->busyHandler.pArg = pArg; db->busyHandler.nBusy = 0; + db->busyTimeout = 0; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK @@ -112911,12 +113118,12 @@ ** This routine installs a default busy handler that waits for the ** specified number of milliseconds before returning 0. */ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ if( ms>0 ){ - db->busyTimeout = ms; sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); + db->busyTimeout = ms; }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } @@ -114771,12 +114978,11 @@ ** with various optimizations disabled to verify that the same answer ** is obtained in every case. */ case SQLITE_TESTCTRL_OPTIMIZATIONS: { sqlite3 *db = va_arg(ap, sqlite3*); - int x = va_arg(ap,int); - db->flags = (x & SQLITE_OptMask) | (db->flags & ~SQLITE_OptMask); + db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff); break; } #ifdef SQLITE_N_KEYWORD /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord) Index: src/sqlite3.h ================================================================== --- src/sqlite3.h +++ src/sqlite3.h @@ -107,11 +107,11 @@ ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.15" #define SQLITE_VERSION_NUMBER 3007015 -#define SQLITE_SOURCE_ID "2012-09-17 21:24:01 698b2a28004a9a2f0eabaadf36d833da4400b2bf" +#define SQLITE_SOURCE_ID "2012-09-28 00:44:28 1e874629d7cf568368b912b295bd3001147d0b52" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -4749,10 +4749,13 @@ ** successfully. An [error code] is returned otherwise.)^ ** ** ^Shared cache is disabled by default. But this might change in ** future releases of SQLite. Applications that care about shared ** cache setting should set it explicitly. +** +** This interface is threadsafe on processors where writing a +** 32-bit integer is atomic. ** ** See Also: [SQLite Shared-Cache Mode] */ SQLITE_API int sqlite3_enable_shared_cache(int); Index: src/th_tcl.c ================================================================== --- src/th_tcl.c +++ src/th_tcl.c @@ -32,17 +32,11 @@ ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6)) /* ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using ** Tcl_EvalObjv instead of invoking the objProc directly. */ -#define USE_TCL_EVALOBJV 1 -#endif - -#ifdef _WIN32 -# include <windows.h> -#else -# include <dlfcn.h> +# define USE_TCL_EVALOBJV 1 #endif /* ** These macros are designed to reduce the redundant code required to marshal ** arguments from TH1 to Tcl. @@ -71,10 +65,76 @@ ** context. */ #define GET_CTX_TCL_INTERP(ctx) \ ((struct TclContext *)(ctx))->interp +/* +** Define the Tcl shared library name, some exported function names, and some +** cross-platform macros for use with the Tcl stubs mechanism, when enabled. + */ +#if defined(USE_TCL_STUBS) +# if defined(_WIN32) +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# ifndef TCL_LIBRARY_NAME +# define TCL_LIBRARY_NAME "tcl86.dll\0" +# endif +# ifndef TCL_MINOR_OFFSET +# define TCL_MINOR_OFFSET (4) +# endif +# ifndef dlopen +# define dlopen(a,b) (void *)LoadLibrary((a)); +# endif +# ifndef dlsym +# define dlsym(a,b) GetProcAddress((HANDLE)(a),(b)); +# endif +# ifndef dlclose +# define dlclose(a) FreeLibrary((HANDLE)(a)); +# endif +# else +# include <dlfcn.h> +# if defined(__CYGWIN__) +# ifndef TCL_LIBRARY_NAME +# define TCL_LIBRARY_NAME "libtcl8.6.dll\0" +# endif +# ifndef TCL_MINOR_OFFSET +# define TCL_MINOR_OFFSET (8) +# endif +# elif defined(__APPLE__) +# ifndef TCL_LIBRARY_NAME +# define TCL_LIBRARY_NAME "libtcl8.6.dylib\0" +# endif +# ifndef TCL_MINOR_OFFSET +# define TCL_MINOR_OFFSET (8) +# endif +# else +# ifndef TCL_LIBRARY_NAME +# define TCL_LIBRARY_NAME "libtcl8.6.so\0" +# endif +# ifndef TCL_MINOR_OFFSET +# define TCL_MINOR_OFFSET (8) +# endif +# endif /* defined(__CYGWIN__) */ +# endif /* defined(_WIN32) */ +# ifndef TCL_FINDEXECUTABLE_NAME +# define TCL_FINDEXECUTABLE_NAME "_Tcl_FindExecutable" +# endif +# ifndef TCL_CREATEINTERP_NAME +# define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp" +# endif +#endif /* defined(USE_TCL_STUBS) */ + +/* +** The function pointer types for Tcl_FindExecutable and Tcl_CreateInterp are +** needed when the Tcl library is being loaded dynamically by a stubs-enabled +** application (i.e. the inverse of using a stubs-enabled package). These are +** the only Tcl API functions that MUST be called prior to being able to call +** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). + */ +typedef void (tcl_FindExecutableProc) (CONST char * argv0); +typedef Tcl_Interp *(tcl_CreateInterpProc) (void); + /* ** Creates and initializes a Tcl interpreter for use with the specified TH1 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied ** by the caller. This must be declared here because quite a few functions in ** this file need to use it before it can be defined. @@ -108,10 +168,13 @@ ** copied from and should be kept in sync with the one in "main.c". */ struct TclContext { int argc; char **argv; + void *library; + tcl_FindExecutableProc *xFindExecutable; + tcl_CreateInterpProc *xCreateInterp; Tcl_Interp *interp; }; /* ** Syntax: @@ -230,18 +293,18 @@ int argc, const char **argv, int *argl ){ Tcl_Interp *tclInterp; -#ifndef USE_TCL_EVALOBJV +#if !defined(USE_TCL_EVALOBJV) Tcl_Command command; Tcl_CmdInfo cmdInfo; #endif int rc; int nResult; const char *zResult; -#ifndef USE_TCL_EVALOBJV +#if !defined(USE_TCL_EVALOBJV) Tcl_Obj *objPtr; #endif USE_ARGV_TO_OBJV(); if ( createTclInterp(interp, ctx)!=TH_OK ){ @@ -254,11 +317,11 @@ if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); return TH_ERROR; } Tcl_Preserve((ClientData)tclInterp); -#ifndef USE_TCL_EVALOBJV +#if !defined(USE_TCL_EVALOBJV) objPtr = Tcl_NewStringObj(argv[1], argl[1]); Tcl_IncrRefCount(objPtr); command = Tcl_GetCommandFromObj(tclInterp, objPtr); if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){ Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); @@ -273,11 +336,11 @@ return TH_ERROR; } Tcl_DecrRefCount(objPtr); #endif COPY_ARGV_TO_OBJV(); -#ifdef USE_TCL_EVALOBJV +#if defined(USE_TCL_EVALOBJV) rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); #else Tcl_ResetResult(tclInterp); rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); #endif @@ -381,10 +444,77 @@ /* Remove the Tcl integration commands. */ for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){ Th_RenameCommand(th1Interp, aCommand[i].zName, -1, NULL, 0); } } + +/* +** When Tcl stubs support is enabled, attempts to dynamically load the Tcl +** shared library and fetch the function pointers necessary to create an +** interpreter and initialize the stubs mechanism; otherwise, simply setup +** the function pointers provided by the caller with the statically linked +** functions. + */ +static int loadTcl( + Th_Interp *interp, + void **pLibrary, + tcl_FindExecutableProc **pxFindExecutable, + tcl_CreateInterpProc **pxCreateInterp +){ +#if defined(USE_TCL_STUBS) + char fileName[] = TCL_LIBRARY_NAME; +#endif + if( !pLibrary || !pxFindExecutable || !pxCreateInterp ){ + Th_ErrorMessage(interp, + "Invalid Tcl loader argument(s)", (const char *)"", 0); + return TH_ERROR; + } +#if defined(USE_TCL_STUBS) + do { + void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL); + if( library ){ + tcl_FindExecutableProc *xFindExecutable; + tcl_CreateInterpProc *xCreateInterp; + const char *procName = TCL_FINDEXECUTABLE_NAME; + xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1); + if( !xFindExecutable ){ + xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName); + } + if( !xFindExecutable ){ + Th_ErrorMessage(interp, + "Could not locate Tcl_FindExecutable", (const char *)"", 0); + dlclose(library); + return TH_ERROR; + } + procName = TCL_CREATEINTERP_NAME; + xCreateInterp = (tcl_CreateInterpProc *)dlsym(library, procName + 1); + if( !xCreateInterp ){ + xCreateInterp = (tcl_CreateInterpProc *)dlsym(library, procName); + } + if( !xCreateInterp ){ + Th_ErrorMessage(interp, + "Could not locate Tcl_CreateInterp", (const char *)"", 0); + dlclose(library); + return TH_ERROR; + } + *pLibrary = library; + *pxFindExecutable = xFindExecutable; + *pxCreateInterp = xCreateInterp; + return TH_OK; + } + } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ + Th_ErrorMessage(interp, + "Could not load Tcl shared library \"" TCL_LIBRARY_NAME "\"", + (const char *)"", 0); + return TH_ERROR; +#else + *pLibrary = 0; + *pxFindExecutable = Tcl_FindExecutable; + *pxCreateInterp = Tcl_CreateInterp; + return TH_OK; +#endif +} /* ** Sets the "argv0", "argc", and "argv" script variables in the Tcl interpreter ** based on the supplied command line arguments. */ @@ -451,72 +581,36 @@ ){ struct TclContext *tclContext = (struct TclContext *)pContext; int argc; char **argv; char *argv0 = 0; -#ifdef USE_TCL_STUBS -#ifdef _WIN32 - WCHAR lib[] = L"tcl87.dll"; -#define minver lib[4] -#define dlopen(a,b) (void *)LoadLibraryW(a); -#define dlsym(a,b) GetProcAddress((HANDLE)(a),b); -#else -#ifdef __CYGWIN__ - char lib[] = "libtcl8.7.dll"; -#else - char lib[] = "libtcl8.7.so"; -#endif -#define minver lib[8] -#endif - void *handle = NULL; - void (*findExecutable)(const char *) = 0; - Tcl_Interp *(*createInterp)() = 0; -#endif /* USE_TCL_STUBS */ Tcl_Interp *tclInterp; if ( !tclContext ){ Th_ErrorMessage(interp, "Invalid Tcl context", (const char *)"", 0); return TH_ERROR; } if ( tclContext->interp ){ return TH_OK; + } + if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable, + &tclContext->xCreateInterp)!=TH_OK ){ + return TH_ERROR; } argc = tclContext->argc; argv = tclContext->argv; if( argc>0 && argv ){ argv0 = argv[0]; } -#ifdef USE_TCL_STUBS - while( --minver>'3' ){ - handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL); - if( handle ) { - const char *sym = "_Tcl_FindExecutable"; - findExecutable = (void (*)(const char *)) dlsym(handle, sym+1); - if (!findExecutable) - findExecutable = (void (*)(const char *)) dlsym(handle, sym); - sym = "_Tcl_CreateInterp"; - createInterp = (Tcl_Interp * (*)(void)) dlsym(handle, sym+1); - if (!createInterp) - createInterp = (Tcl_Interp * (*)(void)) dlsym(handle, sym); - break; - } - } - if( !handle ){ - Th_ErrorMessage(interp, - "Could not create Tcl interpreter", (const char *)"", 0); - return TH_ERROR; - } -# undef Tcl_FindExecutable -# define Tcl_FindExecutable findExecutable -# undef Tcl_CreateInterp -# define Tcl_CreateInterp createInterp -#endif /* USE_TCL_STUBS */ - Tcl_FindExecutable(argv0); - tclInterp = Tcl_CreateInterp(); - if( !tclInterp || !Tcl_InitStubs(tclInterp, "8.4", 0) - || Tcl_InterpDeleted(tclInterp) ){ + tclContext->xFindExecutable(argv0); + tclInterp = tclContext->xCreateInterp(); + if( !tclInterp || +#if defined(USE_TCL_STUBS) + !Tcl_InitStubs(tclInterp, "8.4", 0) || +#endif + Tcl_InterpDeleted(tclInterp) ){ Th_ErrorMessage(interp, "Could not create Tcl interpreter", (const char *)"", 0); return TH_ERROR; } tclContext->interp = tclInterp; Index: win/Makefile.mingw ================================================================== --- win/Makefile.mingw +++ win/Makefile.mingw @@ -47,10 +47,14 @@ # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 + +#### Load Tcl using the stubs mechanism +# +# FOSSIL_ENABLE_TCL_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 @@ -96,11 +100,15 @@ TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # +ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 +else +LIBTCL = -ltcl86 +endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used @@ -136,12 +144,20 @@ RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL -TCC += -DFOSSIL_ENABLE_TCL=1 -DUSE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 +# Either statically linked or via stubs +ifdef FOSSIL_ENABLE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +else +TCC += -DSTATIC_BUILD +RCC += -DSTATIC_BUILD +endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 @@ -171,11 +187,15 @@ #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL +ifdef FOSSIL_ENABLE_TCL_STUBS +LIB += -lkernel32 -lws2_32 +else LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 +endif else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only Index: win/Makefile.mingw.mistachkin ================================================================== --- win/Makefile.mingw.mistachkin +++ win/Makefile.mingw.mistachkin @@ -46,11 +46,15 @@ # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # -# FOSSIL_ENABLE_TCL = 1 +FOSSIL_ENABLE_TCL = 1 + +#### Load Tcl using the stubs mechanism +# +FOSSIL_ENABLE_TCL_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 @@ -96,11 +100,15 @@ TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # +ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 +else +LIBTCL = -ltcl86 +endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used @@ -136,12 +144,20 @@ RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL -TCC += -DFOSSIL_ENABLE_TCL=1 -DUSE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 +# Either statically linked or via stubs +ifdef FOSSIL_ENABLE_TCL_STUBS +TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS +else +TCC += -DSTATIC_BUILD +RCC += -DSTATIC_BUILD +endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 @@ -171,11 +187,15 @@ #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL +ifdef FOSSIL_ENABLE_TCL_STUBS +LIB += -lkernel32 -lws2_32 +else LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 +endif else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only Index: win/fossil.rc ================================================================== --- win/fossil.rc +++ win/fossil.rc @@ -90,10 +90,15 @@ #ifdef FOSSIL_ENABLE_SSL VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0" #endif #ifdef FOSSIL_ENABLE_TCL VALUE "TclEnabled", "Yes, Tcl " TCL_PATCH_LEVEL "\0" +#ifdef FOSSIL_ENABLE_TCL_STUBS + VALUE "TclStubsEnabled", "Yes\0" +#else + VALUE "TclStubsEnabled", "No\0" +#endif #endif #ifdef FOSSIL_ENABLE_JSON VALUE "JsonEnabled", "Yes, cson\0" #endif END