From eb9d55cd5edd2b12655340602e102565e97b70e0 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Mon, 4 Nov 2024 10:16:27 -0800 Subject: [PATCH 01/11] Re-add test code --- Makefile | 2 +- libstuff/sqlite3.c | 32442 ++++++++++++++++++++++++++++------- libstuff/sqlite3.h | 156 +- test/lib/BedrockTester.cpp | 2 +- 4 files changed, 26308 insertions(+), 6294 deletions(-) diff --git a/Makefile b/Makefile index 71a34084a..a1737b23d 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ $(INTERMEDIATEDIR)/%.d $(INTERMEDIATEDIR)/%.o: %.cpp mbedtls/library/libmbedcryp # SQLITE_MAX_MMAP_SIZE is set to 16TB. $(INTERMEDIATEDIR)/%.o: %.c @mkdir -p $(dir $@) - $(CC) $(BEDROCK_OPTIM_COMPILE_FLAG) -fPIC $(AMALGAMATION_FLAGS) -o $@ -c $< + $(CC) -g $(BEDROCK_OPTIM_COMPILE_FLAG) -fPIC $(AMALGAMATION_FLAGS) -o $@ -c $< # Bring in the dependency files. This will cause them to be created if necessary. This is skipped if we're cleaning, as # they'll just get deleted anyway. diff --git a/libstuff/sqlite3.c b/libstuff/sqlite3.c index b4403e43e..c27032cb5 100644 --- a/libstuff/sqlite3.c +++ b/libstuff/sqlite3.c @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 492a0a85438586a8ccd9629239304f4df3f2. +** 0c7b45cfde33ed7f3a9b8ddbe249093968bd. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 @@ -79,6 +79,16 @@ # define SQLITE_TCLAPI #endif +#define SQLITE_ENABLE_HCT 1 +#ifdef SQLITE_ENABLE_HCT +# define SQLITE_OMIT_SHARED_CACHE 1 +#endif + +#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS +# define SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS 1 +#endif +#define SQLITE_SHARED_MAPPING 1 + /* ** Include the header file used to customize the compiler options for MSVC. ** This should be done first so that it can successfully prevent spurious @@ -257,13 +267,10 @@ /* ** Macro to disable warnings about missing "break" at the end of a "case". */ -#if defined(__has_attribute) -# if __has_attribute(fallthrough) -# define deliberate_fall_through __attribute__((fallthrough)); -# endif -#endif -#if !defined(deliberate_fall_through) -# define deliberate_fall_through +#if GCC_VERSION>=7000000 +# define deliberate_fall_through __attribute__((fallthrough)); +#else +# define deliberate_fall_through #endif /* @@ -465,7 +472,7 @@ extern "C" { */ #define SQLITE_VERSION "3.47.0" #define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-11-01 15:25:34 492a0a85438586a8ccd9629239304f4df3f2c6391ec05dd9837b7a553313d632" +#define SQLITE_SOURCE_ID "2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -5932,15 +5939,6 @@ SQLITE_API int sqlite3_create_window_function( ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. -** -** [[SQLITE_SELFORDER1]]
SQLITE_SELFORDER1
-** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate -** that internally orders the values provided to the first argument. The -** ordered-set aggregate SQL notation with a single ORDER BY term can be -** used to invoke this function. If the ordered-set aggregate notation is -** used on a function that lacks this flag, then an error is raised. Note -** that the ordered-set aggregate syntax is only available if SQLite is -** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option. **
** */ @@ -5949,7 +5947,6 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 -#define SQLITE_SELFORDER1 0x002000000 /* ** CAPI3REF: Deprecated Functions @@ -6147,7 +6144,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** -** Every [application-defined SQL function] that invokes this interface +** Every [application-defined SQL function] that invoke this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() @@ -7754,11 +7751,9 @@ struct sqlite3_module { ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a -** mask of SQLITE_INDEX_SCAN_* flags. One such flag is -** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] -** output to show the idxNum has hex instead of as decimal. Another flag is -** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will -** return at most one row. +** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - +** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite +** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -7822,9 +7817,7 @@ struct sqlite3_index_info { ** [sqlite3_index_info].idxFlags field to some combination of ** these bits. */ -#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */ -#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */ - /* in EXPLAIN QUERY PLAN */ +#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes @@ -8661,7 +8654,6 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ -#define SQLITE_TESTCTRL_GETOPT 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8682,7 +8674,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 -#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 +#define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -11278,6 +11271,9 @@ SQLITE_API int sqlite3_commit_status( # undef double #endif +SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset); +SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); + #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 @@ -13513,10 +13509,6 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** -** In all cases, matches are visited in (column ASC, offset ASC) order. -** i.e. all those in column 0, sorted by offset, followed by those in -** column 1, etc. -** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -13583,32 +13575,9 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. -** -** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the locale associated -** with column iCol of the current row. Usually, there is no associated -** locale, and output parameters (*pzLocale) and (*pnLocale) are set -** to NULL and 0, respectively. However, if the fts5_locale() function -** was used to associate a locale with the value when it was inserted -** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated -** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) -** is set to the size in bytes of the buffer, not including the -** nul-terminator. -** -** If successful, SQLITE_OK is returned. Or, if an error occurs, an -** SQLite error code is returned. The final value of the output parameters -** is undefined in this case. -** -** xTokenize_v2: -** Tokenize text using the tokenizer belonging to the FTS5 table. This -** API is the same as the xTokenize() API, except that it allows a tokenizer -** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 4 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -13650,15 +13619,6 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); - - /* Below this point are iVersion>=4 only */ - int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); - int (*xTokenize_v2)(Fts5Context*, - const char *pText, int nText, /* Text to tokenize */ - const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ - void *pCtx, /* Context passed to xToken() */ - int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ - ); }; /* @@ -13671,7 +13631,6 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting -** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -13680,7 +13639,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer_v2 object +** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -13704,7 +13663,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The third argument indicates the reason that FTS5 is requesting +** The second argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -13728,13 +13687,6 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** -** The sixth and seventh arguments passed to xTokenize() - pLocale and -** nLocale - are a pointer to a buffer containing the locale to use for -** tokenization (e.g. "en_US") and its size in bytes, respectively. The -** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in -** which case nLocale is always 0) to indicate that the tokenizer should -** use its default locale. -** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -13758,30 +13710,6 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** -** If the tokenizer is registered using an fts5_tokenizer_v2 object, -** then the xTokenize() method has two additional arguments - pLocale -** and nLocale. These specify the locale that the tokenizer should use -** for the current request. If pLocale and nLocale are both 0, then the -** tokenizer should use its default locale. Otherwise, pLocale points to -** an nLocale byte buffer containing the name of the locale to use as utf-8 -** text. pLocale is not nul-terminated. -** -** FTS5_TOKENIZER -** -** There is also an fts5_tokenizer object. This is an older, deprecated, -** version of fts5_tokenizer_v2. It is similar except that: -** -** -** -** Legacy fts5_tokenizer tokenizers must be registered using the -** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). -** -** Tokenizer implementations registered using either API may be retrieved -** using both xFindTokenizer() and xFindTokenizer_v2(). -** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -13890,33 +13818,6 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; -typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; -struct fts5_tokenizer_v2 { - int iVersion; /* Currently always 2 */ - - int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); - void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, - void *pCtx, - int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, - const char *pLocale, int nLocale, - int (*xToken)( - void *pCtx, /* Copy of 2nd argument to xTokenize() */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Pointer to buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Byte offset of token within input text */ - int iEnd /* Byte offset of end of token within input text */ - ) - ); -}; - -/* -** New code should use the fts5_tokenizer_v2 type to define tokenizer -** implementations. The following type is included for legacy applications -** that still use it. -*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -13936,7 +13837,6 @@ struct fts5_tokenizer { ); }; - /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -13956,7 +13856,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -13983,25 +13883,6 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); - - /* APIs below this point are only available if iVersion>=3 */ - - /* Create a new tokenizer */ - int (*xCreateTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void *pUserData, - fts5_tokenizer_v2 *pTokenizer, - void (*xDestroy)(void*) - ); - - /* Find an existing tokenizer */ - int (*xFindTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void **ppUserData, - fts5_tokenizer_v2 **ppTokenizer - ); }; /* @@ -14414,7 +14295,7 @@ struct fts5_api { ** which case memory allocation statistics are disabled by default. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) -# define SQLITE_DEFAULT_MEMSTATUS 1 +# define SQLITE_DEFAULT_MEMSTATUS 0 #endif /* @@ -14775,174 +14656,174 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_ID 9 -#define TK_COMMIT 10 -#define TK_END 11 -#define TK_ROLLBACK 12 -#define TK_SAVEPOINT 13 -#define TK_RELEASE 14 -#define TK_TO 15 -#define TK_TABLE 16 -#define TK_CREATE 17 -#define TK_IF 18 -#define TK_NOT 19 -#define TK_EXISTS 20 -#define TK_TEMP 21 -#define TK_LP 22 -#define TK_RP 23 -#define TK_AS 24 -#define TK_COMMA 25 -#define TK_WITHOUT 26 -#define TK_ABORT 27 -#define TK_ACTION 28 -#define TK_AFTER 29 -#define TK_ANALYZE 30 -#define TK_ASC 31 -#define TK_ATTACH 32 -#define TK_BEFORE 33 -#define TK_BY 34 -#define TK_CASCADE 35 -#define TK_CAST 36 -#define TK_CONFLICT 37 -#define TK_DATABASE 38 -#define TK_DESC 39 -#define TK_DETACH 40 -#define TK_EACH 41 -#define TK_EXCLUSIVE 42 -#define TK_FAIL 43 -#define TK_OR 44 -#define TK_AND 45 -#define TK_IS 46 -#define TK_ISNOT 47 -#define TK_MATCH 48 -#define TK_LIKE_KW 49 -#define TK_BETWEEN 50 -#define TK_IN 51 -#define TK_ISNULL 52 -#define TK_NOTNULL 53 -#define TK_NE 54 -#define TK_EQ 55 -#define TK_GT 56 -#define TK_LE 57 -#define TK_LT 58 -#define TK_GE 59 -#define TK_ESCAPE 60 -#define TK_COLUMNKW 61 -#define TK_DO 62 -#define TK_FOR 63 -#define TK_IGNORE 64 -#define TK_INITIALLY 65 -#define TK_INSTEAD 66 -#define TK_NO 67 -#define TK_KEY 68 -#define TK_OF 69 -#define TK_OFFSET 70 -#define TK_PRAGMA 71 -#define TK_RAISE 72 -#define TK_RECURSIVE 73 -#define TK_REPLACE 74 -#define TK_RESTRICT 75 -#define TK_ROW 76 -#define TK_ROWS 77 -#define TK_TRIGGER 78 -#define TK_VACUUM 79 -#define TK_VIEW 80 -#define TK_VIRTUAL 81 -#define TK_WITH 82 -#define TK_NULLS 83 -#define TK_FIRST 84 -#define TK_LAST 85 -#define TK_CURRENT 86 -#define TK_FOLLOWING 87 -#define TK_PARTITION 88 -#define TK_PRECEDING 89 -#define TK_RANGE 90 -#define TK_UNBOUNDED 91 -#define TK_EXCLUDE 92 -#define TK_GROUPS 93 -#define TK_OTHERS 94 -#define TK_TIES 95 -#define TK_GENERATED 96 -#define TK_ALWAYS 97 -#define TK_MATERIALIZED 98 -#define TK_REINDEX 99 -#define TK_RENAME 100 -#define TK_CTIME_KW 101 -#define TK_ANY 102 -#define TK_BITAND 103 -#define TK_BITOR 104 -#define TK_LSHIFT 105 -#define TK_RSHIFT 106 -#define TK_PLUS 107 -#define TK_MINUS 108 -#define TK_STAR 109 -#define TK_SLASH 110 -#define TK_REM 111 -#define TK_CONCAT 112 -#define TK_PTR 113 -#define TK_COLLATE 114 -#define TK_BITNOT 115 -#define TK_ON 116 -#define TK_INDEXED 117 -#define TK_STRING 118 -#define TK_JOIN_KW 119 -#define TK_CONSTRAINT 120 -#define TK_DEFAULT 121 -#define TK_NULL 122 -#define TK_PRIMARY 123 -#define TK_UNIQUE 124 -#define TK_CHECK 125 -#define TK_REFERENCES 126 -#define TK_AUTOINCR 127 -#define TK_INSERT 128 -#define TK_DELETE 129 -#define TK_UPDATE 130 -#define TK_SET 131 -#define TK_DEFERRABLE 132 -#define TK_FOREIGN 133 -#define TK_DROP 134 -#define TK_UNION 135 -#define TK_ALL 136 -#define TK_EXCEPT 137 -#define TK_INTERSECT 138 -#define TK_SELECT 139 -#define TK_VALUES 140 -#define TK_DISTINCT 141 -#define TK_DOT 142 -#define TK_FROM 143 -#define TK_JOIN 144 -#define TK_USING 145 -#define TK_ORDER 146 -#define TK_GROUP 147 -#define TK_HAVING 148 -#define TK_LIMIT 149 -#define TK_WHERE 150 -#define TK_RETURNING 151 -#define TK_INTO 152 -#define TK_NOTHING 153 -#define TK_FLOAT 154 -#define TK_BLOB 155 -#define TK_INTEGER 156 -#define TK_VARIABLE 157 -#define TK_CASE 158 -#define TK_WHEN 159 -#define TK_THEN 160 -#define TK_ELSE 161 -#define TK_INDEX 162 -#define TK_ALTER 163 -#define TK_ADD 164 -#define TK_WINDOW 165 -#define TK_OVER 166 -#define TK_FILTER 167 -#define TK_COLUMN 168 -#define TK_AGG_FUNCTION 169 -#define TK_AGG_COLUMN 170 -#define TK_TRUEFALSE 171 -#define TK_FUNCTION 172 -#define TK_UPLUS 173 -#define TK_UMINUS 174 -#define TK_TRUTH 175 -#define TK_REGISTER 176 -#define TK_CONCURRENT 177 +#define TK_CONCURRENT 10 +#define TK_COMMIT 11 +#define TK_END 12 +#define TK_ROLLBACK 13 +#define TK_SAVEPOINT 14 +#define TK_RELEASE 15 +#define TK_TO 16 +#define TK_TABLE 17 +#define TK_CREATE 18 +#define TK_IF 19 +#define TK_NOT 20 +#define TK_EXISTS 21 +#define TK_TEMP 22 +#define TK_LP 23 +#define TK_RP 24 +#define TK_AS 25 +#define TK_COMMA 26 +#define TK_WITHOUT 27 +#define TK_ABORT 28 +#define TK_ACTION 29 +#define TK_AFTER 30 +#define TK_ANALYZE 31 +#define TK_ASC 32 +#define TK_ATTACH 33 +#define TK_BEFORE 34 +#define TK_BY 35 +#define TK_CASCADE 36 +#define TK_CAST 37 +#define TK_CONFLICT 38 +#define TK_DATABASE 39 +#define TK_DESC 40 +#define TK_DETACH 41 +#define TK_EACH 42 +#define TK_EXCLUSIVE 43 +#define TK_FAIL 44 +#define TK_OR 45 +#define TK_AND 46 +#define TK_IS 47 +#define TK_ISNOT 48 +#define TK_MATCH 49 +#define TK_LIKE_KW 50 +#define TK_BETWEEN 51 +#define TK_IN 52 +#define TK_ISNULL 53 +#define TK_NOTNULL 54 +#define TK_NE 55 +#define TK_EQ 56 +#define TK_GT 57 +#define TK_LE 58 +#define TK_LT 59 +#define TK_GE 60 +#define TK_ESCAPE 61 +#define TK_COLUMNKW 62 +#define TK_DO 63 +#define TK_FOR 64 +#define TK_IGNORE 65 +#define TK_INITIALLY 66 +#define TK_INSTEAD 67 +#define TK_NO 68 +#define TK_KEY 69 +#define TK_OF 70 +#define TK_OFFSET 71 +#define TK_PRAGMA 72 +#define TK_RAISE 73 +#define TK_RECURSIVE 74 +#define TK_REPLACE 75 +#define TK_RESTRICT 76 +#define TK_ROW 77 +#define TK_ROWS 78 +#define TK_TRIGGER 79 +#define TK_VACUUM 80 +#define TK_VIEW 81 +#define TK_VIRTUAL 82 +#define TK_WITH 83 +#define TK_NULLS 84 +#define TK_FIRST 85 +#define TK_LAST 86 +#define TK_CURRENT 87 +#define TK_FOLLOWING 88 +#define TK_PARTITION 89 +#define TK_PRECEDING 90 +#define TK_RANGE 91 +#define TK_UNBOUNDED 92 +#define TK_EXCLUDE 93 +#define TK_GROUPS 94 +#define TK_OTHERS 95 +#define TK_TIES 96 +#define TK_GENERATED 97 +#define TK_ALWAYS 98 +#define TK_MATERIALIZED 99 +#define TK_REINDEX 100 +#define TK_RENAME 101 +#define TK_CTIME_KW 102 +#define TK_ANY 103 +#define TK_BITAND 104 +#define TK_BITOR 105 +#define TK_LSHIFT 106 +#define TK_RSHIFT 107 +#define TK_PLUS 108 +#define TK_MINUS 109 +#define TK_STAR 110 +#define TK_SLASH 111 +#define TK_REM 112 +#define TK_CONCAT 113 +#define TK_PTR 114 +#define TK_COLLATE 115 +#define TK_BITNOT 116 +#define TK_ON 117 +#define TK_INDEXED 118 +#define TK_STRING 119 +#define TK_JOIN_KW 120 +#define TK_CONSTRAINT 121 +#define TK_DEFAULT 122 +#define TK_NULL 123 +#define TK_PRIMARY 124 +#define TK_UNIQUE 125 +#define TK_CHECK 126 +#define TK_REFERENCES 127 +#define TK_AUTOINCR 128 +#define TK_INSERT 129 +#define TK_DELETE 130 +#define TK_UPDATE 131 +#define TK_SET 132 +#define TK_DEFERRABLE 133 +#define TK_FOREIGN 134 +#define TK_DROP 135 +#define TK_UNION 136 +#define TK_ALL 137 +#define TK_EXCEPT 138 +#define TK_INTERSECT 139 +#define TK_SELECT 140 +#define TK_VALUES 141 +#define TK_DISTINCT 142 +#define TK_DOT 143 +#define TK_FROM 144 +#define TK_JOIN 145 +#define TK_USING 146 +#define TK_ORDER 147 +#define TK_GROUP 148 +#define TK_HAVING 149 +#define TK_LIMIT 150 +#define TK_WHERE 151 +#define TK_RETURNING 152 +#define TK_INTO 153 +#define TK_NOTHING 154 +#define TK_FLOAT 155 +#define TK_BLOB 156 +#define TK_INTEGER 157 +#define TK_VARIABLE 158 +#define TK_CASE 159 +#define TK_WHEN 160 +#define TK_THEN 161 +#define TK_ELSE 162 +#define TK_INDEX 163 +#define TK_ALTER 164 +#define TK_ADD 165 +#define TK_WINDOW 166 +#define TK_OVER 167 +#define TK_FILTER 168 +#define TK_COLUMN 169 +#define TK_AGG_FUNCTION 170 +#define TK_AGG_COLUMN 171 +#define TK_TRUEFALSE 172 +#define TK_FUNCTION 173 +#define TK_UPLUS 174 +#define TK_UMINUS 175 +#define TK_TRUTH 176 +#define TK_REGISTER 177 #define TK_VECTOR 178 #define TK_SELECT_COLUMN 179 #define TK_IF_NULL_ROW 180 @@ -14980,8 +14861,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define float sqlite_int64 -# define fabs(X) ((X)<0?-(X):(X)) -# define sqlite3IsOverflow(X) 0 # define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) @@ -15660,7 +15539,6 @@ typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; -typedef struct Subquery Subquery; typedef struct SrcItem SrcItem; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ @@ -16331,8 +16209,6 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); #endif -SQLITE_PRIVATE void sqlite3PagerSetCommitTime(Pager *pPager, u64 *aCommitTime); - #endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ @@ -16374,6 +16250,9 @@ SQLITE_PRIVATE void sqlite3PagerSetCommitTime(Pager *pPager, u64 *aCommitTime); #define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ +typedef struct BtCursorMethods BtCursorMethods; +typedef struct BtreeMethods BtreeMethods; + /* ** Forward declarations of structure */ @@ -16759,6 +16638,21 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif +#define BTREE_DIR_NONE 0 +#define BTREE_DIR_FORWARD 1 +#define BTREE_DIR_REVERSE 2 + +#ifdef SQLITE_ENABLE_HCT +SQLITE_PRIVATE void sqlite3BtreeCursorDir(BtCursor*, int eDir); +SQLITE_PRIVATE int sqlite3HctVtabInit(sqlite3*); +SQLITE_PRIVATE int sqlite3BtreeSchemaLoaded(Btree *pBt); +#else +# define sqlite3BtreeCursorDir(a,b) +# define sqlite3BtreeSchemaLoaded(x) SQLITE_OK +#endif + +SQLITE_PRIVATE int sqlite3BtreePragma(Btree *pBtree, char **aFnctl); +SQLITE_PRIVATE int sqlite3BtreeIdxDelete(BtCursor*, UnpackedRecord*); #endif /* SQLITE_BTREE_H */ @@ -16800,19 +16694,6 @@ typedef struct Vdbe Vdbe; */ typedef struct sqlite3_value Mem; typedef struct SubProgram SubProgram; -typedef struct SubrtnSig SubrtnSig; - -/* -** A signature for a reusable subroutine that materializes the RHS of -** an IN operator. -*/ -struct SubrtnSig { - int selId; /* SELECT-id for the SELECT statement on the RHS */ - char *zAff; /* Affinity of the overall IN expression */ - int iTable; /* Ephemeral table generated by the subroutine */ - int iAddr; /* Subroutine entry address */ - int regReturn; /* Register used to hold return address */ -}; /* ** A single instruction of the virtual machine has an opcode @@ -16841,7 +16722,6 @@ struct VdbeOp { u32 *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ - SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif @@ -16909,7 +16789,6 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ #define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ #define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ -#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -16970,8 +16849,8 @@ typedef struct VdbeOpList VdbeOpList; #define OP_If 16 /* jump */ #define OP_IfNot 17 /* jump */ #define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */ -#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_IfNullRow 19 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_Not 20 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ #define OP_SeekLT 21 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */ @@ -16995,24 +16874,24 @@ typedef struct VdbeOpList VdbeOpList; #define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxGE 43 /* jump, synopsis: key=r[P3@P4] */ -#define OP_Or 44 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ -#define OP_And 45 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetRead 44 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_Or 45 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 46 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Program 48 /* jump0 */ #define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ #define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ #define OP_IfNotZero 51 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_IsNull 52 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ -#define OP_NotNull 53 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ -#define OP_Ne 54 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ -#define OP_Eq 55 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ -#define OP_Gt 56 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ -#define OP_Le 57 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ -#define OP_Lt 58 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ -#define OP_ElseEq 60 /* jump, same as TK_ESCAPE */ -#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_DecrJumpZero 52 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IsNull 53 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 54 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 55 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 56 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 57 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 58 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 59 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ +#define OP_ElseEq 61 /* jump, same as TK_ESCAPE */ #define OP_IncrVacuum 62 /* jump */ #define OP_VNext 63 /* jump */ #define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ @@ -17054,23 +16933,23 @@ typedef struct VdbeOpList VdbeOpList; #define OP_SetCookie 100 #define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */ -#define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 107 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 108 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 109 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 110 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 111 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 112 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 103 /* synopsis: root=P2 iDb=P3 */ +#define OP_BitAnd 104 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 105 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 106 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 108 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 109 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 110 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 111 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 112 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 113 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ #define OP_OpenDup 114 -#define OP_BitNot 115 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ -#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */ +#define OP_OpenAutoindex 115 /* synopsis: nColumn=P2 */ +#define OP_BitNot 116 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ #define OP_OpenEphemeral 117 /* synopsis: nColumn=P2 */ -#define OP_String8 118 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_SorterOpen 119 +#define OP_SorterOpen 118 +#define OP_String8 119 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ #define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */ #define OP_Close 122 @@ -17105,8 +16984,8 @@ typedef struct VdbeOpList VdbeOpList; #define OP_DropTable 151 #define OP_DropIndex 152 #define OP_DropTrigger 153 -#define OP_Real 154 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_IntegrityCk 155 +#define OP_IntegrityCk 154 +#define OP_Real 155 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ #define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */ #define OP_Param 157 #define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */ @@ -17157,24 +17036,24 @@ typedef struct VdbeOpList VdbeOpList; #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\ /* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\ -/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\ +/* 16 */ 0x03, 0x03, 0x01, 0x01, 0x12, 0xc9, 0xc9, 0xc9,\ /* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\ /* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\ -/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x26, 0x26, 0x23, 0x0b,\ -/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x41,\ +/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x23, 0x26, 0x26, 0x0b,\ +/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x41,\ /* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ /* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\ -/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x26,\ +/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x00,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x26, 0x00, 0x40, 0x12, 0x40, 0x40, 0x10, 0x00,\ +/* 112 */ 0x26, 0x26, 0x40, 0x40, 0x12, 0x40, 0x00, 0x10,\ /* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\ /* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\ /* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04,\ +/* 152 */ 0x00, 0x00, 0x00, 0x10, 0x06, 0x10, 0x00, 0x04,\ /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ /* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ @@ -17435,59 +17314,171 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr); #endif - -#define COMMIT_TIME_START 0 -#define COMMIT_TIME_BEFORE_HALT 1 -#define COMMIT_TIME_BEFORE_VDBECOMMIT 2 - -#define COMMIT_TIME_BEFORE_PHASEONE 3 -#define COMMIT_TIME_START_FIXUNLOCKED 4 -#define COMMIT_TIME_START_RELOCATE1 5 -#define COMMIT_TIME_START_RELOCATE2 6 - -#define COMMIT_TIME_OTHERWRITERS 7 -#define COMMIT_TIME_RELOCATE1COUNT 8 -#define COMMIT_TIME_RELOCATE2COUNT 9 - -#define COMMIT_TIME_AFTER_FIXUNLOCKED 10 - -#define COMMIT_TIME_BEFORE_WALFRAMES 11 -#define COMMIT_TIME_AFTER_CHANGECOUNTER 13 -#define COMMIT_TIME_AFTER_RESTARTLOG 14 -#define COMMIT_TIME_AFTER_WRITEHDR 15 - -#define COMMIT_TIME_OSWRITE 16 - -#define COMMIT_TIME_AFTER_WRITEFRAMES 17 - -#define COMMIT_TIME_BEFORE_WALINDEX 18 -#define COMMIT_TIME_AFTER_WALINDEX 19 -#define COMMIT_TIME_AFTER_WALINDEXHDR 20 - -#define COMMIT_TIME_WALFRAMESFLAGS 21 - -#define COMMIT_TIME_AFTER_WALFRAMES 22 - -#define COMMIT_TIME_BEFORE_PHASETWO 23 -#define COMMIT_TIME_AFTER_PHASETWO 24 - -#define COMMIT_TIME_AFTER_VDBECOMMIT 25 -#define COMMIT_TIME_AFTER_HALT 26 -#define COMMIT_TIME_FINISH 27 - -#define COMMIT_TIME_N 28 - -/* #define COMMIT_TIME_TIMEOUT (2*1000*1000) */ -#define COMMIT_TIME_TIMEOUT (10*1000) /* 10ms threshold */ - -SQLITE_PRIVATE void sqlite3CommitTimeLog(u64*); -SQLITE_PRIVATE u64 sqlite3STimeNow(); -SQLITE_PRIVATE void sqlite3CommitTimeSet(u64*, int); - #endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include btreeModules.h in the middle of sqliteInt.h **********/ +/************** Begin file btreeModules.h ************************************/ +SQLITE_PRIVATE int sqlite3HctBtreeCursor(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); +SQLITE_PRIVATE sqlite3_uint64 sqlite3HctBtreeSeekCount(Btree*); +SQLITE_PRIVATE Pgno sqlite3HctBtreeLastPage(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeClose(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeSetCacheSize(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeSetSpillSize(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeSetMmapLimit(Btree*, sqlite3_int64); +SQLITE_PRIVATE int sqlite3HctBtreeSetPagerFlags(Btree*, unsigned); +SQLITE_PRIVATE int sqlite3HctBtreeSetPageSize(Btree*, int, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeGetPageSize(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeGetReserveNoMutex(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeGetRequestedReserve(Btree*); +SQLITE_PRIVATE Pgno sqlite3HctBtreeMaxPageCount(Btree*, Pgno); +SQLITE_PRIVATE int sqlite3HctBtreeSecureDelete(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeSetAutoVacuum(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeGetAutoVacuum(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeNewDb(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeBeginTrans(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3HctBtreeIncrVacuum(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseOne(Btree*, const char*); +SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseTwo(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeCommit(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeTripAllCursors(Btree*, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeRollback(Btree*, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeBeginStmt(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeSavepoint(Btree*, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeCreateTable(Btree*, Pgno*, int); +SQLITE_PRIVATE int sqlite3HctBtreeClearTable(Btree*, int, i64*); +SQLITE_PRIVATE int sqlite3HctBtreeDropTable(Btree*, int, int*); +SQLITE_PRIVATE void sqlite3HctBtreeGetMeta(Btree*, int, u32*); +SQLITE_PRIVATE int sqlite3HctBtreeUpdateMeta(Btree*, int, u32); +SQLITE_PRIVATE int sqlite3HctBtreePragma(Btree*, char**); +SQLITE_PRIVATE Pager *sqlite3HctBtreePager(Btree*); +SQLITE_PRIVATE const char *sqlite3HctBtreeGetFilename(Btree*); +SQLITE_PRIVATE const char *sqlite3HctBtreeGetJournalname(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeTxnState(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeIsInBackup(Btree*); +SQLITE_PRIVATE void *sqlite3HctBtreeSchema(Btree*, int, void(*)(void *)); +SQLITE_PRIVATE int sqlite3HctBtreeSchemaLocked(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeIsReadonly(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeSetVersion(Btree*, int); +SQLITE_PRIVATE int sqlite3HctBtreeIntegrityCheck(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); +SQLITE_PRIVATE int sqlite3HctBtreeCheckpoint(Btree*, int, int *, int *); +SQLITE_PRIVATE int sqlite3HctBtreeExclusiveLock(Btree*); +SQLITE_PRIVATE int sqlite3HctBtreeNext(BtCursor*, int); +SQLITE_PRIVATE int sqlite3HctBtreeCursorHasMoved(BtCursor*); +SQLITE_PRIVATE void sqlite3HctBtreeClearCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreeCursorRestore(BtCursor*, int*); +SQLITE_PRIVATE void sqlite3HctBtreeCursorHintFlags(BtCursor*, unsigned); +SQLITE_PRIVATE int sqlite3HctBtreeCloseCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValid(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValidNN(BtCursor*); +SQLITE_PRIVATE i64 sqlite3HctBtreeIntegerKey(BtCursor*); +SQLITE_PRIVATE void sqlite3HctBtreeCursorPin(BtCursor*); +SQLITE_PRIVATE void sqlite3HctBtreeCursorUnpin(BtCursor*); +SQLITE_PRIVATE u32 sqlite3HctBtreePayloadSize(BtCursor*); +SQLITE_PRIVATE sqlite3_int64 sqlite3HctBtreeMaxRecordSize(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreePayload(BtCursor*, u32, u32, void*); +SQLITE_PRIVATE int sqlite3HctBtreePayloadChecked(BtCursor*, u32, u32, void *); +SQLITE_PRIVATE const void *sqlite3HctBtreePayloadFetch(BtCursor*, u32*); +SQLITE_PRIVATE int sqlite3HctBtreeFirst(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3HctBtreeLast(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3HctBtreeTableMoveto(BtCursor*, i64, int, int*); +SQLITE_PRIVATE int sqlite3HctBtreeIndexMoveto(BtCursor*, UnpackedRecord*, int*); +SQLITE_PRIVATE void sqlite3HctBtreeCursorDir(BtCursor*, int); +SQLITE_PRIVATE int sqlite3HctBtreeEof(BtCursor*); +SQLITE_PRIVATE i64 sqlite3HctBtreeRowCountEst(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreePrevious(BtCursor*, int); +SQLITE_PRIVATE int sqlite3HctBtreeInsert(BtCursor*, const BtreePayload*, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeDelete(BtCursor*, u8); +SQLITE_PRIVATE int sqlite3HctBtreeIdxDelete(BtCursor*, UnpackedRecord*); +SQLITE_PRIVATE int sqlite3HctBtreePutData(BtCursor*, u32, u32, void*); +SQLITE_PRIVATE void sqlite3HctBtreeIncrblobCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreeCursorHasHint(BtCursor*, unsigned int); +SQLITE_PRIVATE int sqlite3HctBtreeTransferRow(BtCursor*, BtCursor*, i64); +SQLITE_PRIVATE int sqlite3HctBtreeClearTableOfCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3HctBtreeCount(sqlite3*, BtCursor*, i64*); +SQLITE_PRIVATE int sqlite3StockBtreeCursor(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); +SQLITE_PRIVATE sqlite3_uint64 sqlite3StockBtreeSeekCount(Btree*); +SQLITE_PRIVATE Pgno sqlite3StockBtreeLastPage(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeClose(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeSetCacheSize(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeSetSpillSize(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeSetMmapLimit(Btree*, sqlite3_int64); +SQLITE_PRIVATE int sqlite3StockBtreeSetPagerFlags(Btree*, unsigned); +SQLITE_PRIVATE int sqlite3StockBtreeSetPageSize(Btree*, int, int, int); +SQLITE_PRIVATE int sqlite3StockBtreeGetPageSize(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeGetReserveNoMutex(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeGetRequestedReserve(Btree*); +SQLITE_PRIVATE Pgno sqlite3StockBtreeMaxPageCount(Btree*, Pgno); +SQLITE_PRIVATE int sqlite3StockBtreeSecureDelete(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeSetAutoVacuum(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeGetAutoVacuum(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeNewDb(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeBeginTrans(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3StockBtreeIncrVacuum(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeCommitPhaseOne(Btree*, const char*); +SQLITE_PRIVATE int sqlite3StockBtreeCommitPhaseTwo(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeCommit(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeTripAllCursors(Btree*, int, int); +SQLITE_PRIVATE int sqlite3StockBtreeRollback(Btree*, int, int); +SQLITE_PRIVATE int sqlite3StockBtreeBeginStmt(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeSavepoint(Btree*, int, int); +SQLITE_PRIVATE int sqlite3StockBtreeCreateTable(Btree*, Pgno*, int); +SQLITE_PRIVATE int sqlite3StockBtreeClearTable(Btree*, int, i64*); +SQLITE_PRIVATE int sqlite3StockBtreeDropTable(Btree*, int, int*); +SQLITE_PRIVATE void sqlite3StockBtreeGetMeta(Btree*, int, u32*); +SQLITE_PRIVATE int sqlite3StockBtreeUpdateMeta(Btree*, int, u32); +SQLITE_PRIVATE int sqlite3StockBtreePragma(Btree*, char**); +SQLITE_PRIVATE Pager *sqlite3StockBtreePager(Btree*); +SQLITE_PRIVATE const char *sqlite3StockBtreeGetFilename(Btree*); +SQLITE_PRIVATE const char *sqlite3StockBtreeGetJournalname(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeTxnState(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeIsInBackup(Btree*); +SQLITE_PRIVATE void *sqlite3StockBtreeSchema(Btree*, int, void(*)(void *)); +SQLITE_PRIVATE int sqlite3StockBtreeSchemaLocked(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeIsReadonly(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeSetVersion(Btree*, int); +SQLITE_PRIVATE int sqlite3StockBtreeIntegrityCheck(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); +SQLITE_PRIVATE int sqlite3StockBtreeCheckpoint(Btree*, int, int *, int *); +SQLITE_PRIVATE int sqlite3StockBtreeExclusiveLock(Btree*); +SQLITE_PRIVATE int sqlite3StockBtreeNext(BtCursor*, int); +SQLITE_PRIVATE int sqlite3StockBtreeCursorHasMoved(BtCursor*); +SQLITE_PRIVATE void sqlite3StockBtreeClearCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreeCursorRestore(BtCursor*, int*); +SQLITE_PRIVATE void sqlite3StockBtreeCursorHintFlags(BtCursor*, unsigned); +SQLITE_PRIVATE int sqlite3StockBtreeCloseCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValid(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValidNN(BtCursor*); +SQLITE_PRIVATE i64 sqlite3StockBtreeIntegerKey(BtCursor*); +SQLITE_PRIVATE void sqlite3StockBtreeCursorPin(BtCursor*); +SQLITE_PRIVATE void sqlite3StockBtreeCursorUnpin(BtCursor*); +SQLITE_PRIVATE u32 sqlite3StockBtreePayloadSize(BtCursor*); +SQLITE_PRIVATE sqlite3_int64 sqlite3StockBtreeMaxRecordSize(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreePayload(BtCursor*, u32, u32, void*); +SQLITE_PRIVATE int sqlite3StockBtreePayloadChecked(BtCursor*, u32, u32, void *); +SQLITE_PRIVATE const void *sqlite3StockBtreePayloadFetch(BtCursor*, u32*); +SQLITE_PRIVATE int sqlite3StockBtreeFirst(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3StockBtreeLast(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3StockBtreeTableMoveto(BtCursor*, i64, int, int*); +SQLITE_PRIVATE int sqlite3StockBtreeIndexMoveto(BtCursor*, UnpackedRecord*, int*); +SQLITE_PRIVATE void sqlite3StockBtreeCursorDir(BtCursor*, int); +SQLITE_PRIVATE int sqlite3StockBtreeEof(BtCursor*); +SQLITE_PRIVATE i64 sqlite3StockBtreeRowCountEst(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreePrevious(BtCursor*, int); +SQLITE_PRIVATE int sqlite3StockBtreeInsert(BtCursor*, const BtreePayload*, int, int); +SQLITE_PRIVATE int sqlite3StockBtreeDelete(BtCursor*, u8); +SQLITE_PRIVATE int sqlite3StockBtreeIdxDelete(BtCursor*, UnpackedRecord*); +SQLITE_PRIVATE int sqlite3StockBtreePutData(BtCursor*, u32, u32, void*); +SQLITE_PRIVATE void sqlite3StockBtreeIncrblobCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreeCursorHasHint(BtCursor*, unsigned int); +SQLITE_PRIVATE int sqlite3StockBtreeTransferRow(BtCursor*, BtCursor*, i64); +SQLITE_PRIVATE int sqlite3StockBtreeClearTableOfCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3StockBtreeCount(sqlite3*, BtCursor*, i64*); +SQLITE_PRIVATE BtCursor *sqlite3StockBtreeFakeValidCursor(void); + + +/************** End of btreeModules.h ****************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ /* @@ -18180,57 +18171,16 @@ struct sqlite3 { u32 aCommit[5]; #endif - u64 *aPrepareTime; - u64 *aSchemaTime; -}; - -#define PREPARE_TIME_START 0 -#define PREPARE_TIME_BEGINPARSE 1 -#define PREPARE_TIME_BEGINPRAGMA 2 - -#define PREPARE_TIME_BEGINAUTHCHECK 3 -#define PREPARE_TIME_ENDAUTHCHECK 4 -#define PREPARE_TIME_BEGINLOADSCHEMA 5 -#define PREPARE_TIME_ENDLOADSCHEMA 6 - - -#define PREPARE_TIME_BEGINCACHESIZE 7 -#define PREPARE_TIME_BEGINSETCACHESIZE 8 -#define PREPARE_TIME_ENDSETCACHESIZE 9 -#define PREPARE_TIME_ENDCACHESIZE 10 -#define PREPARE_TIME_ENDPRAGMA 11 -#define PREPARE_TIME_ENDPARSE 12 -#define PREPARE_TIME_FINISH 13 - -#define PREPARE_TIME_N 14 - - + /* Used as part of testing hctree commits */ + void (*xMtCommit)(void*, int); + void *pMtCommitCtx; -#define SCHEMA_TIME_START 0 -#define SCHEMA_TIME_AFTER_CREATE_1 1 -#define SCHEMA_TIME_AFTER_OPEN_TRANS 2 -#define SCHEMA_TIME_AFTER_GET_META 3 -#define SCHEMA_TIME_AFTER_FIX_ENCODING 4 -#define SCHEMA_TIME_AFTER_SETCACHESIZE 5 -#define SCHEMA_TIME_BEGIN_EXEC 6 -#define SCHEMA_TIME_BEFORE_STEP 7 -#define SCHEMA_TIME_BEFORE_PREPARE 8 -#define SCHEMA_TIME_BEFORE_FINALIZE 9 -#define SCHEMA_TIME_BEGIN_ANALYZE_LOAD 10 -#define SCHEMA_TIME_END_ANALYZE_LOAD 11 -#define SCHEMA_TIME_FINISH 12 - -#define SCHEMA_TIME_N 13 -#define SCHEMA_TIME_TIMEOUT (2 * 1000 * 1000) - - - -#define sqlite3PrepareTimeSet(x,y) sqlite3CommitTimeSet(x,y) -SQLITE_PRIVATE void sqlite3PrepareTimeLog(const char *zSql, int nSql, u64 *aPrepareTime); -SQLITE_PRIVATE void sqlite3SchemaTimeLog(u64 *aSchemaTime); - -#define PREPARE_TIME_TIMEOUT (2 * 1000 * 1000) /* 2 second timeout */ + /* The sqlite3_hct_journal_validation_hook() callback */ + void *pValidateArg; + int (*xValidate)(void*, i64, const char*, const void*, int, i64); + int bHctMigrate; +}; /* ** Candidate values for sqlite3.eConcurrent @@ -18359,7 +18309,6 @@ SQLITE_PRIVATE void sqlite3SchemaTimeLog(u64 *aSchemaTime); #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ -#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -19082,6 +19031,7 @@ struct FKey { struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ + u16 nUniqField; u16 nKeyField; /* Number of key columns in the index */ u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ @@ -19347,15 +19297,9 @@ struct AggInfo { ** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg. ** The assert()s that are part of this macro verify that constraint. */ -#ifndef NDEBUG #define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I)) #define AggInfoFuncReg(A,I) \ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I)) -#else -#define AggInfoColumnReg(A,I) ((A)->iFirstReg+(I)) -#define AggInfoFuncReg(A,I) \ - ((A)->iFirstReg+(A)->nColumn+(I)) -#endif /* ** The datatype ynVar is a signed integer, either 16-bit or 32-bit. @@ -19707,16 +19651,6 @@ struct IdList { #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ -/* -** Details of the implementation of a subquery. -*/ -struct Subquery { - Select *pSelect; /* A SELECT statement used in place of a table name */ - int addrFillSub; /* Address of subroutine to initialize a subquery */ - int regReturn; /* Register holding return address of addrFillSub */ - int regResult; /* Registers holding results of a co-routine */ -}; - /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. @@ -19729,40 +19663,29 @@ struct Subquery { ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. ** -** Aggressive use of "union" helps keep the size of the object small. This -** has been shown to boost performance, in addition to saving memory. -** Access to union elements is gated by the following rules which should -** always be checked, either by an if-statement or by an assert(). +** Union member validity: ** -** Field Only access if this is true -** --------------- ----------------------------------- -** u1.zIndexedBy fg.isIndexedBy -** u1.pFuncArg fg.isTabFunc +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy ** -** u2.pIBIndex fg.isIndexedBy -** u2.pCteUse fg.isCte -** -** u3.pOn !fg.isUsing -** u3.pUsing fg.isUsing -** -** u4.zDatabase !fg.fixedSchema && !fg.isSubquery -** u4.pSchema fg.fixedSchema -** u4.pSubq fg.isSubquery -** -** See also the sqlite3SrcListDelete() routine for assert() statements that -** check invariants on the fields of this object, especially the flags -** inside the fg struct. +** u2.pIBIndex fg.isIndexedBy && !fg.isCte +** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { + Schema *pSchema; /* Schema to which this item is fixed */ + char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ - Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */ + Table *pTab; /* An SQL table corresponding to zName */ + Select *pSelect; /* A SELECT statement used in place of a table name */ + int addrFillSub; /* Address of subroutine to manifest a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ + int regResult; /* Registers holding results of a co-routine */ struct { u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ - unsigned isSubquery :1; /* True if this term is a subquery */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned isMaterialized:1; /* This is a materialized view */ @@ -19776,10 +19699,12 @@ struct SrcItem { unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */ unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ unsigned rowidUsed :1; /* The ROWID of this table is referenced */ - unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */ - unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ + union { + Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ + IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ + } u3; Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ union { char *zIndexedBy; /* Identifier from "INDEXED BY " clause */ @@ -19790,15 +19715,6 @@ struct SrcItem { Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ } u2; - union { - Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ - IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ - } u3; - union { - Schema *pSchema; /* Schema to which this item is fixed */ - char *zDatabase; /* Name of database holding this table */ - Subquery *pSubq; /* Description of a subquery */ - } u4; }; /* @@ -20058,10 +19974,8 @@ struct Select { #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ #define SF_Correlated 0x20000000 /* True if references the outer context */ -/* True if SrcItem X is a subquery that has SF_NestedFrom */ -#define IsNestedFrom(X) \ - ((X)->fg.isSubquery && \ - ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0) +/* True if S exists and has SF_NestedFrom */ +#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined @@ -20091,11 +20005,7 @@ struct Select { ** SRT_Set The result must be a single column. Store each ** row of result as the key in table pDest->iSDParm. ** Apply the affinity pDest->affSdst before storing -** results. if pDest->iSDParm2 is positive, then it is -** a regsiter holding a Bloom filter for the IN operator -** that should be populated in addition to the -** pDest->iSDParm table. This SRT is used to -** implement "IN (SELECT ...)". +** results. Used to implement "IN (SELECT ...)". ** ** SRT_EphemTab Create an temporary table pDest->iSDParm and store ** the result there. The cursor is left open after @@ -20303,7 +20213,6 @@ struct Parse { u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ u8 bHasWith; /* True if statement contains WITH */ - u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif @@ -21453,9 +21362,6 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); -SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3*,Subquery*); -SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*); -SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); @@ -22281,6 +22187,11 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void); # define IS_STMT_SCANSTATUS(db) 0 #endif +#ifdef SQLITE_ENABLE_HCT +SQLITE_PRIVATE int sqlite3IsHct(Btree*); +SQLITE_PRIVATE int sqlite3HctSchemaOp(Btree*, const char*); +#endif + #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ @@ -22684,9 +22595,6 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC "ENABLE_OFFSET_SQL_FUNC", #endif -#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES - "ENABLE_ORDERED_SET_AGGREGATES", -#endif #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif @@ -24129,7 +24037,6 @@ struct Vdbe { int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif - u64 *aCommitTime; }; /* @@ -25005,8 +24912,8 @@ static void computeJD(DateTime *p){ Y--; M += 12; } - A = (Y+4800)/100; - B = 38 - A + (A/4); + A = Y/100; + B = 2 - A + (A/4); X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); @@ -25190,7 +25097,7 @@ static int validJulianDay(sqlite3_int64 iJD){ ** Compute the Year, Month, and Day from the julian day number. */ static void computeYMD(DateTime *p){ - int Z, alpha, A, B, C, D, E, X1; + int Z, A, B, C, D, E, X1; if( p->validYMD ) return; if( !p->validJD ){ p->Y = 2000; @@ -25201,8 +25108,8 @@ static void computeYMD(DateTime *p){ return; }else{ Z = (int)((p->iJD + 43200000)/86400000); - alpha = (int)((Z + 32044.75)/36524.25) - 52; - A = Z + 1 + alpha - ((alpha+100)/4) + 25; + A = (int)((Z - 1867216.25)/36524.25); + A = Z + 1 + A - (A/4); B = A + 1524; C = (int)((B - 122.1)/365.25); D = (36525*(C&32767))/100; @@ -32501,19 +32408,16 @@ SQLITE_API void sqlite3_str_vappendf( if( pItem->zAlias && !flag_altform2 ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else if( pItem->zName ){ - if( pItem->fg.fixedSchema==0 - && pItem->fg.isSubquery==0 - && pItem->u4.zDatabase!=0 - ){ - sqlite3_str_appendall(pAccum, pItem->u4.zDatabase); + if( pItem->zDatabase ){ + sqlite3_str_appendall(pAccum, pItem->zDatabase); sqlite3_str_append(pAccum, ".", 1); } sqlite3_str_appendall(pAccum, pItem->zName); }else if( pItem->zAlias ){ sqlite3_str_appendall(pAccum, pItem->zAlias); - }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */ - Select *pSel = pItem->u4.pSubq->pSelect; - assert( pSel!=0 ); + }else{ + Select *pSel = pItem->pSelect; + assert( pSel!=0 ); /* Because of tag-20240424-1 */ if( pSel->selFlags & SF_NestedFrom ){ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); }else if( pSel->selFlags & SF_MultiValue ){ @@ -33295,9 +33199,9 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); - if( pItem->pSTab ){ + if( pItem->pTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s", - pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab, + pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed, pItem->fg.rowidUsed ? "+rowid" : ""); } @@ -33328,30 +33232,25 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine"); if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte"); if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom"); - if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema"); - if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema"); - if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inSrc-1); n = 0; - if( pItem->fg.isSubquery ) n++; + if( pItem->pSelect ) n++; if( pItem->fg.isTabFunc ) n++; if( pItem->fg.isUsing ) n++; if( pItem->fg.isUsing ){ sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); } - if( pItem->fg.isSubquery ){ - assert( n==1 ); - if( pItem->pSTab ){ - Table *pTab = pItem->pSTab; + if( pItem->pSelect ){ + sqlite3TreeViewPush(&pView, i+1nSrc); + if( pItem->pTab ){ + Table *pTab = pItem->pTab; sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); } - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); - sqlite3TreeViewPush(&pView, 0); - sqlite3TreeViewLine(pView, "SUBQUERY"); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); + sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); sqlite3TreeViewPop(&pView); - sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); @@ -33393,7 +33292,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m n = 1000; }else{ n = 0; - if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ) n++; + if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; if( p->pGroupBy ) n++; if( p->pHaving ) n++; @@ -33419,7 +33318,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPop(&pView); } #endif - if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ){ + if( p->pSrc && p->pSrc->nSrc ){ sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, p->pSrc); @@ -37753,8 +37652,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 16 */ "If" OpHelp(""), /* 17 */ "IfNot" OpHelp(""), /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"), - /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), + /* 19 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), + /* 20 */ "Not" OpHelp("r[P2]= !r[P1]"), /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"), /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"), @@ -37778,24 +37677,24 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"), /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 43 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 44 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), - /* 45 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 44 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 45 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 46 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), /* 48 */ "Program" OpHelp(""), /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), /* 51 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 52 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), - /* 53 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), - /* 54 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), - /* 55 */ "Eq" OpHelp("IF r[P3]==r[P1]"), - /* 56 */ "Gt" OpHelp("IF r[P3]>r[P1]"), - /* 57 */ "Le" OpHelp("IF r[P3]<=r[P1]"), - /* 58 */ "Lt" OpHelp("IF r[P3]=r[P1]"), - /* 60 */ "ElseEq" OpHelp(""), - /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 52 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 53 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), + /* 54 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), + /* 55 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), + /* 56 */ "Eq" OpHelp("IF r[P3]==r[P1]"), + /* 57 */ "Gt" OpHelp("IF r[P3]>r[P1]"), + /* 58 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 59 */ "Lt" OpHelp("IF r[P3]=r[P1]"), + /* 61 */ "ElseEq" OpHelp(""), /* 62 */ "IncrVacuum" OpHelp(""), /* 63 */ "VNext" OpHelp(""), /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), @@ -37837,23 +37736,23 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 100 */ "SetCookie" OpHelp(""), /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 107 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 108 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 109 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 110 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 111 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 112 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 103 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 104 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 105 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 106 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 108 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 109 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 110 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 111 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 112 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 113 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), /* 114 */ "OpenDup" OpHelp(""), - /* 115 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), - /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 115 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 116 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), /* 117 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 118 */ "String8" OpHelp("r[P2]='P4'"), - /* 119 */ "SorterOpen" OpHelp(""), + /* 118 */ "SorterOpen" OpHelp(""), + /* 119 */ "String8" OpHelp("r[P2]='P4'"), /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), /* 122 */ "Close" OpHelp(""), @@ -37888,8 +37787,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 151 */ "DropTable" OpHelp(""), /* 152 */ "DropIndex" OpHelp(""), /* 153 */ "DropTrigger" OpHelp(""), - /* 154 */ "Real" OpHelp("r[P2]=P4"), - /* 155 */ "IntegrityCk" OpHelp(""), + /* 154 */ "IntegrityCk" OpHelp(""), + /* 155 */ "Real" OpHelp("r[P2]=P4"), /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), /* 157 */ "Param" OpHelp(""), /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), @@ -39247,7 +39146,7 @@ static pid_t randomnessPid = 0; #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ -#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX) +#ifndef SQLITE_DISABLE_DIRSYNC # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ #else # define UNIXFILE_DIRSYNC 0x00 @@ -43056,6 +42955,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ +#ifndef SQLITE_OMIT_WAL case SQLITE_FCNTL_EXTERNAL_READER: { #if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) return unixFcntlExternalReader((unixFile*)id, (int*)pArg); @@ -43064,6 +42964,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; #endif } +#endif } return SQLITE_NOTFOUND; } @@ -55475,7 +55376,6 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( pPgHdr->pData = pPage->pBuf; pPgHdr->pExtra = (void *)&pPgHdr[1]; memset(pPgHdr->pExtra, 0, 8); - assert( EIGHT_BYTE_ALIGNMENT( pPgHdr->pExtra ) ); pPgHdr->pCache = pCache; pPgHdr->pgno = pgno; pPgHdr->flags = PGHDR_CLEAN; @@ -56222,8 +56122,7 @@ static int pcache1InitBulk(PCache1 *pCache){ do{ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; pX->page.pBuf = zBulk; - pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); - assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); + pX->page.pExtra = &pX[1]; pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; @@ -56360,8 +56259,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ if( pPg==0 ) return 0; p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; p->page.pBuf = pPg; - p->page.pExtra = (u8*)p + ROUND8(sizeof(*p)); - assert( EIGHT_BYTE_ALIGNMENT( p->page.pExtra ) ); + p->page.pExtra = &p[1]; p->isBulkLocal = 0; p->isAnchor = 0; p->pLruPrev = 0; /* Initializing this saves a valgrind error */ @@ -57012,13 +56910,7 @@ static void pcache1Unpin( assert( PAGE_IS_PINNED(pPage) ); if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ - /* If pcache1.separateCache is set, temporarily set the isBulkLocal flag - ** so that pcache1RemoveFromHash() moves the page buffer to the pFree - ** list instead of sqlite3_free()ing it. */ - u16 isBulkLocal = pPage->isBulkLocal; - pPage->isBulkLocal = (u16)pcache1.separateCache; pcache1RemoveFromHash(pPage, 1); - pPage->isBulkLocal = isBulkLocal; }else{ /* Add the page to the PGroup LRU list. */ PgHdr1 **ppFirst = &pGroup->lru.pLruNext; @@ -57920,14 +57812,17 @@ SQLITE_PRIVATE int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); /* sqlite3_wal_info() data */ SQLITE_PRIVATE int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); -SQLITE_PRIVATE void sqlite3WalSetCommitTime(Wal *pWal, u64 *aCommitTime); - #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ +#ifdef SQLITE_ENABLE_HCT +# define IS_HCT(pPager) (pPager->pVfs==0) +#else +# define IS_HCT(pPager) 0 +#endif /******************* NOTES ON THE DESIGN OF THE PAGER ************************ ** @@ -58609,7 +58504,6 @@ struct Pager { Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif - u64 *aCommitTime; }; /* @@ -61170,7 +61064,6 @@ static int pagerWalFrames( pPager->aStat[PAGER_STAT_WRITE] += nList; if( pList->pgno==1 ) pager_write_changecounter(pList); - sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_AFTER_CHANGECOUNTER); rc = sqlite3WalFrames(pPager->pWal, pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags ); @@ -62034,7 +61927,6 @@ static int pagerAcquireMapPage( return SQLITE_NOMEM_BKPT; } p->pExtra = (void *)&p[1]; - assert( EIGHT_BYTE_ALIGNMENT( p->pExtra ) ); p->flags = PGHDR_MMAP; p->nRef = 1; p->pPager = pPager; @@ -64411,6 +64303,7 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){ */ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager, PgHdr *pPage1, u32 *aConflict){ int rc = pPager->errCode; + if( IS_HCT(pPager) ) return SQLITE_OK; assert( assert_pager_state(pPager) ); if( rc==SQLITE_OK ){ assert( pPager->eState==PAGER_WRITER_CACHEMOD @@ -64561,9 +64454,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( } assert( rc==SQLITE_OK ); if( ALWAYS(pList) ){ - sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_BEFORE_WALFRAMES); rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); - sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_AFTER_WALFRAMES); } sqlite3PagerUnref(pPageOne); if( rc==SQLITE_OK ){ @@ -64737,10 +64628,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( return rc; } -SQLITE_PRIVATE void sqlite3PagerSetCommitTime(Pager *pPager, u64 *aCommitTime){ - pPager->aCommitTime = aCommitTime; - sqlite3WalSetCommitTime(pPager->pWal, aCommitTime); -} /* ** When this function is called, the database file has been completely @@ -65165,6 +65052,10 @@ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ ** not yet been opened. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ +#ifdef SQLITE_ENABLE_HCT + static sqlite3_file s = {0}; + if( pPager->pVfs==0 ) return &s; +#endif return pPager->fd; } @@ -65520,6 +65411,7 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){ ** is unmodified. */ SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ + if( IS_HCT(pPager) ) return 0; assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0; if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0; @@ -66481,7 +66373,8 @@ static void walidxSetMxFrame(WalIndexHdr *pHdr, int iWal, u32 mxFrame){ assert( walidxGetMxFrame(pHdr, iWal)==mxFrame ); } -#define walidxGetFile(pHdr) (int)((pHdr)->mxFrame2 >> 31) +#define walidxGetFile(pHdr) ((pHdr)->mxFrame2 >> 31) + #define walidxSetFile(pHdr, iWal) ( \ (pHdr)->mxFrame2 = ((pHdr)->mxFrame2 & 0x7FFFFFFF) | (((u32)(iWal))<<31) \ ) @@ -66711,7 +66604,6 @@ struct Wal { #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3 *db; #endif - u64 *aCommitTime; }; /* @@ -70492,7 +70384,7 @@ static int walLockForCommit( assert( nLoop==1 || nLoop==2 ); for(iLoop=0; rc==SQLITE_OK && iLoophdr, iWal); aWalData[1] = pWal->hdr.aFrameCksum[0]; aWalData[2] = pWal->hdr.aFrameCksum[1]; - aWalData[3] = isWalMode2(pWal) ? (u32)iWal : pWal->nCkpt; + aWalData[3] = isWalMode2(pWal) ? iWal : pWal->nCkpt; } /* @@ -70801,7 +70693,7 @@ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ int rc = SQLITE_OK; int iWal = walidxGetFile(&pWal->hdr); - u32 iCmp = isWalMode2(pWal) ? (u32)iWal : pWal->nCkpt; + int iCmp = isWalMode2(pWal) ? iWal : pWal->nCkpt; assert( pWal->writeLock || aWalData[0]==pWal->hdr.mxFrame ); assert( isWalMode2(pWal) || iWal==0 ); @@ -70846,7 +70738,7 @@ static int walRestartLog(Wal *pWal){ if( isWalMode2(pWal) ){ int iApp = walidxGetFile(&pWal->hdr); - u32 nWalSize = WAL_DEFAULT_WALSIZE; + int nWalSize = WAL_DEFAULT_WALSIZE; if( pWal->mxWalSize>0 ){ nWalSize = (pWal->mxWalSize-WAL_HDRSIZE+pWal->szPage+WAL_FRAME_HDRSIZE-1) / (pWal->szPage+WAL_FRAME_HDRSIZE); @@ -70949,7 +70841,6 @@ static int walWriteToLog( sqlite3_int64 iOffset /* Start writing at this offset */ ){ int rc; - u64 t; if( iOffsetiSyncPoint && iOffset+iAmt>=p->iSyncPoint ){ int iFirstAmt = (int)(p->iSyncPoint - iOffset); rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset); @@ -70961,13 +70852,7 @@ static int walWriteToLog( rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } - if( p->pWal->aCommitTime ){ - t = sqlite3STimeNow(); - } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); - if( p->pWal->aCommitTime ){ - p->pWal->aCommitTime[COMMIT_TIME_OSWRITE] += (sqlite3STimeNow() - t); - } return rc; } @@ -71083,8 +70968,6 @@ static int walFrames( int iApp; int bWal2 = isWalMode2(pWal); - int logFlags = 0; - assert( pList ); assert( pWal->writeLock ); @@ -71105,8 +70988,6 @@ static int walFrames( return rc; } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_RESTARTLOG); - /* If this is the first frame written into the log, write the WAL ** header to the start of the WAL file. See comments at the top of ** this source file for a description of the WAL header format. @@ -71122,7 +71003,6 @@ static int walFrames( } #endif - logFlags |= (iFrame==0 ? 0x01 : 0x00); if( iFrame==0 ){ u32 iCkpt = 0; u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ @@ -71176,7 +71056,6 @@ static int walFrames( if( (int)pWal->szPage!=szPage ){ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */ } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WRITEHDR); /* Setup information needed to write frames into the WAL */ w.pWal = pWal; @@ -71188,7 +71067,6 @@ static int walFrames( szFrame = szPage + WAL_FRAME_HDRSIZE; /* Write all frames into the log file exactly once */ - logFlags |= (iFirst==0 ? 0x00 : 0x02); for(p=pList; p; p=p->pDirty){ int nDbSize; /* 0 normally. Positive == commit flag */ @@ -71227,10 +71105,8 @@ static int walFrames( p->flags |= PGHDR_WAL_APPEND; } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WRITEFRAMES); /* Recalculate checksums within the wal file if required. */ - logFlags |= (pWal->iReCksum==0 ? 0x00 : 0x04); if( isCommit && pWal->iReCksum ){ rc = walRewriteChecksums(pWal, iFrame); if( rc ) return rc; @@ -71250,7 +71126,6 @@ static int walFrames( ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ - logFlags |= (WAL_SYNC_FLAGS(sync_flags)==0 ? 0x00 : 0x08); if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ @@ -71285,8 +71160,6 @@ static int walFrames( pWal->truncateOnCommit = 0; } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_BEFORE_WALINDEX); - /* Append data to the wal-index. It is not necessary to lock the ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index ** guarantees that there are no other writers, and no data that may @@ -71305,8 +71178,6 @@ static int walFrames( rc = walIndexAppend(pWal, iApp, iFrame, pLast->pgno); } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WALINDEX); - if( rc==SQLITE_OK ){ /* Update the private copy of the header. */ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); @@ -71334,11 +71205,6 @@ static int walFrames( } } - sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WALINDEXHDR); - if( pWal->aCommitTime ){ - pWal->aCommitTime[COMMIT_TIME_WALFRAMESFLAGS] = logFlags; - } - WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok")); return rc; } @@ -71750,12 +71616,6 @@ SQLITE_PRIVATE int sqlite3WalJournalMode(Wal *pWal){ return (isWalMode2(pWal) ? PAGER_JOURNALMODE_WAL2 : PAGER_JOURNALMODE_WAL); } -SQLITE_PRIVATE void sqlite3WalSetCommitTime(Wal *pWal, u64 *aCommitTime){ - if( pWal ){ - pWal->aCommitTime = aCommitTime; - } -} - #endif /* #ifndef SQLITE_OMIT_WAL */ /************** End of wal.c *************************************************/ @@ -72128,6 +71988,7 @@ struct BtLock { ** they often do so without holding sqlite3.mutex. */ struct Btree { + const BtreeMethods *pMethods; sqlite3 *db; /* The database connection holding this btree */ BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ @@ -72251,8 +72112,6 @@ struct BtShared { BtreePtrmap *pMap; #endif int nPreformatSize; /* Size of last cell written by TransferRow() */ - - u64 *aCommitTime; }; /* @@ -72319,6 +72178,7 @@ struct CellInfo { ** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { + const BtCursorMethods *pMethods; u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ @@ -72848,6 +72708,93 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ ** Including a description of file format and an overview of operation. */ /* #include "btreeInt.h" */ +/************** Include btreeDefine.h in the middle of btree.c ***************/ +/************** Begin file btreeDefine.h *************************************/ +#define sqlite3BtreeNext sqlite3StockBtreeNext +#define sqlite3BtreeCursorHasMoved sqlite3StockBtreeCursorHasMoved +#define sqlite3BtreeClearCursor sqlite3StockBtreeClearCursor +#define sqlite3BtreeCursorRestore sqlite3StockBtreeCursorRestore +#define sqlite3BtreeCursorHintFlags sqlite3StockBtreeCursorHintFlags +#define sqlite3BtreeCloseCursor sqlite3StockBtreeCloseCursor +#define sqlite3BtreeCursorIsValid sqlite3StockBtreeCursorIsValid +#define sqlite3BtreeCursorIsValidNN sqlite3StockBtreeCursorIsValidNN +#define sqlite3BtreeIntegerKey sqlite3StockBtreeIntegerKey +#define sqlite3BtreeCursorPin sqlite3StockBtreeCursorPin +#define sqlite3BtreeCursorUnpin sqlite3StockBtreeCursorUnpin +#define sqlite3BtreePayloadSize sqlite3StockBtreePayloadSize +#define sqlite3BtreeMaxRecordSize sqlite3StockBtreeMaxRecordSize +#define sqlite3BtreePayload sqlite3StockBtreePayload +#define sqlite3BtreePayloadChecked sqlite3StockBtreePayloadChecked +#define sqlite3BtreePayloadFetch sqlite3StockBtreePayloadFetch +#define sqlite3BtreeFirst sqlite3StockBtreeFirst +#define sqlite3BtreeLast sqlite3StockBtreeLast +#define sqlite3BtreeTableMoveto sqlite3StockBtreeTableMoveto +#define sqlite3BtreeIndexMoveto sqlite3StockBtreeIndexMoveto +#define sqlite3BtreeCursorDir sqlite3StockBtreeCursorDir +#define sqlite3BtreeEof sqlite3StockBtreeEof +#define sqlite3BtreeRowCountEst sqlite3StockBtreeRowCountEst +#define sqlite3BtreePrevious sqlite3StockBtreePrevious +#define sqlite3BtreeInsert sqlite3StockBtreeInsert +#define sqlite3BtreeDelete sqlite3StockBtreeDelete +#define sqlite3BtreeIdxDelete sqlite3StockBtreeIdxDelete +#define sqlite3BtreePutData sqlite3StockBtreePutData +#define sqlite3BtreeIncrblobCursor sqlite3StockBtreeIncrblobCursor +#define sqlite3BtreeCursorHasHint sqlite3StockBtreeCursorHasHint +#define sqlite3BtreeTransferRow sqlite3StockBtreeTransferRow +#define sqlite3BtreeClearTableOfCursor sqlite3StockBtreeClearTableOfCursor +#define sqlite3BtreeCount sqlite3StockBtreeCount +#define sqlite3BtreeCursor sqlite3StockBtreeCursor +#define sqlite3BtreeSeekCount sqlite3StockBtreeSeekCount +#define sqlite3BtreeLastPage sqlite3StockBtreeLastPage +#define sqlite3BtreeClose sqlite3StockBtreeClose +#define sqlite3BtreeSetCacheSize sqlite3StockBtreeSetCacheSize +#define sqlite3BtreeSetSpillSize sqlite3StockBtreeSetSpillSize +#define sqlite3BtreeSetMmapLimit sqlite3StockBtreeSetMmapLimit +#define sqlite3BtreeSetPagerFlags sqlite3StockBtreeSetPagerFlags +#define sqlite3BtreeSetPageSize sqlite3StockBtreeSetPageSize +#define sqlite3BtreeGetPageSize sqlite3StockBtreeGetPageSize +#define sqlite3BtreeGetReserveNoMutex sqlite3StockBtreeGetReserveNoMutex +#define sqlite3BtreeGetRequestedReserve sqlite3StockBtreeGetRequestedReserve +#define sqlite3BtreeMaxPageCount sqlite3StockBtreeMaxPageCount +#define sqlite3BtreeSecureDelete sqlite3StockBtreeSecureDelete +#define sqlite3BtreeSetAutoVacuum sqlite3StockBtreeSetAutoVacuum +#define sqlite3BtreeGetAutoVacuum sqlite3StockBtreeGetAutoVacuum +#define sqlite3BtreeNewDb sqlite3StockBtreeNewDb +#define sqlite3BtreeBeginTrans sqlite3StockBtreeBeginTrans +#define sqlite3BtreeIncrVacuum sqlite3StockBtreeIncrVacuum +#define sqlite3BtreeCommitPhaseOne sqlite3StockBtreeCommitPhaseOne +#define sqlite3BtreeCommitPhaseTwo sqlite3StockBtreeCommitPhaseTwo +#define sqlite3BtreeCommit sqlite3StockBtreeCommit +#define sqlite3BtreeTripAllCursors sqlite3StockBtreeTripAllCursors +#define sqlite3BtreeRollback sqlite3StockBtreeRollback +#define sqlite3BtreeBeginStmt sqlite3StockBtreeBeginStmt +#define sqlite3BtreeSavepoint sqlite3StockBtreeSavepoint +#define sqlite3BtreeCreateTable sqlite3StockBtreeCreateTable +#define sqlite3BtreeClearTable sqlite3StockBtreeClearTable +#define sqlite3BtreeDropTable sqlite3StockBtreeDropTable +#define sqlite3BtreeGetMeta sqlite3StockBtreeGetMeta +#define sqlite3BtreeUpdateMeta sqlite3StockBtreeUpdateMeta +#define sqlite3BtreePragma sqlite3StockBtreePragma +#define sqlite3BtreePager sqlite3StockBtreePager +#define sqlite3BtreeGetFilename sqlite3StockBtreeGetFilename +#define sqlite3BtreeGetJournalname sqlite3StockBtreeGetJournalname +#define sqlite3BtreeTxnState sqlite3StockBtreeTxnState +#define sqlite3BtreeIsInBackup sqlite3StockBtreeIsInBackup +#define sqlite3BtreeSchema sqlite3StockBtreeSchema +#define sqlite3BtreeSchemaLocked sqlite3StockBtreeSchemaLocked +#define sqlite3BtreeIsReadonly sqlite3StockBtreeIsReadonly +#define sqlite3BtreeSetVersion sqlite3StockBtreeSetVersion +#define sqlite3BtreeIntegrityCheck sqlite3StockBtreeIntegrityCheck +#define sqlite3BtreeCheckpoint sqlite3StockBtreeCheckpoint +#define sqlite3BtreeExclusiveLock sqlite3StockBtreeExclusiveLock +#define sqlite3BtreeFakeValidCursor sqlite3StockBtreeFakeValidCursor +#define sqlite3BtreeCursorSize sqlite3StockBtreeCursorSize +#define sqlite3BtreeCursorZero sqlite3StockBtreeCursorZero +#define sqlite3BtreeOpen sqlite3StockBtreeOpen + + +/************** End of btreeDefine.h *****************************************/ +/************** Continuing where we left off in btree.c **********************/ /* ** The header string that appears at the beginning of every @@ -74004,11 +73951,16 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ +#ifdef SQLITE_ENABLE_HCT + assert( EIGHT_BYTE_ALIGNMENT(pCur) ); + return (CURSOR_VALID!=pCur->eState); +#else assert( EIGHT_BYTE_ALIGNMENT(pCur) || pCur==sqlite3BtreeFakeValidCursor() ); assert( offsetof(BtCursor, eState)==0 ); assert( sizeof(pCur->eState)==1 ); return CURSOR_VALID != *(u8*)pCur; +#endif } /* @@ -76062,9 +76014,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); - sqlite3PrepareTimeSet(p->db->aPrepareTime, PREPARE_TIME_BEGINSETCACHESIZE); sqlite3PagerSetCachesize(pBt->pPager, mxPage); - sqlite3PrepareTimeSet(p->db->aPrepareTime, PREPARE_TIME_ENDSETCACHESIZE); sqlite3BtreeLeave(p); return SQLITE_OK; } @@ -77441,8 +77391,6 @@ static int btreeFixUnlocked(Btree *p){ Pgno nPage = btreePagecount(pBt); u32 nFree = get4byte(&p1[36]); - sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_START_FIXUNLOCKED); - assert( pBt->pMap ); rc = sqlite3PagerUpgradeSnapshot(pPager, pPage1->pDbPage); assert( p1==pPage1->aData ); @@ -77489,7 +77437,6 @@ static int btreeFixUnlocked(Btree *p){ nCurrent = MAX(nPage, nHPage); pBt->nPage = nCurrent; - sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_START_RELOCATE1); rc = btreeRelocateRange(pBt, pMap->iFirst, iLast, &nCurrent); /* There are now no collisions with the snapshot at the head of the @@ -77506,14 +77453,6 @@ static int btreeFixUnlocked(Btree *p){ nFin--; } nFin = MAX(nFin, nHPage); - if( p->pBt->aCommitTime ){ - p->pBt->aCommitTime[COMMIT_TIME_OTHERWRITERS] = (1+nHPage-pMap->iFirst); - p->pBt->aCommitTime[COMMIT_TIME_RELOCATE1COUNT] = (1+iLast-pMap->iFirst); - p->pBt->aCommitTime[COMMIT_TIME_RELOCATE2COUNT] = (nCurrent - nFin); - } - sqlite3CommitTimeSet( - p->pBt->aCommitTime, COMMIT_TIME_START_RELOCATE2 - ); rc = btreeRelocateRange(pBt, nFin+1, nCurrent, 0); } @@ -77579,12 +77518,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ #endif if( rc==SQLITE_OK && ISCONCURRENT && p->db->eConcurrent==CONCURRENT_OPEN ){ rc = btreeFixUnlocked(p); - sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_AFTER_FIXUNLOCKED); } if( rc==SQLITE_OK ){ - sqlite3PagerSetCommitTime(pBt->pPager, p->pBt->aCommitTime); rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); - sqlite3PagerSetCommitTime(pBt->pPager, 0); } #ifndef SQLITE_OMIT_CONCURRENT if( rc==SQLITE_OK ){ @@ -77689,9 +77625,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ BtShared *pBt = p->pBt; assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); - sqlite3PagerSetCommitTime(pBt->pPager, p->pBt->aCommitTime); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); - sqlite3PagerSetCommitTime(pBt->pPager, 0); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; @@ -79325,7 +79259,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0 && pIdxKey->errCode==SQLITE_OK ){ - pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast); + pCur->curFlags &= ~BTCF_ValidOvfl; if( !pCur->pPage->isInit ){ return SQLITE_CORRUPT_BKPT; } @@ -84870,13 +84804,13 @@ SQLITE_PRIVATE int sqlite3BtreeExclusiveLock(Btree *p){ if( pSchema ){ for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ Table *pTab = (Table *)sqliteHashData(pE); - if( pTab->tnum==pgnoRoot ){ + if( pTab->tnum==(int)pgnoRoot ){ zObj = pTab->zName; zTab = 0; }else{ Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->tnum==pgnoRoot ){ + if( pIdx->tnum==(int)pgnoRoot ){ zObj = pIdx->zName; zTab = pTab->zName; } @@ -84967,6 +84901,97 @@ SQLITE_API int sqlite3_commit_status( return rc; } +/************** Include btreeUndef.h in the middle of btree.c ****************/ +/************** Begin file btreeUndef.h **************************************/ +#undef sqlite3BtreeNext +#undef sqlite3BtreeCursorHasMoved +#undef sqlite3BtreeClearCursor +#undef sqlite3BtreeCursorRestore +#undef sqlite3BtreeCursorHintFlags +#undef sqlite3BtreeCloseCursor +#undef sqlite3BtreeCursorIsValid +#undef sqlite3BtreeCursorIsValidNN +#undef sqlite3BtreeIntegerKey +#undef sqlite3BtreeCursorPin +#undef sqlite3BtreeCursorUnpin +#undef sqlite3BtreePayloadSize +#undef sqlite3BtreeMaxRecordSize +#undef sqlite3BtreePayload +#undef sqlite3BtreePayloadChecked +#undef sqlite3BtreePayloadFetch +#undef sqlite3BtreeFirst +#undef sqlite3BtreeLast +#undef sqlite3BtreeTableMoveto +#undef sqlite3BtreeIndexMoveto +#undef sqlite3BtreeCursorDir +#undef sqlite3BtreeEof +#undef sqlite3BtreeRowCountEst +#undef sqlite3BtreePrevious +#undef sqlite3BtreeInsert +#undef sqlite3BtreeDelete +#undef sqlite3BtreeIdxDelete +#undef sqlite3BtreePutData +#undef sqlite3BtreeIncrblobCursor +#undef sqlite3BtreeCursorHasHint +#undef sqlite3BtreeTransferRow +#undef sqlite3BtreeClearTableOfCursor +#undef sqlite3BtreeCount +#undef sqlite3BtreeCursor +#undef sqlite3BtreeSeekCount +#undef sqlite3BtreeLastPage +#undef sqlite3BtreeClose +#undef sqlite3BtreeSetCacheSize +#undef sqlite3BtreeSetSpillSize +#undef sqlite3BtreeSetMmapLimit +#undef sqlite3BtreeSetPagerFlags +#undef sqlite3BtreeSetPageSize +#undef sqlite3BtreeGetPageSize +#undef sqlite3BtreeGetReserveNoMutex +#undef sqlite3BtreeGetRequestedReserve +#undef sqlite3BtreeMaxPageCount +#undef sqlite3BtreeSecureDelete +#undef sqlite3BtreeSetAutoVacuum +#undef sqlite3BtreeGetAutoVacuum +#undef sqlite3BtreeNewDb +#undef sqlite3BtreeBeginTrans +#undef sqlite3BtreeIncrVacuum +#undef sqlite3BtreeCommitPhaseOne +#undef sqlite3BtreeCommitPhaseTwo +#undef sqlite3BtreeCommit +#undef sqlite3BtreeTripAllCursors +#undef sqlite3BtreeRollback +#undef sqlite3BtreeBeginStmt +#undef sqlite3BtreeSavepoint +#undef sqlite3BtreeCreateTable +#undef sqlite3BtreeClearTable +#undef sqlite3BtreeDropTable +#undef sqlite3BtreeGetMeta +#undef sqlite3BtreeUpdateMeta +#undef sqlite3BtreePragma +#undef sqlite3BtreePager +#undef sqlite3BtreeGetFilename +#undef sqlite3BtreeGetJournalname +#undef sqlite3BtreeTxnState +#undef sqlite3BtreeIsInBackup +#undef sqlite3BtreeSchema +#undef sqlite3BtreeSchemaLocked +#undef sqlite3BtreeIsReadonly +#undef sqlite3BtreeSetVersion +#undef sqlite3BtreeIntegrityCheck +#undef sqlite3BtreeCheckpoint +#undef sqlite3BtreeExclusiveLock +#undef sqlite3BtreeFakeValidCursor +#undef sqlite3BtreeCursorSize +#undef sqlite3BtreeCursorZero +#undef sqlite3BtreeOpen +#ifndef SQLITE_DEBUG +# define sqlite3BtreeSeekCount(X) 0 +#endif + + +/************** End of btreeUndef.h ******************************************/ +/************** Continuing where we left off in btree.c **********************/ + /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -85738,6 +85763,681 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ #endif /* SQLITE_OMIT_VACUUM */ /************** End of backup.c **********************************************/ +/************** Begin file btwrapper.c ***************************************/ +/* +** 2022 November 10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ + +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_AMALGAMATION +struct BtCursor { + const BtCursorMethods *pMethods; +}; + +struct Btree { + const BtreeMethods *pMethods; +}; +#endif + +SQLITE_PRIVATE int sqlite3HctBtreeCursorSize(void); +SQLITE_PRIVATE int sqlite3HctBtreeOpen(sqlite3_vfs*, const char*, sqlite3*, Btree**, int, int); +SQLITE_PRIVATE int sqlite3HctBtreeSchemaLoaded(Btree*); + +SQLITE_PRIVATE int sqlite3StockBtreeCursorSize(void); +SQLITE_PRIVATE int sqlite3StockBtreeOpen(sqlite3_vfs*, const char*, sqlite3*, Btree**,int,int); + +SQLITE_PRIVATE int sqlite3StockBtreePragma(Btree *p, char **a){ + return SQLITE_NOTFOUND; +} +SQLITE_PRIVATE void sqlite3StockBtreeCursorDir(BtCursor *p, int a){ + /* no-op */ +} + + +SQLITE_PRIVATE int sqlite3StockBtreeIdxDelete(BtCursor *p, UnpackedRecord *pRec){ + int rc = SQLITE_OK; + int res = 0; + + rc = sqlite3BtreeIndexMoveto(p, pRec, &res); + if( rc==SQLITE_OK && res==0 ){ + rc = sqlite3BtreeDelete(p, BTREE_AUXDELETE); + } + + return rc; +} + +#ifndef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValid(BtCursor *pCursor){ + return 1; +} +SQLITE_PRIVATE sqlite3_uint64 sqlite3StockBtreeSeekCount(Btree *p){ + return 0; +} +#endif + +/* BEGIN_HCT_MKBTREEWRAPPER_TCL_CODE */ +/****************************************************************** +** GENERATED CODE - DO NOT EDIT! +** +** Code generated by tool/hct_mkbtreewrapper.tcl +*/ +struct BtCursorMethods { + int(*xBtreeNext)(BtCursor*, int); + int(*xBtreeCursorHasMoved)(BtCursor*); + void(*xBtreeClearCursor)(BtCursor*); + int(*xBtreeCursorRestore)(BtCursor*, int*); + void(*xBtreeCursorHintFlags)(BtCursor*, unsigned); + int(*xBtreeCloseCursor)(BtCursor*); + int(*xBtreeCursorIsValid)(BtCursor*); + int(*xBtreeCursorIsValidNN)(BtCursor*); + i64(*xBtreeIntegerKey)(BtCursor*); + void(*xBtreeCursorPin)(BtCursor*); + void(*xBtreeCursorUnpin)(BtCursor*); + u32(*xBtreePayloadSize)(BtCursor*); + sqlite3_int64(*xBtreeMaxRecordSize)(BtCursor*); + int(*xBtreePayload)(BtCursor*, u32, u32, void*); + int(*xBtreePayloadChecked)(BtCursor*, u32, u32, void *); + const void *(*xBtreePayloadFetch)(BtCursor*, u32*); + int(*xBtreeFirst)(BtCursor*, int*); + int(*xBtreeLast)(BtCursor*, int*); + int(*xBtreeTableMoveto)(BtCursor*, i64, int, int*); + int(*xBtreeIndexMoveto)(BtCursor*, UnpackedRecord*, int*); + void(*xBtreeCursorDir)(BtCursor*, int); + int(*xBtreeEof)(BtCursor*); + i64(*xBtreeRowCountEst)(BtCursor*); + int(*xBtreePrevious)(BtCursor*, int); + int(*xBtreeInsert)(BtCursor*, const BtreePayload*, int, int); + int(*xBtreeDelete)(BtCursor*, u8); + int(*xBtreeIdxDelete)(BtCursor*, UnpackedRecord*); + int(*xBtreePutData)(BtCursor*, u32, u32, void*); + void(*xBtreeIncrblobCursor)(BtCursor*); + int(*xBtreeCursorHasHint)(BtCursor*, unsigned int); + int(*xBtreeTransferRow)(BtCursor*, BtCursor*, i64); + int(*xBtreeClearTableOfCursor)(BtCursor*); + int(*xBtreeCount)(sqlite3*, BtCursor*, i64*); +}; +struct BtreeMethods { + BtCursorMethods const *pCsrMethods; + int(*xBtreeCursor)(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); + sqlite3_uint64(*xBtreeSeekCount)(Btree*); + Pgno(*xBtreeLastPage)(Btree*); + int(*xBtreeClose)(Btree*); + int(*xBtreeSetCacheSize)(Btree*, int); + int(*xBtreeSetSpillSize)(Btree*, int); + int(*xBtreeSetMmapLimit)(Btree*, sqlite3_int64); + int(*xBtreeSetPagerFlags)(Btree*, unsigned); + int(*xBtreeSetPageSize)(Btree*, int, int, int); + int(*xBtreeGetPageSize)(Btree*); + int(*xBtreeGetReserveNoMutex)(Btree*); + int(*xBtreeGetRequestedReserve)(Btree*); + Pgno(*xBtreeMaxPageCount)(Btree*, Pgno); + int(*xBtreeSecureDelete)(Btree*, int); + int(*xBtreeSetAutoVacuum)(Btree*, int); + int(*xBtreeGetAutoVacuum)(Btree*); + int(*xBtreeNewDb)(Btree*); + int(*xBtreeBeginTrans)(Btree*, int, int*); + int(*xBtreeIncrVacuum)(Btree*); + int(*xBtreeCommitPhaseOne)(Btree*, const char*); + int(*xBtreeCommitPhaseTwo)(Btree*, int); + int(*xBtreeCommit)(Btree*); + int(*xBtreeTripAllCursors)(Btree*, int, int); + int(*xBtreeRollback)(Btree*, int, int); + int(*xBtreeBeginStmt)(Btree*, int); + int(*xBtreeSavepoint)(Btree*, int, int); + int(*xBtreeCreateTable)(Btree*, Pgno*, int); + int(*xBtreeClearTable)(Btree*, int, i64*); + int(*xBtreeDropTable)(Btree*, int, int*); + void(*xBtreeGetMeta)(Btree*, int, u32*); + int(*xBtreeUpdateMeta)(Btree*, int, u32); + int(*xBtreePragma)(Btree*, char**); + Pager *(*xBtreePager)(Btree*); + const char *(*xBtreeGetFilename)(Btree*); + const char *(*xBtreeGetJournalname)(Btree*); + int(*xBtreeTxnState)(Btree*); + int(*xBtreeIsInBackup)(Btree*); + void *(*xBtreeSchema)(Btree*, int, void(*)(void *)); + int(*xBtreeSchemaLocked)(Btree*); + int(*xBtreeIsReadonly)(Btree*); + int(*xBtreeSetVersion)(Btree*, int); + int(*xBtreeIntegrityCheck)(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); + int(*xBtreeCheckpoint)(Btree*, int, int *, int *); + int(*xBtreeExclusiveLock)(Btree*); +}; +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *p, int a){ + return p->pMethods->xBtreeNext(p, a); +} +SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *p){ + p->pMethods->xBtreeClearCursor(p); +} +SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *p, int *a){ + return p->pMethods->xBtreeCursorRestore(p, a); +} +SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *p, unsigned a){ + p->pMethods->xBtreeCursorHintFlags(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *p){ + return p->pMethods->xBtreeCursorIsValid(p); +} +SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *p){ + return p->pMethods->xBtreeCursorIsValidNN(p); +} +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *p){ + return p->pMethods->xBtreeIntegerKey(p); +} +SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *p){ + p->pMethods->xBtreeCursorPin(p); +} +SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *p){ + p->pMethods->xBtreeCursorUnpin(p); +} +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *p){ + return p->pMethods->xBtreePayloadSize(p); +} +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *p){ + return p->pMethods->xBtreeMaxRecordSize(p); +} +SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *p, u32 a, u32 b, void *c){ + return p->pMethods->xBtreePayload(p, a, b, c); +} +SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *p, u32 a, u32 b, void *c){ + return p->pMethods->xBtreePayloadChecked(p, a, b, c); +} +const void * sqlite3BtreePayloadFetch(BtCursor *p, u32 *a){ + return p->pMethods->xBtreePayloadFetch(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *p, int *a){ + return p->pMethods->xBtreeFirst(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *p, int *a){ + return p->pMethods->xBtreeLast(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeTableMoveto(BtCursor *p, i64 a, int b, int *c){ + return p->pMethods->xBtreeTableMoveto(p, a, b, c); +} +SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(BtCursor *p, UnpackedRecord *a, int *b){ + return p->pMethods->xBtreeIndexMoveto(p, a, b); +} +SQLITE_PRIVATE void sqlite3BtreeCursorDir(BtCursor *p, int a){ + p->pMethods->xBtreeCursorDir(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *p){ + return p->pMethods->xBtreeEof(p); +} +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *p){ + return p->pMethods->xBtreeRowCountEst(p); +} +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *p, int a){ + return p->pMethods->xBtreePrevious(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor *p, const BtreePayload *a, int b, int c){ + return p->pMethods->xBtreeInsert(p, a, b, c); +} +SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *p, u8 a){ + return p->pMethods->xBtreeDelete(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeIdxDelete(BtCursor *p, UnpackedRecord *a){ + return p->pMethods->xBtreeIdxDelete(p, a); +} +SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *p, u32 a, u32 b, void *c){ + return p->pMethods->xBtreePutData(p, a, b, c); +} +SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *p){ + p->pMethods->xBtreeIncrblobCursor(p); +} +SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *p, unsigned int a){ + return p->pMethods->xBtreeCursorHasHint(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *p, BtCursor *a, i64 b){ + return p->pMethods->xBtreeTransferRow(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *p){ + return p->pMethods->xBtreeClearTableOfCursor(p); +} +SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *a, BtCursor *p, i64 *b){ + return p->pMethods->xBtreeCount(a, p, b); +} +SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){ + return p->pMethods->xBtreeLastPage(p); +} +SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ + return p->pMethods->xBtreeClose(p); +} +SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int a){ + return p->pMethods->xBtreeSetCacheSize(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int a){ + return p->pMethods->xBtreeSetSpillSize(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 a){ + return p->pMethods->xBtreeSetMmapLimit(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree *p, unsigned a){ + return p->pMethods->xBtreeSetPagerFlags(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int a, int b, int c){ + return p->pMethods->xBtreeSetPageSize(p, a, b, c); +} +SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ + return p->pMethods->xBtreeGetPageSize(p); +} +SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ + return p->pMethods->xBtreeGetReserveNoMutex(p); +} +SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){ + return p->pMethods->xBtreeGetRequestedReserve(p); +} +SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno a){ + return p->pMethods->xBtreeMaxPageCount(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int a){ + if( p==0 ) return 0; + return p->pMethods->xBtreeSecureDelete(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int a){ + return p->pMethods->xBtreeSetAutoVacuum(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ + return p->pMethods->xBtreeGetAutoVacuum(p); +} +SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ + return p->pMethods->xBtreeNewDb(p); +} +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int a, int *b){ + return p->pMethods->xBtreeBeginTrans(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ + return p->pMethods->xBtreeIncrVacuum(p); +} +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *a){ + return p->pMethods->xBtreeCommitPhaseOne(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int a){ + return p->pMethods->xBtreeCommitPhaseTwo(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ + return p->pMethods->xBtreeCommit(p); +} +SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *p, int a, int b){ + if( p==0 ) return 0; + return p->pMethods->xBtreeTripAllCursors(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int a, int b){ + return p->pMethods->xBtreeRollback(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int a){ + return p->pMethods->xBtreeBeginStmt(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int a, int b){ + if( p==0 ) return 0; + return p->pMethods->xBtreeSavepoint(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *a, int b){ + return p->pMethods->xBtreeCreateTable(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int a, i64 *b){ + return p->pMethods->xBtreeClearTable(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int a, int *b){ + return p->pMethods->xBtreeDropTable(p, a, b); +} +SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int a, u32 *b){ + p->pMethods->xBtreeGetMeta(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int a, u32 b){ + return p->pMethods->xBtreeUpdateMeta(p, a, b); +} +SQLITE_PRIVATE int sqlite3BtreePragma(Btree *p, char* *a){ + return p->pMethods->xBtreePragma(p, a); +} +Pager * sqlite3BtreePager(Btree *p){ + return p->pMethods->xBtreePager(p); +} +const char * sqlite3BtreeGetFilename(Btree *p){ + return p->pMethods->xBtreeGetFilename(p); +} +const char * sqlite3BtreeGetJournalname(Btree *p){ + return p->pMethods->xBtreeGetJournalname(p); +} +SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){ + if( p==0 ) return 0; + return p->pMethods->xBtreeTxnState(p); +} +SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ + return p->pMethods->xBtreeIsInBackup(p); +} +void * sqlite3BtreeSchema(Btree *p, int a, void (*xFree)(void *)){ + return p->pMethods->xBtreeSchema(p, a, xFree); +} +SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ + return p->pMethods->xBtreeSchemaLocked(p); +} +SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ + return p->pMethods->xBtreeIsReadonly(p); +} +SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *p, int a){ + return p->pMethods->xBtreeSetVersion(p, a); +} +SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(sqlite3 *a, Btree *p, Pgno *b, Mem *c, int d, int e, int *f, char* *g){ + return p->pMethods->xBtreeIntegrityCheck(a, p, b, c, d, e, f, g); +} +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int a, int *b, int *c){ + if( p==0 ) return 0; + return p->pMethods->xBtreeCheckpoint(p, a, b, c); +} +SQLITE_PRIVATE int sqlite3BtreeExclusiveLock(Btree *p){ + return p->pMethods->xBtreeExclusiveLock(p); +} +static const BtCursorMethods hct_btcursor_methods = { + .xBtreeNext = sqlite3HctBtreeNext, + .xBtreeCursorHasMoved = sqlite3HctBtreeCursorHasMoved, + .xBtreeClearCursor = sqlite3HctBtreeClearCursor, + .xBtreeCursorRestore = sqlite3HctBtreeCursorRestore, + .xBtreeCursorHintFlags = sqlite3HctBtreeCursorHintFlags, + .xBtreeCloseCursor = sqlite3HctBtreeCloseCursor, + .xBtreeCursorIsValid = sqlite3HctBtreeCursorIsValid, + .xBtreeCursorIsValidNN = sqlite3HctBtreeCursorIsValidNN, + .xBtreeIntegerKey = sqlite3HctBtreeIntegerKey, + .xBtreeCursorPin = sqlite3HctBtreeCursorPin, + .xBtreeCursorUnpin = sqlite3HctBtreeCursorUnpin, + .xBtreePayloadSize = sqlite3HctBtreePayloadSize, + .xBtreeMaxRecordSize = sqlite3HctBtreeMaxRecordSize, + .xBtreePayload = sqlite3HctBtreePayload, + .xBtreePayloadChecked = sqlite3HctBtreePayloadChecked, + .xBtreePayloadFetch = sqlite3HctBtreePayloadFetch, + .xBtreeFirst = sqlite3HctBtreeFirst, + .xBtreeLast = sqlite3HctBtreeLast, + .xBtreeTableMoveto = sqlite3HctBtreeTableMoveto, + .xBtreeIndexMoveto = sqlite3HctBtreeIndexMoveto, + .xBtreeCursorDir = sqlite3HctBtreeCursorDir, + .xBtreeEof = sqlite3HctBtreeEof, + .xBtreeRowCountEst = sqlite3HctBtreeRowCountEst, + .xBtreePrevious = sqlite3HctBtreePrevious, + .xBtreeInsert = sqlite3HctBtreeInsert, + .xBtreeDelete = sqlite3HctBtreeDelete, + .xBtreeIdxDelete = sqlite3HctBtreeIdxDelete, + .xBtreePutData = sqlite3HctBtreePutData, + .xBtreeIncrblobCursor = sqlite3HctBtreeIncrblobCursor, + .xBtreeCursorHasHint = sqlite3HctBtreeCursorHasHint, + .xBtreeTransferRow = sqlite3HctBtreeTransferRow, + .xBtreeClearTableOfCursor = sqlite3HctBtreeClearTableOfCursor, + .xBtreeCount = sqlite3HctBtreeCount, +}; +static const BtreeMethods hct_btree_methods = { + .pCsrMethods = &hct_btcursor_methods, + .xBtreeCursor = sqlite3HctBtreeCursor, + .xBtreeSeekCount = sqlite3HctBtreeSeekCount, + .xBtreeLastPage = sqlite3HctBtreeLastPage, + .xBtreeClose = sqlite3HctBtreeClose, + .xBtreeSetCacheSize = sqlite3HctBtreeSetCacheSize, + .xBtreeSetSpillSize = sqlite3HctBtreeSetSpillSize, + .xBtreeSetMmapLimit = sqlite3HctBtreeSetMmapLimit, + .xBtreeSetPagerFlags = sqlite3HctBtreeSetPagerFlags, + .xBtreeSetPageSize = sqlite3HctBtreeSetPageSize, + .xBtreeGetPageSize = sqlite3HctBtreeGetPageSize, + .xBtreeGetReserveNoMutex = sqlite3HctBtreeGetReserveNoMutex, + .xBtreeGetRequestedReserve = sqlite3HctBtreeGetRequestedReserve, + .xBtreeMaxPageCount = sqlite3HctBtreeMaxPageCount, + .xBtreeSecureDelete = sqlite3HctBtreeSecureDelete, + .xBtreeSetAutoVacuum = sqlite3HctBtreeSetAutoVacuum, + .xBtreeGetAutoVacuum = sqlite3HctBtreeGetAutoVacuum, + .xBtreeNewDb = sqlite3HctBtreeNewDb, + .xBtreeBeginTrans = sqlite3HctBtreeBeginTrans, + .xBtreeIncrVacuum = sqlite3HctBtreeIncrVacuum, + .xBtreeCommitPhaseOne = sqlite3HctBtreeCommitPhaseOne, + .xBtreeCommitPhaseTwo = sqlite3HctBtreeCommitPhaseTwo, + .xBtreeCommit = sqlite3HctBtreeCommit, + .xBtreeTripAllCursors = sqlite3HctBtreeTripAllCursors, + .xBtreeRollback = sqlite3HctBtreeRollback, + .xBtreeBeginStmt = sqlite3HctBtreeBeginStmt, + .xBtreeSavepoint = sqlite3HctBtreeSavepoint, + .xBtreeCreateTable = sqlite3HctBtreeCreateTable, + .xBtreeClearTable = sqlite3HctBtreeClearTable, + .xBtreeDropTable = sqlite3HctBtreeDropTable, + .xBtreeGetMeta = sqlite3HctBtreeGetMeta, + .xBtreeUpdateMeta = sqlite3HctBtreeUpdateMeta, + .xBtreePragma = sqlite3HctBtreePragma, + .xBtreePager = sqlite3HctBtreePager, + .xBtreeGetFilename = sqlite3HctBtreeGetFilename, + .xBtreeGetJournalname = sqlite3HctBtreeGetJournalname, + .xBtreeTxnState = sqlite3HctBtreeTxnState, + .xBtreeIsInBackup = sqlite3HctBtreeIsInBackup, + .xBtreeSchema = sqlite3HctBtreeSchema, + .xBtreeSchemaLocked = sqlite3HctBtreeSchemaLocked, + .xBtreeIsReadonly = sqlite3HctBtreeIsReadonly, + .xBtreeSetVersion = sqlite3HctBtreeSetVersion, + .xBtreeIntegrityCheck = sqlite3HctBtreeIntegrityCheck, + .xBtreeCheckpoint = sqlite3HctBtreeCheckpoint, + .xBtreeExclusiveLock = sqlite3HctBtreeExclusiveLock, +}; + +static const BtCursorMethods stock_btcursor_methods = { + .xBtreeNext = sqlite3StockBtreeNext, + .xBtreeCursorHasMoved = sqlite3StockBtreeCursorHasMoved, + .xBtreeClearCursor = sqlite3StockBtreeClearCursor, + .xBtreeCursorRestore = sqlite3StockBtreeCursorRestore, + .xBtreeCursorHintFlags = sqlite3StockBtreeCursorHintFlags, + .xBtreeCloseCursor = sqlite3StockBtreeCloseCursor, + .xBtreeCursorIsValid = sqlite3StockBtreeCursorIsValid, + .xBtreeCursorIsValidNN = sqlite3StockBtreeCursorIsValidNN, + .xBtreeIntegerKey = sqlite3StockBtreeIntegerKey, + .xBtreeCursorPin = sqlite3StockBtreeCursorPin, + .xBtreeCursorUnpin = sqlite3StockBtreeCursorUnpin, + .xBtreePayloadSize = sqlite3StockBtreePayloadSize, + .xBtreeMaxRecordSize = sqlite3StockBtreeMaxRecordSize, + .xBtreePayload = sqlite3StockBtreePayload, + .xBtreePayloadChecked = sqlite3StockBtreePayloadChecked, + .xBtreePayloadFetch = sqlite3StockBtreePayloadFetch, + .xBtreeFirst = sqlite3StockBtreeFirst, + .xBtreeLast = sqlite3StockBtreeLast, + .xBtreeTableMoveto = sqlite3StockBtreeTableMoveto, + .xBtreeIndexMoveto = sqlite3StockBtreeIndexMoveto, + .xBtreeCursorDir = sqlite3StockBtreeCursorDir, + .xBtreeEof = sqlite3StockBtreeEof, + .xBtreeRowCountEst = sqlite3StockBtreeRowCountEst, + .xBtreePrevious = sqlite3StockBtreePrevious, + .xBtreeInsert = sqlite3StockBtreeInsert, + .xBtreeDelete = sqlite3StockBtreeDelete, + .xBtreeIdxDelete = sqlite3StockBtreeIdxDelete, + .xBtreePutData = sqlite3StockBtreePutData, + .xBtreeIncrblobCursor = sqlite3StockBtreeIncrblobCursor, + .xBtreeCursorHasHint = sqlite3StockBtreeCursorHasHint, + .xBtreeTransferRow = sqlite3StockBtreeTransferRow, + .xBtreeClearTableOfCursor = sqlite3StockBtreeClearTableOfCursor, + .xBtreeCount = sqlite3StockBtreeCount, +}; +static const BtreeMethods stock_btree_methods = { + .pCsrMethods = &stock_btcursor_methods, + .xBtreeCursor = sqlite3StockBtreeCursor, + .xBtreeSeekCount = sqlite3StockBtreeSeekCount, + .xBtreeLastPage = sqlite3StockBtreeLastPage, + .xBtreeClose = sqlite3StockBtreeClose, + .xBtreeSetCacheSize = sqlite3StockBtreeSetCacheSize, + .xBtreeSetSpillSize = sqlite3StockBtreeSetSpillSize, + .xBtreeSetMmapLimit = sqlite3StockBtreeSetMmapLimit, + .xBtreeSetPagerFlags = sqlite3StockBtreeSetPagerFlags, + .xBtreeSetPageSize = sqlite3StockBtreeSetPageSize, + .xBtreeGetPageSize = sqlite3StockBtreeGetPageSize, + .xBtreeGetReserveNoMutex = sqlite3StockBtreeGetReserveNoMutex, + .xBtreeGetRequestedReserve = sqlite3StockBtreeGetRequestedReserve, + .xBtreeMaxPageCount = sqlite3StockBtreeMaxPageCount, + .xBtreeSecureDelete = sqlite3StockBtreeSecureDelete, + .xBtreeSetAutoVacuum = sqlite3StockBtreeSetAutoVacuum, + .xBtreeGetAutoVacuum = sqlite3StockBtreeGetAutoVacuum, + .xBtreeNewDb = sqlite3StockBtreeNewDb, + .xBtreeBeginTrans = sqlite3StockBtreeBeginTrans, + .xBtreeIncrVacuum = sqlite3StockBtreeIncrVacuum, + .xBtreeCommitPhaseOne = sqlite3StockBtreeCommitPhaseOne, + .xBtreeCommitPhaseTwo = sqlite3StockBtreeCommitPhaseTwo, + .xBtreeCommit = sqlite3StockBtreeCommit, + .xBtreeTripAllCursors = sqlite3StockBtreeTripAllCursors, + .xBtreeRollback = sqlite3StockBtreeRollback, + .xBtreeBeginStmt = sqlite3StockBtreeBeginStmt, + .xBtreeSavepoint = sqlite3StockBtreeSavepoint, + .xBtreeCreateTable = sqlite3StockBtreeCreateTable, + .xBtreeClearTable = sqlite3StockBtreeClearTable, + .xBtreeDropTable = sqlite3StockBtreeDropTable, + .xBtreeGetMeta = sqlite3StockBtreeGetMeta, + .xBtreeUpdateMeta = sqlite3StockBtreeUpdateMeta, + .xBtreePragma = sqlite3StockBtreePragma, + .xBtreePager = sqlite3StockBtreePager, + .xBtreeGetFilename = sqlite3StockBtreeGetFilename, + .xBtreeGetJournalname = sqlite3StockBtreeGetJournalname, + .xBtreeTxnState = sqlite3StockBtreeTxnState, + .xBtreeIsInBackup = sqlite3StockBtreeIsInBackup, + .xBtreeSchema = sqlite3StockBtreeSchema, + .xBtreeSchemaLocked = sqlite3StockBtreeSchemaLocked, + .xBtreeIsReadonly = sqlite3StockBtreeIsReadonly, + .xBtreeSetVersion = sqlite3StockBtreeSetVersion, + .xBtreeIntegrityCheck = sqlite3StockBtreeIntegrityCheck, + .xBtreeCheckpoint = sqlite3StockBtreeCheckpoint, + .xBtreeExclusiveLock = sqlite3StockBtreeExclusiveLock, +}; + +/* +** END OF GENERATED CODE +******************************************************************/ +/* END_HCT_MKBTREEWRAPPER_TCL_CODE */ + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *p){ + return p->pMethods->xBtreeSeekCount(p); +} +#endif + +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ + static BtCursor csr = {0}; + return &csr; +} + +SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ + return MAX( + sqlite3HctBtreeCursorSize(), + sqlite3StockBtreeCursorSize() + ); +} + +SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ + memset(p, 0, sqlite3BtreeCursorSize()); +} + +SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ + if( pCur->pMethods==0 ) return 0; + return pCur->pMethods->xBtreeCursorHasMoved(pCur); +} + +SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ + if( pCur->pMethods==0 ) return 0; + return pCur->pMethods->xBtreeCloseCursor(pCur); +} + +SQLITE_PRIVATE int sqlite3BtreeCursor( + Btree *p, /* The btree */ + Pgno iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ + BtCursor *pCur /* Write new cursor here */ +){ + int rc = p->pMethods->xBtreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); + pCur->pMethods = p->pMethods->pCsrMethods; + return rc; +} + +static int btWrapperUseHct( + sqlite3_vfs *pVfs, + const char *zFilename, + int *pbUseHct +){ + int rc = SQLITE_OK; + char *zFull = 0; + char *zPagemap = 0; + int bUseHct = 0; + + if( zFilename && zFilename[0] ){ + int nAlloc = pVfs->mxPathname+2; + int bExists = 0; + + zFull = (char*)sqlite3_malloc(nAlloc); + if( zFull==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + memset(zFull, 0, nAlloc); + rc = pVfs->xFullPathname(pVfs, zFilename, pVfs->mxPathname, zFull); + } + + if( rc==SQLITE_OK ){ + rc = pVfs->xAccess(pVfs, zFull, SQLITE_ACCESS_EXISTS, &bExists); + } + if( rc==SQLITE_OK ){ + zPagemap = sqlite3_mprintf("%s-pagemap", zFull); + if( zPagemap==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else if( bExists ){ + rc = pVfs->xAccess(pVfs, zPagemap, SQLITE_ACCESS_EXISTS, &bUseHct); + }else{ + sqlite3OsDelete(pVfs, zPagemap, 0); + bUseHct = sqlite3_uri_boolean(zFilename, "hctree", 0); + } + } + } + + sqlite3_free(zFull); + sqlite3_free(zPagemap); + *pbUseHct = bUseHct; + return rc; +} + +SQLITE_PRIVATE int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ + const char *zFilename, /* Name of the file containing the BTree database */ + sqlite3 *db, /* Associated database handle */ + Btree **ppBtree, /* Pointer to new Btree object written here */ + int flags, /* Options */ + int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ +){ + Btree *pBtree = 0; + int rc = SQLITE_OK; + int bUseHct = 0; + + rc = btWrapperUseHct(pVfs, zFilename, &bUseHct); + if( rc==SQLITE_OK ){ + if( bUseHct ){ + rc = sqlite3HctBtreeOpen(pVfs, zFilename, db, &pBtree, flags, vfsFlags); + if( rc==SQLITE_OK ) pBtree->pMethods = &hct_btree_methods; + }else{ + rc = sqlite3StockBtreeOpen(pVfs, zFilename, db, &pBtree, flags, vfsFlags); + if( rc==SQLITE_OK ) pBtree->pMethods = &stock_btree_methods; + } + } + *ppBtree = pBtree; + return rc; +} + +SQLITE_PRIVATE int sqlite3IsHct(Btree *pBt){ + return (pBt && pBt->pMethods==&hct_btree_methods); +} + +SQLITE_PRIVATE int sqlite3BtreeSchemaLoaded(Btree *pBt){ + int rc = SQLITE_OK; + if( sqlite3IsHct(pBt) ){ + rc = sqlite3HctBtreeSchemaLoaded(pBt); + } + return rc; +} + + + +/************** End of btwrapper.c *******************************************/ /************** Begin file vdbemem.c *****************************************/ /* ** 2004 May 26 @@ -87811,8 +88511,6 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ -/* #include "btreeInt.h" */ - /* Forward references */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef); static void vdbeFreeOpArray(sqlite3 *, Op *, int); @@ -89211,12 +89909,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); break; } - case P4_SUBRTNSIG: { - SubrtnSig *pSig = (SubrtnSig*)p4; - sqlite3DbFree(db, pSig->zAff); - sqlite3DbFree(db, pSig); - break; - } } } @@ -89796,11 +90488,6 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ zP4 = pOp->p4.pTab->zName; break; } - case P4_SUBRTNSIG: { - SubrtnSig *pSig = pOp->p4.pSubrtnSig; - sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff); - break; - } default: { zP4 = pOp->p4.z; } @@ -90798,18 +91485,13 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ - sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_PHASEONE); for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ - pBt->pBt->aCommitTime = p->aCommitTime; rc = sqlite3BtreeCommitPhaseOne(pBt, 0); - pBt->pBt->aCommitTime = 0; } } - sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_PHASETWO); - /* Do the commit only if all databases successfully complete phase 1. ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an ** IO error while deleting or truncating a journal file. It is unlikely, @@ -90818,13 +91500,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ - pBt->pBt->aCommitTime = p->aCommitTime; rc = sqlite3BtreeCommitPhaseTwo(pBt, 0); - pBt->pBt->aCommitTime = 0; } } - - sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_AFTER_PHASETWO); if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } @@ -91221,9 +91899,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ - sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_VDBECOMMIT); rc = vdbeCommit(db, p); - sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_AFTER_VDBECOMMIT); } if( (rc & 0xFF)==SQLITE_BUSY && p->readOnly ){ sqlite3VdbeLeave(p); @@ -93255,84 +93931,6 @@ SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr) } #endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */ -/* #include */ -SQLITE_PRIVATE void sqlite3CommitTimeLog(u64 *aCommit){ - u64 i1 = aCommit[COMMIT_TIME_START]; - assert( COMMIT_TIME_START==0 && COMMIT_TIME_FINISH==COMMIT_TIME_N-1 ); - if( aCommit[COMMIT_TIME_FINISH]>(i1+COMMIT_TIME_TIMEOUT) ){ - char *zStr = 0; - int ii; - for(ii=1; ii(i1+PREPARE_TIME_TIMEOUT) ){ - int nByte = nSql; - char *zStr = 0; - int ii; - for(ii=1; ii(i1+SCHEMA_TIME_TIMEOUT) ){ - char *zStr = 0; - int ii; - for(ii=1; iipayloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); assert( pC->szRow<=pC->payloadSize ); +#if 0 assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ +#endif } pC->cacheStatus = p->cacheCtr; if( (aOffset[0] = pC->aRow[0])<0x80 ){ @@ -100147,14 +100747,10 @@ case OP_AutoCommit: { assert( desiredAutoCommit==0 || bConcurrent==0 ); assert( db->autoCommit==0 || db->eConcurrent==CONCURRENT_NONE ); assert( db->nVdbeActive>0 ); /* At least this one VM is active */ + assert( db->nVdbeActive>0 ); /* At least this one VM is active */ assert( p->bIsReader ); if( desiredAutoCommit!=db->autoCommit ){ - - u64 aCommit[COMMIT_TIME_N]; - memset(aCommit, 0, sizeof(aCommit)); - sqlite3CommitTimeSet(aCommit, COMMIT_TIME_START); - if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); @@ -100179,11 +100775,7 @@ case OP_AutoCommit: { }else{ db->autoCommit = (u8)desiredAutoCommit; } - sqlite3CommitTimeSet(aCommit, COMMIT_TIME_BEFORE_HALT); - p->aCommitTime = aCommit; hrc = sqlite3VdbeHalt(p); - p->aCommitTime = 0; - sqlite3CommitTimeSet(aCommit, COMMIT_TIME_AFTER_HALT); if( (hrc & 0xFF)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); @@ -100199,8 +100791,6 @@ case OP_AutoCommit: { }else{ rc = SQLITE_ERROR; } - sqlite3CommitTimeSet(aCommit, COMMIT_TIME_FINISH); - if( desiredAutoCommit ) sqlite3CommitTimeLog(aCommit); goto vdbe_return; }else{ sqlite3VdbeError(p, @@ -100425,6 +101015,11 @@ case OP_SetCookie: { *(u32*)&pDb->pSchema->schema_cookie = *(u32*)&pOp->p3 - pOp->p5; db->mDbFlags |= DBFLAG_SchemaChange; sqlite3FkClearTriggerCache(db, pOp->p1); +#ifdef SQLITE_ENABLE_HCT + if( sqlite3IsHct(pDb->pBt) ){ + rc = sqlite3HctSchemaOp(pDb->pBt, p->zSql); + } +#endif }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; @@ -101070,6 +101665,9 @@ case OP_SeekGT: { /* jump0, in3, group, ncycle */ if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } + sqlite3BtreeCursorDir(pC->uc.pCursor, + (oc==OP_SeekGE || oc==OP_SeekGT) ? BTREE_DIR_FORWARD : BTREE_DIR_REVERSE + ); rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ @@ -101123,6 +101721,9 @@ case OP_SeekGT: { /* jump0, in3, group, ncycle */ } #endif r.eqSeen = 0; + sqlite3BtreeCursorDir(pC->uc.pCursor, + (oc==OP_SeekGE || oc==OP_SeekGT) ? BTREE_DIR_FORWARD : BTREE_DIR_REVERSE + ); rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -101544,13 +102145,15 @@ case OP_Found: { /* jump, in3, ncycle */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); + sqlite3BtreeCursorDir(pC->uc.pCursor, + pOp->opcode==OP_NoConflict ? BTREE_DIR_NONE : BTREE_DIR_FORWARD + ); r.nField = (u16)pOp->p4.i; if( r.nField>0 ){ /* Key values in an array of registers */ r.pKeyInfo = pC->pKeyInfo; r.default_rc = 0; #ifdef SQLITE_DEBUG - (void)sqlite3FaultSim(50); /* For use by --counter in TH3 */ for(ii=0; iiuc.pCursor; assert( pCrsr!=0 ); res = 0; + sqlite3BtreeCursorDir(pCrsr, 0); rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ @@ -102775,7 +103379,6 @@ case OP_SorterInsert: { /* in2 */ case OP_IdxDelete: { VdbeCursor *pC; BtCursor *pCrsr; - int res; UnpackedRecord r; assert( pOp->p3>0 ); @@ -102791,6 +103394,10 @@ case OP_IdxDelete: { r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; +#if 1 + rc = sqlite3BtreeIdxDelete(pCrsr, &r); + if( rc ) goto abort_due_to_error; +#else rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ @@ -102800,6 +103407,7 @@ case OP_IdxDelete: { rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); goto abort_due_to_error; } +#endif assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; @@ -103913,29 +104521,18 @@ case OP_AggInverse: case OP_AggStep: { int n; sqlite3_context *pCtx; - u64 nAlloc; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - - /* Allocate space for (a) the context object and (n-1) extra pointers - ** to append to the sqlite3_context.argv[1] array, and (b) a memory - ** cell in which to store the accumulation. Be careful that the memory - ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits. - ** - ** Note: We could avoid this by using a regular memory cell from aMem[] for - ** the accumulator, instead of allocating one here. */ - nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) ); - pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); + pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) + + (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*))); if( pCtx==0 ) goto no_mem; - pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); - assert( EIGHT_BYTE_ALIGNMENT(pCtx->pOut) ); - - sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pMem = 0; + pCtx->pOut = (Mem*)&(pCtx->argv[n]); + sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; @@ -105636,11 +106233,6 @@ SQLITE_API int sqlite3_blob_open( pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } - if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){ - pTab = 0; - sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s", - zTable); - } #ifndef SQLITE_OMIT_VIEW if( pTab && IsView(pTab) ){ pTab = 0; @@ -106548,14 +107140,13 @@ static int vdbePmaReadBlob( while( nRem>0 ){ int rc; /* vdbePmaReadBlob() return code */ int nCopy; /* Number of bytes to copy */ - u8 *aNext = 0; /* Pointer to buffer to copy data from */ + u8 *aNext; /* Pointer to buffer to copy data from */ nCopy = nRem; if( nRem>p->nBuffer ) nCopy = p->nBuffer; rc = vdbePmaReadBlob(p, nCopy, &aNext); if( rc!=SQLITE_OK ) return rc; assert( aNext!=p->aAlloc ); - assert( aNext!=0 ); memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); nRem -= nCopy; } @@ -109825,9 +110416,7 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( pItem->fg.isSubquery - && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect) - ){ + if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc @@ -110133,7 +110722,7 @@ static void extendFJMatch( if( pNew ){ pNew->iTable = pMatch->iCursor; pNew->iColumn = iColumn; - pNew->y.pTab = pMatch->pSTab; + pNew->y.pTab = pMatch->pTab; assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ); ExprSetProperty(pNew, EP_CanBeNull); *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew); @@ -110264,10 +110853,10 @@ static int lookupName( if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ u8 hCol; - pTab = pItem->pSTab; + pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem)); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); if( pItem->fg.isNestedFrom ){ /* In this case, pItem is a subquery that has been formed from a ** parenthesized subset of the FROM clause terms. Example: @@ -110276,12 +110865,8 @@ static int lookupName( ** This pItem -------------^ */ int hit = 0; - Select *pSel; - assert( pItem->fg.isSubquery ); - assert( pItem->u4.pSubq!=0 ); - pSel = pItem->u4.pSubq->pSelect; - assert( pSel!=0 ); - pEList = pSel->pEList; + assert( pItem->pSelect!=0 ); + pEList = pItem->pSelect->pEList; assert( pEList!=0 ); assert( pEList->nExpr==pTab->nCol ); for(j=0; jnExpr; j++){ @@ -110405,8 +110990,8 @@ static int lookupName( if( cntTab==0 || (cntTab==1 && ALWAYS(pMatch!=0) - && ALWAYS(pMatch->pSTab!=0) - && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0 + && ALWAYS(pMatch->pTab!=0) + && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 && (pTab->tabFlags & TF_Ephemeral)==0) ){ cntTab = 1; @@ -110427,7 +111012,7 @@ static int lookupName( if( pMatch ){ pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); - pExpr->y.pTab = pMatch->pSTab; + pExpr->y.pTab = pMatch->pTab; if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } @@ -110469,7 +111054,7 @@ static int lookupName( if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ - pTab = pUpsert->pUpsertSrc->a[0].pSTab; + pTab = pUpsert->pUpsertSrc->a[0].pTab; pExpr->iTable = EXCLUDED_TABLE_NUMBER; } } @@ -110552,11 +111137,11 @@ static int lookupName( && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) - && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom) + && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) ){ cnt = cntTab; #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2 - if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){ + if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){ eNewExprOp = TK_NULL; } #endif @@ -110793,7 +111378,7 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr SrcItem *pItem = &pSrc->a[iSrc]; Table *pTab; assert( ExprUseYTab(p) ); - pTab = p->y.pTab = pItem->pSTab; + pTab = p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; @@ -110912,7 +111497,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pItem = pSrcList->a; pExpr->op = TK_COLUMN; assert( ExprUseYTab(pExpr) ); - pExpr->y.pTab = pItem->pSTab; + pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn--; pExpr->affExpr = SQLITE_AFF_INTEGER; @@ -111218,9 +111803,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC - if( pWin && pParse->nErr==0 ){ + if( pWin ){ Select *pSel = pNC->pWinSelect; - assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin ); + assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); if( pParse->db->mallocFailed ) break; @@ -111802,11 +112387,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** moves the pOrderBy down to the sub-query. It will be moved back ** after the names have been resolved. */ if( p->selFlags & SF_Converted ){ - Select *pSub; - assert( p->pSrc->a[0].fg.isSubquery ); - assert( p->pSrc->a[0].u4.pSubq!=0 ); - pSub = p->pSrc->a[0].u4.pSubq->pSelect; - assert( pSub!=0 ); + Select *pSub = p->pSrc->a[0].pSelect; assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( pSub->pPrior && pSub->pOrderBy==0 ); pSub->pOrderBy = p->pOrderBy; @@ -111818,16 +112399,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ if( pOuterNC ) pOuterNC->nNestedSelect++; for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; - assert( pItem->zName!=0 - || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/ - if( pItem->fg.isSubquery - && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0 - ){ + assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/ + if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; if( pItem->zName ) pParse->zAuthContext = pItem->zName; - sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC); + sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr ) return WRC_Abort; assert( db->mallocFailed==0 ); @@ -111929,10 +112507,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** These integers will be replaced by copies of the corresponding result ** set expressions by the call to resolveOrderGroupBy() below. */ if( p->selFlags & SF_Converted ){ - Select *pSub; - assert( p->pSrc->a[0].fg.isSubquery ); - pSub = p->pSrc->a[0].u4.pSubq->pSelect; - assert( pSub!=0 ); + Select *pSub = p->pSrc->a[0].pSelect; p->pOrderBy = pSub->pOrderBy; pSub->pOrderBy = 0; } @@ -112086,9 +112661,6 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. -** -** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a -** failure. */ SQLITE_PRIVATE int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ @@ -112097,7 +112669,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( int i; int savedHasAgg = 0; Walker w; - if( pList==0 ) return SQLITE_OK; + if( pList==0 ) return WRC_Continue; w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -112111,7 +112683,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ - return SQLITE_ERROR; + return WRC_Abort; } #endif sqlite3WalkExprNN(&w, pExpr); @@ -112128,10 +112700,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } - if( w.pParse->nErr>0 ) return SQLITE_ERROR; + if( w.pParse->nErr>0 ) return WRC_Abort; } pNC->ncFlags |= savedHasAgg; - return SQLITE_OK; + return WRC_Continue; } /* @@ -112199,7 +112771,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( if( pTab ){ sSrc.nSrc = 1; sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pSTab = pTab; + sSrc.a[0].pTab = pTab; sSrc.a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP @@ -112304,9 +112876,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ op = pExpr->op; continue; } - if( op!=TK_REGISTER ) break; - op = pExpr->op2; - if( NEVER( op==TK_REGISTER ) ) break; + if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break; } return pExpr->affExpr; } @@ -114096,30 +114666,15 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla SrcItem *pNewItem = &pNew->a[i]; const SrcItem *pOldItem = &p->a[i]; Table *pTab; - pNewItem->fg = pOldItem->fg; - if( pOldItem->fg.isSubquery ){ - Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery)); - if( pNewSubq==0 ){ - assert( db->mallocFailed ); - pNewItem->fg.isSubquery = 0; - }else{ - memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq)); - pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags); - if( pNewSubq->pSelect==0 ){ - sqlite3DbFree(db, pNewSubq); - pNewSubq = 0; - pNewItem->fg.isSubquery = 0; - } - } - pNewItem->u4.pSubq = pNewSubq; - }else if( pOldItem->fg.fixedSchema ){ - pNewItem->u4.pSchema = pOldItem->u4.pSchema; - }else{ - pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase); - } + pNewItem->pSchema = pOldItem->pSchema; + pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); + pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; + pNewItem->addrFillSub = pOldItem->addrFillSub; + pNewItem->regReturn = pOldItem->regReturn; + pNewItem->regResult = pOldItem->regResult; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); }else if( pNewItem->fg.isTabFunc ){ @@ -114132,10 +114687,11 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla if( pNewItem->fg.isCte ){ pNewItem->u2.pCteUse->nUse++; } - pTab = pNewItem->pSTab = pOldItem->pSTab; + pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nTabRef++; } + pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); if( pOldItem->fg.isUsing ){ assert( pNewItem->fg.isUsing ); pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing); @@ -114209,6 +114765,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pp = &pNew->pPrior; pNext = pNew; } + return pRet; } #else @@ -115228,8 +115785,8 @@ static Select *isCandidateForInOpt(const Expr *pX){ pSrc = p->pSrc; assert( pSrc!=0 ); if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ - if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */ - pTab = pSrc->a[0].pSTab; + if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ + pTab = pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ @@ -115412,7 +115969,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ - pTab = p->pSrc->a[0].pSTab; + pTab = p->pSrc->a[0].pTab; /* Code an OP_Transaction and OP_TableLock for . */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -115652,49 +116209,6 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ } } -#ifndef SQLITE_OMIT_SUBQUERY -/* -** Scan all previously generated bytecode looking for an OP_BeginSubrtn -** that is compatible with pExpr. If found, add the y.sub values -** to pExpr and return true. If not found, return false. -*/ -static int findCompatibleInRhsSubrtn( - Parse *pParse, /* Parsing context */ - Expr *pExpr, /* IN operator with RHS that we want to reuse */ - SubrtnSig *pNewSig /* Signature for the IN operator */ -){ - VdbeOp *pOp, *pEnd; - SubrtnSig *pSig; - Vdbe *v; - - if( pNewSig==0 ) return 0; - if( (pParse->mSubrtnSig & (1<<(pNewSig->selId&7)))==0 ) return 0; - assert( pExpr->op==TK_IN ); - assert( !ExprUseYSub(pExpr) ); - assert( ExprUseXSelect(pExpr) ); - assert( pExpr->x.pSelect!=0 ); - assert( (pExpr->x.pSelect->selFlags & SF_All)==0 ); - v = pParse->pVdbe; - assert( v!=0 ); - pOp = sqlite3VdbeGetOp(v, 1); - pEnd = sqlite3VdbeGetLastOp(v); - for(; pOpp4type!=P4_SUBRTNSIG ) continue; - assert( pOp->opcode==OP_BeginSubrtn ); - pSig = pOp->p4.pSubrtnSig; - assert( pSig!=0 ); - if( pNewSig->selId!=pSig->selId ) continue; - if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue; - pExpr->y.sub.iAddr = pSig->iAddr; - pExpr->y.sub.regReturn = pSig->regReturn; - pExpr->iTable = pSig->iTable; - ExprSetProperty(pExpr, EP_Subrtn); - return 1; - } - return 0; -} -#endif /* SQLITE_OMIT_SUBQUERY */ - #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that will construct an ephemeral table containing all terms @@ -115744,28 +116258,11 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ - /* Reuse of the RHS is allowed - ** - ** Compute a signature for the RHS of the IN operator to facility - ** finding and reusing prior instances of the same IN operator. - */ - SubrtnSig *pSig = 0; - assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 ); - if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){ - pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0])); - if( pSig ){ - pSig->selId = pExpr->x.pSelect->selId; - pSig->zAff = exprINAffinity(pParse, pExpr); - } - } - - /* Check to see if there is a prior materialization of the RHS of - ** this IN operator. If there is, then make use of that prior - ** materialization rather than recomputing it. + /* Reuse of the RHS is allowed */ + /* If this routine has already been coded, but the previous code + ** might not have been invoked yet, so invoke it now as a subroutine. */ - if( ExprHasProperty(pExpr, EP_Subrtn) - || findCompatibleInRhsSubrtn(pParse, pExpr, pSig) - ){ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); if( ExprUseXSelect(pExpr) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", @@ -115777,10 +116274,6 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( assert( iTab!=pExpr->iTable ); sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); sqlite3VdbeJumpHere(v, addrOnce); - if( pSig ){ - sqlite3DbFree(pParse->db, pSig->zAff); - sqlite3DbFree(pParse->db, pSig); - } return; } @@ -115791,13 +116284,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; - if( pSig ){ - pSig->iAddr = pExpr->y.sub.iAddr; - pSig->regReturn = pExpr->y.sub.regReturn; - pSig->iTable = iTab; - pParse->mSubrtnSig = 1 << (pSig->selId&7); - sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG); - } + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } @@ -115838,30 +116325,15 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( SelectDest dest; int i; int rc; - int addrBloom = 0; sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; - if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ - int regBloom = ++pParse->nMem; - addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); - VdbeComment((v, "Bloom filter")); - dest.iSDParm2 = regBloom; - } testcase( pSelect->selFlags & SF_Distinct ); testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); - if( addrBloom ){ - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; - if( dest.iSDParm2==0 ){ - sqlite3VdbeChangeToNoop(v, addrBloom); - }else{ - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; - } - } if( rc ){ sqlite3KeyInfoUnref(pKeyInfo); return; @@ -116159,7 +116631,9 @@ static void sqlite3ExprCodeIN( if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); - aiMap = (int*)sqlite3DbMallocZero(pParse->db, nVector*sizeof(int)); + aiMap = (int*)sqlite3DbMallocZero( + pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 + ); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than @@ -116302,15 +116776,6 @@ static void sqlite3ExprCodeIN( sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ - if( ExprHasProperty(pExpr, EP_Subrtn) ){ - const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); - assert( pOp->opcode==OP_Once || pParse->nErr ); - if( pOp->opcode==OP_Once && pOp->p3>0 ){ - assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); - sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, - rLhs, nVector); VdbeCoverage(v); - } - } sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; @@ -116596,14 +117061,10 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n SQLITE_PRIVATE void sqlite3ExprToRegister(Expr *pExpr, int iReg){ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); if( NEVER(p==0) ) return; - if( p->op==TK_REGISTER ){ - assert( p->iTable==iReg ); - }else{ - p->op2 = p->op; - p->op = TK_REGISTER; - p->iTable = iReg; - ExprClearProperty(p, EP_Skip); - } + p->op2 = p->op; + p->op = TK_REGISTER; + p->iTable = iReg; + ExprClearProperty(p, EP_Skip); } /* @@ -120804,7 +121265,7 @@ static int renameResolveTrigger(Parse *pParse){ /* ALWAYS() because if the table of the trigger does not exist, the ** error would have been hit before this point */ if( ALWAYS(pParse->pTriggerTab) ){ - rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0; + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); } /* Resolve symbols in WHEN clause */ @@ -120850,9 +121311,8 @@ static int renameResolveTrigger(Parse *pParse){ int i; for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ SrcItem *p = &pStep->pFrom->a[i]; - if( p->fg.isSubquery ){ - assert( p->u4.pSubq!=0 ); - sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0); + if( p->pSelect ){ + sqlite3SelectPrep(pParse, p->pSelect, 0); } } } @@ -120920,12 +121380,8 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ } if( pStep->pFrom ){ int i; - SrcList *pFrom = pStep->pFrom; - for(i=0; inSrc; i++){ - if( pFrom->a[i].fg.isSubquery ){ - assert( pFrom->a[i].u4.pSubq!=0 ); - sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect); - } + for(i=0; ipFrom->nSrc; i++){ + sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); } } } @@ -121172,7 +121628,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ } for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; - if( pItem->pSTab==p->pTab ){ + if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } @@ -123600,13 +124056,12 @@ static int loadStatTbl( while( sqlite3_step(pStmt)==SQLITE_ROW ){ int nIdxCol = 1; /* Number of columns in stat4 records */ - char *zIndex; /* Index name */ - Index *pIdx; /* Pointer to the index object */ - int nSample; /* Number of samples */ - int nByte; /* Bytes of space required */ - int i; /* Bytes of space required */ - tRowcnt *pSpace; /* Available allocated memory space */ - u8 *pPtr; /* Available memory as a u8 for easier manipulation */ + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int nSample; /* Number of samples */ + int nByte; /* Bytes of space required */ + int i; /* Bytes of space required */ + tRowcnt *pSpace; zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; @@ -123626,7 +124081,7 @@ static int loadStatTbl( } pIdx->nSampleCol = nIdxCol; pIdx->mxSample = nSample; - nByte = ROUND8(sizeof(IndexSample) * nSample); + nByte = sizeof(IndexSample) * nSample; nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ @@ -123635,10 +124090,7 @@ static int loadStatTbl( sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; } - pPtr = (u8*)pIdx->aSample; - pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0])); - pSpace = (tRowcnt*)pPtr; - assert( EIGHT_BYTE_ALIGNMENT( pSpace ) ); + pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; ia; inSrc; i++, pItem++){ - if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){ - if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ - if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){ + if( pFix->bTemp==0 ){ + if( pItem->zDatabase ){ + if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", - pFix->zType, pFix->pName, pItem->u4.zDatabase); + pFix->zType, pFix->pName, pItem->zDatabase); return WRC_Abort; } - sqlite3DbFree(db, pItem->u4.zDatabase); + sqlite3DbFree(db, pItem->zDatabase); + pItem->zDatabase = 0; pItem->fg.notCte = 1; - pItem->fg.hadSchema = 1; } - pItem->u4.pSchema = pFix->pSchema; + pItem->pSchema = pFix->pSchema; pItem->fg.fromDDL = 1; - pItem->fg.fixedSchema = 1; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( pList->a[i].fg.isUsing==0 @@ -124613,7 +125064,7 @@ SQLITE_PRIVATE void sqlite3AuthRead( assert( pTabList ); for(iSrc=0; iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ - pTab = pTabList->a[iSrc].pSTab; + pTab = pTabList->a[iSrc].pTab; break; } } @@ -125216,12 +125667,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( SrcItem *p ){ const char *zDb; - if( p->fg.fixedSchema ){ - int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); + assert( p->pSchema==0 || p->zDatabase==0 ); + if( p->pSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zDbSName; }else{ - assert( !p->fg.isSubquery ); - zDb = p->u4.zDatabase; + zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } @@ -128206,8 +128657,6 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); - assert( pName->a[0].fg.fixedSchema==0 ); - assert( pName->a[0].fg.isSubquery==0 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); @@ -128216,7 +128665,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, if( pTab==0 ){ if( noErr ){ - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } goto exit_drop_table; @@ -129307,17 +129756,15 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists } assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pName->nSrc==1 ); - assert( pName->a[0].fg.fixedSchema==0 ); - assert( pName->a[0].fg.isSubquery==0 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } - pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase); + pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; @@ -129614,14 +130061,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( if( pDatabase && pDatabase->z==0 ){ pDatabase = 0; } - assert( pItem->fg.fixedSchema==0 ); - assert( pItem->fg.isSubquery==0 ); if( pDatabase ){ pItem->zName = sqlite3NameFromToken(db, pDatabase); - pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = sqlite3NameFromToken(db, pTable); }else{ pItem->zName = sqlite3NameFromToken(db, pTable); - pItem->u4.zDatabase = 0; + pItem->zDatabase = 0; } return pList; } @@ -129637,40 +130082,13 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; - if( pItem->fg.isSubquery ){ - assert( pItem->u4.pSubq!=0 ); - assert( pItem->u4.pSubq->pSelect!=0 ); - assert( pItem->u4.pSubq->pSelect->pSrc!=0 ); - sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc); + if( pItem->pSelect ){ + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); } } } } -/* -** Delete a Subquery object and its substructure. -*/ -SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){ - assert( pSubq!=0 && pSubq->pSelect!=0 ); - sqlite3SelectDelete(db, pSubq->pSelect); - sqlite3DbFree(db, pSubq); -} - -/* -** Remove a Subquery from a SrcItem. Return the associated Select object. -** The returned Select becomes the responsibility of the caller. -*/ -SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){ - Select *pSel; - assert( pItem!=0 ); - assert( pItem->fg.isSubquery ); - pSel = pItem->u4.pSubq->pSelect; - sqlite3DbFree(db, pItem->u4.pSubq); - pItem->u4.pSubq = 0; - pItem->fg.isSubquery = 0; - return pSel; -} - /* ** Delete an entire SrcList including all its substructure. */ @@ -129680,24 +130098,13 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ assert( db!=0 ); if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ - - /* Check invariants on SrcItem */ - assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc ); - assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy ); - assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery ); - assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 && - pItem->u4.pSubq->pSelect!=0) ); - + if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase); if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); - if( pItem->fg.isSubquery ){ - sqlite3SubqueryDelete(db, pItem->u4.pSubq); - }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ - sqlite3DbNNFreeNN(db, pItem->u4.zDatabase); - } if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); - sqlite3DeleteTable(db, pItem->pSTab); + sqlite3DeleteTable(db, pItem->pTab); + if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); if( pItem->fg.isUsing ){ sqlite3IdListDelete(db, pItem->u3.pUsing); }else if( pItem->u3.pOn ){ @@ -129707,54 +130114,6 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3DbNNFreeNN(db, pList); } -/* -** Attach a Subquery object to pItem->uv.pSubq. Set the -** pSelect value but leave all the other values initialized -** to zero. -** -** A copy of the Select object is made if dupSelect is true, and the -** SrcItem takes responsibility for deleting the copy. If dupSelect is -** false, ownership of the Select passes to the SrcItem. Either way, -** the SrcItem will take responsibility for deleting the Select. -** -** When dupSelect is zero, that means the Select might get deleted right -** away if there is an OOM error. Beware. -** -** Return non-zero on success. Return zero on an OOM error. -*/ -SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery( - Parse *pParse, /* Parsing context */ - SrcItem *pItem, /* Item to which the subquery is to be attached */ - Select *pSelect, /* The subquery SELECT. Must be non-NULL */ - int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/ -){ - Subquery *p; - assert( pSelect!=0 ); - assert( pItem->fg.isSubquery==0 ); - if( pItem->fg.fixedSchema ){ - pItem->u4.pSchema = 0; - pItem->fg.fixedSchema = 0; - }else if( pItem->u4.zDatabase!=0 ){ - sqlite3DbFree(pParse->db, pItem->u4.zDatabase); - pItem->u4.zDatabase = 0; - } - if( dupSelect ){ - pSelect = sqlite3SelectDup(pParse->db, pSelect, 0); - if( pSelect==0 ) return 0; - } - p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery)); - if( p==0 ){ - sqlite3SelectDelete(pParse->db, pSelect); - return 0; - } - pItem->fg.isSubquery = 1; - p->pSelect = pSelect; - assert( offsetof(Subquery, pSelect)==0 ); - memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect)); - return 1; -} - - /* ** This routine is called by the parser to add a new term to the ** end of a growing FROM clause. The "p" parameter is the part of @@ -129804,12 +130163,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } - assert( pSubquery==0 || pDatabase==0 ); if( pSubquery ){ - if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){ - if( pSubquery->selFlags & SF_NestedFrom ){ - pItem->fg.isNestedFrom = 1; - } + pItem->pSelect = pSubquery; + if( pSubquery->selFlags & SF_NestedFrom ){ + pItem->fg.isNestedFrom = 1; } } assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); @@ -130372,6 +130729,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } if( pKey ){ + if( pIdx->onError ) pKey->nUniqField = pIdx->nKeyCol; assert( sqlite3KeyInfoIsWriteable(pKey) ); for(i=0; iazColl[i]; @@ -131087,8 +131445,8 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ ** ** The following fields are initialized appropriate in pSrc: ** -** pSrc->a[0].spTab Pointer to the Table object -** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one +** pSrc->a[0].pTab Pointer to the Table object +** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ @@ -131096,8 +131454,8 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ Table *pTab; assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); - if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab); - pItem->pSTab = pTab; + if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); + pItem->pTab = pTab; pItem->fg.notCte = 1; if( pTab ){ pTab->nTabRef++; @@ -131219,8 +131577,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView( if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 ); - pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].fg.isUsing==0 ); assert( pFrom->a[0].u3.pOn==0 ); } @@ -131282,7 +131639,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( ** ); */ - pTab = pSrc->a[0].pSTab; + pTab = pSrc->a[0].pTab; if( HasRowid(pTab) ){ pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pEList = sqlite3ExprListAppend( @@ -131315,9 +131672,9 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ - pSrc->a[0].pSTab = 0; + pSrc->a[0].pTab = 0; pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); - pSrc->a[0].pSTab = pTab; + pSrc->a[0].pTab = pTab; if( pSrc->a[0].fg.isIndexedBy ){ assert( pSrc->a[0].fg.isCte==0 ); pSrc->a[0].u2.pIBIndex = 0; @@ -134146,11 +134503,7 @@ static void minMaxFinalize(sqlite3_context *context){ ** group_concat(EXPR, ?SEPARATOR?) ** string_agg(EXPR, SEPARATOR) ** -** Content is accumulated in GroupConcatCtx.str with the SEPARATOR -** coming before the EXPR value, except for the first entry which -** omits the SEPARATOR. -** -** It is tragic that the SEPARATOR goes before the EXPR string. The +** The SEPARATOR goes before the EXPR string. This is tragic. The ** groupConcatInverse() implementation would have been easier if the ** SEPARATOR were appended after EXPR. And the order is undocumented, ** so we could change it, in theory. But the old behavior has been @@ -134254,7 +134607,7 @@ static void groupConcatInverse( /* pGCC is always non-NULL since groupConcatStep() will have always ** run first to initialize it */ if( ALWAYS(pGCC) ){ - int nVS; /* Number of characters to remove */ + int nVS; /* Must call sqlite3_value_text() to convert the argument into text prior ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ (void)sqlite3_value_text(argv[0]); @@ -135905,9 +136258,9 @@ SQLITE_PRIVATE void sqlite3FkCheck( pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ SrcItem *pItem = pSrc->a; - pItem->pSTab = pFKey->pFrom; + pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; - pItem->pSTab->nTabRef++; + pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ @@ -136199,8 +136552,7 @@ static Trigger *fkActionTrigger( if( pSrc ){ assert( pSrc->nSrc==1 ); pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); - assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 ); - pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), @@ -136934,11 +137286,8 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ SrcItem *pItem = &pVal->pSrc->a[0]; - assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr ); - if( pItem->fg.isSubquery ){ - sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn); - sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1); - } + sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); + sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1); } } @@ -137066,42 +137415,36 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList if( pRet ){ SelectDest dest; - Subquery *pSubq; pRet->pSrc->nSrc = 1; pRet->pPrior = pLeft->pPrior; pRet->op = pLeft->op; - if( pRet->pPrior ) pRet->selFlags |= SF_Values; pLeft->pPrior = 0; pLeft->op = TK_SELECT; assert( pLeft->pNext==0 ); assert( pRet->pNext==0 ); p = &pRet->pSrc->a[0]; + p->pSelect = pLeft; p->fg.viaCoroutine = 1; + p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; + p->regReturn = ++pParse->nMem; p->iCursor = -1; - assert( !p->fg.isIndexedBy && !p->fg.isTabFunc ); p->u1.nRow = 2; - if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){ - pSubq = p->u4.pSubq; - pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; - pSubq->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, - pSubq->regReturn, 0, pSubq->addrFillSub); - sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); - - /* Allocate registers for the output of the co-routine. Do so so - ** that there are two unused registers immediately before those - ** used by the co-routine. This allows the code in sqlite3Insert() - ** to use these registers directly, instead of copying the output - ** of the co-routine to a separate array for processing. */ - dest.iSdst = pParse->nMem + 3; - dest.nSdst = pLeft->pEList->nExpr; - pParse->nMem += 2 + dest.nSdst; - - pLeft->selFlags |= SF_MultiValue; - sqlite3Select(pParse, pLeft, &dest); - pSubq->regResult = dest.iSdst; - assert( pParse->nErr || dest.iSdst>0 ); - } + sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); + sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn); + + /* Allocate registers for the output of the co-routine. Do so so + ** that there are two unused registers immediately before those + ** used by the co-routine. This allows the code in sqlite3Insert() + ** to use these registers directly, instead of copying the output + ** of the co-routine to a separate array for processing. */ + dest.iSdst = pParse->nMem + 3; + dest.nSdst = pLeft->pEList->nExpr; + pParse->nMem += 2 + dest.nSdst; + + pLeft->selFlags |= SF_MultiValue; + sqlite3Select(pParse, pLeft, &dest); + p->regResult = dest.iSdst; + assert( pParse->nErr || dest.iSdst>0 ); pLeft = pRet; } }else{ @@ -137111,18 +137454,12 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList } if( pParse->nErr==0 ){ - Subquery *pSubq; assert( p!=0 ); - assert( p->fg.isSubquery ); - pSubq = p->u4.pSubq; - assert( pSubq!=0 ); - assert( pSubq->pSelect!=0 ); - assert( pSubq->pSelect->pEList!=0 ); - if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){ - sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect); + if( p->pSelect->pEList->nExpr!=pRow->nExpr ){ + sqlite3SelectWrongNumTermsError(pParse, p->pSelect); }else{ - sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0); - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn); + sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); + sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); } } sqlite3ExprListDelete(pParse->db, pRow); @@ -137473,14 +137810,9 @@ SQLITE_PRIVATE void sqlite3Insert( && pSelect->pPrior==0 ){ SrcItem *pItem = &pSelect->pSrc->a[0]; - Subquery *pSubq; - assert( pItem->fg.isSubquery ); - pSubq = pItem->u4.pSubq; - dest.iSDParm = pSubq->regReturn; - regFromSelect = pSubq->regResult; - assert( pSubq->pSelect!=0 ); - assert( pSubq->pSelect->pEList!=0 ); - nColumn = pSubq->pSelect->pEList->nExpr; + dest.iSDParm = pItem->regReturn; + regFromSelect = pItem->regResult; + nColumn = pItem->pSelect->pEList->nExpr; ExplainQueryPlan((pParse, 0, "SCAN %S", pItem)); if( bIdListInOrder && nColumn==pTab->nCol ){ regData = regFromSelect; @@ -137933,6 +138265,7 @@ SQLITE_PRIVATE void sqlite3Insert( ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT ** functionality. */ bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v)); + if( db->bHctMigrate ) bUseSeek = 0; sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); @@ -138642,7 +138975,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** the following conflict logic if it does not. */ VdbeNoopComment((v, "uniqueness check for ROWID")); sqlite3VdbeVerifyAbortable(v, onError); - sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); + if( db->bHctMigrate ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRowidOk); + }else{ + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); + } VdbeCoverage(v); switch( onError ){ @@ -138858,9 +139195,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); - addrConflictCk = - sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, - regIdx, pIdx->nKeyCol); VdbeCoverage(v); + if( db->bHctMigrate ){ + addrConflictCk = sqlite3VdbeAddOp2(v, OP_Goto, 0, addrUniqueOk); + }else{ + addrConflictCk = + sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, + regIdx, pIdx->nKeyCol); VdbeCoverage(v); + } /* Generate code to handle collisions */ regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField); @@ -139400,7 +139741,7 @@ static int xferOptimization( if( pSelect->pSrc->nSrc!=1 ){ return 0; /* FROM clause must have exactly one term */ } - if( pSelect->pSrc->a[0].fg.isSubquery ){ + if( pSelect->pSrc->a[0].pSelect ){ return 0; /* FROM clause cannot contain a subquery */ } if( pSelect->pWhere ){ @@ -139793,7 +140134,6 @@ SQLITE_API int sqlite3_exec( int nCol = 0; char **azVals = 0; - sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_PREPARE); pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); @@ -139807,7 +140147,6 @@ SQLITE_API int sqlite3_exec( } callbackIsInit = 0; - sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_STEP); while( 1 ){ int i; rc = sqlite3_step(pStmt); @@ -139853,7 +140192,6 @@ SQLITE_API int sqlite3_exec( } } - sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_FINALIZE); if( rc!=SQLITE_ROW ){ rc = sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; @@ -142637,7 +142975,6 @@ SQLITE_PRIVATE void sqlite3Pragma( Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPRAGMA); if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; @@ -142663,13 +143000,11 @@ SQLITE_PRIVATE void sqlite3Pragma( zRight = sqlite3NameFromToken(db, pValue); } - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINAUTHCHECK); assert( pId2 ); zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDAUTHCHECK); /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS ** connection. If it returns SQLITE_OK, then assume that the VFS @@ -142691,7 +143026,10 @@ SQLITE_PRIVATE void sqlite3Pragma( aFcntl[2] = zRight; aFcntl[3] = 0; db->busyHandler.nBusy = 0; - rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); + rc = sqlite3BtreePragma(pDb->pBt, aFcntl); + if( rc==SQLITE_NOTFOUND ){ + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); + } if( rc==SQLITE_OK ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT); @@ -142717,12 +143055,10 @@ SQLITE_PRIVATE void sqlite3Pragma( goto pragma_out; } - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINLOADSCHEMA); /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDLOADSCHEMA); /* Register the result column names for pragmas that return results */ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 @@ -143082,7 +143418,6 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_CACHE_SIZE: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINCACHESIZE); if( !zRight ){ returnSingleInt(v, pDb->pSchema->cache_size); }else{ @@ -143090,7 +143425,6 @@ SQLITE_PRIVATE void sqlite3Pragma( pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDCACHESIZE); break; } @@ -144977,7 +145311,6 @@ SQLITE_PRIVATE void sqlite3Pragma( pragma_out: sqlite3DbFree(db, zLeft); sqlite3DbFree(db, zRight); - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPRAGMA); } #ifndef SQLITE_OMIT_VIRTUALTABLE /***************************************************************************** @@ -145508,11 +145841,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); - u64 aSchemaTime[SCHEMA_TIME_N]; - memset(aSchemaTime, 0, sizeof(aSchemaTime)); - db->aSchemaTime = aSchemaTime; - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_START); - assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); @@ -145547,8 +145875,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl goto error_out; } - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_CREATE_1); - /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; @@ -145572,8 +145898,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl openedTransaction = 1; } - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_OPEN_TRANS); - /* Get the database meta information. ** ** Meta values are as follows: @@ -145599,8 +145923,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_GET_META); - /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same @@ -145636,8 +145958,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl } pDb->pSchema->enc = ENC(db); - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_FIX_ENCODING); - if( pDb->pSchema->cache_size==0 ){ #ifndef SQLITE_OMIT_DEPRECATED size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]); @@ -145649,8 +145969,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_SETCACHESIZE); - /* ** file_format==1 Version 3.0.0. ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN @@ -145691,7 +146009,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl xAuth = db->xAuth; db->xAuth = 0; #endif - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_BEGIN_EXEC); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; @@ -145699,13 +146016,11 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #endif if( rc==SQLITE_OK ) rc = initData.rc; sqlite3DbFree(db, zSql); - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_BEGIN_ANALYZE_LOAD); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_END_ANALYZE_LOAD); } assert( pDb == &(db->aDb[iDb]) ); if( db->mallocFailed ){ @@ -145739,9 +146054,6 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl sqlite3BtreeLeave(pDb->pBt); error_out: - db->aSchemaTime = 0; - sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_FINISH); - sqlite3SchemaTimeLog(aSchemaTime); if( rc ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); @@ -145805,6 +146117,14 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ }else if( db->noSharedCache ){ db->mDbFlags |= DBFLAG_SchemaKnownOk; } +#ifdef SQLITE_ENABLE_HCT + { + int iDb; + for(iDb=0; rc==SQLITE_OK && iDbnDb; iDb++){ + rc = sqlite3BtreeSchemaLoaded(db->aDb[iDb].pBt); + } + } +#endif } return rc; } @@ -146102,18 +146422,14 @@ static int sqlite3Prepare( } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPARSE); sqlite3RunParser(&sParse, zSqlCopy); - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPARSE); sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); }else{ sParse.zTail = &zSql[nBytes]; } }else{ - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPARSE); sqlite3RunParser(&sParse, zSql); - sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPARSE); } assert( 0==sParse.nQueryLoop ); @@ -146174,12 +146490,6 @@ static int sqlite3LockAndPrepare( ){ int rc; int cnt = 0; - u64 *aPrepareSave = db->aPrepareTime; - - u64 aPrepareTime[PREPARE_TIME_N]; - memset(aPrepareTime, 0, sizeof(aPrepareTime)); - sqlite3PrepareTimeSet(aPrepareTime, PREPARE_TIME_START); - db->aPrepareTime = aPrepareTime; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; @@ -146205,11 +146515,6 @@ static int sqlite3LockAndPrepare( db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || (*ppStmt)==0 ); - - db->aPrepareTime = aPrepareSave; - sqlite3PrepareTimeSet(aPrepareTime, PREPARE_TIME_FINISH); - sqlite3PrepareTimeLog(zSql, nBytes, aPrepareTime); - return rc; } @@ -146755,13 +147060,11 @@ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ */ SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){ assert( pItem!=0 ); - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); if( pItem->fg.isNestedFrom ){ ExprList *pResults; - assert( pItem->fg.isSubquery ); - assert( pItem->u4.pSubq!=0 ); - assert( pItem->u4.pSubq->pSelect!=0 ); - pResults = pItem->u4.pSubq->pSelect->pEList; + assert( pItem->pSelect!=0 ); + pResults = pItem->pSelect->pEList; assert( pResults!=0 ); assert( iCol>=0 && iColnExpr ); pResults->a[iCol].fg.bUsed = 1; @@ -146795,9 +147098,9 @@ static int tableAndColumnIndex( assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ for(i=iStart; i<=iEnd; i++){ - iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol); + iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); if( iCol>=0 - && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0) + && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) ){ if( piTab ){ sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol); @@ -146926,10 +147229,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ - Table *pRightTab = pRight->pSTab; + Table *pRightTab = pRight->pTab; u32 joinType; - if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue; + if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; /* If this is a NATURAL join, synthesize an appropriate USING clause @@ -147802,18 +148105,12 @@ static void selectInnerLoop( ** case the order does matter */ pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); - pDest->iSDParm2 = 0; /* Signal that any Bloom filter is unpopulated */ }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); - if( pDest->iSDParm2 ){ - sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, - regResult, nResultCol); - ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); - } sqlite3ReleaseTempReg(pParse, r1); } break; @@ -147946,6 +148243,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->enc = ENC(db); p->db = db; p->nRef = 1; + p->nUniqField = 0; memset(&p[1], 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); @@ -148355,12 +148653,8 @@ static const char *columnTypeImpl( SrcList *pTabList = pNC->pSrcList; for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( jnSrc ){ - pTab = pTabList->a[j].pSTab; - if( pTabList->a[j].fg.isSubquery ){ - pS = pTabList->a[j].u4.pSubq->pSelect; - }else{ - pS = 0; - } + pTab = pTabList->a[j].pTab; + pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } @@ -149751,11 +150045,6 @@ static int generateOutputSubroutine( r1, pDest->zAffSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); - if( pDest->iSDParm2>0 ){ - sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, - pIn->iSdst, pIn->nSdst); - ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); - } sqlite3ReleaseTempReg(pParse, r1); break; } @@ -150412,9 +150701,7 @@ static void substSelect( pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( pItem->fg.isSubquery ){ - substSelect(pSubst, pItem->u4.pSubq->pSelect, 1); - } + substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isTabFunc ){ substExprList(pSubst, pItem->u1.pFuncArg); } @@ -150445,7 +150732,7 @@ static void recomputeColumnsUsed( SrcItem *pSrcItem /* Which FROM clause item to recompute */ ){ Walker w; - if( NEVER(pSrcItem->pSTab==0) ) return; + if( NEVER(pSrcItem->pTab==0) ) return; memset(&w, 0, sizeof(w)); w.xExprCallback = recomputeColumnsUsedExpr; w.xSelectCallback = sqlite3SelectWalkNoop; @@ -150485,10 +150772,8 @@ static void srclistRenumberCursors( aCsrMap[pItem->iCursor+1] = pParse->nTab++; } pItem->iCursor = aCsrMap[pItem->iCursor+1]; - if( pItem->fg.isSubquery ){ - for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){ - srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); - } + for(p=pItem->pSelect; p; p=p->pPrior){ + srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); } } } @@ -150799,8 +151084,7 @@ static int flattenSubquery( assert( pSrc && iFrom>=0 && iFromnSrc ); pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; - assert( pSubitem->fg.isSubquery ); - pSub = pSubitem->u4.pSubq->pSelect; + pSub = pSubitem->pSelect; assert( pSub!=0 ); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -150853,7 +151137,7 @@ static int flattenSubquery( */ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( pSubSrc->nSrc>1 /* (3a) */ - || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */ + || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ ){ @@ -150939,18 +151223,14 @@ static int flattenSubquery( pParse->zAuthContext = zSavedAuthContext; /* Delete the transient structures associated with the subquery */ - - if( ALWAYS(pSubitem->fg.isSubquery) ){ - pSub1 = sqlite3SubqueryDetach(db, pSubitem); - }else{ - pSub1 = 0; - } - assert( pSubitem->fg.isSubquery==0 ); - assert( pSubitem->fg.fixedSchema==0 ); + pSub1 = pSubitem->pSelect; + sqlite3DbFree(db, pSubitem->zDatabase); sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zAlias); + pSubitem->zDatabase = 0; pSubitem->zName = 0; pSubitem->zAlias = 0; + pSubitem->pSelect = 0; assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 ); /* If the sub-query is a compound SELECT statement, then (by restrictions @@ -150991,8 +151271,8 @@ static int flattenSubquery( ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; - Table *pItemTab = pSubitem->pSTab; - pSubitem->pSTab = 0; + Table *pItemTab = pSubitem->pTab; + pSubitem->pTab = 0; p->pOrderBy = 0; p->pPrior = 0; p->pLimit = 0; @@ -151000,7 +151280,7 @@ static int flattenSubquery( p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->op = TK_ALL; - pSubitem->pSTab = pItemTab; + pSubitem->pTab = pItemTab; if( pNew==0 ){ p->pPrior = pPrior; }else{ @@ -151015,14 +151295,11 @@ static int flattenSubquery( TREETRACE(0x4,pParse,p,("compound-subquery flattener" " creates %u as peer\n",pNew->selId)); } - assert( pSubitem->fg.isSubquery==0 ); + assert( pSubitem->pSelect==0 ); } sqlite3DbFree(db, aCsrMap); if( db->mallocFailed ){ - assert( pSubitem->fg.fixedSchema==0 ); - assert( pSubitem->fg.isSubquery==0 ); - assert( pSubitem->u4.zDatabase==0 ); - sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0); + pSubitem->pSelect = pSub1; return 1; } @@ -151033,8 +151310,8 @@ static int flattenSubquery( ** ** pSubitem->pTab is always non-NULL by test restrictions and tests above. */ - if( ALWAYS(pSubitem->pSTab!=0) ){ - Table *pTabToDel = pSubitem->pSTab; + if( ALWAYS(pSubitem->pTab!=0) ){ + Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); @@ -151042,7 +151319,7 @@ static int flattenSubquery( }else{ pTabToDel->nTabRef--; } - pSubitem->pSTab = 0; + pSubitem->pTab = 0; } /* The following loop runs once for each term in a compound-subquery @@ -151098,11 +151375,8 @@ static int flattenSubquery( */ for(i=0; ia[i+iFrom]; - assert( pItem->fg.isTabFunc==0 ); - assert( pItem->fg.isSubquery - || pItem->fg.fixedSchema - || pItem->u4.zDatabase==0 ); if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); + assert( pItem->fg.isTabFunc==0 ); *pItem = pSubSrc->a[i]; pItem->fg.jointype |= ltorj; iNewParent = pSubSrc->a[i].iCursor; @@ -151521,8 +151795,7 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ ** ** NAME AMBIGUITY ** -** This optimization is called the "WHERE-clause push-down optimization" -** or sometimes the "predicate push-down optimization". +** This optimization is called the "WHERE-clause push-down optimization". ** ** Do not confuse this optimization with another unrelated optimization ** with a similar name: The "MySQL push-down optimization" causes WHERE @@ -151786,10 +152059,10 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){ if( pItem->fg.isCorrelated || pItem->fg.isCte ){ return 0; } - assert( pItem->pSTab!=0 ); - pTab = pItem->pSTab; - assert( pItem->fg.isSubquery ); - pSub = pItem->u4.pSubq->pSelect; + assert( pItem->pTab!=0 ); + pTab = pItem->pTab; + assert( pItem->pSelect!=0 ); + pSub = pItem->pSelect; assert( pSub->pEList->nExpr==pTab->nCol ); for(pX=pSub; pX; pX=pX->pPrior){ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ @@ -151918,13 +152191,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ if( p->pWhere || p->pEList->nExpr!=1 || p->pSrc->nSrc!=1 - || p->pSrc->a[0].fg.isSubquery + || p->pSrc->a[0].pSelect || pAggInfo->nFunc!=1 || p->pHaving ){ return 0; } - pTab = p->pSrc->a[0].pSTab; + pTab = p->pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); if( !IsOrdinaryTable(pTab) ) return 0; @@ -151949,7 +152222,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ ** pFrom->pIndex and return SQLITE_OK. */ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ - Table *pTab = pFrom->pSTab; + Table *pTab = pFrom->pTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; assert( pTab!=0 ); @@ -152026,11 +152299,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0); - assert( pNewSrc!=0 || pParse->nErr ); - if( pParse->nErr ){ - sqlite3SrcListDelete(db, pNewSrc); - return WRC_Abort; - } + if( pNewSrc==0 ) return WRC_Abort; *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); @@ -152085,7 +152354,7 @@ static struct Cte *searchWith( ){ const char *zName = pItem->zName; With *p; - assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 ); + assert( pItem->zDatabase==0 ); assert( zName!=0 ); for(p=pWith; p; p=p->pOuter){ int i; @@ -152155,7 +152424,7 @@ static int resolveFromTermToCte( Cte *pCte; /* Matched CTE (or NULL if no match) */ With *pWith; /* The matching WITH */ - assert( pFrom->pSTab==0 ); + assert( pFrom->pTab==0 ); if( pParse->pWith==0 ){ /* There are no WITH clauses in the stack. No match is possible */ return 0; @@ -152165,8 +152434,7 @@ static int resolveFromTermToCte( ** go no further. */ return 0; } - assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 ); - if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){ + if( pFrom->zDatabase!=0 ){ /* The FROM term contains a schema qualifier (ex: main.t1) and so ** it cannot possibly be a CTE reference. */ return 0; @@ -152202,7 +152470,7 @@ static int resolveFromTermToCte( } if( cannotBeFunction(pParse, pFrom) ) return 2; - assert( pFrom->pSTab==0 ); + assert( pFrom->pTab==0 ); pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 2; pCteUse = pCte->pUse; @@ -152216,29 +152484,26 @@ static int resolveFromTermToCte( } pCteUse->eM10d = pCte->eM10d; } - pFrom->pSTab = pTab; + pFrom->pTab = pTab; pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; - sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1); + pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return 2; - assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); - pSel = pFrom->u4.pSubq->pSelect; - assert( pSel!=0 ); - pSel->selFlags |= SF_CopyCte; + pFrom->pSelect->selFlags |= SF_CopyCte; + assert( pFrom->pSelect ); if( pFrom->fg.isIndexedBy ){ sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); return 2; } - assert( !pFrom->fg.isIndexedBy ); pFrom->fg.isCte = 1; pFrom->u2.pCteUse = pCteUse; pCteUse->nUse++; /* Check if this is a recursive CTE. */ - pRecTerm = pSel; + pRecTerm = pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; @@ -152246,13 +152511,11 @@ static int resolveFromTermToCte( assert( pRecTerm->pPrior!=0 ); for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; - if( pItem->zName!=0 - && !pItem->fg.hadSchema - && ALWAYS( !pItem->fg.isSubquery ) - && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0) + if( pItem->zDatabase==0 + && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ - pItem->pSTab = pTab; + pItem->pTab = pTab; pTab->nTabRef++; pItem->fg.isRecursive = 1; if( pRecTerm->selFlags & SF_Recursive ){ @@ -152354,14 +152617,11 @@ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){ ** SQLITE_NOMEM. */ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ - Select *pSel; + Select *pSel = pFrom->pSelect; Table *pTab; - assert( pFrom->fg.isSubquery ); - assert( pFrom->u4.pSubq!=0 ); - pSel = pFrom->u4.pSubq->pSelect; assert( pSel ); - pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); + pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); if( pTab==0 ) return SQLITE_NOMEM; pTab->nTabRef = 1; if( pFrom->zAlias ){ @@ -152481,35 +152741,33 @@ static int selectExpander(Walker *pWalker, Select *p){ */ for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab; - assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 ); - if( pFrom->pSTab ) continue; + assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); + if( pFrom->pTab ) continue; assert( pFrom->fg.isRecursive==0 ); if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY - Select *pSel; - assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 ); - pSel = pFrom->u4.pSubq->pSelect; + Select *pSel = pFrom->pSelect; /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); - assert( pFrom->pSTab==0 ); + assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; #endif #ifndef SQLITE_OMIT_CTE }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ if( rc>1 ) return WRC_Abort; - pTab = pFrom->pSTab; + pTab = pFrom->pTab; assert( pTab!=0 ); #endif }else{ /* An ordinary table or view name in the FROM clause */ - assert( pFrom->pSTab==0 ); - pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); + assert( pFrom->pTab==0 ); + pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; if( pTab->nTabRef>=0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); - pFrom->pSTab = 0; + pFrom->pTab = 0; return WRC_Abort; } pTab->nTabRef++; @@ -152521,7 +152779,7 @@ static int selectExpander(Walker *pWalker, Select *p){ i16 nCol; u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; - assert( pFrom->fg.isSubquery==0 ); + assert( pFrom->pSelect==0 ); if( IsView(pTab) ){ if( (db->flags & SQLITE_EnableView)==0 && pTab->pSchema!=db->aDb[1].pSchema @@ -152529,7 +152787,7 @@ static int selectExpander(Walker *pWalker, Select *p){ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", pTab->zName); } - sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1); + pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) @@ -152545,9 +152803,7 @@ static int selectExpander(Walker *pWalker, Select *p){ nCol = pTab->nCol; pTab->nCol = -1; pWalker->eCode = 1; /* Turn on Select.selId renumbering */ - if( pFrom->fg.isSubquery ){ - sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect); - } + sqlite3WalkSelect(pWalker, pFrom->pSelect); pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } @@ -152634,7 +152890,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ int nAdd; /* Number of cols including rowid */ - Table *pTab = pFrom->pSTab; /* Table for this data source */ + Table *pTab = pFrom->pTab; /* Table for this data source */ ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ char *zTabName; /* AS name for this data source */ const char *zSchemaName = 0; /* Schema name for this data source */ @@ -152645,11 +152901,10 @@ static int selectExpander(Walker *pWalker, Select *p){ zTabName = pTab->zName; } if( db->mallocFailed ) break; - assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) ); + assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) ); if( pFrom->fg.isNestedFrom ){ - assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); - assert( pFrom->u4.pSubq->pSelect!=0 ); - pNestedFrom = pFrom->u4.pSubq->pSelect->pEList; + assert( pFrom->pSelect!=0 ); + pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); @@ -152888,12 +153143,14 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ assert( (p->selFlags & SF_Resolved) ); pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ - Table *pTab = pFrom->pSTab; + Table *pTab = pFrom->pTab; assert( pTab!=0 ); - if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){ + if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ - Select *pSel = pFrom->u4.pSubq->pSelect; - sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); + Select *pSel = pFrom->pSelect; + if( pSel ){ + sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); + } } } } @@ -153207,7 +153464,6 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); - if( pParse->nErr ) return; pList = pF->pFExpr->x.pList; if( pF->iOBTab>=0 ){ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs @@ -153417,7 +153673,6 @@ static void updateAccumulator( if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } - if( pParse->nErr ) return; } if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; @@ -153427,7 +153682,6 @@ static void updateAccumulator( } for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i)); - if( pParse->nErr ) return; } pAggInfo->directMode = 0; @@ -153543,28 +153797,25 @@ static SrcItem *isSelfJoinView( int iFirst, int iEnd /* Range of FROM-clause entries to search. */ ){ SrcItem *pItem; - Select *pSel; - assert( pThis->fg.isSubquery ); - pSel = pThis->u4.pSubq->pSelect; - assert( pSel!=0 ); - if( pSel->selFlags & SF_PushDown ) return 0; + assert( pThis->pSelect!=0 ); + if( pThis->pSelect->selFlags & SF_PushDown ) return 0; while( iFirsta[iFirst++]; - if( !pItem->fg.isSubquery ) continue; + if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; - assert( pItem->pSTab!=0 ); - assert( pThis->pSTab!=0 ); - if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue; + assert( pItem->pTab!=0 ); + assert( pThis->pTab!=0 ); + if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; - pS1 = pItem->u4.pSubq->pSelect; - if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){ + pS1 = pItem->pSelect; + if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } - if( pS1->selFlags & SF_PushDown ){ + if( pItem->pSelect->selFlags & SF_PushDown ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; @@ -153608,7 +153859,6 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ Expr *pExpr; Expr *pCount; sqlite3 *db; - SrcItem *pFrom; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ if( p->pWhere ) return 0; @@ -153623,9 +153873,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ - pFrom = p->pSrc->a; - if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */ - pSub = pFrom->u4.pSubq->pSelect; + pSub = p->pSrc->a[0].pSelect; + if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound */ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ do{ @@ -153634,7 +153883,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ assert( pSub->pHaving==0 ); /* Due to the previous */ - pSub = pSub->pPrior; /* Repeat over compound */ + pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ @@ -153642,7 +153891,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ db = pParse->db; pCount = pExpr; pExpr = 0; - pSub = sqlite3SubqueryDetach(db, pFrom); + pSub = p->pSrc->a[0].pSelect; + p->pSrc->a[0].pSelect = 0; sqlite3SrcListDelete(db, p->pSrc); p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); while( pSub ){ @@ -153687,12 +153937,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ for(i=0; inSrc; i++){ SrcItem *p1 = &pSrc->a[i]; if( p1==p0 ) continue; - if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ + if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ return 1; } - if( p1->fg.isSubquery - && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 - && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc) + if( p1->pSelect + && (p1->pSelect->selFlags & SF_NestedFrom)!=0 + && sameSrcAlias(p0, p1->pSelect->pSrc) ){ return 1; } @@ -153757,13 +154007,13 @@ static int fromClauseTermCanBeCoroutine( if( i==0 ) break; i--; pItem--; - if( pItem->fg.isSubquery ) return 0; /* (1c-i) */ + if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ } return 1; } /* -** Generate byte-code for the SELECT statement given in the p argument. +** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. @@ -153774,40 +154024,6 @@ static int fromClauseTermCanBeCoroutine( ** ** This routine does NOT free the Select structure passed in. The ** calling function needs to do that. -** -** This is a long function. The following is an outline of the processing -** steps, with tags referencing various milestones: -** -** * Resolve names and similar preparation tag-select-0100 -** * Scan of the FROM clause tag-select-0200 -** + OUTER JOIN strength reduction tag-select-0220 -** + Sub-query ORDER BY removal tag-select-0230 -** + Query flattening tag-select-0240 -** * Separate subroutine for compound-SELECT tag-select-0300 -** * WHERE-clause constant propagation tag-select-0330 -** * Count()-of-VIEW optimization tag-select-0350 -** * Scan of the FROM clause again tag-select-0400 -** + Authorize unreferenced tables tag-select-0410 -** + Predicate push-down optimization tag-select-0420 -** + Omit unused subquery columns optimization tag-select-0440 -** + Generate code to implement subqueries tag-select-0480 -** - Co-routines tag-select-0482 -** - Reuse previously computed CTE tag-select-0484 -** - REuse previously computed VIEW tag-select-0486 -** - Materialize a VIEW or CTE tag-select-0488 -** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500 -** * Set up for ORDER BY tag-select-0600 -** * Create output table tag-select-0630 -** * Prepare registers for LIMIT tag-select-0650 -** * Setup for DISTINCT tag-select-0680 -** * Generate code for non-aggregate and non-GROUP BY tag-select-0700 -** * Generate code for aggregate and/or GROUP BY tag-select-0800 -** + GROUP BY queries tag-select-0810 -** + non-GROUP BY queries tag-select-0820 -** - Special case of count() w/o GROUP BY tag-select-0821 -** - General case of non-GROUP BY aggregates tag-select-0822 -** * Sort results, as needed tag-select-0900 -** * Internal self-checks tag-select-1000 */ SQLITE_PRIVATE int sqlite3Select( Parse *pParse, /* The parser context */ @@ -153851,7 +154067,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* tag-select-0100 */ assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); @@ -153903,7 +154118,7 @@ SQLITE_PRIVATE int sqlite3Select( if( sameSrcAlias(p0, p->pSrc) ){ sqlite3ErrorMsg(pParse, "target object/alias may not appear in FROM clause: %s", - p0->zAlias ? p0->zAlias : p0->pSTab->zName + p0->zAlias ? p0->zAlias : p0->pTab->zName ); goto select_end; } @@ -153938,13 +154153,12 @@ SQLITE_PRIVATE int sqlite3Select( /* Try to do various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query - ** tag-select-0200 */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; - Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0; - Table *pTab = pItem->pSTab; + Select *pSub = pItem->pSelect; + Table *pTab = pItem->pTab; /* The expander should have already created transient Table objects ** even for FROM clause elements such as subqueries that do not correspond @@ -153961,7 +154175,6 @@ SQLITE_PRIVATE int sqlite3Select( ** way that the i-th table cannot be the NULL row of a join, then ** perform the appropriate simplification. This is called ** "OUTER JOIN strength reduction" in the SQLite documentation. - ** tag-select-0220 */ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor, @@ -154032,8 +154245,7 @@ SQLITE_PRIVATE int sqlite3Select( if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); - /* tag-select-0230: - ** If a FROM-clause subquery has an ORDER BY clause that is not + /* If a FROM-clause subquery has an ORDER BY clause that is not ** really doing anything, then delete it now so that it does not ** interfere with query flattening. See the discussion at ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a @@ -154099,7 +154311,6 @@ SQLITE_PRIVATE int sqlite3Select( continue; } - /* tag-select-0240 */ if( flattenSubquery(pParse, p, i, isAgg) ){ if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ @@ -154115,7 +154326,7 @@ SQLITE_PRIVATE int sqlite3Select( #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() - ** procedure. tag-select-0300 + ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); @@ -154131,9 +154342,9 @@ SQLITE_PRIVATE int sqlite3Select( #endif /* Do the WHERE-clause constant propagation optimization if this is - ** a join. No need to spend time on this operation for non-join queries + ** a join. No need to speed time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in - ** sqlite3WhereBegin(). tag-select-0330 + ** sqlite3WhereBegin(). */ if( p->pWhere!=0 && p->pWhere->op==TK_AND @@ -154150,7 +154361,6 @@ SQLITE_PRIVATE int sqlite3Select( TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n")); } - /* tag-select-0350 */ if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) && countOfViewOptimization(pParse, p) ){ @@ -154158,26 +154368,20 @@ SQLITE_PRIVATE int sqlite3Select( pTabList = p->pSrc; } - /* Loop over all terms in the FROM clause and do two things for each term: - ** - ** (1) Authorize unreferenced tables - ** (2) Generate code for all sub-queries - ** - ** tag-select-0400 + /* For each term in the FROM clause, do two things: + ** (1) Authorized unreferenced tables + ** (2) Generate code for all sub-queries */ for(i=0; inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; SrcItem *pPrior; SelectDest dest; - Subquery *pSubq; Select *pSub; #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) const char *zSavedAuthContext; #endif - /* Authorized unreferenced tables. tag-select-0410 - ** - ** Issue SQLITE_READ authorizations with a fake column name for any + /* Issue SQLITE_READ authorizations with a fake column name for any ** tables that are referenced but from which no values are extracted. ** Examples of where these kinds of null SQLITE_READ authorizations ** would occur: @@ -154194,28 +154398,17 @@ SQLITE_PRIVATE int sqlite3Select( ** string for the fake column name seems safer. */ if( pItem->colUsed==0 && pItem->zName!=0 ){ - const char *zDb; - if( pItem->fg.fixedSchema ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema); - zDb = db->aDb[iDb].zDbSName; - }else if( pItem->fg.isSubquery ){ - zDb = 0; - }else{ - zDb = pItem->u4.zDatabase; - } - sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb); + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause */ - if( pItem->fg.isSubquery==0 ) continue; - pSubq = pItem->u4.pSubq; - assert( pSubq!=0 ); - pSub = pSubq->pSelect; + pSub = pItem->pSelect; + if( pSub==0 || pItem->addrFillSub!=0 ) continue; /* The code for a subquery should only be generated once. */ - if( pSubq->addrFillSub!=0 ) continue; + assert( pItem->addrFillSub==0 ); /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select @@ -154228,7 +154421,6 @@ SQLITE_PRIVATE int sqlite3Select( /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. - ** This is the "predicate push-down optimization". tag-select-0420 */ if( OptimizationEnabled(db, SQLITE_PushDown) && (pItem->fg.isCte==0 @@ -154242,14 +154434,13 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3TreeViewSelect(0, p, 0); } #endif - assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 ); + assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); }else{ TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL ** expressions, to avoid unneeded searching and computation. - ** tag-select-0440 */ if( OptimizationEnabled(db, SQLITE_NullUnusedCols) && disableUnusedSubqueryResultColumns(pItem) @@ -154267,33 +154458,32 @@ SQLITE_PRIVATE int sqlite3Select( zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; - /* Generate byte-code to implement the subquery tag-select-0480 + /* Generate code to implement the subquery */ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ /* Implement a co-routine that will return a single row of the result - ** set on each invocation. tag-select-0482 + ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; - pSubq->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop); + pItem->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); - pSubq->addrFillSub = addrTop; - sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); + pItem->addrFillSub = addrTop; + sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); - pItem->pSTab->nRowLogEst = pSub->nSelectRow; + pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; - pSubq->regResult = dest.iSdst; - sqlite3VdbeEndCoroutine(v, pSubq->regReturn); - VdbeComment((v, "end %!S", pItem)); + pItem->regResult = dest.iSdst; + sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, - ** then make the pItem->iCursor be a copy of the ephemeral table that - ** holds the result of the materialization. tag-select-0484 */ + ** the make the pItem->iCursor be a copy of the ephemeral table that + ** holds the result of the materialization. */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ @@ -154303,30 +154493,25 @@ SQLITE_PRIVATE int sqlite3Select( pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ /* This view has already been materialized by a prior entry in - ** this same FROM clause. Reuse it. tag-select-0486 */ - Subquery *pPriorSubq; - assert( pPrior->fg.isSubquery ); - pPriorSubq = pPrior->u4.pSubq; - assert( pPriorSubq!=0 ); - if( pPriorSubq->addrFillSub ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn, - pPriorSubq->addrFillSub); + ** this same FROM clause. Reuse it. */ + if( pPrior->addrFillSub ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); } sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); - pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow; + pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ /* Materialize the view. If the view is not correlated, generate a ** subroutine to do the materialization so that subsequent uses of - ** the same view can reuse the materialization. tag-select-0488 */ + ** the same view can reuse the materialization. */ int topAddr; int onceAddr = 0; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; #endif - pSubq->regReturn = ++pParse->nMem; + pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp0(v, OP_Goto); - pSubq->addrFillSub = topAddr+1; + pItem->addrFillSub = topAddr+1; pItem->fg.isMaterialized = 1; if( pItem->fg.isCorrelated==0 ){ /* If the subquery is not correlated and if we are not inside of @@ -154341,17 +154526,17 @@ SQLITE_PRIVATE int sqlite3Select( ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); - pItem->pSTab->nRowLogEst = pSub->nSelectRow; + pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); - sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1); + sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ CteUse *pCteUse = pItem->u2.pCteUse; - pCteUse->addrM9e = pSubq->addrFillSub; - pCteUse->regRtn = pSubq->regReturn; + pCteUse->addrM9e = pItem->addrFillSub; + pCteUse->regRtn = pItem->regReturn; pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } @@ -154377,9 +154562,7 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* tag-select-0500 - ** - ** If the query is DISTINCT with an ORDER BY but is not an aggregate, and + /* 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 ** can be rewritten as a GROUP BY. In other words, this: ** @@ -154429,7 +154612,7 @@ SQLITE_PRIVATE int sqlite3Select( ** If that is the case, then the OP_OpenEphemeral instruction will be ** changed to an OP_Noop once we figure out that the sorting index is ** not needed. The sSort.addrSortIndex variable is used to facilitate - ** that change. tag-select-0600 + ** that change. */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; @@ -154446,7 +154629,6 @@ SQLITE_PRIVATE int sqlite3Select( } /* If the output is destined for a temporary table, open that table. - ** tag-select-0630 */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); @@ -154464,7 +154646,7 @@ SQLITE_PRIVATE int sqlite3Select( } } - /* Set the limiter. tag-select-0650 + /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ @@ -154476,7 +154658,7 @@ SQLITE_PRIVATE int sqlite3Select( sSort.sortFlags |= SORTFLAG_UseSorter; } - /* Open an ephemeral index to use for the distinct set. tag-select-0680 + /* Open an ephemeral index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; @@ -154491,7 +154673,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( !isAgg && pGroupBy==0 ){ - /* No aggregate functions and no GROUP BY clause. tag-select-0700 */ + /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) | (p->selFlags & SF_FixedLimit); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -154564,8 +154746,8 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3WhereEnd(pWInfo); } }else{ - /* This case is for when there exist aggregate functions or a GROUP BY - ** clause or both. tag-select-0800 */ + /* 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 */ @@ -154684,7 +154866,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Processing for aggregates with GROUP BY is very different and - ** much more complex than aggregates without a GROUP BY. tag-select-0810 + ** much more complex than aggregates without a GROUP BY. */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ @@ -154883,10 +155065,7 @@ SQLITE_PRIVATE int sqlite3Select( if( iOrderByCol ){ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); - if( ALWAYS(pBase!=0) - && pBase->op!=TK_AGG_COLUMN - && pBase->op!=TK_REGISTER - ){ + if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN ){ sqlite3ExprToRegister(pX, iAMem+j); } } @@ -154981,12 +155160,9 @@ SQLITE_PRIVATE int sqlite3Select( } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { - /* Aggregate functions without GROUP BY. tag-select-0820 */ Table *pTab; if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ - /* tag-select-0821 - ** - ** If isSimpleCount() returns a pointer to a Table structure, then + /* If isSimpleCount() returns a pointer to a Table structure, then ** the SQL statement is of the form: ** ** SELECT count(*) FROM @@ -155045,8 +155221,6 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else{ - /* The general case of an aggregate query without GROUP BY - ** tag-select-0822 */ int regAcc = 0; /* "populate accumulators" flag */ ExprList *pDistinct = 0; u16 distFlag = 0; @@ -155135,7 +155309,7 @@ SQLITE_PRIVATE int sqlite3Select( } /* If there is an ORDER BY clause, then we need to sort the results - ** and send them to the callback one by one. tag-select-0900 + ** and send them to the callback one by one. */ if( sSort.pOrderBy ){ assert( p->pEList==pEList ); @@ -155158,7 +155332,6 @@ SQLITE_PRIVATE int sqlite3Select( assert( db->mallocFailed==0 || pParse->nErr!=0 ); sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG - /* Internal self-checks. tag-select-1000 */ if( pAggInfo && !db->mallocFailed ){ #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20 ){ @@ -155548,10 +155721,8 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( ** name on pTableName if we are reparsing out of the schema table */ if( db->init.busy && iDb!=1 ){ - assert( pTableName->a[0].fg.fixedSchema==0 ); - assert( pTableName->a[0].fg.isSubquery==0 ); - sqlite3DbFree(db, pTableName->a[0].u4.zDatabase); - pTableName->a[0].u4.zDatabase = 0; + sqlite3DbFree(db, pTableName->a[0].zDatabase); + pTableName->a[0].zDatabase = 0; } /* If the trigger name was unqualified, and the table is a temp table, @@ -156029,8 +156200,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) } assert( pName->nSrc==1 ); - assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 ); - zDb = pName->a[0].u4.zDatabase; + zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ @@ -156267,9 +156437,7 @@ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( Schema *pSchema = pStep->pTrig->pSchema; pSrc->a[0].zName = zName; if( pSchema!=db->aDb[1].pSchema ){ - assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 ); - pSrc->a[0].u4.pSchema = pSchema; - pSrc->a[0].fg.fixedSchema = 1; + pSrc->a[0].pSchema = pSchema; } if( pStep->pFrom ){ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); @@ -156382,7 +156550,7 @@ static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){ pSrc = pSelect->pSrc; assert( pSrc!=0 ); for(i=0; inSrc; i++){ - if( pSrc->a[i].pSTab==pWalker->u.pTab ){ + if( pSrc->a[i].pTab==pWalker->u.pTab ){ testcase( pSelect->selFlags & SF_Correlated ); pSelect->selFlags |= SF_Correlated; pWalker->eCode = 1; @@ -156453,7 +156621,7 @@ static void codeReturningTrigger( sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); sSelect.pSrc = &sFrom; sFrom.nSrc = 1; - sFrom.a[0].pSTab = pTab; + sFrom.a[0].pTab = pTab; sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); @@ -157164,7 +157332,7 @@ static void updateFromSelect( Expr *pLimit2 = 0; ExprList *pOrderBy2 = 0; sqlite3 *db = pParse->db; - Table *pTab = pTabList->a[0].pSTab; + Table *pTab = pTabList->a[0].pTab; SrcList *pSrc; Expr *pWhere2; int eDest; @@ -157188,8 +157356,8 @@ static void updateFromSelect( if( pSrc ){ assert( pSrc->a[0].fg.notCte ); pSrc->a[0].iCursor = -1; - pSrc->a[0].pSTab->nTabRef--; - pSrc->a[0].pSTab = 0; + pSrc->a[0].pTab->nTabRef--; + pSrc->a[0].pTab = 0; } if( pPk ){ for(i=0; inKeyCol; i++){ @@ -158448,7 +158616,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( int nClause = 0; /* Counter of ON CONFLICT clauses */ assert( pTabList->nSrc==1 ); - assert( pTabList->a[0].pSTab!=0 ); + assert( pTabList->a[0].pTab!=0 ); assert( pUpsert!=0 ); assert( pUpsert->pUpsertTarget!=0 ); @@ -158467,7 +158635,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( if( rc ) return rc; /* Check to see if the conflict target matches the rowid. */ - pTab = pTabList->a[0].pSTab; + pTab = pTabList->a[0].pTab; pTarget = pUpsert->pUpsertTarget; iCursor = pTabList->a[0].iCursor; if( HasRowid(pTab) @@ -158838,9 +159006,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( const char *zDbMain; /* Schema name of database to vacuum */ const char *zOut; /* Name of output file */ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */ - u64 iRandom; /* Random value used for zDbVacuum[] */ - char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */ - if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); @@ -158850,6 +159015,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; /* IMP: R-15610-35227 */ } + if( sqlite3IsHct(db->aDb[iDb].pBt) ){ + if( pOut==0 ){ + /* Silent noop */ + return SQLITE_OK; + } + sqlite3SetString(pzErrMsg, db, "cannot VACUUM - hctree database"); + return SQLITE_ERROR; + } + saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ @@ -158881,29 +159055,27 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( pMain = db->aDb[iDb].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); - /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma + /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a ** (possibly synchronous) transaction opened on the main database before ** sqlite3BtreeCopyFile() is called. ** ** An optimization would be to use a non-journaled pager. - ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but + ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but ** that actually made the VACUUM run slower. Very little journalling ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ - sqlite3_randomness(sizeof(iRandom),&iRandom); - sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom); nDb = db->nDb; - rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum); + rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; - assert( strcmp(pDb->zDbSName,zDbVacuum)==0 ); + assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); @@ -158980,11 +159152,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** the contents to the temporary database. */ rc = execSqlF(db, pzErrMsg, - "SELECT'INSERT INTO %s.'||quote(name)" + "SELECT'INSERT INTO vacuum_db.'||quote(name)" "||' SELECT*FROM\"%w\".'||quote(name)" - "FROM %s.sqlite_schema " + "FROM vacuum_db.sqlite_schema " "WHERE type='table'AND coalesce(rootpage,1)>0", - zDbVacuum, zDbMain, zDbVacuum + zDbMain ); assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); db->mDbFlags &= ~DBFLAG_Vacuum; @@ -158996,11 +159168,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** from the schema table. */ rc = execSqlF(db, pzErrMsg, - "INSERT INTO %s.sqlite_schema" + "INSERT INTO vacuum_db.sqlite_schema" " SELECT*FROM \"%w\".sqlite_schema" " WHERE type IN('view','trigger')" " OR(type='table'AND rootpage=0)", - zDbVacuum, zDbMain + zDbMain ); if( rc ) goto end_of_vacuum; @@ -160639,13 +160811,11 @@ struct WhereLoop { u16 nTop; /* Size of TOP vector */ u16 nDistinctCol; /* Index columns used to sort for DISTINCT */ Index *pIndex; /* Index used, or NULL */ - ExprList *pOrderBy; /* ORDER BY clause if this is really a subquery */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */ u32 bOmitOffset : 1; /* True to let virtual table handle offset */ - u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */ i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ @@ -161134,8 +161304,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); #define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ #define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ #define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ -#define WHERE_COROUTINE 0x02000000 /* Implemented by co-routine. - ** NB: False-negatives are possible */ + /* 0x02000000 -- available for reuse */ #define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */ #endif /* !defined(SQLITE_WHEREINT_H) */ @@ -161280,7 +161449,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( assert( pLoop->u.btree.pIndex!=0 ); pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); - if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){ + if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ if( isSearch ){ zFmt = "PRIMARY KEY"; } @@ -161323,9 +161492,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ - sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX "); - sqlite3_str_appendf(&str, - pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s", + sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif @@ -161379,7 +161546,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); pLoop = pLevel->pWLoop; if( pLoop->wsFlags & WHERE_IPK ){ - const Table *pTab = pItem->pSTab; + const Table *pTab = pItem->pTab; if( pTab->iPKey>=0 ){ sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); }else{ @@ -161442,9 +161609,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); } }else{ - int addr; - assert( pSrclist->a[pLvl->iFrom].fg.isSubquery ); - addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub; + int addr = pSrclist->a[pLvl->iFrom].addrFillSub; VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); @@ -162581,8 +162746,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; - VdbeModuleComment((v, "Begin WHERE-loop%d: %s", - iLevel, pTabItem->pSTab->zName)); + VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); #if WHERETRACE_ENABLED /* 0x4001 */ if( sqlite3WhereTrace & 0x1 ){ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", @@ -162637,15 +162801,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ - int regYield; - Subquery *pSubq; - assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 ); - pSubq = pTabItem->u4.pSubq; - regYield = pSubq->regReturn; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); + int regYield = pTabItem->regReturn; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of %s", pTabItem->pSTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else @@ -163374,7 +163534,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ - Table *pTab = pTabItem->pSTab; + Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); @@ -163833,7 +163993,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** least once. This is accomplished by storing the PK for the row in ** both the iMatch index and the regBloom Bloom filter. */ - pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab; + pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; if( HasRowid(pTab) ){ r = sqlite3GetTempRange(pParse, 2); sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); @@ -163940,7 +164100,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( Bitmask mAll = 0; int k; - ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName)); + ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn, pRJ->regReturn); for(k=0; kpTabList->a[pWInfo->a[k].iFrom]; mAll |= pWInfo->a[k].pWLoop->maskSelf; if( pRight->fg.viaCoroutine ){ - Subquery *pSubq; - assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 ); - pSubq = pRight->u4.pSubq; - assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 ); sqlite3VdbeAddOp3( - v, OP_Null, 0, pSubq->regResult, - pSubq->regResult + pSubq->pSelect->pEList->nExpr-1 + v, OP_Null, 0, pRight->regResult, + pRight->regResult + pRight->pSelect->pEList->nExpr-1 ); } sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); @@ -163994,7 +164150,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( int nPk; int jmp; int addrCont = sqlite3WhereContinueLabel(pSubWInfo); - Table *pTab = pTabItem->pSTab; + Table *pTab = pTabItem->pTab; if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); nPk = 1; @@ -164246,20 +164402,11 @@ static int isLikeOrGlob( } if( z ){ - /* Count the number of prefix characters prior to the first wildcard. - ** If the underlying database has a UTF16LE encoding, then only consider - ** ASCII characters. Note that the encoding of z[] is UTF8 - we are - ** dealing with only UTF8 here in this code, but the database engine - ** itself might be processing content using a different encoding. */ + /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; - if( c==wc[3] && z[cnt]!=0 ){ - cnt++; - }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){ - cnt--; - break; - } + if( c==wc[3] && z[cnt]!=0 ) cnt++; } /* The optimization is possible only if (1) the pattern does not begin @@ -164274,7 +164421,7 @@ static int isLikeOrGlob( Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ - *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE; + *pisComplete = c==wc[0] && z[cnt+1]==0; /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); @@ -164993,9 +165140,7 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ if( ALWAYS(pSrc!=0) ){ int i; for(i=0; inSrc; i++){ - if( pSrc->a[i].fg.isSubquery ){ - mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect); - } + mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); if( pSrc->a[i].fg.isUsing==0 ){ mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn); } @@ -165033,7 +165178,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2( int iCur; do{ iCur = pFrom->a[j].iCursor; - for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ + for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr==0 ) continue; for(i=0; inKeyCol; i++){ if( pIdx->aiColumn[i]!=XN_EXPR ) continue; @@ -165077,7 +165222,7 @@ static int exprMightBeIndexed( for(i=0; inSrc; i++){ Index *pIdx; - for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ + for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr ){ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); } @@ -165665,7 +165810,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */ if( p->pGroupBy==0 && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ - && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */ + && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ ){ ExprList *pOrderBy = p->pOrderBy; int iCsr = p->pSrc->a[0].iCursor; @@ -165886,7 +166031,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( Expr *pColRef; Expr *pTerm; if( pItem->fg.isTabFunc==0 ) return; - pTab = pItem->pSTab; + pTab = pItem->pTab; assert( pTab!=0 ); pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; @@ -166570,7 +166715,7 @@ static int isDistinctRedundant( ** clause is redundant. */ if( pTabList->nSrc!=1 ) return 0; iBase = pTabList->a[0].iCursor; - pTab = pTabList->a[0].pSTab; + pTab = pTabList->a[0].pTab; /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the @@ -166645,12 +166790,6 @@ static void translateColumnToCopy( VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); if( pParse->db->mallocFailed ) return; -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("CHECKING for column-to-copy on cursor %d for %d..%d\n", - iTabCur, iStart, iEnd); - } -#endif for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ @@ -166834,10 +166973,10 @@ static int termCanDriveIndex( assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); leftCol = pTerm->u.x.leftColumn; if( leftCol<0 ) return 0; - aff = pSrc->pSTab->aCol[leftCol].affinity; + aff = pSrc->pTab->aCol[leftCol].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); - return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol); + return columnIsGoodIndexCandidate(pSrc->pTab, leftCol); } #endif @@ -166945,7 +167084,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( nKeyCol = 0; pTabList = pWC->pWInfo->pTabList; pSrc = &pTabList->a[pLevel->iFrom]; - pTable = pSrc->pSTab; + pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; @@ -167087,17 +167226,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex( /* Fill the automatic index with content */ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); if( pSrc->fg.viaCoroutine ){ - int regYield; - Subquery *pSubq; - assert( pSrc->fg.isSubquery ); - pSubq = pSrc->u4.pSubq; - assert( pSubq!=0 ); - regYield = pSubq->regReturn; + int regYield = pSrc->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of %s", pSrc->pSTab->zName)); + VdbeComment((v, "next row of %s", pSrc->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } @@ -167119,12 +167253,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex( sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pSrc->fg.viaCoroutine ){ - assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 ); sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, - pSrc->u4.pSubq->regResult, pLevel->iIdxCur); + pSrc->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pSrc->fg.viaCoroutine = 0; }else{ @@ -167215,7 +167348,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( iSrc = pLevel->iFrom; pItem = &pTabList->a[iSrc]; assert( pItem!=0 ); - pTab = pItem->pSTab; + pTab = pItem->pTab; assert( pTab!=0 ); sz = sqlite3LogEstToInt(pTab->nRowLogEst); if( sz<10000 ){ @@ -167246,7 +167379,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( int r1 = sqlite3GetTempRange(pParse, n); int jj; for(jj=0; jjpTable==pItem->pSTab ); + assert( pIdx->pTable==pItem->pTab ); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); } sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); @@ -167327,7 +167460,7 @@ static sqlite3_index_info *allocateIndexInfo( WhereClause *p; assert( pSrc!=0 ); - pTab = pSrc->pSTab; + pTab = pSrc->pTab; assert( pTab!=0 ); assert( IsVirtual(pTab) ); @@ -167433,19 +167566,6 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->aConstraint = pIdxCons; pIdxInfo->aOrderBy = pIdxOrderBy; pIdxInfo->aConstraintUsage = pUsage; - pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; - if( HasRowid(pTab)==0 ){ - /* Ensure that all bits associated with PK columns are set. This is to - ** ensure they are available for cases like RIGHT joins or OR loops. */ - Index *pPk = sqlite3PrimaryKeyIndex((Table*)pTab); - assert( pPk!=0 ); - for(i=0; inKeyCol; i++){ - int iCol = pPk->aiColumn[i]; - assert( iCol>=0 ); - if( iCol>=BMS-1 ) iCol = BMS-1; - pIdxInfo->colUsed |= MASKBIT(iCol); - } - } pHidden->pWC = pWC; pHidden->pParse = pParse; pHidden->eDistinct = eDistinct; @@ -168335,7 +168455,7 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; SrcItem *pItem = pWInfo->pTabList->a + p->iTab; - Table *pTab = pItem->pSTab; + Table *pTab = pItem->pTab; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); @@ -169323,7 +169443,7 @@ static int whereLoopAddBtreeIndex( ** 2. Stepping forward in the index pNew->nOut times to find all ** additional matching entries. */ - assert( pSrc->pSTab->szTabRow>0 ); + assert( pSrc->pTab->szTabRow>0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* The pProbe->szIdxRow is low for an IPK table since the interior ** pages are small. Thus szIdxRow gives a good estimate of seek cost. @@ -169331,7 +169451,7 @@ static int whereLoopAddBtreeIndex( ** under-estimate the scanning cost. */ rCostIdx = pNew->nOut + 16; }else{ - rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow; + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; } rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx); @@ -169796,9 +169916,9 @@ static int whereLoopAddBtree( pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; - pTab = pSrc->pSTab; + pTab = pSrc->pTab; pWC = pBuilder->pWC; - assert( !IsVirtual(pSrc->pSTab) ); + assert( !IsVirtual(pSrc->pTab) ); if( pSrc->fg.isIndexedBy ){ assert( pSrc->fg.isCte==0 ); @@ -169823,7 +169943,7 @@ static int whereLoopAddBtree( sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; - pFirst = pSrc->pSTab->pIndex; + pFirst = pSrc->pTab->pIndex; if( pSrc->fg.notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ @@ -169913,7 +170033,6 @@ static int whereLoopAddBtree( pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; - pNew->u.btree.pOrderBy = 0; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ @@ -169943,10 +170062,6 @@ static int whereLoopAddBtree( #endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); - if( pSrc->fg.isSubquery ){ - if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; - pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; - } rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -169984,9 +170099,7 @@ static int whereLoopAddBtree( " according to whereIsCoveringIndex()\n", pProbe->zName)); } } - }else if( m==0 - && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) - ){ + }else if( m==0 ){ WHERETRACE(0x200, ("-> %s a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); @@ -170168,10 +170281,11 @@ static int whereLoopAddVirtualOne( pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; pHidden->mHandleIn = 0; /* Invoke the virtual table xBestIndex() method */ - rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo); + rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); if( rc ){ if( rc==SQLITE_CONSTRAINT ){ /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means @@ -170201,7 +170315,7 @@ static int whereLoopAddVirtualOne( || pNew->aLTerm[iTerm]!=0 || pIdxCons->usable==0 ){ - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); freeIdxStr(pIdxInfo); return SQLITE_ERROR; } @@ -170264,7 +170378,7 @@ static int whereLoopAddVirtualOne( if( pNew->aLTerm[i]==0 ){ /* The non-zero argvIdx values must be contiguous. Raise an ** error if they are not */ - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); freeIdxStr(pIdxInfo); return SQLITE_ERROR; } @@ -170276,7 +170390,6 @@ static int whereLoopAddVirtualOne( pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? pIdxInfo->nOrderBy : 0); - pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0; pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); @@ -170467,7 +170580,7 @@ static int whereLoopAddVirtual( pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; - assert( IsVirtual(pSrc->pSTab) ); + assert( IsVirtual(pSrc->pTab) ); p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; @@ -170481,7 +170594,7 @@ static int whereLoopAddVirtual( } /* First call xBestIndex() with all constraints usable. */ - WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName)); + WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x800, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry @@ -170563,7 +170676,7 @@ static int whereLoopAddVirtual( } freeIndexInfo(pParse->db, p); - WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc)); + WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -170635,7 +170748,7 @@ static int whereLoopAddOr( } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pItem->pSTab) ){ + if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif @@ -170749,7 +170862,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pItem->pSTab) ){ + if( IsVirtual(pItem->pTab) ){ SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_OUTER|JT_CROSS)) ){ @@ -170781,97 +170894,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ return rc; } -/* Implementation of the order-by-subquery optimization: -** -** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really -** a subquery or CTE that has an ORDER BY clause. See if any of the terms -** in the subquery ORDER BY clause will satisfy pOrderBy from the outer -** query. Mark off all satisfied terms (by setting bits in *pOBSat) and -** return TRUE if they do. If not, return false. -** -** Example: -** -** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b)); -** CREATE TABLE t2(x,y); -** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y) -** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b; -** -** The CTE named "t3" comes out in the natural order of "p", so the first -** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3" -** and sorting only needs to occur on the second term "b". -** -** Limitations: -** -** (1) The optimization is not applied if the outer ORDER BY contains -** a COLLATE clause. The optimization might be applied if the -** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as -** long as the subquery ORDER BY does the same. But if the -** outer ORDER BY uses COLLATE, even a redundant COLLATE, the -** optimization is bypassed. -** -** (2) The subquery ORDER BY terms must exactly match subquery result -** columns, including any COLLATE annotations. This routine relies -** on iOrderByCol to do matching between order by terms and result -** columns, and iOrderByCol will not be set if the result column -** and ORDER BY collations differ. -** -** (3) The subquery and outer ORDER BY can be in opposite directions as -** long as the subquery is materialized. If the subquery is -** implemented as a co-routine, the sort orders must be in the same -** direction because there is no way to run a co-routine backwards. -*/ -static SQLITE_NOINLINE int wherePathMatchSubqueryOB( - WhereInfo *pWInfo, /* The WHERE clause */ - WhereLoop *pLoop, /* The nested loop term that is a subquery */ - int iLoop, /* Which level of the nested loop. 0==outermost */ - int iCur, /* Cursor used by the this loop */ - ExprList *pOrderBy, /* The ORDER BY clause on the whole query */ - Bitmask *pRevMask, /* When loops need to go in reverse order */ - Bitmask *pOBSat /* Which terms of pOrderBy are satisfied so far */ -){ - int iOB; /* Index into pOrderBy->a[] */ - int jSub; /* Index into pSubOB->a[] */ - u8 rev = 0; /* True if iOB and jSub sort in opposite directions */ - u8 revIdx = 0; /* Sort direction for jSub */ - Expr *pOBExpr; /* Current term of outer ORDER BY */ - ExprList *pSubOB; /* Complete ORDER BY on the subquery */ - - pSubOB = pLoop->u.btree.pOrderBy; - assert( pSubOB!=0 ); - for(iOB=0; (MASKBIT(iOB) & *pOBSat)!=0; iOB++){} - for(jSub=0; jSubnExpr && iOBnExpr; jSub++, iOB++){ - if( pSubOB->a[jSub].u.x.iOrderByCol==0 ) break; - pOBExpr = pOrderBy->a[iOB].pExpr; - if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) break; - if( pOBExpr->iTable!=iCur ) break; - if( pOBExpr->iColumn!=pSubOB->a[jSub].u.x.iOrderByCol-1 ) break; - if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ - u8 sfOB = pOrderBy->a[iOB].fg.sortFlags; /* sortFlags for iOB */ - u8 sfSub = pSubOB->a[jSub].fg.sortFlags; /* sortFlags for jSub */ - if( (sfSub & KEYINFO_ORDER_BIGNULL) != (sfOB & KEYINFO_ORDER_BIGNULL) ){ - break; - } - revIdx = sfSub & KEYINFO_ORDER_DESC; - if( jSub>0 ){ - if( (rev^revIdx)!=(sfOB & KEYINFO_ORDER_DESC) ){ - break; - } - }else{ - rev = revIdx ^ (sfOB & KEYINFO_ORDER_DESC); - if( rev ){ - if( (pLoop->wsFlags & WHERE_COROUTINE)!=0 ){ - /* Cannot run a co-routine in reverse order */ - break; - } - *pRevMask |= MASKBIT(iLoop); - } - } - } - *pOBSat |= MASKBIT(iOB); - } - return jSub>0; -} - /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 6th ** parameters) to see if it outputs rows in the requested ORDER BY @@ -171017,18 +171039,9 @@ static i8 wherePathSatisfiesOrderBy( if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ - if( pLoop->u.btree.pOrderBy - && OptimizationEnabled(db, SQLITE_OrderBySubq) - && wherePathMatchSubqueryOB(pWInfo,pLoop,iLoop,iCur, - pOrderBy,pRevMask, &obSat) - ){ - nColumn = 0; - isOrderDistinct = 0; - }else{ - nColumn = 1; - } pIndex = 0; nKeyCol = 0; + nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ @@ -171123,7 +171136,7 @@ static i8 wherePathSatisfiesOrderBy( } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and mark that ORDER BY term having been satisfied. + ** of the index and mark that ORDER BY term off */ isMatch = 0; for(i=0; bOnce && ipTabList->a + iLoop; sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", - pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName, + pItem->zAlias ? pItem->zAlias : pItem->pTab->zName, nDep, rDelta); } #endif @@ -171935,7 +171948,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; - pTab = pItem->pSTab; + pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){ testcase( pItem->fg.isIndexedBy ); @@ -172198,7 +172211,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( WhereLoop *pLoop = pWInfo->a[i].pWLoop; const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; - Table *pTab = pItem->pSTab; + Table *pTab = pItem->pTab; if( (pTab->tabFlags & TF_HasStat1)==0 ) break; pTab->tabFlags |= TF_MaybeReanalyze; if( i>=1 @@ -172355,8 +172368,8 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){ SrcItem *pItem = &pWInfo->pTabList->a[ii]; if( !pItem->fg.isCte || pItem->u2.pCteUse->eM10d!=M10d_Yes - || NEVER(pItem->fg.isSubquery==0) - || pItem->u4.pSubq->pSelect->pOrderBy==0 + || NEVER(pItem->pSelect==0) + || pItem->pSelect->pOrderBy==0 ){ pWInfo->revMask |= MASKBIT(ii); } @@ -172846,15 +172859,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; - assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) ); + assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) - && !IsVirtual(pTabList->a[0].pSTab) + && !IsVirtual(pTabList->a[0].pTab) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) && OptimizationEnabled(db, SQLITE_OnePass) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; - if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){ + if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ bFordelete = OPFLAG_FORDELETE; } @@ -172872,7 +172885,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( SrcItem *pTabItem; pTabItem = &pTabList->a[pLevel->iFrom]; - pTab = pTabItem->pSTab; + pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ @@ -172943,7 +172956,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( iIndexCur = pLevel->iTabCur; op = 0; }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ - Index *pJ = pTabItem->pSTab->pIndex; + Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iAuxArg; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ @@ -173010,7 +173023,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); - assert( pTab==pTabItem->pSTab ); + assert( pTab==pTabItem->pTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); @@ -173049,18 +173062,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( wsFlags = pLevel->pWLoop->wsFlags; pSrc = &pTabList->a[pLevel->iFrom]; if( pSrc->fg.isMaterialized ){ - Subquery *pSubq; - int iOnce = 0; - assert( pSrc->fg.isSubquery ); - pSubq = pSrc->u4.pSubq; - if( pSrc->fg.isCorrelated==0 ){ - iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + if( pSrc->fg.isCorrelated ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); }else{ - iOnce = 0; + int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); + sqlite3VdbeJumpHere(v, iOnce); } - sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub); - VdbeComment((v, "materialize %!S", pSrc)); - if( iOnce ) sqlite3VdbeJumpHere(v, iOnce); } assert( pTabList == pWInfo->pTabList ); if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){ @@ -173123,6 +173131,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } #endif +#ifdef SQLITE_DEBUG +/* +** Return true if cursor iCur is opened by instruction k of the +** bytecode. Used inside of assert() only. +*/ +static int cursorIsOpen(Vdbe *v, int iCur, int k){ + while( k>=0 ){ + VdbeOp *pOp = sqlite3VdbeGetOp(v,k--); + if( pOp->p1!=iCur ) continue; + if( pOp->opcode==OP_Close ) return 0; + if( pOp->opcode==OP_OpenRead ) return 1; + if( pOp->opcode==OP_OpenWrite ) return 1; + if( pOp->opcode==OP_OpenDup ) return 1; + if( pOp->opcode==OP_OpenAutoindex ) return 1; + if( pOp->opcode==OP_OpenEphemeral ) return 1; + } + return 0; +} +#endif /* SQLITE_DEBUG */ + /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. @@ -173273,10 +173301,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pLevel->iTabCur==pSrc->iCursor ); if( pSrc->fg.viaCoroutine ){ int m, n; - assert( pSrc->fg.isSubquery ); - n = pSrc->u4.pSubq->regResult; - assert( pSrc->pSTab!=0 ); - m = pSrc->pSTab->nCol; + n = pSrc->regResult; + assert( pSrc->pTab!=0 ); + m = pSrc->pTab->nCol; sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1); } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); @@ -173300,7 +173327,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, addr); } VdbeModuleComment((v, "End WHERE-loop%d: %s", i, - pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName)); + pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); } assert( pWInfo->nLevel<=pTabList->nSrc ); @@ -173309,7 +173336,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeOp *pOp, *pLastOp; Index *pIdx = 0; SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; - Table *pTab = pTabItem->pSTab; + Table *pTab = pTabItem->pTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; @@ -173328,10 +173355,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ */ if( pTabItem->fg.viaCoroutine ){ testcase( pParse->db->mallocFailed ); - assert( pTabItem->fg.isSubquery ); - assert( pTabItem->u4.pSubq->regResult>=0 ); + assert( pTabItem->regResult>=0 ); translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, - pTabItem->u4.pSubq->regResult, 0); + pTabItem->regResult, 0); continue; } @@ -173424,10 +173450,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** reference. Verify that this is harmless - that the ** table being referenced really is open. */ - if( pLoop->wsFlags & WHERE_IDX_ONLY ){ - sqlite3ErrorMsg(pParse, "internal query planner error"); - pParse->rc = SQLITE_INTERNAL; - } +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + || cursorIsOpen(v,pOp->p1,k) + || pOp->opcode==OP_Offset + ); +#else + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + || cursorIsOpen(v,pOp->p1,k) + ); +#endif } }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; @@ -174541,10 +174573,9 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside ** of sqlite3DbMallocRawNN() called from ** sqlite3SrcListAppend() */ - if( p->pSrc==0 ){ - sqlite3SelectDelete(db, pSub); - }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){ + if( p->pSrc ){ Table *pTab2; + p->pSrc->a[0].pSelect = pSub; p->pSrc->a[0].fg.isCorrelated = 1; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded|SF_OrderByReqd; @@ -174558,7 +174589,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; - p->pSrc->a[0].pSTab = pTab; + p->pSrc->a[0].pTab = pTab; pTab = pTab2; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3WindowExtraAggFuncDepth; @@ -174566,6 +174597,8 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ w.xSelectCallback2 = sqlite3WalkerDepthDecrease; sqlite3WalkSelect(&w, pSub); } + }else{ + sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; @@ -174852,15 +174885,10 @@ SQLITE_PRIVATE int sqlite3WindowCompare( ** and initialize registers and cursors used by sqlite3WindowCodeStep(). */ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ + int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; + Window *pMWin = pSelect->pWin; Window *pWin; - int nEphExpr; - Window *pMWin; - Vdbe *v; - - assert( pSelect->pSrc->a[0].fg.isSubquery ); - nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr; - pMWin = pSelect->pWin; - v = sqlite3GetVdbe(pParse); + Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); @@ -176257,7 +176285,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( Vdbe *v = sqlite3GetVdbe(pParse); int csrWrite; /* Cursor used to write to eph. table */ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ - int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */ + int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ int iInput; /* To iterate through sub cols */ int addrNe; /* Address of OP_Ne */ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ @@ -176711,9 +176739,9 @@ static void updateDeleteLimitError( break; } } - if( (p->selFlags & (SF_MultiValue|SF_Values))==0 - && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 - && cnt>mxSelect + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } @@ -176827,174 +176855,174 @@ static void updateDeleteLimitError( #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_ID 9 -#define TK_COMMIT 10 -#define TK_END 11 -#define TK_ROLLBACK 12 -#define TK_SAVEPOINT 13 -#define TK_RELEASE 14 -#define TK_TO 15 -#define TK_TABLE 16 -#define TK_CREATE 17 -#define TK_IF 18 -#define TK_NOT 19 -#define TK_EXISTS 20 -#define TK_TEMP 21 -#define TK_LP 22 -#define TK_RP 23 -#define TK_AS 24 -#define TK_COMMA 25 -#define TK_WITHOUT 26 -#define TK_ABORT 27 -#define TK_ACTION 28 -#define TK_AFTER 29 -#define TK_ANALYZE 30 -#define TK_ASC 31 -#define TK_ATTACH 32 -#define TK_BEFORE 33 -#define TK_BY 34 -#define TK_CASCADE 35 -#define TK_CAST 36 -#define TK_CONFLICT 37 -#define TK_DATABASE 38 -#define TK_DESC 39 -#define TK_DETACH 40 -#define TK_EACH 41 -#define TK_EXCLUSIVE 42 -#define TK_FAIL 43 -#define TK_OR 44 -#define TK_AND 45 -#define TK_IS 46 -#define TK_ISNOT 47 -#define TK_MATCH 48 -#define TK_LIKE_KW 49 -#define TK_BETWEEN 50 -#define TK_IN 51 -#define TK_ISNULL 52 -#define TK_NOTNULL 53 -#define TK_NE 54 -#define TK_EQ 55 -#define TK_GT 56 -#define TK_LE 57 -#define TK_LT 58 -#define TK_GE 59 -#define TK_ESCAPE 60 -#define TK_COLUMNKW 61 -#define TK_DO 62 -#define TK_FOR 63 -#define TK_IGNORE 64 -#define TK_INITIALLY 65 -#define TK_INSTEAD 66 -#define TK_NO 67 -#define TK_KEY 68 -#define TK_OF 69 -#define TK_OFFSET 70 -#define TK_PRAGMA 71 -#define TK_RAISE 72 -#define TK_RECURSIVE 73 -#define TK_REPLACE 74 -#define TK_RESTRICT 75 -#define TK_ROW 76 -#define TK_ROWS 77 -#define TK_TRIGGER 78 -#define TK_VACUUM 79 -#define TK_VIEW 80 -#define TK_VIRTUAL 81 -#define TK_WITH 82 -#define TK_NULLS 83 -#define TK_FIRST 84 -#define TK_LAST 85 -#define TK_CURRENT 86 -#define TK_FOLLOWING 87 -#define TK_PARTITION 88 -#define TK_PRECEDING 89 -#define TK_RANGE 90 -#define TK_UNBOUNDED 91 -#define TK_EXCLUDE 92 -#define TK_GROUPS 93 -#define TK_OTHERS 94 -#define TK_TIES 95 -#define TK_GENERATED 96 -#define TK_ALWAYS 97 -#define TK_MATERIALIZED 98 -#define TK_REINDEX 99 -#define TK_RENAME 100 -#define TK_CTIME_KW 101 -#define TK_ANY 102 -#define TK_BITAND 103 -#define TK_BITOR 104 -#define TK_LSHIFT 105 -#define TK_RSHIFT 106 -#define TK_PLUS 107 -#define TK_MINUS 108 -#define TK_STAR 109 -#define TK_SLASH 110 -#define TK_REM 111 -#define TK_CONCAT 112 -#define TK_PTR 113 -#define TK_COLLATE 114 -#define TK_BITNOT 115 -#define TK_ON 116 -#define TK_INDEXED 117 -#define TK_STRING 118 -#define TK_JOIN_KW 119 -#define TK_CONSTRAINT 120 -#define TK_DEFAULT 121 -#define TK_NULL 122 -#define TK_PRIMARY 123 -#define TK_UNIQUE 124 -#define TK_CHECK 125 -#define TK_REFERENCES 126 -#define TK_AUTOINCR 127 -#define TK_INSERT 128 -#define TK_DELETE 129 -#define TK_UPDATE 130 -#define TK_SET 131 -#define TK_DEFERRABLE 132 -#define TK_FOREIGN 133 -#define TK_DROP 134 -#define TK_UNION 135 -#define TK_ALL 136 -#define TK_EXCEPT 137 -#define TK_INTERSECT 138 -#define TK_SELECT 139 -#define TK_VALUES 140 -#define TK_DISTINCT 141 -#define TK_DOT 142 -#define TK_FROM 143 -#define TK_JOIN 144 -#define TK_USING 145 -#define TK_ORDER 146 -#define TK_GROUP 147 -#define TK_HAVING 148 -#define TK_LIMIT 149 -#define TK_WHERE 150 -#define TK_RETURNING 151 -#define TK_INTO 152 -#define TK_NOTHING 153 -#define TK_FLOAT 154 -#define TK_BLOB 155 -#define TK_INTEGER 156 -#define TK_VARIABLE 157 -#define TK_CASE 158 -#define TK_WHEN 159 -#define TK_THEN 160 -#define TK_ELSE 161 -#define TK_INDEX 162 -#define TK_ALTER 163 -#define TK_ADD 164 -#define TK_WINDOW 165 -#define TK_OVER 166 -#define TK_FILTER 167 -#define TK_COLUMN 168 -#define TK_AGG_FUNCTION 169 -#define TK_AGG_COLUMN 170 -#define TK_TRUEFALSE 171 -#define TK_FUNCTION 172 -#define TK_UPLUS 173 -#define TK_UMINUS 174 -#define TK_TRUTH 175 -#define TK_REGISTER 176 -#define TK_CONCURRENT 177 +#define TK_CONCURRENT 10 +#define TK_COMMIT 11 +#define TK_END 12 +#define TK_ROLLBACK 13 +#define TK_SAVEPOINT 14 +#define TK_RELEASE 15 +#define TK_TO 16 +#define TK_TABLE 17 +#define TK_CREATE 18 +#define TK_IF 19 +#define TK_NOT 20 +#define TK_EXISTS 21 +#define TK_TEMP 22 +#define TK_LP 23 +#define TK_RP 24 +#define TK_AS 25 +#define TK_COMMA 26 +#define TK_WITHOUT 27 +#define TK_ABORT 28 +#define TK_ACTION 29 +#define TK_AFTER 30 +#define TK_ANALYZE 31 +#define TK_ASC 32 +#define TK_ATTACH 33 +#define TK_BEFORE 34 +#define TK_BY 35 +#define TK_CASCADE 36 +#define TK_CAST 37 +#define TK_CONFLICT 38 +#define TK_DATABASE 39 +#define TK_DESC 40 +#define TK_DETACH 41 +#define TK_EACH 42 +#define TK_EXCLUSIVE 43 +#define TK_FAIL 44 +#define TK_OR 45 +#define TK_AND 46 +#define TK_IS 47 +#define TK_ISNOT 48 +#define TK_MATCH 49 +#define TK_LIKE_KW 50 +#define TK_BETWEEN 51 +#define TK_IN 52 +#define TK_ISNULL 53 +#define TK_NOTNULL 54 +#define TK_NE 55 +#define TK_EQ 56 +#define TK_GT 57 +#define TK_LE 58 +#define TK_LT 59 +#define TK_GE 60 +#define TK_ESCAPE 61 +#define TK_COLUMNKW 62 +#define TK_DO 63 +#define TK_FOR 64 +#define TK_IGNORE 65 +#define TK_INITIALLY 66 +#define TK_INSTEAD 67 +#define TK_NO 68 +#define TK_KEY 69 +#define TK_OF 70 +#define TK_OFFSET 71 +#define TK_PRAGMA 72 +#define TK_RAISE 73 +#define TK_RECURSIVE 74 +#define TK_REPLACE 75 +#define TK_RESTRICT 76 +#define TK_ROW 77 +#define TK_ROWS 78 +#define TK_TRIGGER 79 +#define TK_VACUUM 80 +#define TK_VIEW 81 +#define TK_VIRTUAL 82 +#define TK_WITH 83 +#define TK_NULLS 84 +#define TK_FIRST 85 +#define TK_LAST 86 +#define TK_CURRENT 87 +#define TK_FOLLOWING 88 +#define TK_PARTITION 89 +#define TK_PRECEDING 90 +#define TK_RANGE 91 +#define TK_UNBOUNDED 92 +#define TK_EXCLUDE 93 +#define TK_GROUPS 94 +#define TK_OTHERS 95 +#define TK_TIES 96 +#define TK_GENERATED 97 +#define TK_ALWAYS 98 +#define TK_MATERIALIZED 99 +#define TK_REINDEX 100 +#define TK_RENAME 101 +#define TK_CTIME_KW 102 +#define TK_ANY 103 +#define TK_BITAND 104 +#define TK_BITOR 105 +#define TK_LSHIFT 106 +#define TK_RSHIFT 107 +#define TK_PLUS 108 +#define TK_MINUS 109 +#define TK_STAR 110 +#define TK_SLASH 111 +#define TK_REM 112 +#define TK_CONCAT 113 +#define TK_PTR 114 +#define TK_COLLATE 115 +#define TK_BITNOT 116 +#define TK_ON 117 +#define TK_INDEXED 118 +#define TK_STRING 119 +#define TK_JOIN_KW 120 +#define TK_CONSTRAINT 121 +#define TK_DEFAULT 122 +#define TK_NULL 123 +#define TK_PRIMARY 124 +#define TK_UNIQUE 125 +#define TK_CHECK 126 +#define TK_REFERENCES 127 +#define TK_AUTOINCR 128 +#define TK_INSERT 129 +#define TK_DELETE 130 +#define TK_UPDATE 131 +#define TK_SET 132 +#define TK_DEFERRABLE 133 +#define TK_FOREIGN 134 +#define TK_DROP 135 +#define TK_UNION 136 +#define TK_ALL 137 +#define TK_EXCEPT 138 +#define TK_INTERSECT 139 +#define TK_SELECT 140 +#define TK_VALUES 141 +#define TK_DISTINCT 142 +#define TK_DOT 143 +#define TK_FROM 144 +#define TK_JOIN 145 +#define TK_USING 146 +#define TK_ORDER 147 +#define TK_GROUP 148 +#define TK_HAVING 149 +#define TK_LIMIT 150 +#define TK_WHERE 151 +#define TK_RETURNING 152 +#define TK_INTO 153 +#define TK_NOTHING 154 +#define TK_FLOAT 155 +#define TK_BLOB 156 +#define TK_INTEGER 157 +#define TK_VARIABLE 158 +#define TK_CASE 159 +#define TK_WHEN 160 +#define TK_THEN 161 +#define TK_ELSE 162 +#define TK_INDEX 163 +#define TK_ALTER 164 +#define TK_ADD 165 +#define TK_WINDOW 166 +#define TK_OVER 167 +#define TK_FILTER 168 +#define TK_COLUMN 169 +#define TK_AGG_FUNCTION 170 +#define TK_AGG_COLUMN 171 +#define TK_TRUEFALSE 172 +#define TK_FUNCTION 173 +#define TK_UPLUS 174 +#define TK_UMINUS 175 +#define TK_TRUTH 176 +#define TK_REGISTER 177 #define TK_VECTOR 178 #define TK_SELECT_COLUMN 179 #define TK_IF_NULL_ROW 180 @@ -177070,7 +177098,7 @@ static void updateDeleteLimitError( #define YYCODETYPE unsigned short int #define YYNOCODE 323 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 102 +#define YYWILDCARD 103 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; @@ -177112,17 +177140,17 @@ typedef union { #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 #define YYNSTATE 587 -#define YYNRULE 409 -#define YYNRULE_WITH_ACTION 344 +#define YYNRULE 410 +#define YYNRULE_WITH_ACTION 345 #define YYNTOKEN 187 #define YY_MAX_SHIFT 586 -#define YY_MIN_SHIFTREDUCE 849 -#define YY_MAX_SHIFTREDUCE 1257 -#define YY_ERROR_ACTION 1258 -#define YY_ACCEPT_ACTION 1259 -#define YY_NO_ACTION 1260 -#define YY_MIN_REDUCE 1261 -#define YY_MAX_REDUCE 1669 +#define YY_MIN_SHIFTREDUCE 850 +#define YY_MAX_SHIFTREDUCE 1259 +#define YY_ERROR_ACTION 1260 +#define YY_ACCEPT_ACTION 1261 +#define YY_NO_ACTION 1262 +#define YY_MIN_REDUCE 1263 +#define YY_MAX_REDUCE 1672 #define YY_MIN_DSTRCTR 206 #define YY_MAX_DSTRCTR 320 /************* End control #defines *******************************************/ @@ -177207,637 +177235,677 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2176) +#define YY_ACTTAB_COUNT (2379) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 1332, 580, 1311, 580, 379, 580, 1285, 282, 282, 1626, - /* 10 */ 1332, 1259, 1, 1, 586, 2, 1263, 1304, 1283, 417, - /* 20 */ 577, 321, 566, 155, 81, 81, 51, 51, 51, 51, - /* 30 */ 1345, 987, 130, 127, 234, 1153, 1661, 1294, 1661, 988, - /* 40 */ 130, 127, 234, 436, 137, 138, 91, 534, 1232, 1232, - /* 50 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 60 */ 1208, 1546, 580, 38, 1285, 288, 288, 1606, 586, 2, - /* 70 */ 1263, 285, 1208, 973, 582, 321, 582, 155, 577, 502, - /* 80 */ 566, 214, 288, 288, 1345, 82, 82, 391, 136, 136, - /* 90 */ 136, 136, 129, 245, 416, 577, 39, 566, 1337, 1337, - /* 100 */ 264, 231, 283, 134, 134, 134, 134, 133, 133, 132, - /* 110 */ 132, 132, 131, 128, 455, 1151, 307, 1581, 307, 288, - /* 120 */ 288, 7, 561, 417, 1545, 459, 1586, 384, 1586, 548, - /* 130 */ 1208, 535, 577, 1572, 566, 134, 134, 134, 134, 133, - /* 140 */ 133, 132, 132, 132, 131, 128, 455, 245, 137, 138, - /* 150 */ 91, 455, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, - /* 160 */ 136, 136, 136, 136, 130, 127, 234, 233, 1208, 1209, - /* 170 */ 1208, 257, 953, 1297, 515, 512, 511, 182, 441, 459, - /* 180 */ 1208, 1209, 1208, 368, 510, 132, 132, 132, 131, 128, - /* 190 */ 455, 1178, 973, 1178, 134, 134, 134, 134, 133, 133, - /* 200 */ 132, 132, 132, 131, 128, 455, 362, 134, 134, 134, - /* 210 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 133, - /* 220 */ 133, 132, 132, 132, 131, 128, 455, 417, 452, 451, - /* 230 */ 44, 289, 289, 112, 485, 1023, 261, 1237, 1208, 1209, - /* 240 */ 1208, 111, 1239, 44, 577, 1574, 566, 381, 580, 329, - /* 250 */ 1238, 502, 137, 138, 91, 518, 1232, 1232, 1067, 1070, - /* 260 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 357, 465, - /* 270 */ 360, 19, 19, 438, 392, 1240, 388, 1240, 139, 274, - /* 280 */ 291, 376, 521, 371, 520, 262, 430, 320, 571, 348, - /* 290 */ 1296, 367, 1173, 1173, 527, 527, 1509, 1023, 417, 7, - /* 300 */ 320, 571, 487, 544, 422, 1173, 1173, 294, 1173, 1173, - /* 310 */ 296, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 320 */ 131, 128, 455, 137, 138, 91, 1632, 1232, 1232, 1067, - /* 330 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 417, - /* 340 */ 1510, 1455, 288, 288, 94, 257, 214, 93, 515, 512, - /* 350 */ 511, 348, 471, 334, 396, 577, 385, 566, 510, 410, - /* 360 */ 182, 543, 386, 502, 137, 138, 91, 417, 1232, 1232, - /* 370 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 380 */ 377, 1599, 134, 134, 134, 134, 133, 133, 132, 132, - /* 390 */ 132, 131, 128, 455, 91, 421, 1232, 1232, 1067, 1070, - /* 400 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 425, 1602, - /* 410 */ 417, 1208, 130, 127, 234, 44, 579, 1208, 130, 127, - /* 420 */ 234, 476, 350, 134, 134, 134, 134, 133, 133, 132, - /* 430 */ 132, 132, 131, 128, 455, 137, 138, 91, 427, 1232, - /* 440 */ 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, - /* 450 */ 136, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 460 */ 131, 128, 455, 580, 452, 451, 1439, 460, 1208, 580, - /* 470 */ 157, 1208, 320, 571, 562, 45, 554, 552, 552, 496, - /* 480 */ 528, 46, 7, 493, 197, 275, 82, 82, 1054, 1054, - /* 490 */ 1068, 1071, 61, 61, 134, 134, 134, 134, 133, 133, - /* 500 */ 132, 132, 132, 131, 128, 455, 468, 1208, 331, 288, - /* 510 */ 288, 1240, 580, 1240, 417, 288, 288, 415, 364, 1208, - /* 520 */ 1209, 1208, 577, 561, 566, 1208, 1209, 1208, 577, 529, - /* 530 */ 566, 382, 563, 580, 417, 51, 51, 432, 516, 137, - /* 540 */ 138, 91, 219, 1232, 1232, 1067, 1070, 1057, 1057, 135, - /* 550 */ 135, 136, 136, 136, 136, 379, 82, 82, 539, 137, - /* 560 */ 138, 91, 1058, 1232, 1232, 1067, 1070, 1057, 1057, 135, - /* 570 */ 135, 136, 136, 136, 136, 1173, 1208, 1209, 1208, 1208, - /* 580 */ 1209, 1208, 536, 108, 320, 571, 551, 580, 1173, 987, - /* 590 */ 580, 1173, 1575, 540, 446, 407, 1208, 988, 134, 134, - /* 600 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 610 */ 82, 82, 538, 82, 82, 1208, 1209, 1208, 134, 134, - /* 620 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 630 */ 288, 288, 550, 1153, 1662, 1588, 1662, 383, 417, 574, - /* 640 */ 574, 574, 890, 577, 542, 566, 578, 561, 940, 940, - /* 650 */ 561, 549, 131, 128, 455, 1208, 560, 238, 417, 443, - /* 660 */ 1184, 483, 883, 137, 138, 91, 303, 1232, 1232, 1067, - /* 670 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 108, - /* 680 */ 537, 464, 111, 137, 138, 91, 533, 1232, 1232, 1067, - /* 690 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 464, - /* 700 */ 463, 288, 288, 1248, 1208, 1209, 1208, 1439, 538, 22, - /* 710 */ 22, 427, 1184, 1151, 577, 1208, 566, 580, 232, 1343, - /* 720 */ 1572, 554, 134, 134, 134, 134, 133, 133, 132, 132, - /* 730 */ 132, 131, 128, 455, 580, 1281, 580, 229, 526, 96, - /* 740 */ 82, 82, 134, 134, 134, 134, 133, 133, 132, 132, - /* 750 */ 132, 131, 128, 455, 288, 288, 580, 19, 19, 19, - /* 760 */ 19, 6, 417, 1208, 1209, 1208, 1191, 577, 48, 566, - /* 770 */ 288, 288, 435, 464, 437, 320, 571, 316, 433, 145, - /* 780 */ 145, 212, 417, 577, 897, 566, 1045, 137, 138, 91, - /* 790 */ 975, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 800 */ 136, 136, 136, 580, 390, 580, 523, 137, 138, 91, - /* 810 */ 6, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 820 */ 136, 136, 136, 1208, 1209, 1208, 19, 19, 19, 19, - /* 830 */ 427, 469, 1573, 948, 381, 209, 555, 555, 947, 580, - /* 840 */ 475, 306, 415, 442, 530, 1556, 134, 134, 134, 134, - /* 850 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1558, - /* 860 */ 580, 1579, 82, 82, 580, 7, 134, 134, 134, 134, - /* 870 */ 133, 133, 132, 132, 132, 131, 128, 455, 1208, 288, - /* 880 */ 288, 19, 19, 19, 19, 491, 417, 19, 19, 492, - /* 890 */ 1028, 198, 577, 1111, 566, 461, 206, 1111, 207, 317, - /* 900 */ 213, 1208, 556, 1631, 580, 915, 417, 136, 136, 136, - /* 910 */ 136, 137, 138, 91, 40, 1232, 1232, 1067, 1070, 1057, - /* 920 */ 1057, 135, 135, 136, 136, 136, 136, 147, 147, 1515, - /* 930 */ 497, 137, 138, 91, 1228, 1232, 1232, 1067, 1070, 1057, - /* 940 */ 1057, 135, 135, 136, 136, 136, 136, 1515, 1517, 267, - /* 950 */ 340, 1130, 141, 1439, 134, 134, 134, 134, 133, 133, - /* 960 */ 132, 132, 132, 131, 128, 455, 1131, 1109, 1572, 536, - /* 970 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 980 */ 128, 455, 1132, 477, 1208, 298, 1208, 1209, 1208, 1208, - /* 990 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1000 */ 128, 455, 5, 926, 580, 485, 345, 1208, 1044, 1208, - /* 1010 */ 1209, 1208, 337, 927, 339, 478, 50, 580, 125, 417, - /* 1020 */ 3, 1515, 1349, 1129, 434, 1033, 415, 66, 66, 1032, - /* 1030 */ 453, 453, 453, 290, 577, 866, 566, 414, 413, 417, - /* 1040 */ 67, 67, 1572, 1228, 137, 138, 91, 115, 1232, 1232, - /* 1050 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 1060 */ 580, 1032, 1032, 1034, 137, 138, 91, 537, 1232, 1232, - /* 1070 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 1080 */ 1573, 299, 381, 82, 82, 476, 350, 1228, 1554, 485, - /* 1090 */ 47, 1192, 1208, 1209, 1208, 474, 338, 1208, 1209, 1208, - /* 1100 */ 10, 564, 267, 134, 134, 134, 134, 133, 133, 132, - /* 1110 */ 132, 132, 131, 128, 455, 1208, 1209, 1208, 1572, 974, - /* 1120 */ 449, 507, 580, 134, 134, 134, 134, 133, 133, 132, - /* 1130 */ 132, 132, 131, 128, 455, 580, 288, 288, 1089, 557, - /* 1140 */ 580, 1114, 1114, 499, 580, 21, 21, 580, 485, 577, - /* 1150 */ 261, 566, 417, 1620, 1573, 1439, 381, 215, 82, 82, - /* 1160 */ 260, 259, 258, 82, 82, 302, 49, 53, 53, 1211, - /* 1170 */ 68, 68, 417, 1335, 1335, 1454, 1502, 137, 138, 91, - /* 1180 */ 119, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 1190 */ 136, 136, 136, 906, 324, 450, 1228, 137, 138, 91, - /* 1200 */ 454, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 1210 */ 136, 136, 136, 1453, 377, 1599, 1663, 403, 422, 854, - /* 1220 */ 855, 856, 1286, 423, 304, 519, 498, 973, 1372, 315, - /* 1230 */ 1573, 580, 381, 907, 367, 502, 134, 134, 134, 134, - /* 1240 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 227, - /* 1250 */ 580, 491, 377, 1599, 54, 54, 134, 134, 134, 134, - /* 1260 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1173, - /* 1270 */ 580, 69, 69, 70, 70, 580, 417, 214, 1211, 227, - /* 1280 */ 1344, 557, 1173, 325, 878, 1173, 573, 423, 1439, 439, - /* 1290 */ 405, 71, 71, 72, 72, 580, 417, 160, 73, 73, - /* 1300 */ 158, 137, 126, 91, 502, 1232, 1232, 1067, 1070, 1057, - /* 1310 */ 1057, 135, 135, 136, 136, 136, 136, 580, 55, 55, - /* 1320 */ 886, 233, 138, 91, 580, 1232, 1232, 1067, 1070, 1057, - /* 1330 */ 1057, 135, 135, 136, 136, 136, 136, 402, 1253, 491, - /* 1340 */ 56, 56, 1130, 424, 184, 456, 973, 57, 57, 1340, - /* 1350 */ 502, 347, 580, 466, 580, 123, 572, 1131, 4, 447, - /* 1360 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1370 */ 128, 455, 575, 1132, 109, 59, 59, 60, 60, 580, - /* 1380 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1390 */ 128, 455, 580, 878, 568, 355, 580, 222, 585, 580, - /* 1400 */ 1263, 580, 74, 74, 120, 321, 117, 155, 569, 402, - /* 1410 */ 1152, 161, 1044, 16, 1345, 75, 75, 1254, 44, 76, - /* 1420 */ 76, 482, 20, 20, 77, 77, 1580, 1578, 886, 1033, - /* 1430 */ 7, 7, 415, 1032, 1577, 489, 580, 1044, 7, 305, - /* 1440 */ 1227, 467, 948, 121, 121, 467, 580, 947, 297, 288, - /* 1450 */ 288, 122, 297, 456, 581, 456, 580, 319, 1032, 143, - /* 1460 */ 143, 456, 577, 166, 566, 1032, 1032, 1034, 415, 144, - /* 1470 */ 144, 123, 572, 242, 4, 320, 571, 245, 328, 78, - /* 1480 */ 78, 287, 231, 293, 481, 479, 456, 580, 575, 1254, - /* 1490 */ 1032, 1032, 1034, 1035, 35, 1192, 123, 572, 580, 4, - /* 1500 */ 97, 218, 9, 580, 1148, 580, 404, 580, 300, 459, - /* 1510 */ 62, 62, 580, 575, 23, 375, 580, 323, 580, 221, - /* 1520 */ 1192, 79, 79, 580, 569, 374, 63, 63, 80, 80, - /* 1530 */ 64, 64, 580, 490, 1384, 170, 170, 532, 546, 171, - /* 1540 */ 171, 87, 87, 545, 912, 913, 65, 65, 346, 569, - /* 1550 */ 111, 1383, 580, 1044, 428, 83, 83, 580, 222, 121, - /* 1560 */ 121, 470, 1025, 546, 266, 905, 904, 122, 547, 456, - /* 1570 */ 581, 456, 1561, 893, 1032, 146, 146, 456, 1044, 1096, - /* 1580 */ 84, 84, 990, 991, 121, 121, 524, 123, 572, 341, - /* 1590 */ 4, 244, 122, 1534, 456, 581, 456, 580, 484, 1032, - /* 1600 */ 266, 580, 456, 580, 575, 1036, 1032, 1032, 1034, 1035, - /* 1610 */ 35, 205, 123, 572, 580, 4, 1157, 1108, 580, 1108, - /* 1620 */ 168, 168, 1533, 494, 148, 148, 142, 142, 486, 575, - /* 1630 */ 266, 1032, 1032, 1034, 1035, 35, 1192, 169, 169, 292, - /* 1640 */ 569, 162, 162, 352, 400, 400, 399, 277, 397, 580, - /* 1650 */ 351, 863, 111, 1380, 546, 580, 508, 580, 263, 545, - /* 1660 */ 365, 1192, 111, 356, 239, 569, 327, 359, 580, 1044, - /* 1670 */ 361, 363, 152, 152, 326, 121, 121, 1328, 151, 151, - /* 1680 */ 149, 149, 893, 122, 1315, 456, 581, 456, 1096, 1314, - /* 1690 */ 1032, 150, 150, 1313, 1044, 580, 165, 1092, 111, 263, - /* 1700 */ 121, 121, 952, 1312, 978, 241, 266, 580, 122, 370, - /* 1710 */ 456, 581, 456, 175, 1036, 1032, 43, 380, 86, 86, - /* 1720 */ 1370, 1393, 1032, 1032, 1034, 1035, 35, 1605, 1196, 458, - /* 1730 */ 88, 88, 292, 240, 946, 1438, 125, 400, 400, 399, - /* 1740 */ 277, 397, 580, 943, 863, 125, 1366, 1032, 1032, 1034, - /* 1750 */ 1035, 35, 1192, 1593, 1107, 580, 1107, 239, 876, 327, - /* 1760 */ 159, 945, 1378, 125, 580, 85, 85, 326, 418, 567, - /* 1770 */ 503, 1443, 1293, 320, 571, 1284, 1272, 1192, 52, 52, - /* 1780 */ 1271, 1273, 1613, 280, 401, 167, 1363, 58, 58, 12, - /* 1790 */ 312, 313, 314, 1425, 224, 237, 295, 462, 241, 333, - /* 1800 */ 336, 343, 344, 301, 349, 488, 175, 1375, 456, 43, - /* 1810 */ 1430, 513, 1429, 228, 1376, 1311, 408, 210, 123, 572, - /* 1820 */ 373, 4, 1506, 1505, 1374, 1373, 240, 1616, 456, 570, - /* 1830 */ 211, 395, 1248, 270, 1553, 575, 1245, 223, 90, 572, - /* 1840 */ 1551, 4, 426, 186, 96, 1511, 220, 92, 235, 1426, - /* 1850 */ 95, 195, 140, 557, 332, 575, 13, 180, 1420, 188, - /* 1860 */ 1413, 418, 335, 472, 190, 191, 320, 571, 473, 192, - /* 1870 */ 193, 569, 506, 247, 109, 1434, 406, 199, 495, 1432, - /* 1880 */ 251, 102, 1431, 480, 409, 14, 501, 1522, 281, 354, - /* 1890 */ 462, 569, 1500, 203, 253, 522, 358, 254, 504, 1274, - /* 1900 */ 1044, 255, 1331, 411, 1330, 1329, 121, 121, 440, 104, - /* 1910 */ 1301, 412, 1322, 1630, 122, 1629, 456, 581, 456, 897, - /* 1920 */ 1044, 1032, 372, 1300, 1299, 1628, 121, 121, 1321, 229, - /* 1930 */ 1598, 444, 531, 310, 122, 445, 456, 581, 456, 311, - /* 1940 */ 559, 1032, 378, 268, 269, 448, 1398, 11, 1487, 389, - /* 1950 */ 116, 318, 110, 1032, 1032, 1034, 1035, 35, 1354, 387, - /* 1960 */ 558, 1353, 216, 1584, 1583, 541, 1397, 393, 42, 394, - /* 1970 */ 583, 1202, 276, 1032, 1032, 1034, 1035, 35, 1196, 458, - /* 1980 */ 278, 279, 292, 1192, 584, 1538, 172, 400, 400, 399, - /* 1990 */ 277, 397, 156, 1539, 863, 1269, 1264, 1537, 1536, 308, - /* 2000 */ 456, 225, 173, 1192, 226, 174, 850, 239, 457, 327, - /* 2010 */ 123, 572, 89, 4, 217, 322, 419, 326, 185, 420, - /* 2020 */ 154, 236, 1106, 1104, 330, 187, 176, 575, 1227, 189, - /* 2030 */ 929, 243, 342, 246, 1120, 194, 177, 178, 429, 98, - /* 2040 */ 99, 196, 100, 101, 179, 431, 1123, 248, 241, 1119, - /* 2050 */ 249, 163, 24, 250, 266, 353, 175, 1242, 1112, 43, - /* 2060 */ 500, 252, 200, 569, 201, 15, 374, 865, 505, 509, - /* 2070 */ 256, 895, 202, 103, 25, 26, 240, 366, 164, 514, - /* 2080 */ 369, 105, 309, 517, 1189, 908, 106, 525, 107, 1073, - /* 2090 */ 1159, 17, 1044, 1158, 27, 181, 230, 284, 121, 121, - /* 2100 */ 286, 204, 265, 976, 28, 125, 122, 982, 456, 581, - /* 2110 */ 456, 418, 29, 1032, 1175, 30, 320, 571, 31, 1179, - /* 2120 */ 8, 1177, 1182, 32, 1164, 41, 553, 33, 34, 208, - /* 2130 */ 111, 1087, 1074, 1072, 1076, 1128, 271, 113, 565, 114, - /* 2140 */ 462, 118, 1077, 36, 18, 1032, 1032, 1034, 1035, 35, - /* 2150 */ 1037, 877, 1183, 939, 124, 37, 398, 272, 153, 576, - /* 2160 */ 273, 183, 1621, 1198, 1197, 1260, 1260, 1260, 1260, 1260, - /* 2170 */ 1260, 1260, 1260, 1260, 1260, 1192, + /* 0 */ 1297, 580, 1584, 580, 284, 1629, 7, 130, 127, 234, + /* 10 */ 580, 1210, 580, 1307, 580, 130, 127, 234, 580, 1300, + /* 20 */ 417, 1335, 1299, 1314, 51, 51, 51, 51, 1549, 528, + /* 30 */ 888, 1335, 989, 51, 51, 82, 82, 82, 82, 533, + /* 40 */ 990, 61, 61, 1666, 403, 137, 138, 91, 427, 1234, + /* 50 */ 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, + /* 60 */ 136, 417, 22, 22, 289, 289, 130, 127, 234, 283, + /* 70 */ 283, 1210, 561, 362, 561, 1210, 45, 577, 529, 566, + /* 80 */ 1213, 535, 577, 560, 566, 502, 137, 138, 91, 197, + /* 90 */ 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, + /* 100 */ 136, 136, 487, 1210, 134, 134, 134, 134, 133, 133, + /* 110 */ 132, 132, 132, 131, 128, 455, 1442, 385, 331, 580, + /* 120 */ 1210, 1211, 1210, 1046, 1589, 384, 1591, 6, 383, 1180, + /* 130 */ 425, 1180, 417, 1589, 548, 357, 46, 360, 112, 888, + /* 140 */ 1035, 329, 82, 82, 1034, 134, 134, 134, 134, 133, + /* 150 */ 133, 132, 132, 132, 131, 128, 455, 137, 138, 91, + /* 160 */ 261, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, + /* 170 */ 136, 136, 136, 130, 127, 234, 1034, 1034, 1036, 561, + /* 180 */ 1210, 1211, 1210, 139, 1210, 1211, 1210, 432, 443, 460, + /* 190 */ 1213, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 200 */ 131, 128, 455, 1575, 417, 1194, 492, 136, 136, 136, + /* 210 */ 136, 129, 1210, 1211, 1210, 455, 134, 134, 134, 134, + /* 220 */ 133, 133, 132, 132, 132, 131, 128, 455, 422, 137, + /* 230 */ 138, 91, 1513, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 240 */ 135, 136, 136, 136, 136, 417, 578, 96, 942, 942, + /* 250 */ 94, 48, 386, 93, 134, 134, 134, 134, 133, 133, + /* 260 */ 132, 132, 132, 131, 128, 455, 1210, 574, 574, 574, + /* 270 */ 137, 138, 91, 1575, 1234, 1234, 1069, 1072, 1059, 1059, + /* 280 */ 135, 135, 136, 136, 136, 136, 1635, 1210, 134, 134, + /* 290 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 300 */ 133, 133, 132, 132, 132, 131, 128, 455, 130, 127, + /* 310 */ 234, 136, 136, 136, 136, 1576, 417, 381, 132, 132, + /* 320 */ 132, 131, 128, 455, 427, 1056, 1056, 1070, 1073, 134, + /* 330 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, + /* 340 */ 455, 137, 138, 91, 214, 1234, 1234, 1069, 1072, 1059, + /* 350 */ 1059, 135, 135, 136, 136, 136, 136, 405, 134, 134, + /* 360 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 370 */ 1605, 182, 1025, 1175, 464, 1210, 1211, 1210, 257, 468, + /* 380 */ 44, 515, 512, 511, 544, 1577, 1175, 381, 955, 1175, + /* 390 */ 415, 510, 464, 463, 212, 294, 1210, 1211, 1210, 1060, + /* 400 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 410 */ 128, 455, 1442, 1261, 1, 1, 586, 2, 1265, 1609, + /* 420 */ 586, 2, 1265, 321, 417, 155, 348, 321, 364, 155, + /* 430 */ 289, 289, 1348, 1210, 1288, 554, 1348, 320, 571, 44, + /* 440 */ 476, 350, 543, 577, 582, 566, 582, 198, 219, 137, + /* 450 */ 138, 91, 1046, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 460 */ 135, 136, 136, 136, 136, 1288, 464, 289, 289, 1035, + /* 470 */ 1132, 289, 289, 1034, 229, 526, 441, 1286, 465, 580, + /* 480 */ 577, 368, 566, 433, 577, 1133, 566, 469, 527, 527, + /* 490 */ 562, 1025, 1210, 7, 485, 245, 320, 571, 415, 245, + /* 500 */ 1582, 1134, 82, 82, 7, 1034, 1034, 1036, 134, 134, + /* 510 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 520 */ 1210, 585, 928, 1265, 579, 289, 289, 459, 321, 417, + /* 530 */ 155, 459, 929, 516, 1194, 1210, 427, 1348, 577, 561, + /* 540 */ 566, 1210, 1210, 1211, 1210, 348, 471, 334, 563, 40, + /* 550 */ 555, 555, 580, 518, 137, 138, 91, 534, 1234, 1234, + /* 560 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, + /* 570 */ 296, 438, 289, 289, 1210, 82, 82, 274, 292, 376, + /* 580 */ 521, 371, 520, 262, 392, 577, 388, 566, 5, 367, + /* 590 */ 1210, 257, 289, 289, 515, 512, 511, 291, 421, 157, + /* 600 */ 245, 1210, 1211, 1210, 510, 577, 213, 566, 275, 382, + /* 610 */ 264, 231, 540, 134, 134, 134, 134, 133, 133, 132, + /* 620 */ 132, 132, 131, 128, 455, 1210, 1175, 539, 977, 1210, + /* 630 */ 1211, 1210, 459, 1442, 417, 453, 453, 453, 892, 1175, + /* 640 */ 452, 451, 1175, 407, 1210, 1211, 1210, 478, 1575, 1239, + /* 650 */ 1210, 1211, 1210, 502, 1241, 485, 976, 580, 415, 137, + /* 660 */ 138, 91, 1240, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 670 */ 135, 136, 136, 136, 136, 182, 1210, 485, 289, 289, + /* 680 */ 19, 19, 496, 1210, 1211, 1210, 493, 1242, 580, 1242, + /* 690 */ 3, 577, 580, 566, 1175, 430, 50, 303, 1548, 1210, + /* 700 */ 1211, 1210, 1346, 1575, 434, 551, 1284, 1175, 485, 483, + /* 710 */ 1175, 82, 82, 320, 571, 19, 19, 1623, 134, 134, + /* 720 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 730 */ 435, 299, 289, 289, 1210, 1211, 1210, 289, 289, 417, + /* 740 */ 1583, 289, 289, 885, 7, 577, 530, 566, 316, 1210, + /* 750 */ 577, 47, 566, 302, 577, 564, 566, 131, 128, 455, + /* 760 */ 1576, 232, 381, 542, 137, 138, 91, 214, 1234, 1234, + /* 770 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, + /* 780 */ 416, 289, 289, 580, 304, 1210, 1211, 1210, 402, 1255, + /* 790 */ 289, 289, 552, 552, 577, 880, 566, 7, 1575, 390, + /* 800 */ 214, 1518, 307, 577, 307, 566, 19, 19, 396, 160, + /* 810 */ 502, 908, 580, 410, 580, 1576, 580, 381, 580, 1518, + /* 820 */ 1520, 437, 491, 134, 134, 134, 134, 133, 133, 132, + /* 830 */ 132, 132, 131, 128, 455, 19, 19, 19, 19, 19, + /* 840 */ 19, 19, 19, 519, 417, 6, 49, 502, 1193, 1581, + /* 850 */ 306, 909, 442, 7, 206, 1512, 207, 868, 1210, 1211, + /* 860 */ 1210, 1155, 1664, 580, 1664, 580, 1559, 580, 1256, 137, + /* 870 */ 138, 91, 580, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 880 */ 135, 136, 136, 136, 136, 580, 82, 82, 19, 19, + /* 890 */ 82, 82, 1347, 1518, 536, 81, 81, 580, 290, 290, + /* 900 */ 238, 452, 451, 556, 111, 880, 340, 439, 82, 82, + /* 910 */ 1576, 577, 381, 566, 507, 1155, 1665, 474, 1665, 209, + /* 920 */ 82, 82, 298, 317, 475, 402, 1154, 449, 134, 134, + /* 930 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 940 */ 166, 1153, 1442, 261, 44, 450, 1250, 1230, 1242, 417, + /* 950 */ 1242, 1580, 286, 1047, 975, 7, 1175, 454, 391, 491, + /* 960 */ 1091, 10, 1132, 267, 855, 856, 857, 858, 337, 1175, + /* 970 */ 339, 550, 1175, 580, 137, 138, 91, 1133, 1234, 1234, + /* 980 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, + /* 990 */ 549, 108, 537, 1134, 580, 1153, 145, 145, 1505, 1186, + /* 1000 */ 580, 320, 571, 320, 571, 1256, 1111, 580, 1340, 1340, + /* 1010 */ 120, 422, 117, 498, 568, 554, 491, 147, 147, 1318, + /* 1020 */ 538, 989, 580, 66, 66, 1458, 580, 367, 1457, 990, + /* 1030 */ 67, 67, 580, 134, 134, 134, 134, 133, 133, 132, + /* 1040 */ 132, 132, 131, 128, 455, 21, 21, 580, 233, 53, + /* 1050 */ 53, 1186, 338, 580, 417, 68, 68, 1230, 1030, 347, + /* 1060 */ 1116, 1116, 499, 524, 377, 1602, 1230, 377, 1602, 466, + /* 1070 */ 54, 54, 580, 975, 580, 417, 69, 69, 1456, 137, + /* 1080 */ 138, 91, 267, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 1090 */ 135, 136, 136, 136, 136, 70, 70, 71, 71, 580, + /* 1100 */ 137, 138, 91, 580, 1234, 1234, 1069, 1072, 1059, 1059, + /* 1110 */ 135, 135, 136, 136, 136, 136, 305, 377, 1602, 260, + /* 1120 */ 259, 258, 72, 72, 476, 350, 73, 73, 580, 467, + /* 1130 */ 580, 1578, 580, 467, 580, 1338, 1338, 502, 134, 134, + /* 1140 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 1150 */ 580, 55, 55, 56, 56, 57, 57, 59, 59, 134, + /* 1160 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, + /* 1170 */ 455, 580, 1352, 60, 60, 580, 1230, 580, 141, 580, + /* 1180 */ 1442, 580, 1343, 580, 577, 297, 566, 580, 417, 297, + /* 1190 */ 379, 1634, 1131, 917, 74, 74, 1375, 315, 75, 75, + /* 1200 */ 76, 76, 20, 20, 77, 77, 143, 143, 536, 417, + /* 1210 */ 144, 144, 502, 137, 138, 91, 115, 1234, 1234, 1069, + /* 1220 */ 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, 436, + /* 1230 */ 580, 379, 580, 1561, 137, 138, 91, 580, 1234, 1234, + /* 1240 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, + /* 1250 */ 557, 447, 975, 78, 78, 62, 62, 355, 1289, 423, + /* 1260 */ 79, 79, 227, 414, 413, 111, 580, 227, 580, 158, + /* 1270 */ 446, 125, 134, 134, 134, 134, 133, 133, 132, 132, + /* 1280 */ 132, 131, 128, 455, 580, 461, 580, 523, 580, 63, + /* 1290 */ 63, 80, 80, 134, 134, 134, 134, 133, 133, 132, + /* 1300 */ 132, 132, 131, 128, 455, 580, 537, 64, 64, 170, + /* 1310 */ 170, 171, 171, 482, 950, 573, 423, 477, 580, 949, + /* 1320 */ 424, 184, 417, 319, 415, 489, 1113, 215, 87, 87, + /* 1330 */ 1113, 288, 231, 950, 415, 97, 218, 108, 949, 1557, + /* 1340 */ 345, 65, 65, 417, 907, 906, 233, 137, 138, 91, + /* 1350 */ 119, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, + /* 1360 */ 136, 136, 136, 497, 417, 23, 538, 899, 137, 138, + /* 1370 */ 91, 975, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, + /* 1380 */ 136, 136, 136, 136, 481, 222, 161, 109, 16, 137, + /* 1390 */ 126, 91, 557, 1234, 1234, 1069, 1072, 1059, 1059, 135, + /* 1400 */ 135, 136, 136, 136, 136, 428, 134, 134, 134, 134, + /* 1410 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 221, + /* 1420 */ 580, 1229, 580, 490, 1150, 895, 404, 134, 134, 134, + /* 1430 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 580, + /* 1440 */ 293, 83, 83, 146, 146, 84, 84, 38, 134, 134, + /* 1450 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 1460 */ 479, 375, 168, 168, 580, 346, 324, 111, 580, 417, + /* 1470 */ 580, 374, 242, 532, 323, 1027, 484, 266, 266, 486, + /* 1480 */ 39, 266, 351, 300, 111, 914, 915, 148, 148, 580, + /* 1490 */ 417, 142, 142, 169, 169, 138, 91, 1098, 1234, 1234, + /* 1500 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, + /* 1510 */ 992, 993, 162, 162, 508, 325, 263, 91, 1038, 1234, + /* 1520 */ 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, + /* 1530 */ 136, 365, 165, 111, 111, 895, 328, 456, 1094, 222, + /* 1540 */ 263, 1387, 980, 580, 266, 580, 1386, 580, 123, 572, + /* 1550 */ 470, 4, 1159, 134, 134, 134, 134, 133, 133, 132, + /* 1560 */ 132, 132, 131, 128, 455, 575, 152, 152, 151, 151, + /* 1570 */ 149, 149, 580, 1564, 134, 134, 134, 134, 133, 133, + /* 1580 */ 132, 132, 132, 131, 128, 455, 580, 341, 1537, 580, + /* 1590 */ 244, 580, 948, 580, 125, 150, 150, 580, 1536, 494, + /* 1600 */ 945, 569, 125, 1110, 878, 1110, 159, 1098, 352, 86, + /* 1610 */ 86, 44, 88, 88, 85, 85, 52, 52, 1383, 1373, + /* 1620 */ 58, 58, 947, 1109, 125, 1109, 356, 359, 1038, 361, + /* 1630 */ 1046, 363, 1331, 1317, 1316, 1315, 121, 121, 370, 380, + /* 1640 */ 1396, 1441, 205, 1596, 122, 1369, 456, 581, 456, 1381, + /* 1650 */ 567, 1034, 1446, 503, 1296, 1287, 1275, 1274, 1276, 1616, + /* 1660 */ 401, 456, 281, 167, 237, 1366, 312, 313, 320, 571, + /* 1670 */ 343, 12, 123, 572, 295, 4, 314, 344, 301, 488, + /* 1680 */ 333, 224, 349, 1034, 1034, 1036, 1037, 35, 1428, 575, + /* 1690 */ 336, 280, 1619, 513, 373, 1433, 1432, 400, 400, 399, + /* 1700 */ 277, 397, 408, 9, 865, 228, 1314, 1509, 1508, 1250, + /* 1710 */ 270, 186, 1194, 1556, 1554, 235, 570, 239, 1378, 327, + /* 1720 */ 1247, 426, 223, 395, 96, 569, 210, 326, 1379, 220, + /* 1730 */ 195, 1377, 211, 140, 1376, 456, 92, 1423, 557, 546, + /* 1740 */ 332, 180, 188, 1416, 545, 473, 123, 572, 335, 4, + /* 1750 */ 472, 506, 190, 247, 1046, 191, 13, 1429, 241, 192, + /* 1760 */ 121, 121, 193, 575, 109, 406, 175, 495, 122, 43, + /* 1770 */ 456, 581, 456, 1435, 1434, 1034, 14, 95, 1514, 480, + /* 1780 */ 1437, 409, 199, 1503, 102, 251, 240, 501, 1525, 282, + /* 1790 */ 253, 203, 354, 504, 358, 254, 411, 1277, 255, 569, + /* 1800 */ 522, 1334, 1333, 440, 1325, 1332, 104, 1034, 1034, 1036, + /* 1810 */ 1037, 35, 1633, 546, 1632, 899, 412, 229, 547, 1304, + /* 1820 */ 1601, 418, 1303, 372, 1302, 1324, 320, 571, 1046, 1631, + /* 1830 */ 444, 445, 531, 310, 121, 121, 1194, 378, 311, 268, + /* 1840 */ 269, 448, 122, 1587, 456, 581, 456, 1586, 11, 1034, + /* 1850 */ 462, 389, 456, 116, 1357, 110, 387, 216, 1401, 1490, + /* 1860 */ 318, 541, 1356, 123, 572, 393, 4, 394, 42, 1400, + /* 1870 */ 583, 1204, 276, 278, 279, 419, 456, 185, 584, 1272, + /* 1880 */ 575, 1034, 1034, 1036, 1037, 35, 1266, 123, 572, 172, + /* 1890 */ 4, 156, 308, 1541, 1542, 851, 457, 1540, 173, 217, + /* 1900 */ 322, 236, 1108, 1539, 575, 154, 225, 226, 174, 89, + /* 1910 */ 1194, 1106, 420, 330, 187, 1229, 569, 176, 189, 243, + /* 1920 */ 931, 246, 342, 1122, 194, 177, 178, 429, 431, 196, + /* 1930 */ 546, 98, 179, 99, 1125, 545, 100, 101, 248, 249, + /* 1940 */ 569, 1121, 163, 24, 250, 1046, 1244, 353, 500, 1114, + /* 1950 */ 266, 121, 121, 200, 252, 201, 15, 867, 505, 122, + /* 1960 */ 256, 456, 581, 456, 374, 202, 1034, 509, 103, 1046, + /* 1970 */ 25, 514, 366, 26, 897, 121, 121, 954, 369, 105, + /* 1980 */ 517, 910, 309, 122, 181, 456, 581, 456, 164, 27, + /* 1990 */ 1034, 106, 525, 107, 1191, 1075, 1161, 17, 1034, 1034, + /* 2000 */ 1036, 1037, 35, 1608, 1198, 458, 1160, 285, 280, 230, + /* 2010 */ 287, 265, 204, 984, 400, 400, 399, 277, 397, 978, + /* 2020 */ 125, 865, 1034, 1034, 1036, 1037, 35, 1194, 28, 1177, + /* 2030 */ 29, 30, 31, 8, 239, 1181, 327, 1179, 1185, 1184, + /* 2040 */ 32, 1166, 41, 553, 326, 33, 456, 208, 111, 1089, + /* 2050 */ 1076, 1194, 113, 114, 1074, 1078, 34, 123, 572, 1079, + /* 2060 */ 4, 565, 118, 1130, 271, 36, 18, 941, 1039, 879, + /* 2070 */ 272, 124, 37, 398, 575, 241, 576, 273, 1624, 183, + /* 2080 */ 153, 1200, 1199, 175, 1262, 1262, 43, 1262, 1262, 1262, + /* 2090 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2100 */ 1262, 1262, 1262, 240, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2110 */ 569, 1262, 1262, 456, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2120 */ 1262, 1262, 1262, 1262, 90, 572, 1262, 4, 1262, 1262, + /* 2130 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 418, 1046, + /* 2140 */ 1262, 575, 1262, 320, 571, 121, 121, 1262, 1262, 1262, + /* 2150 */ 1262, 1262, 1262, 122, 1262, 456, 581, 456, 1198, 458, + /* 2160 */ 1034, 1262, 280, 1262, 1262, 1262, 1262, 462, 400, 400, + /* 2170 */ 399, 277, 397, 1262, 1262, 865, 1262, 569, 1262, 559, + /* 2180 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 239, 1262, + /* 2190 */ 327, 1262, 1034, 1034, 1036, 1037, 35, 1262, 326, 1262, + /* 2200 */ 1262, 1262, 1262, 456, 1262, 1262, 1046, 1262, 1262, 1262, + /* 2210 */ 1262, 1262, 121, 121, 123, 572, 1262, 4, 1262, 1262, + /* 2220 */ 122, 1194, 456, 581, 456, 1262, 1262, 1034, 1262, 241, + /* 2230 */ 1262, 575, 1262, 1262, 1262, 1262, 1262, 175, 1262, 1262, + /* 2240 */ 43, 1262, 1262, 1262, 1262, 1262, 558, 1262, 1262, 1262, + /* 2250 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 240, 1262, 1034, + /* 2260 */ 1034, 1036, 1037, 35, 1262, 1262, 1262, 569, 1262, 1262, + /* 2270 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2280 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1194, 1262, + /* 2290 */ 1262, 1262, 418, 1262, 1262, 1262, 1046, 320, 571, 1262, + /* 2300 */ 1262, 1262, 121, 121, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2310 */ 122, 1262, 456, 581, 456, 1262, 1262, 1034, 1262, 1262, + /* 2320 */ 1262, 462, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2330 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2340 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1034, + /* 2350 */ 1034, 1036, 1037, 35, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2360 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, + /* 2370 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1194, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 225, 195, 227, 195, 195, 195, 195, 241, 242, 217, - /* 10 */ 235, 187, 188, 189, 190, 191, 192, 225, 207, 19, - /* 20 */ 254, 197, 256, 199, 218, 219, 218, 219, 218, 219, - /* 30 */ 206, 31, 277, 278, 279, 22, 23, 218, 25, 39, - /* 40 */ 277, 278, 279, 234, 44, 45, 46, 206, 48, 49, + /* 0 */ 218, 195, 313, 195, 215, 217, 317, 277, 278, 279, + /* 10 */ 195, 9, 195, 225, 195, 277, 278, 279, 195, 218, + /* 20 */ 20, 225, 218, 227, 218, 219, 218, 219, 298, 206, + /* 30 */ 9, 235, 32, 218, 219, 218, 219, 218, 219, 195, + /* 40 */ 40, 218, 219, 304, 305, 45, 46, 47, 195, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 60 */ 9, 298, 195, 22, 195, 241, 242, 189, 190, 191, - /* 70 */ 192, 23, 9, 25, 205, 197, 207, 199, 254, 195, - /* 80 */ 256, 195, 241, 242, 206, 218, 219, 281, 56, 57, - /* 90 */ 58, 59, 60, 269, 208, 254, 55, 256, 237, 238, - /* 100 */ 259, 260, 215, 103, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 114, 102, 230, 313, 232, 241, - /* 120 */ 242, 317, 255, 19, 240, 301, 318, 319, 318, 319, - /* 130 */ 9, 264, 254, 195, 256, 103, 104, 105, 106, 107, - /* 140 */ 108, 109, 110, 111, 112, 113, 114, 269, 44, 45, - /* 150 */ 46, 114, 48, 49, 50, 51, 52, 53, 54, 55, - /* 160 */ 56, 57, 58, 59, 277, 278, 279, 119, 117, 118, - /* 170 */ 119, 120, 109, 218, 123, 124, 125, 195, 19, 301, - /* 180 */ 117, 118, 119, 24, 133, 109, 110, 111, 112, 113, - /* 190 */ 114, 87, 144, 89, 103, 104, 105, 106, 107, 108, - /* 200 */ 109, 110, 111, 112, 113, 114, 16, 103, 104, 105, - /* 210 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 107, - /* 220 */ 108, 109, 110, 111, 112, 113, 114, 19, 107, 108, - /* 230 */ 82, 241, 242, 25, 195, 74, 48, 116, 117, 118, - /* 240 */ 119, 25, 121, 82, 254, 307, 256, 309, 195, 195, - /* 250 */ 129, 195, 44, 45, 46, 96, 48, 49, 50, 51, - /* 260 */ 52, 53, 54, 55, 56, 57, 58, 59, 78, 121, - /* 270 */ 80, 218, 219, 114, 251, 154, 253, 156, 70, 120, - /* 280 */ 121, 122, 123, 124, 125, 126, 233, 139, 140, 128, - /* 290 */ 218, 132, 77, 77, 312, 313, 240, 74, 19, 317, - /* 300 */ 139, 140, 195, 88, 116, 90, 90, 206, 93, 93, - /* 310 */ 271, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 320 */ 112, 113, 114, 44, 45, 46, 232, 48, 49, 50, - /* 330 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 19, - /* 340 */ 286, 276, 241, 242, 24, 120, 195, 68, 123, 124, - /* 350 */ 125, 128, 129, 130, 203, 254, 221, 256, 133, 208, - /* 360 */ 195, 146, 221, 195, 44, 45, 46, 19, 48, 49, - /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 380 */ 315, 316, 103, 104, 105, 106, 107, 108, 109, 110, - /* 390 */ 111, 112, 113, 114, 46, 200, 48, 49, 50, 51, - /* 400 */ 52, 53, 54, 55, 56, 57, 58, 59, 240, 195, - /* 410 */ 19, 9, 277, 278, 279, 82, 195, 9, 277, 278, - /* 420 */ 279, 129, 130, 103, 104, 105, 106, 107, 108, 109, - /* 430 */ 110, 111, 112, 113, 114, 44, 45, 46, 195, 48, - /* 440 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 450 */ 59, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 460 */ 112, 113, 114, 195, 107, 108, 195, 299, 9, 195, - /* 470 */ 25, 9, 139, 140, 206, 73, 195, 312, 313, 284, - /* 480 */ 206, 73, 317, 288, 22, 26, 218, 219, 48, 49, - /* 490 */ 50, 51, 218, 219, 103, 104, 105, 106, 107, 108, - /* 500 */ 109, 110, 111, 112, 113, 114, 246, 9, 265, 241, - /* 510 */ 242, 154, 195, 156, 19, 241, 242, 257, 23, 117, - /* 520 */ 118, 119, 254, 255, 256, 117, 118, 119, 254, 255, - /* 530 */ 256, 195, 264, 195, 19, 218, 219, 266, 23, 44, - /* 540 */ 45, 46, 151, 48, 49, 50, 51, 52, 53, 54, - /* 550 */ 55, 56, 57, 58, 59, 195, 218, 219, 195, 44, - /* 560 */ 45, 46, 122, 48, 49, 50, 51, 52, 53, 54, - /* 570 */ 55, 56, 57, 58, 59, 77, 117, 118, 119, 117, - /* 580 */ 118, 119, 19, 116, 139, 140, 88, 195, 90, 31, - /* 590 */ 195, 93, 311, 255, 234, 206, 9, 39, 103, 104, - /* 600 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 610 */ 218, 219, 145, 218, 219, 117, 118, 119, 103, 104, - /* 620 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 630 */ 241, 242, 67, 22, 23, 318, 25, 320, 19, 212, - /* 640 */ 213, 214, 23, 254, 146, 256, 135, 255, 137, 138, - /* 650 */ 255, 86, 112, 113, 114, 9, 264, 15, 19, 264, - /* 660 */ 95, 272, 23, 44, 45, 46, 206, 48, 49, 50, - /* 670 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 116, - /* 680 */ 117, 195, 25, 44, 45, 46, 195, 48, 49, 50, - /* 690 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 213, - /* 700 */ 214, 241, 242, 61, 117, 118, 119, 195, 145, 218, - /* 710 */ 219, 195, 147, 102, 254, 9, 256, 195, 195, 206, - /* 720 */ 195, 195, 103, 104, 105, 106, 107, 108, 109, 110, - /* 730 */ 111, 112, 113, 114, 195, 206, 195, 166, 167, 152, - /* 740 */ 218, 219, 103, 104, 105, 106, 107, 108, 109, 110, - /* 750 */ 111, 112, 113, 114, 241, 242, 195, 218, 219, 218, - /* 760 */ 219, 215, 19, 117, 118, 119, 23, 254, 243, 256, - /* 770 */ 241, 242, 233, 287, 233, 139, 140, 255, 266, 218, - /* 780 */ 219, 265, 19, 254, 127, 256, 23, 44, 45, 46, - /* 790 */ 144, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 800 */ 57, 58, 59, 195, 195, 195, 109, 44, 45, 46, - /* 810 */ 215, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 820 */ 57, 58, 59, 117, 118, 119, 218, 219, 218, 219, - /* 830 */ 195, 246, 307, 136, 309, 289, 310, 311, 141, 195, - /* 840 */ 294, 233, 257, 233, 206, 195, 103, 104, 105, 106, - /* 850 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 195, - /* 860 */ 195, 313, 218, 219, 195, 317, 103, 104, 105, 106, - /* 870 */ 107, 108, 109, 110, 111, 112, 113, 114, 9, 241, - /* 880 */ 242, 218, 219, 218, 219, 195, 19, 218, 219, 294, - /* 890 */ 23, 22, 254, 29, 256, 195, 233, 33, 233, 255, - /* 900 */ 265, 9, 233, 23, 195, 25, 19, 56, 57, 58, - /* 910 */ 59, 44, 45, 46, 22, 48, 49, 50, 51, 52, - /* 920 */ 53, 54, 55, 56, 57, 58, 59, 218, 219, 195, - /* 930 */ 66, 44, 45, 46, 9, 48, 49, 50, 51, 52, - /* 940 */ 53, 54, 55, 56, 57, 58, 59, 213, 214, 24, - /* 950 */ 16, 12, 22, 195, 103, 104, 105, 106, 107, 108, - /* 960 */ 109, 110, 111, 112, 113, 114, 27, 11, 195, 19, - /* 970 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 980 */ 113, 114, 43, 130, 9, 295, 117, 118, 119, 9, - /* 990 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1000 */ 113, 114, 22, 64, 195, 195, 153, 9, 101, 117, - /* 1010 */ 118, 119, 78, 74, 80, 246, 243, 195, 25, 19, - /* 1020 */ 22, 287, 242, 23, 266, 118, 257, 218, 219, 122, - /* 1030 */ 212, 213, 214, 22, 254, 21, 256, 107, 108, 19, - /* 1040 */ 218, 219, 195, 118, 44, 45, 46, 160, 48, 49, - /* 1050 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 1060 */ 195, 154, 155, 156, 44, 45, 46, 117, 48, 49, - /* 1070 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 1080 */ 307, 271, 309, 218, 219, 129, 130, 9, 195, 195, - /* 1090 */ 243, 184, 117, 118, 119, 81, 162, 117, 118, 119, - /* 1100 */ 22, 206, 24, 103, 104, 105, 106, 107, 108, 109, - /* 1110 */ 110, 111, 112, 113, 114, 117, 118, 119, 195, 144, - /* 1120 */ 255, 19, 195, 103, 104, 105, 106, 107, 108, 109, - /* 1130 */ 110, 111, 112, 113, 114, 195, 241, 242, 124, 146, - /* 1140 */ 195, 128, 129, 130, 195, 218, 219, 195, 195, 254, - /* 1150 */ 48, 256, 19, 142, 307, 195, 309, 24, 218, 219, - /* 1160 */ 128, 129, 130, 218, 219, 271, 243, 218, 219, 9, - /* 1170 */ 218, 219, 19, 237, 238, 276, 162, 44, 45, 46, - /* 1180 */ 160, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1190 */ 57, 58, 59, 35, 195, 255, 118, 44, 45, 46, - /* 1200 */ 255, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1210 */ 57, 58, 59, 276, 315, 316, 304, 305, 116, 7, - /* 1220 */ 8, 9, 210, 211, 271, 67, 266, 25, 262, 263, - /* 1230 */ 307, 195, 309, 75, 132, 195, 103, 104, 105, 106, - /* 1240 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 25, - /* 1250 */ 195, 195, 315, 316, 218, 219, 103, 104, 105, 106, - /* 1260 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 77, - /* 1270 */ 195, 218, 219, 218, 219, 195, 19, 195, 118, 25, - /* 1280 */ 240, 146, 90, 195, 9, 93, 210, 211, 195, 131, - /* 1290 */ 208, 218, 219, 218, 219, 195, 19, 22, 218, 219, - /* 1300 */ 165, 44, 45, 46, 195, 48, 49, 50, 51, 52, - /* 1310 */ 53, 54, 55, 56, 57, 58, 59, 195, 218, 219, - /* 1320 */ 9, 119, 45, 46, 195, 48, 49, 50, 51, 52, - /* 1330 */ 53, 54, 55, 56, 57, 58, 59, 22, 23, 195, - /* 1340 */ 218, 219, 12, 302, 303, 9, 144, 218, 219, 240, - /* 1350 */ 195, 295, 195, 272, 195, 19, 20, 27, 22, 266, - /* 1360 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1370 */ 113, 114, 36, 43, 150, 218, 219, 218, 219, 195, - /* 1380 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1390 */ 113, 114, 195, 118, 64, 240, 195, 143, 190, 195, - /* 1400 */ 192, 195, 218, 219, 159, 197, 161, 199, 72, 22, - /* 1410 */ 23, 22, 101, 24, 206, 218, 219, 102, 82, 218, - /* 1420 */ 219, 246, 218, 219, 218, 219, 313, 313, 117, 118, - /* 1430 */ 317, 317, 257, 122, 313, 19, 195, 101, 317, 295, - /* 1440 */ 25, 263, 136, 107, 108, 267, 195, 141, 263, 241, - /* 1450 */ 242, 115, 267, 117, 118, 119, 195, 246, 122, 218, - /* 1460 */ 219, 9, 254, 23, 256, 154, 155, 156, 257, 218, - /* 1470 */ 219, 19, 20, 24, 22, 139, 140, 269, 195, 218, - /* 1480 */ 219, 259, 260, 100, 116, 130, 9, 195, 36, 102, - /* 1490 */ 154, 155, 156, 157, 158, 184, 19, 20, 195, 22, - /* 1500 */ 150, 151, 50, 195, 23, 195, 25, 195, 153, 301, - /* 1510 */ 218, 219, 195, 36, 22, 122, 195, 134, 195, 151, - /* 1520 */ 184, 218, 219, 195, 72, 132, 218, 219, 218, 219, - /* 1530 */ 218, 219, 195, 117, 195, 218, 219, 19, 86, 218, - /* 1540 */ 219, 218, 219, 91, 7, 8, 218, 219, 23, 72, - /* 1550 */ 25, 195, 195, 101, 62, 218, 219, 195, 143, 107, - /* 1560 */ 108, 195, 23, 86, 25, 121, 122, 115, 91, 117, - /* 1570 */ 118, 119, 195, 9, 122, 218, 219, 9, 101, 9, - /* 1580 */ 218, 219, 84, 85, 107, 108, 146, 19, 20, 195, - /* 1590 */ 22, 142, 115, 195, 117, 118, 119, 195, 23, 122, - /* 1600 */ 25, 195, 9, 195, 36, 9, 154, 155, 156, 157, - /* 1610 */ 158, 258, 19, 20, 195, 22, 98, 154, 195, 156, - /* 1620 */ 218, 219, 195, 195, 218, 219, 218, 219, 23, 36, - /* 1630 */ 25, 154, 155, 156, 157, 158, 184, 218, 219, 5, - /* 1640 */ 72, 218, 219, 195, 10, 11, 12, 13, 14, 195, - /* 1650 */ 23, 17, 25, 195, 86, 195, 23, 195, 25, 91, - /* 1660 */ 23, 184, 25, 195, 30, 72, 32, 195, 195, 101, - /* 1670 */ 195, 195, 218, 219, 40, 107, 108, 195, 218, 219, - /* 1680 */ 218, 219, 118, 115, 228, 117, 118, 119, 118, 228, - /* 1690 */ 122, 218, 219, 228, 101, 195, 23, 23, 25, 25, - /* 1700 */ 107, 108, 109, 195, 23, 71, 25, 195, 115, 195, - /* 1710 */ 117, 118, 119, 79, 118, 122, 82, 195, 218, 219, - /* 1720 */ 261, 195, 154, 155, 156, 157, 158, 0, 1, 2, - /* 1730 */ 218, 219, 5, 99, 23, 195, 25, 10, 11, 12, - /* 1740 */ 13, 14, 195, 23, 17, 25, 195, 154, 155, 156, - /* 1750 */ 157, 158, 184, 322, 154, 195, 156, 30, 23, 32, - /* 1760 */ 25, 23, 195, 25, 195, 218, 219, 40, 134, 238, - /* 1770 */ 291, 195, 195, 139, 140, 195, 195, 184, 218, 219, - /* 1780 */ 195, 195, 195, 290, 193, 244, 258, 218, 219, 245, - /* 1790 */ 258, 258, 258, 274, 216, 300, 247, 163, 71, 270, - /* 1800 */ 270, 296, 248, 248, 247, 296, 79, 262, 9, 82, - /* 1810 */ 274, 222, 274, 231, 262, 227, 274, 251, 19, 20, - /* 1820 */ 221, 22, 221, 221, 262, 262, 99, 198, 9, 283, - /* 1830 */ 251, 247, 61, 142, 202, 36, 38, 245, 19, 20, - /* 1840 */ 202, 22, 202, 300, 152, 286, 151, 297, 300, 275, - /* 1850 */ 297, 22, 149, 146, 251, 36, 273, 44, 252, 236, - /* 1860 */ 252, 134, 251, 18, 239, 239, 139, 140, 202, 239, - /* 1870 */ 239, 72, 18, 201, 150, 236, 248, 236, 202, 275, - /* 1880 */ 201, 159, 275, 248, 248, 273, 63, 293, 202, 292, - /* 1890 */ 163, 72, 248, 22, 201, 116, 202, 201, 223, 202, - /* 1900 */ 101, 201, 220, 223, 220, 220, 107, 108, 65, 22, - /* 1910 */ 220, 223, 229, 226, 115, 226, 117, 118, 119, 127, - /* 1920 */ 101, 122, 220, 222, 220, 220, 107, 108, 229, 166, - /* 1930 */ 316, 24, 308, 285, 115, 114, 117, 118, 119, 285, - /* 1940 */ 141, 122, 223, 202, 92, 83, 268, 22, 280, 202, - /* 1950 */ 159, 282, 148, 154, 155, 156, 157, 158, 252, 251, - /* 1960 */ 141, 252, 250, 321, 321, 147, 268, 249, 25, 248, - /* 1970 */ 204, 13, 196, 154, 155, 156, 157, 158, 1, 2, - /* 1980 */ 196, 6, 5, 184, 194, 215, 209, 10, 11, 12, - /* 1990 */ 13, 14, 224, 215, 17, 194, 194, 215, 215, 224, - /* 2000 */ 9, 216, 209, 184, 216, 209, 4, 30, 3, 32, - /* 2010 */ 19, 20, 215, 22, 22, 164, 306, 40, 303, 306, - /* 2020 */ 16, 15, 23, 23, 140, 152, 131, 36, 25, 143, - /* 2030 */ 20, 24, 16, 145, 1, 143, 131, 131, 62, 55, - /* 2040 */ 55, 152, 55, 55, 131, 37, 117, 34, 71, 1, - /* 2050 */ 142, 5, 22, 116, 25, 162, 79, 76, 69, 82, - /* 2060 */ 41, 142, 69, 72, 116, 24, 132, 20, 19, 68, - /* 2070 */ 126, 9, 22, 22, 22, 22, 99, 23, 23, 68, - /* 2080 */ 24, 22, 68, 97, 23, 28, 150, 22, 25, 23, - /* 2090 */ 23, 22, 101, 98, 34, 37, 142, 23, 107, 108, - /* 2100 */ 23, 22, 34, 144, 34, 25, 115, 117, 117, 118, - /* 2110 */ 119, 134, 34, 122, 89, 34, 139, 140, 34, 76, - /* 2120 */ 45, 87, 94, 34, 23, 22, 24, 34, 22, 25, - /* 2130 */ 25, 23, 23, 23, 23, 23, 22, 143, 25, 143, - /* 2140 */ 163, 25, 11, 22, 22, 154, 155, 156, 157, 158, - /* 2150 */ 23, 23, 76, 136, 22, 22, 15, 142, 23, 25, - /* 2160 */ 142, 25, 142, 1, 1, 323, 323, 323, 323, 323, - /* 2170 */ 323, 323, 323, 323, 323, 184, 323, 323, 323, 323, - /* 2180 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2190 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2200 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2210 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2220 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2230 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2240 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2260 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 60 */ 60, 20, 218, 219, 241, 242, 277, 278, 279, 241, + /* 70 */ 242, 9, 255, 17, 255, 9, 74, 254, 255, 256, + /* 80 */ 9, 264, 254, 264, 256, 195, 45, 46, 47, 23, + /* 90 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 100 */ 59, 60, 195, 9, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 114, 115, 195, 221, 265, 195, + /* 120 */ 118, 119, 120, 102, 318, 319, 318, 215, 320, 88, + /* 130 */ 240, 90, 20, 318, 319, 79, 74, 81, 26, 118, + /* 140 */ 119, 195, 218, 219, 123, 104, 105, 106, 107, 108, + /* 150 */ 109, 110, 111, 112, 113, 114, 115, 45, 46, 47, + /* 160 */ 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 170 */ 58, 59, 60, 277, 278, 279, 155, 156, 157, 255, + /* 180 */ 118, 119, 120, 71, 118, 119, 120, 266, 264, 299, + /* 190 */ 119, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 200 */ 113, 114, 115, 195, 20, 184, 294, 57, 58, 59, + /* 210 */ 60, 61, 118, 119, 120, 115, 104, 105, 106, 107, + /* 220 */ 108, 109, 110, 111, 112, 113, 114, 115, 117, 45, + /* 230 */ 46, 47, 286, 49, 50, 51, 52, 53, 54, 55, + /* 240 */ 56, 57, 58, 59, 60, 20, 136, 153, 138, 139, + /* 250 */ 25, 243, 221, 69, 104, 105, 106, 107, 108, 109, + /* 260 */ 110, 111, 112, 113, 114, 115, 9, 212, 213, 214, + /* 270 */ 45, 46, 47, 195, 49, 50, 51, 52, 53, 54, + /* 280 */ 55, 56, 57, 58, 59, 60, 232, 9, 104, 105, + /* 290 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 300 */ 108, 109, 110, 111, 112, 113, 114, 115, 277, 278, + /* 310 */ 279, 57, 58, 59, 60, 307, 20, 309, 110, 111, + /* 320 */ 112, 113, 114, 115, 195, 49, 50, 51, 52, 104, + /* 330 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 340 */ 115, 45, 46, 47, 195, 49, 50, 51, 52, 53, + /* 350 */ 54, 55, 56, 57, 58, 59, 60, 208, 104, 105, + /* 360 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 370 */ 195, 195, 75, 78, 195, 118, 119, 120, 121, 246, + /* 380 */ 83, 124, 125, 126, 89, 307, 91, 309, 110, 94, + /* 390 */ 257, 134, 213, 214, 265, 206, 118, 119, 120, 123, + /* 400 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + /* 410 */ 114, 115, 195, 187, 188, 189, 190, 191, 192, 189, + /* 420 */ 190, 191, 192, 197, 20, 199, 129, 197, 24, 199, + /* 430 */ 241, 242, 206, 9, 195, 195, 206, 140, 141, 83, + /* 440 */ 130, 131, 147, 254, 205, 256, 207, 23, 152, 45, + /* 450 */ 46, 47, 102, 49, 50, 51, 52, 53, 54, 55, + /* 460 */ 56, 57, 58, 59, 60, 195, 287, 241, 242, 119, + /* 470 */ 13, 241, 242, 123, 167, 168, 20, 207, 122, 195, + /* 480 */ 254, 25, 256, 266, 254, 28, 256, 246, 312, 313, + /* 490 */ 206, 75, 9, 317, 195, 269, 140, 141, 257, 269, + /* 500 */ 313, 44, 218, 219, 317, 155, 156, 157, 104, 105, + /* 510 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 520 */ 9, 190, 65, 192, 195, 241, 242, 301, 197, 20, + /* 530 */ 199, 301, 75, 24, 184, 9, 195, 206, 254, 255, + /* 540 */ 256, 9, 118, 119, 120, 129, 130, 131, 264, 23, + /* 550 */ 310, 311, 195, 97, 45, 46, 47, 206, 49, 50, + /* 560 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 570 */ 271, 115, 241, 242, 9, 218, 219, 121, 122, 123, + /* 580 */ 124, 125, 126, 127, 251, 254, 253, 256, 23, 133, + /* 590 */ 9, 121, 241, 242, 124, 125, 126, 23, 200, 26, + /* 600 */ 269, 118, 119, 120, 134, 254, 265, 256, 27, 195, + /* 610 */ 259, 260, 255, 104, 105, 106, 107, 108, 109, 110, + /* 620 */ 111, 112, 113, 114, 115, 9, 78, 195, 145, 118, + /* 630 */ 119, 120, 301, 195, 20, 212, 213, 214, 24, 91, + /* 640 */ 108, 109, 94, 206, 118, 119, 120, 246, 195, 117, + /* 650 */ 118, 119, 120, 195, 122, 195, 145, 195, 257, 45, + /* 660 */ 46, 47, 130, 49, 50, 51, 52, 53, 54, 55, + /* 670 */ 56, 57, 58, 59, 60, 195, 9, 195, 241, 242, + /* 680 */ 218, 219, 284, 118, 119, 120, 288, 155, 195, 157, + /* 690 */ 23, 254, 195, 256, 78, 233, 243, 206, 240, 118, + /* 700 */ 119, 120, 206, 195, 266, 89, 206, 91, 195, 272, + /* 710 */ 94, 218, 219, 140, 141, 218, 219, 143, 104, 105, + /* 720 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 730 */ 233, 271, 241, 242, 118, 119, 120, 241, 242, 20, + /* 740 */ 313, 241, 242, 24, 317, 254, 206, 256, 255, 9, + /* 750 */ 254, 243, 256, 271, 254, 206, 256, 113, 114, 115, + /* 760 */ 307, 195, 309, 147, 45, 46, 47, 195, 49, 50, + /* 770 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 780 */ 208, 241, 242, 195, 271, 118, 119, 120, 23, 24, + /* 790 */ 241, 242, 312, 313, 254, 9, 256, 317, 195, 195, + /* 800 */ 195, 195, 230, 254, 232, 256, 218, 219, 203, 23, + /* 810 */ 195, 36, 195, 208, 195, 307, 195, 309, 195, 213, + /* 820 */ 214, 233, 195, 104, 105, 106, 107, 108, 109, 110, + /* 830 */ 111, 112, 113, 114, 115, 218, 219, 218, 219, 218, + /* 840 */ 219, 218, 219, 68, 20, 215, 243, 195, 24, 313, + /* 850 */ 233, 76, 233, 317, 233, 240, 233, 22, 118, 119, + /* 860 */ 120, 23, 24, 195, 26, 195, 195, 195, 103, 45, + /* 870 */ 46, 47, 195, 49, 50, 51, 52, 53, 54, 55, + /* 880 */ 56, 57, 58, 59, 60, 195, 218, 219, 218, 219, + /* 890 */ 218, 219, 240, 287, 20, 218, 219, 195, 241, 242, + /* 900 */ 16, 108, 109, 233, 26, 119, 17, 132, 218, 219, + /* 910 */ 307, 254, 309, 256, 20, 23, 24, 82, 26, 289, + /* 920 */ 218, 219, 295, 255, 294, 23, 24, 255, 104, 105, + /* 930 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 940 */ 24, 103, 195, 49, 83, 255, 62, 9, 155, 20, + /* 950 */ 157, 313, 24, 24, 26, 317, 78, 255, 281, 195, + /* 960 */ 125, 23, 13, 25, 7, 8, 9, 10, 79, 91, + /* 970 */ 81, 68, 94, 195, 45, 46, 47, 28, 49, 50, + /* 980 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 990 */ 87, 117, 118, 44, 195, 103, 218, 219, 163, 96, + /* 1000 */ 195, 140, 141, 140, 141, 103, 12, 195, 237, 238, + /* 1010 */ 160, 117, 162, 266, 65, 195, 195, 218, 219, 228, + /* 1020 */ 146, 32, 195, 218, 219, 276, 195, 133, 276, 40, + /* 1030 */ 218, 219, 195, 104, 105, 106, 107, 108, 109, 110, + /* 1040 */ 111, 112, 113, 114, 115, 218, 219, 195, 120, 218, + /* 1050 */ 219, 148, 163, 195, 20, 218, 219, 119, 24, 295, + /* 1060 */ 129, 130, 131, 147, 315, 316, 9, 315, 316, 272, + /* 1070 */ 218, 219, 195, 145, 195, 20, 218, 219, 276, 45, + /* 1080 */ 46, 47, 25, 49, 50, 51, 52, 53, 54, 55, + /* 1090 */ 56, 57, 58, 59, 60, 218, 219, 218, 219, 195, + /* 1100 */ 45, 46, 47, 195, 49, 50, 51, 52, 53, 54, + /* 1110 */ 55, 56, 57, 58, 59, 60, 295, 315, 316, 129, + /* 1120 */ 130, 131, 218, 219, 130, 131, 218, 219, 195, 263, + /* 1130 */ 195, 311, 195, 267, 195, 237, 238, 195, 104, 105, + /* 1140 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 1150 */ 195, 218, 219, 218, 219, 218, 219, 218, 219, 104, + /* 1160 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 1170 */ 115, 195, 242, 218, 219, 195, 119, 195, 23, 195, + /* 1180 */ 195, 195, 240, 195, 254, 263, 256, 195, 20, 267, + /* 1190 */ 195, 24, 24, 26, 218, 219, 262, 263, 218, 219, + /* 1200 */ 218, 219, 218, 219, 218, 219, 218, 219, 20, 20, + /* 1210 */ 218, 219, 195, 45, 46, 47, 161, 49, 50, 51, + /* 1220 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 234, + /* 1230 */ 195, 195, 195, 195, 45, 46, 47, 195, 49, 50, + /* 1240 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 1250 */ 147, 266, 26, 218, 219, 218, 219, 240, 210, 211, + /* 1260 */ 218, 219, 26, 108, 109, 26, 195, 26, 195, 166, + /* 1270 */ 234, 26, 104, 105, 106, 107, 108, 109, 110, 111, + /* 1280 */ 112, 113, 114, 115, 195, 195, 195, 110, 195, 218, + /* 1290 */ 219, 218, 219, 104, 105, 106, 107, 108, 109, 110, + /* 1300 */ 111, 112, 113, 114, 115, 195, 118, 218, 219, 218, + /* 1310 */ 219, 218, 219, 246, 137, 210, 211, 131, 195, 142, + /* 1320 */ 302, 303, 20, 246, 257, 20, 30, 25, 218, 219, + /* 1330 */ 34, 259, 260, 137, 257, 151, 152, 117, 142, 195, + /* 1340 */ 154, 218, 219, 20, 122, 123, 120, 45, 46, 47, + /* 1350 */ 161, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 1360 */ 58, 59, 60, 67, 20, 23, 146, 128, 45, 46, + /* 1370 */ 47, 145, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1380 */ 57, 58, 59, 60, 117, 144, 23, 151, 25, 45, + /* 1390 */ 46, 47, 147, 49, 50, 51, 52, 53, 54, 55, + /* 1400 */ 56, 57, 58, 59, 60, 63, 104, 105, 106, 107, + /* 1410 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 152, + /* 1420 */ 195, 26, 195, 118, 24, 9, 26, 104, 105, 106, + /* 1430 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 195, + /* 1440 */ 101, 218, 219, 218, 219, 218, 219, 23, 104, 105, + /* 1450 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 1460 */ 131, 123, 218, 219, 195, 24, 195, 26, 195, 20, + /* 1470 */ 195, 133, 25, 20, 135, 24, 24, 26, 26, 24, + /* 1480 */ 56, 26, 24, 154, 26, 7, 8, 218, 219, 195, + /* 1490 */ 20, 218, 219, 218, 219, 46, 47, 9, 49, 50, + /* 1500 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* 1510 */ 85, 86, 218, 219, 24, 195, 26, 47, 9, 49, + /* 1520 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 1530 */ 60, 24, 24, 26, 26, 119, 195, 9, 24, 144, + /* 1540 */ 26, 195, 24, 195, 26, 195, 195, 195, 20, 21, + /* 1550 */ 195, 23, 99, 104, 105, 106, 107, 108, 109, 110, + /* 1560 */ 111, 112, 113, 114, 115, 37, 218, 219, 218, 219, + /* 1570 */ 218, 219, 195, 195, 104, 105, 106, 107, 108, 109, + /* 1580 */ 110, 111, 112, 113, 114, 115, 195, 195, 195, 195, + /* 1590 */ 143, 195, 24, 195, 26, 218, 219, 195, 195, 195, + /* 1600 */ 24, 73, 26, 155, 24, 157, 26, 119, 195, 218, + /* 1610 */ 219, 83, 218, 219, 218, 219, 218, 219, 195, 261, + /* 1620 */ 218, 219, 24, 155, 26, 157, 195, 195, 119, 195, + /* 1630 */ 102, 195, 195, 228, 228, 195, 108, 109, 195, 195, + /* 1640 */ 195, 195, 258, 322, 116, 195, 118, 119, 120, 195, + /* 1650 */ 238, 123, 195, 291, 195, 195, 195, 195, 195, 195, + /* 1660 */ 193, 9, 290, 244, 300, 258, 258, 258, 140, 141, + /* 1670 */ 296, 245, 20, 21, 247, 23, 258, 248, 248, 296, + /* 1680 */ 270, 216, 247, 155, 156, 157, 158, 159, 274, 37, + /* 1690 */ 270, 5, 198, 222, 221, 274, 274, 11, 12, 13, + /* 1700 */ 14, 15, 274, 51, 18, 231, 227, 221, 221, 62, + /* 1710 */ 143, 300, 184, 202, 202, 300, 283, 31, 262, 33, + /* 1720 */ 39, 202, 245, 247, 153, 73, 251, 41, 262, 152, + /* 1730 */ 23, 262, 251, 150, 262, 9, 297, 252, 147, 87, + /* 1740 */ 251, 45, 236, 252, 92, 202, 20, 21, 251, 23, + /* 1750 */ 19, 19, 239, 201, 102, 239, 273, 275, 72, 239, + /* 1760 */ 108, 109, 239, 37, 151, 248, 80, 202, 116, 83, + /* 1770 */ 118, 119, 120, 275, 275, 123, 273, 297, 286, 248, + /* 1780 */ 236, 248, 236, 248, 160, 201, 100, 64, 293, 202, + /* 1790 */ 201, 23, 292, 223, 202, 201, 223, 202, 201, 73, + /* 1800 */ 117, 220, 220, 66, 229, 220, 23, 155, 156, 157, + /* 1810 */ 158, 159, 226, 87, 226, 128, 223, 167, 92, 220, + /* 1820 */ 316, 135, 222, 220, 220, 229, 140, 141, 102, 220, + /* 1830 */ 25, 115, 308, 285, 108, 109, 184, 223, 285, 202, + /* 1840 */ 93, 84, 116, 321, 118, 119, 120, 321, 23, 123, + /* 1850 */ 164, 202, 9, 160, 252, 149, 251, 250, 268, 280, + /* 1860 */ 282, 148, 252, 20, 21, 249, 23, 248, 26, 268, + /* 1870 */ 204, 14, 196, 196, 6, 306, 9, 303, 194, 194, + /* 1880 */ 37, 155, 156, 157, 158, 159, 194, 20, 21, 209, + /* 1890 */ 23, 224, 224, 215, 215, 4, 3, 215, 209, 23, + /* 1900 */ 165, 16, 24, 215, 37, 17, 216, 216, 209, 215, + /* 1910 */ 184, 24, 306, 141, 153, 26, 73, 132, 144, 25, + /* 1920 */ 21, 146, 17, 1, 144, 132, 132, 63, 38, 153, + /* 1930 */ 87, 56, 132, 56, 118, 92, 56, 56, 35, 143, + /* 1940 */ 73, 1, 5, 23, 117, 102, 77, 163, 42, 70, + /* 1950 */ 26, 108, 109, 70, 143, 117, 25, 21, 20, 116, + /* 1960 */ 127, 118, 119, 120, 133, 23, 123, 69, 23, 102, + /* 1970 */ 23, 69, 24, 23, 9, 108, 109, 110, 25, 23, + /* 1980 */ 98, 29, 69, 116, 38, 118, 119, 120, 24, 35, + /* 1990 */ 123, 151, 23, 26, 24, 24, 24, 23, 155, 156, + /* 2000 */ 157, 158, 159, 0, 1, 2, 99, 24, 5, 143, + /* 2010 */ 24, 35, 23, 118, 11, 12, 13, 14, 15, 145, + /* 2020 */ 26, 18, 155, 156, 157, 158, 159, 184, 35, 90, + /* 2030 */ 35, 35, 35, 46, 31, 77, 33, 88, 77, 95, + /* 2040 */ 35, 24, 23, 25, 41, 35, 9, 26, 26, 24, + /* 2050 */ 24, 184, 144, 144, 24, 24, 23, 20, 21, 12, + /* 2060 */ 23, 26, 26, 24, 23, 23, 23, 137, 24, 24, + /* 2070 */ 143, 23, 23, 16, 37, 72, 26, 143, 143, 26, + /* 2080 */ 24, 1, 1, 80, 323, 323, 83, 323, 323, 323, + /* 2090 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2100 */ 323, 323, 323, 100, 323, 323, 323, 323, 323, 323, + /* 2110 */ 73, 323, 323, 9, 323, 323, 323, 323, 323, 323, + /* 2120 */ 323, 323, 323, 323, 20, 21, 323, 23, 323, 323, + /* 2130 */ 323, 323, 323, 323, 323, 323, 323, 323, 135, 102, + /* 2140 */ 323, 37, 323, 140, 141, 108, 109, 323, 323, 323, + /* 2150 */ 323, 323, 323, 116, 323, 118, 119, 120, 1, 2, + /* 2160 */ 123, 323, 5, 323, 323, 323, 323, 164, 11, 12, + /* 2170 */ 13, 14, 15, 323, 323, 18, 323, 73, 323, 142, + /* 2180 */ 323, 323, 323, 323, 323, 323, 323, 323, 31, 323, + /* 2190 */ 33, 323, 155, 156, 157, 158, 159, 323, 41, 323, + /* 2200 */ 323, 323, 323, 9, 323, 323, 102, 323, 323, 323, + /* 2210 */ 323, 323, 108, 109, 20, 21, 323, 23, 323, 323, + /* 2220 */ 116, 184, 118, 119, 120, 323, 323, 123, 323, 72, + /* 2230 */ 323, 37, 323, 323, 323, 323, 323, 80, 323, 323, + /* 2240 */ 83, 323, 323, 323, 323, 323, 142, 323, 323, 323, + /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 100, 323, 155, + /* 2260 */ 156, 157, 158, 159, 323, 323, 323, 73, 323, 323, /* 2270 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2290 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2300 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2310 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2320 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 184, 323, + /* 2290 */ 323, 323, 135, 323, 323, 323, 102, 140, 141, 323, + /* 2300 */ 323, 323, 108, 109, 323, 323, 323, 323, 323, 323, + /* 2310 */ 116, 323, 118, 119, 120, 323, 323, 123, 323, 323, + /* 2320 */ 323, 164, 323, 323, 323, 323, 323, 323, 323, 323, /* 2330 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2350 */ 323, 323, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2360 */ 187, 187, 187, + /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 155, + /* 2350 */ 156, 157, 158, 159, 323, 323, 323, 323, 323, 323, + /* 2360 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2370 */ 323, 323, 323, 323, 323, 323, 323, 323, 184, 323, + /* 2380 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2390 */ 323, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2400 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2410 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2420 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2430 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2440 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2450 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2460 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2470 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2480 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2490 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2500 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2510 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2520 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2530 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2540 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2550 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2560 */ 187, 187, 187, 187, 187, 187, }; #define YY_SHIFT_COUNT (586) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2163) +#define YY_SHIFT_MAX (2194) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 1977, 1727, 1634, 1336, 1336, 333, 161, 1452, 1477, 1568, - /* 10 */ 1991, 1991, 1991, 148, 333, 333, 333, 333, 333, 0, - /* 20 */ 0, 279, 1153, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 30 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 121, 121, - /* 40 */ 498, 498, 51, 402, 408, 706, 706, 445, 445, 445, - /* 50 */ 445, 104, 208, 320, 391, 495, 515, 619, 639, 743, - /* 60 */ 763, 867, 887, 1000, 1020, 1133, 1153, 1153, 1153, 1153, - /* 70 */ 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, - /* 80 */ 1153, 1153, 1153, 1153, 1257, 1153, 1277, 348, 348, 1593, - /* 90 */ 1799, 1819, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 100 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 110 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 120 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 130 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, - /* 140 */ 1991, 1991, 32, 851, 851, 851, 851, 851, 851, 851, - /* 150 */ 91, 112, 76, 459, 706, 1014, 1102, 706, 706, 357, - /* 160 */ 357, 706, 540, 292, 571, 571, 571, 636, 37, 37, - /* 170 */ 2176, 2176, 159, 159, 159, 587, 462, 462, 462, 462, - /* 180 */ 939, 939, 215, 459, 13, 611, 706, 706, 706, 706, - /* 190 */ 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, - /* 200 */ 706, 706, 706, 706, 706, 563, 216, 216, 706, 956, - /* 210 */ 1192, 1192, 950, 950, 1160, 1160, 1135, 2176, 2176, 2176, - /* 220 */ 2176, 2176, 2176, 2176, 1311, 907, 907, 869, 225, 892, - /* 230 */ 63, 980, 646, 975, 998, 706, 706, 706, 706, 706, - /* 240 */ 706, 706, 706, 706, 706, 223, 706, 706, 706, 706, - /* 250 */ 706, 706, 706, 706, 706, 706, 706, 706, 1158, 1158, - /* 260 */ 1158, 706, 706, 706, 48, 706, 706, 706, 1078, 565, - /* 270 */ 706, 1330, 706, 706, 706, 706, 706, 706, 706, 706, - /* 280 */ 1013, 864, 511, 925, 925, 925, 925, 1202, 511, 511, - /* 290 */ 697, 930, 1212, 642, 1368, 1350, 1254, 1350, 1416, 1224, - /* 300 */ 1368, 1368, 1224, 1368, 1254, 1416, 657, 880, 188, 558, - /* 310 */ 558, 558, 467, 467, 467, 467, 993, 993, 1245, 1415, - /* 320 */ 1306, 1389, 1771, 1771, 1691, 1691, 1798, 1798, 1691, 1692, - /* 330 */ 1695, 1829, 1703, 1707, 1813, 1703, 1707, 1845, 1845, 1845, - /* 340 */ 1845, 1691, 1854, 1724, 1695, 1695, 1724, 1829, 1813, 1724, - /* 350 */ 1813, 1724, 1691, 1854, 1722, 1823, 1691, 1854, 1871, 1691, - /* 360 */ 1854, 1691, 1854, 1871, 1779, 1779, 1779, 1843, 1887, 1887, - /* 370 */ 1871, 1779, 1792, 1779, 1843, 1779, 1779, 1763, 1907, 1821, - /* 380 */ 1821, 1871, 1691, 1852, 1852, 1862, 1862, 1703, 1707, 1925, - /* 390 */ 1691, 1791, 1703, 1804, 1818, 1724, 1943, 1958, 1958, 1975, - /* 400 */ 1975, 1975, 2176, 2176, 2176, 2176, 2176, 2176, 2176, 2176, - /* 410 */ 2176, 2176, 2176, 2176, 2176, 2176, 2176, 440, 934, 1315, - /* 420 */ 1387, 190, 1032, 1275, 1481, 1383, 41, 1449, 853, 1355, - /* 430 */ 1525, 1492, 1539, 1575, 1605, 1627, 1633, 1637, 1564, 1444, - /* 440 */ 1537, 1393, 1673, 1440, 1518, 1570, 1674, 1681, 1498, 1711, - /* 450 */ 1720, 1463, 1600, 1735, 1738, 1596, 1011, 2002, 2005, 1992, - /* 460 */ 1851, 2006, 2004, 1999, 2000, 1884, 1873, 1895, 2003, 2003, - /* 470 */ 2007, 1886, 2010, 1888, 2016, 2033, 1892, 1905, 2003, 1906, - /* 480 */ 1976, 2008, 2003, 1889, 1984, 1985, 1987, 1988, 1913, 1929, - /* 490 */ 2013, 1908, 2048, 2046, 2030, 1937, 1893, 1989, 2029, 1993, - /* 500 */ 1981, 2019, 1919, 1948, 2041, 2047, 2049, 1934, 1944, 2050, - /* 510 */ 2001, 2051, 2052, 2054, 2053, 2011, 2062, 2056, 1986, 2057, - /* 520 */ 2059, 2014, 2058, 2055, 2060, 1936, 2065, 2061, 2066, 2063, - /* 530 */ 2067, 2069, 1995, 1954, 2074, 2077, 1990, 2068, 2079, 1959, - /* 540 */ 2080, 2070, 2078, 2081, 2084, 2025, 2043, 2034, 2075, 2076, - /* 550 */ 2028, 2089, 2101, 2103, 2102, 2104, 2105, 2093, 1994, 1996, - /* 560 */ 2108, 2080, 2109, 2110, 2111, 2106, 2113, 2116, 2112, 2114, - /* 570 */ 2131, 2121, 2122, 2127, 2128, 2132, 2133, 2134, 2017, 2015, - /* 580 */ 2018, 2020, 2136, 2135, 2141, 2162, 2163, + /* 0 */ 2157, 2003, 1686, 1528, 1528, 861, 297, 1652, 1726, 1843, + /* 10 */ 2194, 2194, 2194, 356, 861, 861, 861, 861, 861, 0, + /* 20 */ 0, 184, 1323, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 30 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 532, 532, + /* 40 */ 616, 616, 257, 2, 62, 740, 740, 573, 573, 573, + /* 50 */ 573, 41, 112, 225, 296, 404, 509, 614, 719, 824, + /* 60 */ 929, 1034, 1055, 1168, 1189, 1302, 1323, 1323, 1323, 1323, + /* 70 */ 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, + /* 80 */ 1323, 1323, 1323, 1323, 1344, 1323, 1449, 1470, 1470, 1867, + /* 90 */ 2037, 2104, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 100 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 110 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 120 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 130 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, + /* 140 */ 2194, 2194, 150, 254, 254, 254, 254, 254, 254, 254, + /* 150 */ 87, 192, 208, 581, 740, 835, 894, 740, 740, 793, + /* 160 */ 793, 740, 644, 310, 307, 307, 307, 863, 100, 100, + /* 170 */ 2379, 2379, 456, 456, 456, 94, 66, 66, 66, 66, + /* 180 */ 457, 457, 295, 581, 838, 892, 740, 740, 740, 740, + /* 190 */ 740, 740, 740, 740, 740, 740, 740, 740, 740, 740, + /* 200 */ 740, 740, 740, 740, 740, 874, 878, 878, 740, 994, + /* 210 */ 548, 548, 1188, 1188, 71, 71, 1103, 2379, 2379, 2379, + /* 220 */ 2379, 2379, 2379, 2379, 21, 350, 350, 424, 470, 526, + /* 230 */ 278, 565, 483, 511, 667, 740, 740, 740, 740, 740, + /* 240 */ 740, 740, 740, 740, 740, 416, 740, 740, 740, 740, + /* 250 */ 740, 740, 740, 740, 740, 740, 740, 740, 775, 775, + /* 260 */ 775, 740, 740, 740, 928, 740, 740, 740, 938, 903, + /* 270 */ 740, 949, 740, 740, 740, 740, 740, 740, 740, 740, + /* 280 */ 957, 931, 1296, 110, 1057, 1057, 1057, 1057, 1226, 110, + /* 290 */ 110, 1177, 1155, 884, 1267, 1184, 1241, 1184, 1305, 1236, + /* 300 */ 1267, 1267, 1236, 1267, 1241, 1305, 1239, 1167, 111, 989, + /* 310 */ 989, 989, 1220, 1220, 1220, 1220, 1245, 1245, 850, 1395, + /* 320 */ 1196, 1363, 1647, 1647, 1567, 1567, 1681, 1681, 1567, 1571, + /* 330 */ 1577, 1707, 1583, 1591, 1696, 1583, 1591, 1731, 1731, 1731, + /* 340 */ 1731, 1567, 1732, 1613, 1577, 1577, 1613, 1707, 1696, 1613, + /* 350 */ 1696, 1613, 1567, 1732, 1624, 1723, 1567, 1732, 1768, 1567, + /* 360 */ 1732, 1567, 1732, 1768, 1683, 1683, 1683, 1737, 1783, 1783, + /* 370 */ 1768, 1683, 1687, 1683, 1737, 1683, 1683, 1650, 1805, 1716, + /* 380 */ 1716, 1768, 1567, 1747, 1747, 1757, 1757, 1583, 1591, 1825, + /* 390 */ 1567, 1693, 1583, 1706, 1713, 1613, 1842, 1857, 1857, 1868, + /* 400 */ 1868, 1868, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, + /* 410 */ 2379, 2379, 2379, 2379, 2379, 2379, 2379, 276, 889, 765, + /* 420 */ 902, 56, 990, 786, 1400, 1339, 1424, 1447, 1186, 1329, + /* 430 */ 1441, 1342, 1451, 1452, 1455, 1458, 1490, 1507, 1416, 1222, + /* 440 */ 1478, 1338, 1508, 916, 1453, 1488, 1514, 1518, 1425, 1568, + /* 450 */ 1576, 1448, 1468, 1580, 1598, 1509, 574, 1891, 1893, 1876, + /* 460 */ 1735, 1885, 1888, 1878, 1887, 1772, 1761, 1785, 1889, 1889, + /* 470 */ 1894, 1774, 1899, 1775, 1905, 1922, 1780, 1793, 1889, 1794, + /* 480 */ 1864, 1890, 1889, 1776, 1875, 1877, 1880, 1881, 1800, 1816, + /* 490 */ 1903, 1796, 1940, 1937, 1920, 1827, 1784, 1879, 1924, 1883, + /* 500 */ 1869, 1906, 1811, 1838, 1931, 1936, 1938, 1831, 1833, 1942, + /* 510 */ 1898, 1945, 1947, 1948, 1950, 1902, 1965, 1953, 1882, 1952, + /* 520 */ 1956, 1913, 1946, 1964, 1954, 1840, 1969, 1970, 1971, 1967, + /* 530 */ 1972, 1974, 1907, 1866, 1983, 1986, 1895, 1976, 1989, 1874, + /* 540 */ 1994, 1993, 1995, 1996, 1997, 1939, 1958, 1949, 1987, 1961, + /* 550 */ 1944, 2005, 2017, 2019, 2018, 2021, 2022, 2010, 1908, 1909, + /* 560 */ 2025, 1994, 2026, 2030, 2031, 2033, 2035, 2036, 2039, 2041, + /* 570 */ 2047, 2042, 2043, 2044, 2045, 2048, 2049, 2050, 1930, 1927, + /* 580 */ 1934, 1935, 2053, 2056, 2057, 2080, 2081, }; #define YY_REDUCE_COUNT (416) -#define YY_REDUCE_MIN (-245) -#define YY_REDUCE_MAX (1802) +#define YY_REDUCE_MIN (-311) +#define YY_REDUCE_MAX (1699) static const short yy_reduce_ofst[] = { - /* 0 */ -176, -122, 1208, 268, 274, -159, 389, -192, 317, -190, - /* 10 */ -133, 392, 395, 101, 460, 513, 529, 638, 895, 135, - /* 20 */ 141, -237, -113, 53, 539, 541, 608, 610, 338, 663, - /* 30 */ 665, 522, 644, 669, 865, -194, 940, 945, 486, 734, - /* 40 */ -18, 165, -114, 525, 773, 847, 923, -234, -10, -234, - /* 50 */ -10, -245, -245, -245, -245, -245, -245, -245, -245, -245, - /* 60 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, -245, - /* 70 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, -245, - /* 80 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, 491, - /* 90 */ 561, 709, 809, 822, 927, 949, 952, 1036, 1053, 1055, - /* 100 */ 1073, 1075, 1080, 1100, 1122, 1129, 1157, 1159, 1184, 1197, - /* 110 */ 1201, 1204, 1206, 1241, 1251, 1261, 1292, 1303, 1308, 1310, - /* 120 */ 1312, 1317, 1321, 1323, 1328, 1337, 1357, 1362, 1402, 1406, - /* 130 */ 1408, 1419, 1423, 1454, 1460, 1462, 1473, 1500, 1512, 1547, - /* 140 */ 1560, 1569, -245, -245, -245, -245, -245, -245, -245, -245, - /* 150 */ -245, -245, -245, -131, 168, 195, -225, -62, 526, 427, - /* 160 */ 818, 151, -245, 546, 65, 899, 937, 780, -245, -245, - /* 170 */ -245, -245, -208, -208, -208, 54, 39, 810, 894, 953, - /* 180 */ -139, 936, -196, -189, 912, 912, 1082, 243, 516, 635, - /* 190 */ -116, 56, 1040, 1109, 690, 271, 1056, 512, 758, 1144, - /* 200 */ 960, 1155, -191, 360, 1093, 966, 548, 1113, 281, 595, - /* 210 */ 1114, 1121, 1178, 1185, 1012, 1076, 23, 1041, 260, 585, - /* 220 */ 769, 1175, 1222, 1211, -181, -45, 72, 107, 94, 214, - /* 230 */ 221, 336, 363, 523, 609, 650, 664, 700, 893, 999, - /* 240 */ 1088, 1283, 1339, 1356, 1366, 1081, 1377, 1394, 1398, 1427, - /* 250 */ 1428, 1448, 1458, 1468, 1472, 1475, 1476, 1482, 1456, 1461, - /* 260 */ 1465, 1508, 1514, 1522, 1459, 1526, 1540, 1551, 1353, 1431, - /* 270 */ 1567, 1531, 1576, 221, 1577, 1580, 1581, 1585, 1586, 1587, - /* 280 */ 1479, 1493, 1541, 1528, 1532, 1533, 1534, 1459, 1541, 1541, - /* 290 */ 1544, 1578, 1591, 1495, 1519, 1529, 1549, 1530, 1505, 1554, - /* 300 */ 1536, 1538, 1555, 1542, 1557, 1509, 1589, 1582, 1588, 1599, - /* 310 */ 1601, 1602, 1545, 1552, 1562, 1563, 1566, 1579, 1546, 1584, - /* 320 */ 1592, 1629, 1543, 1548, 1632, 1638, 1550, 1553, 1640, 1559, - /* 330 */ 1574, 1583, 1606, 1603, 1623, 1608, 1611, 1625, 1626, 1630, - /* 340 */ 1631, 1666, 1672, 1628, 1604, 1607, 1635, 1612, 1639, 1636, - /* 350 */ 1641, 1644, 1676, 1679, 1594, 1597, 1686, 1693, 1675, 1694, - /* 360 */ 1696, 1697, 1700, 1680, 1682, 1684, 1685, 1683, 1687, 1689, - /* 370 */ 1688, 1690, 1701, 1702, 1699, 1704, 1705, 1614, 1624, 1648, - /* 380 */ 1654, 1719, 1741, 1642, 1643, 1678, 1698, 1706, 1708, 1668, - /* 390 */ 1747, 1669, 1709, 1712, 1718, 1721, 1766, 1776, 1784, 1790, - /* 400 */ 1801, 1802, 1710, 1713, 1715, 1777, 1770, 1778, 1782, 1783, - /* 410 */ 1793, 1768, 1775, 1785, 1788, 1797, 1796, + /* 0 */ 226, 230, 331, 284, -177, 351, 437, -194, -192, -185, + /* 10 */ -183, -181, -76, 189, 491, 496, 500, 540, 549, -104, + /* 20 */ 31, -270, -211, 462, 497, 588, 617, 619, 357, 621, + /* 30 */ 623, 493, 668, 670, 672, 677, 690, 702, 179, 606, + /* 40 */ 176, 480, 572, 8, 453, 508, 603, -172, 657, -172, + /* 50 */ 657, -262, -262, -262, -262, -262, -262, -262, -262, -262, + /* 60 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -262, + /* 70 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -262, + /* 80 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -156, + /* 90 */ 778, 799, 805, 812, 827, 831, 837, 852, 858, 877, + /* 100 */ 879, 904, 908, 933, 935, 937, 939, 955, 976, 980, + /* 110 */ 982, 984, 986, 988, 992, 1035, 1037, 1042, 1071, 1073, + /* 120 */ 1089, 1091, 1093, 1110, 1123, 1223, 1225, 1227, 1244, 1269, + /* 130 */ 1273, 1275, 1294, 1348, 1350, 1352, 1377, 1391, 1394, 1396, + /* 140 */ 1398, 1402, -262, -262, -262, -262, -262, -262, -262, -262, + /* 150 */ -262, -262, -262, 239, -110, 398, -204, 78, 240, 55, + /* 160 */ 423, 605, -262, 630, 749, 752, 802, 930, -262, -262, + /* 170 */ -262, -262, -212, -212, -212, -54, 299, 460, 482, 513, + /* 180 */ 771, 898, -311, 270, -261, -261, 149, -147, 129, 341, + /* 190 */ 458, 615, 652, 942, 627, -79, 764, 217, 438, 821, + /* 200 */ 747, 1017, 995, 1036, 985, 934, 187, 427, 820, -88, + /* 210 */ 536, 638, 866, 922, 1048, 1105, 333, 1018, 133, 241, + /* 220 */ 401, 1067, 1072, 1077, -218, -199, -196, -93, 54, 175, + /* 230 */ 329, 414, 432, 566, 604, 671, 1038, 1090, 1144, 1271, + /* 240 */ 1320, 1341, 1346, 1351, 1355, 797, 1378, 1392, 1393, 1403, + /* 250 */ 1404, 1413, 1423, 1431, 1432, 1434, 1436, 1437, 791, 1405, + /* 260 */ 1406, 1440, 1443, 1444, 1358, 1445, 1446, 1450, 1384, 1321, + /* 270 */ 1454, 1412, 1457, 329, 1459, 1460, 1461, 1462, 1463, 1464, + /* 280 */ 1467, 1362, 1372, 1419, 1407, 1408, 1409, 1418, 1358, 1419, + /* 290 */ 1419, 1426, 1465, 1364, 1414, 1410, 1427, 1420, 1374, 1429, + /* 300 */ 1421, 1422, 1430, 1428, 1435, 1383, 1471, 1474, 1479, 1473, + /* 310 */ 1486, 1487, 1456, 1466, 1469, 1472, 1475, 1481, 1433, 1476, + /* 320 */ 1477, 1494, 1411, 1415, 1511, 1512, 1439, 1480, 1519, 1492, + /* 330 */ 1482, 1483, 1485, 1489, 1506, 1491, 1497, 1513, 1516, 1520, + /* 340 */ 1523, 1543, 1552, 1517, 1498, 1499, 1531, 1503, 1544, 1533, + /* 350 */ 1546, 1535, 1565, 1584, 1495, 1500, 1587, 1589, 1570, 1592, + /* 360 */ 1594, 1595, 1597, 1573, 1581, 1582, 1585, 1575, 1586, 1588, + /* 370 */ 1593, 1599, 1600, 1603, 1596, 1604, 1609, 1504, 1524, 1548, + /* 380 */ 1553, 1614, 1637, 1522, 1526, 1590, 1601, 1602, 1605, 1579, + /* 390 */ 1649, 1578, 1610, 1607, 1616, 1619, 1666, 1676, 1677, 1684, + /* 400 */ 1685, 1692, 1569, 1606, 1574, 1680, 1678, 1679, 1682, 1688, + /* 410 */ 1689, 1667, 1668, 1690, 1691, 1694, 1699, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1667, 1667, 1667, 1495, 1258, 1371, 1258, 1258, 1258, 1258, - /* 10 */ 1495, 1495, 1495, 1258, 1258, 1258, 1258, 1258, 1258, 1401, - /* 20 */ 1401, 1548, 1291, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 30 */ 1258, 1258, 1258, 1258, 1258, 1494, 1258, 1258, 1258, 1258, - /* 40 */ 1582, 1582, 1258, 1258, 1258, 1258, 1258, 1567, 1566, 1258, - /* 50 */ 1258, 1258, 1410, 1258, 1417, 1258, 1258, 1258, 1258, 1258, - /* 60 */ 1496, 1497, 1258, 1258, 1258, 1258, 1547, 1549, 1512, 1424, - /* 70 */ 1423, 1422, 1421, 1530, 1389, 1415, 1408, 1412, 1491, 1492, - /* 80 */ 1490, 1645, 1497, 1496, 1258, 1411, 1459, 1475, 1458, 1258, - /* 90 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 100 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 110 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 120 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 130 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 140 */ 1258, 1258, 1467, 1474, 1473, 1472, 1481, 1471, 1468, 1461, - /* 150 */ 1460, 1462, 1463, 1282, 1258, 1279, 1333, 1258, 1258, 1258, - /* 160 */ 1258, 1258, 1464, 1291, 1452, 1451, 1450, 1258, 1478, 1465, - /* 170 */ 1477, 1476, 1555, 1619, 1618, 1513, 1258, 1258, 1258, 1258, - /* 180 */ 1258, 1258, 1582, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 190 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 200 */ 1258, 1258, 1258, 1258, 1258, 1391, 1582, 1582, 1258, 1291, - /* 210 */ 1582, 1582, 1392, 1392, 1287, 1287, 1395, 1562, 1362, 1362, - /* 220 */ 1362, 1362, 1371, 1362, 1258, 1258, 1258, 1258, 1258, 1258, - /* 230 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1552, - /* 240 */ 1550, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 250 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 260 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1367, 1258, - /* 270 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1612, - /* 280 */ 1258, 1525, 1347, 1367, 1367, 1367, 1367, 1369, 1348, 1346, - /* 290 */ 1361, 1292, 1265, 1659, 1427, 1416, 1368, 1416, 1656, 1414, - /* 300 */ 1427, 1427, 1414, 1427, 1368, 1656, 1308, 1634, 1303, 1401, - /* 310 */ 1401, 1401, 1391, 1391, 1391, 1391, 1395, 1395, 1493, 1368, - /* 320 */ 1361, 1258, 1659, 1659, 1377, 1377, 1658, 1658, 1377, 1513, - /* 330 */ 1642, 1436, 1409, 1395, 1336, 1409, 1395, 1342, 1342, 1342, - /* 340 */ 1342, 1377, 1276, 1414, 1642, 1642, 1414, 1436, 1336, 1414, - /* 350 */ 1336, 1414, 1377, 1276, 1529, 1653, 1377, 1276, 1503, 1377, - /* 360 */ 1276, 1377, 1276, 1503, 1334, 1334, 1334, 1323, 1258, 1258, - /* 370 */ 1503, 1334, 1308, 1334, 1323, 1334, 1334, 1600, 1258, 1507, - /* 380 */ 1507, 1503, 1377, 1592, 1592, 1404, 1404, 1409, 1395, 1498, - /* 390 */ 1377, 1258, 1409, 1407, 1405, 1414, 1326, 1615, 1615, 1611, - /* 400 */ 1611, 1611, 1664, 1664, 1562, 1627, 1291, 1291, 1291, 1291, - /* 410 */ 1627, 1310, 1310, 1292, 1292, 1291, 1627, 1258, 1258, 1258, - /* 420 */ 1258, 1258, 1258, 1622, 1258, 1557, 1514, 1381, 1258, 1258, - /* 430 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 440 */ 1258, 1258, 1258, 1258, 1568, 1258, 1258, 1258, 1258, 1258, - /* 450 */ 1258, 1258, 1258, 1258, 1258, 1258, 1441, 1258, 1261, 1559, - /* 460 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1418, 1419, - /* 470 */ 1382, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1433, 1258, - /* 480 */ 1258, 1258, 1428, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 490 */ 1258, 1655, 1258, 1258, 1258, 1258, 1258, 1258, 1528, 1527, - /* 500 */ 1258, 1258, 1379, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 510 */ 1258, 1258, 1258, 1258, 1258, 1258, 1306, 1258, 1258, 1258, - /* 520 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 530 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 540 */ 1406, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, - /* 550 */ 1258, 1258, 1258, 1258, 1258, 1597, 1396, 1258, 1258, 1258, - /* 560 */ 1258, 1646, 1258, 1258, 1258, 1258, 1356, 1258, 1258, 1258, - /* 570 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1638, 1350, 1442, - /* 580 */ 1258, 1445, 1280, 1258, 1270, 1258, 1258, + /* 0 */ 1670, 1670, 1670, 1498, 1260, 1374, 1260, 1260, 1260, 1260, + /* 10 */ 1498, 1498, 1498, 1260, 1260, 1260, 1260, 1260, 1260, 1404, + /* 20 */ 1404, 1551, 1294, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 30 */ 1260, 1260, 1260, 1260, 1260, 1497, 1260, 1260, 1260, 1260, + /* 40 */ 1585, 1585, 1260, 1260, 1260, 1260, 1260, 1570, 1569, 1260, + /* 50 */ 1260, 1260, 1413, 1260, 1420, 1260, 1260, 1260, 1260, 1260, + /* 60 */ 1499, 1500, 1260, 1260, 1260, 1260, 1550, 1552, 1515, 1427, + /* 70 */ 1426, 1425, 1424, 1533, 1392, 1418, 1411, 1415, 1494, 1495, + /* 80 */ 1493, 1648, 1500, 1499, 1260, 1414, 1462, 1478, 1461, 1260, + /* 90 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 100 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 110 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 120 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 130 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 140 */ 1260, 1260, 1470, 1477, 1476, 1475, 1484, 1474, 1471, 1464, + /* 150 */ 1463, 1465, 1466, 1285, 1260, 1282, 1336, 1260, 1260, 1260, + /* 160 */ 1260, 1260, 1467, 1294, 1455, 1454, 1453, 1260, 1481, 1468, + /* 170 */ 1480, 1479, 1558, 1622, 1621, 1516, 1260, 1260, 1260, 1260, + /* 180 */ 1260, 1260, 1585, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 190 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 200 */ 1260, 1260, 1260, 1260, 1260, 1394, 1585, 1585, 1260, 1294, + /* 210 */ 1585, 1585, 1395, 1395, 1290, 1290, 1398, 1565, 1365, 1365, + /* 220 */ 1365, 1365, 1374, 1365, 1260, 1260, 1260, 1260, 1260, 1260, + /* 230 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1555, + /* 240 */ 1553, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 250 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 260 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1370, 1260, + /* 270 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1615, + /* 280 */ 1267, 1260, 1528, 1350, 1370, 1370, 1370, 1370, 1372, 1351, + /* 290 */ 1349, 1364, 1295, 1662, 1430, 1419, 1371, 1419, 1659, 1417, + /* 300 */ 1430, 1430, 1417, 1430, 1371, 1659, 1311, 1637, 1306, 1404, + /* 310 */ 1404, 1404, 1394, 1394, 1394, 1394, 1398, 1398, 1496, 1371, + /* 320 */ 1364, 1260, 1662, 1662, 1380, 1380, 1661, 1661, 1380, 1516, + /* 330 */ 1645, 1439, 1412, 1398, 1339, 1412, 1398, 1345, 1345, 1345, + /* 340 */ 1345, 1380, 1279, 1417, 1645, 1645, 1417, 1439, 1339, 1417, + /* 350 */ 1339, 1417, 1380, 1279, 1532, 1656, 1380, 1279, 1506, 1380, + /* 360 */ 1279, 1380, 1279, 1506, 1337, 1337, 1337, 1326, 1260, 1260, + /* 370 */ 1506, 1337, 1311, 1337, 1326, 1337, 1337, 1603, 1260, 1510, + /* 380 */ 1510, 1506, 1380, 1595, 1595, 1407, 1407, 1412, 1398, 1501, + /* 390 */ 1380, 1260, 1412, 1410, 1408, 1417, 1329, 1618, 1618, 1614, + /* 400 */ 1614, 1614, 1667, 1667, 1565, 1630, 1294, 1294, 1294, 1294, + /* 410 */ 1630, 1313, 1313, 1295, 1295, 1294, 1630, 1260, 1260, 1260, + /* 420 */ 1260, 1260, 1260, 1625, 1260, 1560, 1517, 1384, 1260, 1260, + /* 430 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 440 */ 1260, 1260, 1260, 1260, 1571, 1260, 1260, 1260, 1260, 1260, + /* 450 */ 1260, 1260, 1260, 1260, 1260, 1260, 1444, 1260, 1263, 1562, + /* 460 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1421, 1422, + /* 470 */ 1385, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1436, 1260, + /* 480 */ 1260, 1260, 1431, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 490 */ 1260, 1658, 1260, 1260, 1260, 1260, 1260, 1260, 1531, 1530, + /* 500 */ 1260, 1260, 1382, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 510 */ 1260, 1260, 1260, 1260, 1260, 1260, 1309, 1260, 1260, 1260, + /* 520 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 530 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 540 */ 1409, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 550 */ 1260, 1260, 1260, 1260, 1260, 1600, 1399, 1260, 1260, 1260, + /* 560 */ 1260, 1649, 1260, 1260, 1260, 1260, 1359, 1260, 1260, 1260, + /* 570 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1641, 1353, 1445, + /* 580 */ 1260, 1448, 1283, 1260, 1273, 1260, 1260, }; /********** End of lemon-generated parsing tables *****************************/ @@ -177867,6 +177935,7 @@ static const YYCODETYPE yyFallback[] = { 9, /* DEFERRED => ID */ 9, /* IMMEDIATE => ID */ 0, /* ID => nothing */ + 9, /* CONCURRENT => ID */ 0, /* COMMIT => nothing */ 9, /* END => ID */ 9, /* ROLLBACK => ID */ @@ -178034,7 +178103,6 @@ static const YYCODETYPE yyFallback[] = { 0, /* UMINUS => nothing */ 0, /* TRUTH => nothing */ 0, /* REGISTER => nothing */ - 0, /* CONCURRENT => nothing */ 0, /* VECTOR => nothing */ 0, /* SELECT_COLUMN => nothing */ 0, /* IF_NULL_ROW => nothing */ @@ -178137,174 +178205,174 @@ static const char *const yyTokenName[] = { /* 7 */ "DEFERRED", /* 8 */ "IMMEDIATE", /* 9 */ "ID", - /* 10 */ "COMMIT", - /* 11 */ "END", - /* 12 */ "ROLLBACK", - /* 13 */ "SAVEPOINT", - /* 14 */ "RELEASE", - /* 15 */ "TO", - /* 16 */ "TABLE", - /* 17 */ "CREATE", - /* 18 */ "IF", - /* 19 */ "NOT", - /* 20 */ "EXISTS", - /* 21 */ "TEMP", - /* 22 */ "LP", - /* 23 */ "RP", - /* 24 */ "AS", - /* 25 */ "COMMA", - /* 26 */ "WITHOUT", - /* 27 */ "ABORT", - /* 28 */ "ACTION", - /* 29 */ "AFTER", - /* 30 */ "ANALYZE", - /* 31 */ "ASC", - /* 32 */ "ATTACH", - /* 33 */ "BEFORE", - /* 34 */ "BY", - /* 35 */ "CASCADE", - /* 36 */ "CAST", - /* 37 */ "CONFLICT", - /* 38 */ "DATABASE", - /* 39 */ "DESC", - /* 40 */ "DETACH", - /* 41 */ "EACH", - /* 42 */ "EXCLUSIVE", - /* 43 */ "FAIL", - /* 44 */ "OR", - /* 45 */ "AND", - /* 46 */ "IS", - /* 47 */ "ISNOT", - /* 48 */ "MATCH", - /* 49 */ "LIKE_KW", - /* 50 */ "BETWEEN", - /* 51 */ "IN", - /* 52 */ "ISNULL", - /* 53 */ "NOTNULL", - /* 54 */ "NE", - /* 55 */ "EQ", - /* 56 */ "GT", - /* 57 */ "LE", - /* 58 */ "LT", - /* 59 */ "GE", - /* 60 */ "ESCAPE", - /* 61 */ "COLUMNKW", - /* 62 */ "DO", - /* 63 */ "FOR", - /* 64 */ "IGNORE", - /* 65 */ "INITIALLY", - /* 66 */ "INSTEAD", - /* 67 */ "NO", - /* 68 */ "KEY", - /* 69 */ "OF", - /* 70 */ "OFFSET", - /* 71 */ "PRAGMA", - /* 72 */ "RAISE", - /* 73 */ "RECURSIVE", - /* 74 */ "REPLACE", - /* 75 */ "RESTRICT", - /* 76 */ "ROW", - /* 77 */ "ROWS", - /* 78 */ "TRIGGER", - /* 79 */ "VACUUM", - /* 80 */ "VIEW", - /* 81 */ "VIRTUAL", - /* 82 */ "WITH", - /* 83 */ "NULLS", - /* 84 */ "FIRST", - /* 85 */ "LAST", - /* 86 */ "CURRENT", - /* 87 */ "FOLLOWING", - /* 88 */ "PARTITION", - /* 89 */ "PRECEDING", - /* 90 */ "RANGE", - /* 91 */ "UNBOUNDED", - /* 92 */ "EXCLUDE", - /* 93 */ "GROUPS", - /* 94 */ "OTHERS", - /* 95 */ "TIES", - /* 96 */ "GENERATED", - /* 97 */ "ALWAYS", - /* 98 */ "MATERIALIZED", - /* 99 */ "REINDEX", - /* 100 */ "RENAME", - /* 101 */ "CTIME_KW", - /* 102 */ "ANY", - /* 103 */ "BITAND", - /* 104 */ "BITOR", - /* 105 */ "LSHIFT", - /* 106 */ "RSHIFT", - /* 107 */ "PLUS", - /* 108 */ "MINUS", - /* 109 */ "STAR", - /* 110 */ "SLASH", - /* 111 */ "REM", - /* 112 */ "CONCAT", - /* 113 */ "PTR", - /* 114 */ "COLLATE", - /* 115 */ "BITNOT", - /* 116 */ "ON", - /* 117 */ "INDEXED", - /* 118 */ "STRING", - /* 119 */ "JOIN_KW", - /* 120 */ "CONSTRAINT", - /* 121 */ "DEFAULT", - /* 122 */ "NULL", - /* 123 */ "PRIMARY", - /* 124 */ "UNIQUE", - /* 125 */ "CHECK", - /* 126 */ "REFERENCES", - /* 127 */ "AUTOINCR", - /* 128 */ "INSERT", - /* 129 */ "DELETE", - /* 130 */ "UPDATE", - /* 131 */ "SET", - /* 132 */ "DEFERRABLE", - /* 133 */ "FOREIGN", - /* 134 */ "DROP", - /* 135 */ "UNION", - /* 136 */ "ALL", - /* 137 */ "EXCEPT", - /* 138 */ "INTERSECT", - /* 139 */ "SELECT", - /* 140 */ "VALUES", - /* 141 */ "DISTINCT", - /* 142 */ "DOT", - /* 143 */ "FROM", - /* 144 */ "JOIN", - /* 145 */ "USING", - /* 146 */ "ORDER", - /* 147 */ "GROUP", - /* 148 */ "HAVING", - /* 149 */ "LIMIT", - /* 150 */ "WHERE", - /* 151 */ "RETURNING", - /* 152 */ "INTO", - /* 153 */ "NOTHING", - /* 154 */ "FLOAT", - /* 155 */ "BLOB", - /* 156 */ "INTEGER", - /* 157 */ "VARIABLE", - /* 158 */ "CASE", - /* 159 */ "WHEN", - /* 160 */ "THEN", - /* 161 */ "ELSE", - /* 162 */ "INDEX", - /* 163 */ "ALTER", - /* 164 */ "ADD", - /* 165 */ "WINDOW", - /* 166 */ "OVER", - /* 167 */ "FILTER", - /* 168 */ "COLUMN", - /* 169 */ "AGG_FUNCTION", - /* 170 */ "AGG_COLUMN", - /* 171 */ "TRUEFALSE", - /* 172 */ "FUNCTION", - /* 173 */ "UPLUS", - /* 174 */ "UMINUS", - /* 175 */ "TRUTH", - /* 176 */ "REGISTER", - /* 177 */ "CONCURRENT", + /* 10 */ "CONCURRENT", + /* 11 */ "COMMIT", + /* 12 */ "END", + /* 13 */ "ROLLBACK", + /* 14 */ "SAVEPOINT", + /* 15 */ "RELEASE", + /* 16 */ "TO", + /* 17 */ "TABLE", + /* 18 */ "CREATE", + /* 19 */ "IF", + /* 20 */ "NOT", + /* 21 */ "EXISTS", + /* 22 */ "TEMP", + /* 23 */ "LP", + /* 24 */ "RP", + /* 25 */ "AS", + /* 26 */ "COMMA", + /* 27 */ "WITHOUT", + /* 28 */ "ABORT", + /* 29 */ "ACTION", + /* 30 */ "AFTER", + /* 31 */ "ANALYZE", + /* 32 */ "ASC", + /* 33 */ "ATTACH", + /* 34 */ "BEFORE", + /* 35 */ "BY", + /* 36 */ "CASCADE", + /* 37 */ "CAST", + /* 38 */ "CONFLICT", + /* 39 */ "DATABASE", + /* 40 */ "DESC", + /* 41 */ "DETACH", + /* 42 */ "EACH", + /* 43 */ "EXCLUSIVE", + /* 44 */ "FAIL", + /* 45 */ "OR", + /* 46 */ "AND", + /* 47 */ "IS", + /* 48 */ "ISNOT", + /* 49 */ "MATCH", + /* 50 */ "LIKE_KW", + /* 51 */ "BETWEEN", + /* 52 */ "IN", + /* 53 */ "ISNULL", + /* 54 */ "NOTNULL", + /* 55 */ "NE", + /* 56 */ "EQ", + /* 57 */ "GT", + /* 58 */ "LE", + /* 59 */ "LT", + /* 60 */ "GE", + /* 61 */ "ESCAPE", + /* 62 */ "COLUMNKW", + /* 63 */ "DO", + /* 64 */ "FOR", + /* 65 */ "IGNORE", + /* 66 */ "INITIALLY", + /* 67 */ "INSTEAD", + /* 68 */ "NO", + /* 69 */ "KEY", + /* 70 */ "OF", + /* 71 */ "OFFSET", + /* 72 */ "PRAGMA", + /* 73 */ "RAISE", + /* 74 */ "RECURSIVE", + /* 75 */ "REPLACE", + /* 76 */ "RESTRICT", + /* 77 */ "ROW", + /* 78 */ "ROWS", + /* 79 */ "TRIGGER", + /* 80 */ "VACUUM", + /* 81 */ "VIEW", + /* 82 */ "VIRTUAL", + /* 83 */ "WITH", + /* 84 */ "NULLS", + /* 85 */ "FIRST", + /* 86 */ "LAST", + /* 87 */ "CURRENT", + /* 88 */ "FOLLOWING", + /* 89 */ "PARTITION", + /* 90 */ "PRECEDING", + /* 91 */ "RANGE", + /* 92 */ "UNBOUNDED", + /* 93 */ "EXCLUDE", + /* 94 */ "GROUPS", + /* 95 */ "OTHERS", + /* 96 */ "TIES", + /* 97 */ "GENERATED", + /* 98 */ "ALWAYS", + /* 99 */ "MATERIALIZED", + /* 100 */ "REINDEX", + /* 101 */ "RENAME", + /* 102 */ "CTIME_KW", + /* 103 */ "ANY", + /* 104 */ "BITAND", + /* 105 */ "BITOR", + /* 106 */ "LSHIFT", + /* 107 */ "RSHIFT", + /* 108 */ "PLUS", + /* 109 */ "MINUS", + /* 110 */ "STAR", + /* 111 */ "SLASH", + /* 112 */ "REM", + /* 113 */ "CONCAT", + /* 114 */ "PTR", + /* 115 */ "COLLATE", + /* 116 */ "BITNOT", + /* 117 */ "ON", + /* 118 */ "INDEXED", + /* 119 */ "STRING", + /* 120 */ "JOIN_KW", + /* 121 */ "CONSTRAINT", + /* 122 */ "DEFAULT", + /* 123 */ "NULL", + /* 124 */ "PRIMARY", + /* 125 */ "UNIQUE", + /* 126 */ "CHECK", + /* 127 */ "REFERENCES", + /* 128 */ "AUTOINCR", + /* 129 */ "INSERT", + /* 130 */ "DELETE", + /* 131 */ "UPDATE", + /* 132 */ "SET", + /* 133 */ "DEFERRABLE", + /* 134 */ "FOREIGN", + /* 135 */ "DROP", + /* 136 */ "UNION", + /* 137 */ "ALL", + /* 138 */ "EXCEPT", + /* 139 */ "INTERSECT", + /* 140 */ "SELECT", + /* 141 */ "VALUES", + /* 142 */ "DISTINCT", + /* 143 */ "DOT", + /* 144 */ "FROM", + /* 145 */ "JOIN", + /* 146 */ "USING", + /* 147 */ "ORDER", + /* 148 */ "GROUP", + /* 149 */ "HAVING", + /* 150 */ "LIMIT", + /* 151 */ "WHERE", + /* 152 */ "RETURNING", + /* 153 */ "INTO", + /* 154 */ "NOTHING", + /* 155 */ "FLOAT", + /* 156 */ "BLOB", + /* 157 */ "INTEGER", + /* 158 */ "VARIABLE", + /* 159 */ "CASE", + /* 160 */ "WHEN", + /* 161 */ "THEN", + /* 162 */ "ELSE", + /* 163 */ "INDEX", + /* 164 */ "ALTER", + /* 165 */ "ADD", + /* 166 */ "WINDOW", + /* 167 */ "OVER", + /* 168 */ "FILTER", + /* 169 */ "COLUMN", + /* 170 */ "AGG_FUNCTION", + /* 171 */ "AGG_COLUMN", + /* 172 */ "TRUEFALSE", + /* 173 */ "FUNCTION", + /* 174 */ "UPLUS", + /* 175 */ "UMINUS", + /* 176 */ "TRUTH", + /* 177 */ "REGISTER", /* 178 */ "VECTOR", /* 179 */ "SELECT_COLUMN", /* 180 */ "IF_NULL_ROW", @@ -178465,407 +178533,408 @@ static const char *const yyRuleName[] = { /* 5 */ "transtype ::= DEFERRED", /* 6 */ "transtype ::= IMMEDIATE", /* 7 */ "transtype ::= ID", - /* 8 */ "cmd ::= COMMIT|END trans_opt", - /* 9 */ "cmd ::= ROLLBACK trans_opt", - /* 10 */ "cmd ::= SAVEPOINT nm", - /* 11 */ "cmd ::= RELEASE savepoint_opt nm", - /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", - /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", - /* 14 */ "createkw ::= CREATE", - /* 15 */ "ifnotexists ::=", - /* 16 */ "ifnotexists ::= IF NOT EXISTS", - /* 17 */ "temp ::= TEMP", - /* 18 */ "temp ::=", - /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", - /* 20 */ "create_table_args ::= AS select", - /* 21 */ "table_option_set ::=", - /* 22 */ "table_option_set ::= table_option_set COMMA table_option", - /* 23 */ "table_option ::= WITHOUT nm", - /* 24 */ "table_option ::= nm", - /* 25 */ "columnname ::= nm typetoken", - /* 26 */ "typetoken ::=", - /* 27 */ "typetoken ::= typename LP signed RP", - /* 28 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 29 */ "typename ::= typename ID|STRING", - /* 30 */ "scanpt ::=", - /* 31 */ "scantok ::=", - /* 32 */ "ccons ::= CONSTRAINT nm", - /* 33 */ "ccons ::= DEFAULT scantok term", - /* 34 */ "ccons ::= DEFAULT LP expr RP", - /* 35 */ "ccons ::= DEFAULT PLUS scantok term", - /* 36 */ "ccons ::= DEFAULT MINUS scantok term", - /* 37 */ "ccons ::= DEFAULT scantok ID|INDEXED", - /* 38 */ "ccons ::= NOT NULL onconf", - /* 39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 40 */ "ccons ::= UNIQUE onconf", - /* 41 */ "ccons ::= CHECK LP expr RP", - /* 42 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 43 */ "ccons ::= defer_subclause", - /* 44 */ "ccons ::= COLLATE ID|STRING", - /* 45 */ "generated ::= LP expr RP", - /* 46 */ "generated ::= LP expr RP ID", - /* 47 */ "autoinc ::=", - /* 48 */ "autoinc ::= AUTOINCR", - /* 49 */ "refargs ::=", - /* 50 */ "refargs ::= refargs refarg", - /* 51 */ "refarg ::= MATCH nm", - /* 52 */ "refarg ::= ON INSERT refact", - /* 53 */ "refarg ::= ON DELETE refact", - /* 54 */ "refarg ::= ON UPDATE refact", - /* 55 */ "refact ::= SET NULL", - /* 56 */ "refact ::= SET DEFAULT", - /* 57 */ "refact ::= CASCADE", - /* 58 */ "refact ::= RESTRICT", - /* 59 */ "refact ::= NO ACTION", - /* 60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 62 */ "init_deferred_pred_opt ::=", - /* 63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 65 */ "conslist_opt ::=", - /* 66 */ "tconscomma ::= COMMA", - /* 67 */ "tcons ::= CONSTRAINT nm", - /* 68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 69 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 70 */ "tcons ::= CHECK LP expr RP onconf", - /* 71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 72 */ "defer_subclause_opt ::=", - /* 73 */ "onconf ::=", - /* 74 */ "onconf ::= ON CONFLICT resolvetype", - /* 75 */ "orconf ::=", - /* 76 */ "orconf ::= OR resolvetype", - /* 77 */ "resolvetype ::= IGNORE", - /* 78 */ "resolvetype ::= REPLACE", - /* 79 */ "cmd ::= DROP TABLE ifexists fullname", - /* 80 */ "ifexists ::= IF EXISTS", - /* 81 */ "ifexists ::=", - /* 82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 83 */ "cmd ::= DROP VIEW ifexists fullname", - /* 84 */ "cmd ::= select", - /* 85 */ "select ::= WITH wqlist selectnowith", - /* 86 */ "select ::= WITH RECURSIVE wqlist selectnowith", - /* 87 */ "select ::= selectnowith", - /* 88 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 89 */ "multiselect_op ::= UNION", - /* 90 */ "multiselect_op ::= UNION ALL", - /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", - /* 94 */ "values ::= VALUES LP nexprlist RP", - /* 95 */ "oneselect ::= mvalues", - /* 96 */ "mvalues ::= values COMMA LP nexprlist RP", - /* 97 */ "mvalues ::= mvalues COMMA LP nexprlist RP", - /* 98 */ "distinct ::= DISTINCT", - /* 99 */ "distinct ::= ALL", - /* 100 */ "distinct ::=", - /* 101 */ "sclp ::=", - /* 102 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 103 */ "selcollist ::= sclp scanpt STAR", - /* 104 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 105 */ "as ::= AS nm", - /* 106 */ "as ::=", - /* 107 */ "from ::=", - /* 108 */ "from ::= FROM seltablist", - /* 109 */ "stl_prefix ::= seltablist joinop", - /* 110 */ "stl_prefix ::=", - /* 111 */ "seltablist ::= stl_prefix nm dbnm as on_using", - /* 112 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", - /* 113 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", - /* 114 */ "seltablist ::= stl_prefix LP select RP as on_using", - /* 115 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", - /* 116 */ "dbnm ::=", - /* 117 */ "dbnm ::= DOT nm", - /* 118 */ "fullname ::= nm", - /* 119 */ "fullname ::= nm DOT nm", - /* 120 */ "xfullname ::= nm", - /* 121 */ "xfullname ::= nm DOT nm", - /* 122 */ "xfullname ::= nm DOT nm AS nm", - /* 123 */ "xfullname ::= nm AS nm", - /* 124 */ "joinop ::= COMMA|JOIN", - /* 125 */ "joinop ::= JOIN_KW JOIN", - /* 126 */ "joinop ::= JOIN_KW nm JOIN", - /* 127 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 128 */ "on_using ::= ON expr", - /* 129 */ "on_using ::= USING LP idlist RP", - /* 130 */ "on_using ::=", - /* 131 */ "indexed_opt ::=", - /* 132 */ "indexed_by ::= INDEXED BY nm", - /* 133 */ "indexed_by ::= NOT INDEXED", - /* 134 */ "orderby_opt ::=", - /* 135 */ "orderby_opt ::= ORDER BY sortlist", - /* 136 */ "sortlist ::= sortlist COMMA expr sortorder nulls", - /* 137 */ "sortlist ::= expr sortorder nulls", - /* 138 */ "sortorder ::= ASC", - /* 139 */ "sortorder ::= DESC", - /* 140 */ "sortorder ::=", - /* 141 */ "nulls ::= NULLS FIRST", - /* 142 */ "nulls ::= NULLS LAST", - /* 143 */ "nulls ::=", - /* 144 */ "groupby_opt ::=", - /* 145 */ "groupby_opt ::= GROUP BY nexprlist", - /* 146 */ "having_opt ::=", - /* 147 */ "having_opt ::= HAVING expr", - /* 148 */ "limit_opt ::=", - /* 149 */ "limit_opt ::= LIMIT expr", - /* 150 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 151 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 152 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt", - /* 153 */ "where_opt ::=", - /* 154 */ "where_opt ::= WHERE expr", - /* 155 */ "where_opt_ret ::=", - /* 156 */ "where_opt_ret ::= WHERE expr", - /* 157 */ "where_opt_ret ::= RETURNING selcollist", - /* 158 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", - /* 159 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt", - /* 160 */ "setlist ::= setlist COMMA nm EQ expr", - /* 161 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 162 */ "setlist ::= nm EQ expr", - /* 163 */ "setlist ::= LP idlist RP EQ expr", - /* 164 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", - /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", - /* 166 */ "upsert ::=", - /* 167 */ "upsert ::= RETURNING selcollist", - /* 168 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", - /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", - /* 170 */ "upsert ::= ON CONFLICT DO NOTHING returning", - /* 171 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", - /* 172 */ "returning ::= RETURNING selcollist", - /* 173 */ "insert_cmd ::= INSERT orconf", - /* 174 */ "insert_cmd ::= REPLACE", - /* 175 */ "idlist_opt ::=", - /* 176 */ "idlist_opt ::= LP idlist RP", - /* 177 */ "idlist ::= idlist COMMA nm", - /* 178 */ "idlist ::= nm", - /* 179 */ "expr ::= LP expr RP", - /* 180 */ "expr ::= ID|INDEXED|JOIN_KW", - /* 181 */ "expr ::= nm DOT nm", - /* 182 */ "expr ::= nm DOT nm DOT nm", - /* 183 */ "term ::= NULL|FLOAT|BLOB", - /* 184 */ "term ::= STRING", - /* 185 */ "term ::= INTEGER", - /* 186 */ "expr ::= VARIABLE", - /* 187 */ "expr ::= expr COLLATE ID|STRING", - /* 188 */ "expr ::= CAST LP expr AS typetoken RP", - /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", - /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", - /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", - /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", - /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", - /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", - /* 195 */ "term ::= CTIME_KW", - /* 196 */ "expr ::= LP nexprlist COMMA expr RP", - /* 197 */ "expr ::= expr AND expr", - /* 198 */ "expr ::= expr OR expr", - /* 199 */ "expr ::= expr LT|GT|GE|LE expr", - /* 200 */ "expr ::= expr EQ|NE expr", - /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 202 */ "expr ::= expr PLUS|MINUS expr", - /* 203 */ "expr ::= expr STAR|SLASH|REM expr", - /* 204 */ "expr ::= expr CONCAT expr", - /* 205 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 206 */ "expr ::= expr likeop expr", - /* 207 */ "expr ::= expr likeop expr ESCAPE expr", - /* 208 */ "expr ::= expr ISNULL|NOTNULL", - /* 209 */ "expr ::= expr NOT NULL", - /* 210 */ "expr ::= expr IS expr", - /* 211 */ "expr ::= expr IS NOT expr", - /* 212 */ "expr ::= expr IS NOT DISTINCT FROM expr", - /* 213 */ "expr ::= expr IS DISTINCT FROM expr", - /* 214 */ "expr ::= NOT expr", - /* 215 */ "expr ::= BITNOT expr", - /* 216 */ "expr ::= PLUS|MINUS expr", - /* 217 */ "expr ::= expr PTR expr", - /* 218 */ "between_op ::= BETWEEN", - /* 219 */ "between_op ::= NOT BETWEEN", - /* 220 */ "expr ::= expr between_op expr AND expr", - /* 221 */ "in_op ::= IN", - /* 222 */ "in_op ::= NOT IN", - /* 223 */ "expr ::= expr in_op LP exprlist RP", - /* 224 */ "expr ::= LP select RP", - /* 225 */ "expr ::= expr in_op LP select RP", - /* 226 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 227 */ "expr ::= EXISTS LP select RP", - /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 230 */ "case_exprlist ::= WHEN expr THEN expr", - /* 231 */ "case_else ::= ELSE expr", - /* 232 */ "case_else ::=", - /* 233 */ "case_operand ::=", - /* 234 */ "exprlist ::=", - /* 235 */ "nexprlist ::= nexprlist COMMA expr", - /* 236 */ "nexprlist ::= expr", - /* 237 */ "paren_exprlist ::=", - /* 238 */ "paren_exprlist ::= LP exprlist RP", - /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 240 */ "uniqueflag ::= UNIQUE", - /* 241 */ "uniqueflag ::=", - /* 242 */ "eidlist_opt ::=", - /* 243 */ "eidlist_opt ::= LP eidlist RP", - /* 244 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 245 */ "eidlist ::= nm collate sortorder", - /* 246 */ "collate ::=", - /* 247 */ "collate ::= COLLATE ID|STRING", - /* 248 */ "cmd ::= DROP INDEX ifexists fullname", - /* 249 */ "cmd ::= VACUUM vinto", - /* 250 */ "cmd ::= VACUUM nm vinto", - /* 251 */ "vinto ::= INTO expr", - /* 252 */ "vinto ::=", - /* 253 */ "cmd ::= PRAGMA nm dbnm", - /* 254 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 255 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 256 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 257 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 258 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 259 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 260 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 261 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 262 */ "trigger_time ::= BEFORE|AFTER", - /* 263 */ "trigger_time ::= INSTEAD OF", - /* 264 */ "trigger_time ::=", - /* 265 */ "trigger_event ::= DELETE|INSERT", - /* 266 */ "trigger_event ::= UPDATE", - /* 267 */ "trigger_event ::= UPDATE OF idlist", - /* 268 */ "when_clause ::=", - /* 269 */ "when_clause ::= WHEN expr", - /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 272 */ "trnm ::= nm DOT nm", - /* 273 */ "tridxby ::= INDEXED BY nm", - /* 274 */ "tridxby ::= NOT INDEXED", - /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 278 */ "trigger_cmd ::= scanpt select scanpt", - /* 279 */ "expr ::= RAISE LP IGNORE RP", - /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP", - /* 281 */ "raisetype ::= ROLLBACK", - /* 282 */ "raisetype ::= ABORT", - /* 283 */ "raisetype ::= FAIL", - /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 286 */ "cmd ::= DETACH database_kw_opt expr", - /* 287 */ "key_opt ::=", - /* 288 */ "key_opt ::= KEY expr", - /* 289 */ "cmd ::= REINDEX", - /* 290 */ "cmd ::= REINDEX nm dbnm", - /* 291 */ "cmd ::= ANALYZE", - /* 292 */ "cmd ::= ANALYZE nm dbnm", - /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 296 */ "add_column_fullname ::= fullname", - /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 298 */ "cmd ::= create_vtab", - /* 299 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 301 */ "vtabarg ::=", - /* 302 */ "vtabargtoken ::= ANY", - /* 303 */ "vtabargtoken ::= lp anylist RP", - /* 304 */ "lp ::= LP", - /* 305 */ "with ::= WITH wqlist", - /* 306 */ "with ::= WITH RECURSIVE wqlist", - /* 307 */ "wqas ::= AS", - /* 308 */ "wqas ::= AS MATERIALIZED", - /* 309 */ "wqas ::= AS NOT MATERIALIZED", - /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", - /* 311 */ "withnm ::= nm", - /* 312 */ "wqlist ::= wqitem", - /* 313 */ "wqlist ::= wqlist COMMA wqitem", - /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 315 */ "windowdefn ::= nm AS LP window RP", - /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 318 */ "window ::= ORDER BY sortlist frame_opt", - /* 319 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 320 */ "window ::= nm frame_opt", - /* 321 */ "frame_opt ::=", - /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 325 */ "frame_bound_s ::= frame_bound", - /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 327 */ "frame_bound_e ::= frame_bound", - /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 330 */ "frame_bound ::= CURRENT ROW", - /* 331 */ "frame_exclude_opt ::=", - /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 333 */ "frame_exclude ::= NO OTHERS", - /* 334 */ "frame_exclude ::= CURRENT ROW", - /* 335 */ "frame_exclude ::= GROUP|TIES", - /* 336 */ "window_clause ::= WINDOW windowdefn_list", - /* 337 */ "filter_over ::= filter_clause over_clause", - /* 338 */ "filter_over ::= over_clause", - /* 339 */ "filter_over ::= filter_clause", - /* 340 */ "over_clause ::= OVER LP window RP", - /* 341 */ "over_clause ::= OVER nm", - /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 343 */ "term ::= QNUMBER", - /* 344 */ "input ::= cmdlist", - /* 345 */ "cmdlist ::= cmdlist ecmd", - /* 346 */ "cmdlist ::= ecmd", - /* 347 */ "ecmd ::= SEMI", - /* 348 */ "ecmd ::= cmdx SEMI", - /* 349 */ "ecmd ::= explain cmdx SEMI", - /* 350 */ "trans_opt ::=", - /* 351 */ "trans_opt ::= TRANSACTION", - /* 352 */ "trans_opt ::= TRANSACTION nm", - /* 353 */ "savepoint_opt ::= SAVEPOINT", - /* 354 */ "savepoint_opt ::=", - /* 355 */ "cmd ::= create_table create_table_args", - /* 356 */ "table_option_set ::= table_option", - /* 357 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 358 */ "columnlist ::= columnname carglist", - /* 359 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 360 */ "nm ::= STRING", - /* 361 */ "typetoken ::= typename", - /* 362 */ "typename ::= ID|STRING", - /* 363 */ "signed ::= plus_num", - /* 364 */ "signed ::= minus_num", - /* 365 */ "carglist ::= carglist ccons", - /* 366 */ "carglist ::=", - /* 367 */ "ccons ::= NULL onconf", - /* 368 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 369 */ "ccons ::= AS generated", - /* 370 */ "conslist_opt ::= COMMA conslist", - /* 371 */ "conslist ::= conslist tconscomma tcons", - /* 372 */ "conslist ::= tcons", - /* 373 */ "tconscomma ::=", - /* 374 */ "defer_subclause_opt ::= defer_subclause", - /* 375 */ "resolvetype ::= raisetype", - /* 376 */ "selectnowith ::= oneselect", - /* 377 */ "oneselect ::= values", - /* 378 */ "sclp ::= selcollist COMMA", - /* 379 */ "as ::= ID|STRING", - /* 380 */ "indexed_opt ::= indexed_by", - /* 381 */ "returning ::=", - /* 382 */ "expr ::= term", - /* 383 */ "likeop ::= LIKE_KW|MATCH", - /* 384 */ "case_operand ::= expr", - /* 385 */ "exprlist ::= nexprlist", - /* 386 */ "nmnum ::= plus_num", - /* 387 */ "nmnum ::= nm", - /* 388 */ "nmnum ::= ON", - /* 389 */ "nmnum ::= DELETE", - /* 390 */ "nmnum ::= DEFAULT", - /* 391 */ "plus_num ::= INTEGER|FLOAT", - /* 392 */ "foreach_clause ::=", - /* 393 */ "foreach_clause ::= FOR EACH ROW", - /* 394 */ "trnm ::= nm", - /* 395 */ "tridxby ::=", - /* 396 */ "database_kw_opt ::= DATABASE", - /* 397 */ "database_kw_opt ::=", - /* 398 */ "kwcolumn_opt ::=", - /* 399 */ "kwcolumn_opt ::= COLUMNKW", - /* 400 */ "vtabarglist ::= vtabarg", - /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 402 */ "vtabarg ::= vtabarg vtabargtoken", - /* 403 */ "anylist ::=", - /* 404 */ "anylist ::= anylist LP anylist RP", - /* 405 */ "anylist ::= anylist ANY", - /* 406 */ "with ::=", - /* 407 */ "windowdefn_list ::= windowdefn", - /* 408 */ "window ::= frame_opt", + /* 8 */ "transtype ::= CONCURRENT", + /* 9 */ "cmd ::= COMMIT|END trans_opt", + /* 10 */ "cmd ::= ROLLBACK trans_opt", + /* 11 */ "cmd ::= SAVEPOINT nm", + /* 12 */ "cmd ::= RELEASE savepoint_opt nm", + /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 15 */ "createkw ::= CREATE", + /* 16 */ "ifnotexists ::=", + /* 17 */ "ifnotexists ::= IF NOT EXISTS", + /* 18 */ "temp ::= TEMP", + /* 19 */ "temp ::=", + /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", + /* 21 */ "create_table_args ::= AS select", + /* 22 */ "table_option_set ::=", + /* 23 */ "table_option_set ::= table_option_set COMMA table_option", + /* 24 */ "table_option ::= WITHOUT nm", + /* 25 */ "table_option ::= nm", + /* 26 */ "columnname ::= nm typetoken", + /* 27 */ "typetoken ::=", + /* 28 */ "typetoken ::= typename LP signed RP", + /* 29 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 30 */ "typename ::= typename ID|STRING", + /* 31 */ "scanpt ::=", + /* 32 */ "scantok ::=", + /* 33 */ "ccons ::= CONSTRAINT nm", + /* 34 */ "ccons ::= DEFAULT scantok term", + /* 35 */ "ccons ::= DEFAULT LP expr RP", + /* 36 */ "ccons ::= DEFAULT PLUS scantok term", + /* 37 */ "ccons ::= DEFAULT MINUS scantok term", + /* 38 */ "ccons ::= DEFAULT scantok ID|INDEXED", + /* 39 */ "ccons ::= NOT NULL onconf", + /* 40 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 41 */ "ccons ::= UNIQUE onconf", + /* 42 */ "ccons ::= CHECK LP expr RP", + /* 43 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 44 */ "ccons ::= defer_subclause", + /* 45 */ "ccons ::= COLLATE ID|STRING", + /* 46 */ "generated ::= LP expr RP", + /* 47 */ "generated ::= LP expr RP ID", + /* 48 */ "autoinc ::=", + /* 49 */ "autoinc ::= AUTOINCR", + /* 50 */ "refargs ::=", + /* 51 */ "refargs ::= refargs refarg", + /* 52 */ "refarg ::= MATCH nm", + /* 53 */ "refarg ::= ON INSERT refact", + /* 54 */ "refarg ::= ON DELETE refact", + /* 55 */ "refarg ::= ON UPDATE refact", + /* 56 */ "refact ::= SET NULL", + /* 57 */ "refact ::= SET DEFAULT", + /* 58 */ "refact ::= CASCADE", + /* 59 */ "refact ::= RESTRICT", + /* 60 */ "refact ::= NO ACTION", + /* 61 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 62 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 63 */ "init_deferred_pred_opt ::=", + /* 64 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 65 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 66 */ "conslist_opt ::=", + /* 67 */ "tconscomma ::= COMMA", + /* 68 */ "tcons ::= CONSTRAINT nm", + /* 69 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 70 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 71 */ "tcons ::= CHECK LP expr RP onconf", + /* 72 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 73 */ "defer_subclause_opt ::=", + /* 74 */ "onconf ::=", + /* 75 */ "onconf ::= ON CONFLICT resolvetype", + /* 76 */ "orconf ::=", + /* 77 */ "orconf ::= OR resolvetype", + /* 78 */ "resolvetype ::= IGNORE", + /* 79 */ "resolvetype ::= REPLACE", + /* 80 */ "cmd ::= DROP TABLE ifexists fullname", + /* 81 */ "ifexists ::= IF EXISTS", + /* 82 */ "ifexists ::=", + /* 83 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 84 */ "cmd ::= DROP VIEW ifexists fullname", + /* 85 */ "cmd ::= select", + /* 86 */ "select ::= WITH wqlist selectnowith", + /* 87 */ "select ::= WITH RECURSIVE wqlist selectnowith", + /* 88 */ "select ::= selectnowith", + /* 89 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 90 */ "multiselect_op ::= UNION", + /* 91 */ "multiselect_op ::= UNION ALL", + /* 92 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 94 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 95 */ "values ::= VALUES LP nexprlist RP", + /* 96 */ "oneselect ::= mvalues", + /* 97 */ "mvalues ::= values COMMA LP nexprlist RP", + /* 98 */ "mvalues ::= mvalues COMMA LP nexprlist RP", + /* 99 */ "distinct ::= DISTINCT", + /* 100 */ "distinct ::= ALL", + /* 101 */ "distinct ::=", + /* 102 */ "sclp ::=", + /* 103 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 104 */ "selcollist ::= sclp scanpt STAR", + /* 105 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 106 */ "as ::= AS nm", + /* 107 */ "as ::=", + /* 108 */ "from ::=", + /* 109 */ "from ::= FROM seltablist", + /* 110 */ "stl_prefix ::= seltablist joinop", + /* 111 */ "stl_prefix ::=", + /* 112 */ "seltablist ::= stl_prefix nm dbnm as on_using", + /* 113 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", + /* 114 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", + /* 115 */ "seltablist ::= stl_prefix LP select RP as on_using", + /* 116 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", + /* 117 */ "dbnm ::=", + /* 118 */ "dbnm ::= DOT nm", + /* 119 */ "fullname ::= nm", + /* 120 */ "fullname ::= nm DOT nm", + /* 121 */ "xfullname ::= nm", + /* 122 */ "xfullname ::= nm DOT nm", + /* 123 */ "xfullname ::= nm DOT nm AS nm", + /* 124 */ "xfullname ::= nm AS nm", + /* 125 */ "joinop ::= COMMA|JOIN", + /* 126 */ "joinop ::= JOIN_KW JOIN", + /* 127 */ "joinop ::= JOIN_KW nm JOIN", + /* 128 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 129 */ "on_using ::= ON expr", + /* 130 */ "on_using ::= USING LP idlist RP", + /* 131 */ "on_using ::=", + /* 132 */ "indexed_opt ::=", + /* 133 */ "indexed_by ::= INDEXED BY nm", + /* 134 */ "indexed_by ::= NOT INDEXED", + /* 135 */ "orderby_opt ::=", + /* 136 */ "orderby_opt ::= ORDER BY sortlist", + /* 137 */ "sortlist ::= sortlist COMMA expr sortorder nulls", + /* 138 */ "sortlist ::= expr sortorder nulls", + /* 139 */ "sortorder ::= ASC", + /* 140 */ "sortorder ::= DESC", + /* 141 */ "sortorder ::=", + /* 142 */ "nulls ::= NULLS FIRST", + /* 143 */ "nulls ::= NULLS LAST", + /* 144 */ "nulls ::=", + /* 145 */ "groupby_opt ::=", + /* 146 */ "groupby_opt ::= GROUP BY nexprlist", + /* 147 */ "having_opt ::=", + /* 148 */ "having_opt ::= HAVING expr", + /* 149 */ "limit_opt ::=", + /* 150 */ "limit_opt ::= LIMIT expr", + /* 151 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 152 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 153 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt", + /* 154 */ "where_opt ::=", + /* 155 */ "where_opt ::= WHERE expr", + /* 156 */ "where_opt_ret ::=", + /* 157 */ "where_opt_ret ::= WHERE expr", + /* 158 */ "where_opt_ret ::= RETURNING selcollist", + /* 159 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", + /* 160 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt", + /* 161 */ "setlist ::= setlist COMMA nm EQ expr", + /* 162 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 163 */ "setlist ::= nm EQ expr", + /* 164 */ "setlist ::= LP idlist RP EQ expr", + /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 166 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", + /* 167 */ "upsert ::=", + /* 168 */ "upsert ::= RETURNING selcollist", + /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", + /* 170 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", + /* 171 */ "upsert ::= ON CONFLICT DO NOTHING returning", + /* 172 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", + /* 173 */ "returning ::= RETURNING selcollist", + /* 174 */ "insert_cmd ::= INSERT orconf", + /* 175 */ "insert_cmd ::= REPLACE", + /* 176 */ "idlist_opt ::=", + /* 177 */ "idlist_opt ::= LP idlist RP", + /* 178 */ "idlist ::= idlist COMMA nm", + /* 179 */ "idlist ::= nm", + /* 180 */ "expr ::= LP expr RP", + /* 181 */ "expr ::= ID|INDEXED|JOIN_KW", + /* 182 */ "expr ::= nm DOT nm", + /* 183 */ "expr ::= nm DOT nm DOT nm", + /* 184 */ "term ::= NULL|FLOAT|BLOB", + /* 185 */ "term ::= STRING", + /* 186 */ "term ::= INTEGER", + /* 187 */ "expr ::= VARIABLE", + /* 188 */ "expr ::= expr COLLATE ID|STRING", + /* 189 */ "expr ::= CAST LP expr AS typetoken RP", + /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", + /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", + /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", + /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", + /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", + /* 195 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", + /* 196 */ "term ::= CTIME_KW", + /* 197 */ "expr ::= LP nexprlist COMMA expr RP", + /* 198 */ "expr ::= expr AND expr", + /* 199 */ "expr ::= expr OR expr", + /* 200 */ "expr ::= expr LT|GT|GE|LE expr", + /* 201 */ "expr ::= expr EQ|NE expr", + /* 202 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 203 */ "expr ::= expr PLUS|MINUS expr", + /* 204 */ "expr ::= expr STAR|SLASH|REM expr", + /* 205 */ "expr ::= expr CONCAT expr", + /* 206 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 207 */ "expr ::= expr likeop expr", + /* 208 */ "expr ::= expr likeop expr ESCAPE expr", + /* 209 */ "expr ::= expr ISNULL|NOTNULL", + /* 210 */ "expr ::= expr NOT NULL", + /* 211 */ "expr ::= expr IS expr", + /* 212 */ "expr ::= expr IS NOT expr", + /* 213 */ "expr ::= expr IS NOT DISTINCT FROM expr", + /* 214 */ "expr ::= expr IS DISTINCT FROM expr", + /* 215 */ "expr ::= NOT expr", + /* 216 */ "expr ::= BITNOT expr", + /* 217 */ "expr ::= PLUS|MINUS expr", + /* 218 */ "expr ::= expr PTR expr", + /* 219 */ "between_op ::= BETWEEN", + /* 220 */ "between_op ::= NOT BETWEEN", + /* 221 */ "expr ::= expr between_op expr AND expr", + /* 222 */ "in_op ::= IN", + /* 223 */ "in_op ::= NOT IN", + /* 224 */ "expr ::= expr in_op LP exprlist RP", + /* 225 */ "expr ::= LP select RP", + /* 226 */ "expr ::= expr in_op LP select RP", + /* 227 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 228 */ "expr ::= EXISTS LP select RP", + /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 231 */ "case_exprlist ::= WHEN expr THEN expr", + /* 232 */ "case_else ::= ELSE expr", + /* 233 */ "case_else ::=", + /* 234 */ "case_operand ::=", + /* 235 */ "exprlist ::=", + /* 236 */ "nexprlist ::= nexprlist COMMA expr", + /* 237 */ "nexprlist ::= expr", + /* 238 */ "paren_exprlist ::=", + /* 239 */ "paren_exprlist ::= LP exprlist RP", + /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 241 */ "uniqueflag ::= UNIQUE", + /* 242 */ "uniqueflag ::=", + /* 243 */ "eidlist_opt ::=", + /* 244 */ "eidlist_opt ::= LP eidlist RP", + /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 246 */ "eidlist ::= nm collate sortorder", + /* 247 */ "collate ::=", + /* 248 */ "collate ::= COLLATE ID|STRING", + /* 249 */ "cmd ::= DROP INDEX ifexists fullname", + /* 250 */ "cmd ::= VACUUM vinto", + /* 251 */ "cmd ::= VACUUM nm vinto", + /* 252 */ "vinto ::= INTO expr", + /* 253 */ "vinto ::=", + /* 254 */ "cmd ::= PRAGMA nm dbnm", + /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 256 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 257 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 258 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 259 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 260 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 261 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 262 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 263 */ "trigger_time ::= BEFORE|AFTER", + /* 264 */ "trigger_time ::= INSTEAD OF", + /* 265 */ "trigger_time ::=", + /* 266 */ "trigger_event ::= DELETE|INSERT", + /* 267 */ "trigger_event ::= UPDATE", + /* 268 */ "trigger_event ::= UPDATE OF idlist", + /* 269 */ "when_clause ::=", + /* 270 */ "when_clause ::= WHEN expr", + /* 271 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 272 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 273 */ "trnm ::= nm DOT nm", + /* 274 */ "tridxby ::= INDEXED BY nm", + /* 275 */ "tridxby ::= NOT INDEXED", + /* 276 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", + /* 277 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 278 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 279 */ "trigger_cmd ::= scanpt select scanpt", + /* 280 */ "expr ::= RAISE LP IGNORE RP", + /* 281 */ "expr ::= RAISE LP raisetype COMMA expr RP", + /* 282 */ "raisetype ::= ROLLBACK", + /* 283 */ "raisetype ::= ABORT", + /* 284 */ "raisetype ::= FAIL", + /* 285 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 286 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 287 */ "cmd ::= DETACH database_kw_opt expr", + /* 288 */ "key_opt ::=", + /* 289 */ "key_opt ::= KEY expr", + /* 290 */ "cmd ::= REINDEX", + /* 291 */ "cmd ::= REINDEX nm dbnm", + /* 292 */ "cmd ::= ANALYZE", + /* 293 */ "cmd ::= ANALYZE nm dbnm", + /* 294 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 295 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 296 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", + /* 297 */ "add_column_fullname ::= fullname", + /* 298 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 299 */ "cmd ::= create_vtab", + /* 300 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 301 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 302 */ "vtabarg ::=", + /* 303 */ "vtabargtoken ::= ANY", + /* 304 */ "vtabargtoken ::= lp anylist RP", + /* 305 */ "lp ::= LP", + /* 306 */ "with ::= WITH wqlist", + /* 307 */ "with ::= WITH RECURSIVE wqlist", + /* 308 */ "wqas ::= AS", + /* 309 */ "wqas ::= AS MATERIALIZED", + /* 310 */ "wqas ::= AS NOT MATERIALIZED", + /* 311 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", + /* 312 */ "withnm ::= nm", + /* 313 */ "wqlist ::= wqitem", + /* 314 */ "wqlist ::= wqlist COMMA wqitem", + /* 315 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 316 */ "windowdefn ::= nm AS LP window RP", + /* 317 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 318 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 319 */ "window ::= ORDER BY sortlist frame_opt", + /* 320 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 321 */ "window ::= nm frame_opt", + /* 322 */ "frame_opt ::=", + /* 323 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 324 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 325 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 326 */ "frame_bound_s ::= frame_bound", + /* 327 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 328 */ "frame_bound_e ::= frame_bound", + /* 329 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 330 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 331 */ "frame_bound ::= CURRENT ROW", + /* 332 */ "frame_exclude_opt ::=", + /* 333 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 334 */ "frame_exclude ::= NO OTHERS", + /* 335 */ "frame_exclude ::= CURRENT ROW", + /* 336 */ "frame_exclude ::= GROUP|TIES", + /* 337 */ "window_clause ::= WINDOW windowdefn_list", + /* 338 */ "filter_over ::= filter_clause over_clause", + /* 339 */ "filter_over ::= over_clause", + /* 340 */ "filter_over ::= filter_clause", + /* 341 */ "over_clause ::= OVER LP window RP", + /* 342 */ "over_clause ::= OVER nm", + /* 343 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 344 */ "term ::= QNUMBER", + /* 345 */ "input ::= cmdlist", + /* 346 */ "cmdlist ::= cmdlist ecmd", + /* 347 */ "cmdlist ::= ecmd", + /* 348 */ "ecmd ::= SEMI", + /* 349 */ "ecmd ::= cmdx SEMI", + /* 350 */ "ecmd ::= explain cmdx SEMI", + /* 351 */ "trans_opt ::=", + /* 352 */ "trans_opt ::= TRANSACTION", + /* 353 */ "trans_opt ::= TRANSACTION nm", + /* 354 */ "savepoint_opt ::= SAVEPOINT", + /* 355 */ "savepoint_opt ::=", + /* 356 */ "cmd ::= create_table create_table_args", + /* 357 */ "table_option_set ::= table_option", + /* 358 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 359 */ "columnlist ::= columnname carglist", + /* 360 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 361 */ "nm ::= STRING", + /* 362 */ "typetoken ::= typename", + /* 363 */ "typename ::= ID|STRING", + /* 364 */ "signed ::= plus_num", + /* 365 */ "signed ::= minus_num", + /* 366 */ "carglist ::= carglist ccons", + /* 367 */ "carglist ::=", + /* 368 */ "ccons ::= NULL onconf", + /* 369 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 370 */ "ccons ::= AS generated", + /* 371 */ "conslist_opt ::= COMMA conslist", + /* 372 */ "conslist ::= conslist tconscomma tcons", + /* 373 */ "conslist ::= tcons", + /* 374 */ "tconscomma ::=", + /* 375 */ "defer_subclause_opt ::= defer_subclause", + /* 376 */ "resolvetype ::= raisetype", + /* 377 */ "selectnowith ::= oneselect", + /* 378 */ "oneselect ::= values", + /* 379 */ "sclp ::= selcollist COMMA", + /* 380 */ "as ::= ID|STRING", + /* 381 */ "indexed_opt ::= indexed_by", + /* 382 */ "returning ::=", + /* 383 */ "expr ::= term", + /* 384 */ "likeop ::= LIKE_KW|MATCH", + /* 385 */ "case_operand ::= expr", + /* 386 */ "exprlist ::= nexprlist", + /* 387 */ "nmnum ::= plus_num", + /* 388 */ "nmnum ::= nm", + /* 389 */ "nmnum ::= ON", + /* 390 */ "nmnum ::= DELETE", + /* 391 */ "nmnum ::= DEFAULT", + /* 392 */ "plus_num ::= INTEGER|FLOAT", + /* 393 */ "foreach_clause ::=", + /* 394 */ "foreach_clause ::= FOR EACH ROW", + /* 395 */ "trnm ::= nm", + /* 396 */ "tridxby ::=", + /* 397 */ "database_kw_opt ::= DATABASE", + /* 398 */ "database_kw_opt ::=", + /* 399 */ "kwcolumn_opt ::=", + /* 400 */ "kwcolumn_opt ::= COLUMNKW", + /* 401 */ "vtabarglist ::= vtabarg", + /* 402 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 403 */ "vtabarg ::= vtabarg vtabargtoken", + /* 404 */ "anylist ::=", + /* 405 */ "anylist ::= anylist LP anylist RP", + /* 406 */ "anylist ::= anylist ANY", + /* 407 */ "with ::=", + /* 408 */ "windowdefn_list ::= windowdefn", + /* 409 */ "window ::= frame_opt", }; #endif /* NDEBUG */ @@ -179390,407 +179459,408 @@ static const YYCODETYPE yyRuleInfoLhs[] = { 193, /* (5) transtype ::= DEFERRED */ 193, /* (6) transtype ::= IMMEDIATE */ 193, /* (7) transtype ::= ID */ - 192, /* (8) cmd ::= COMMIT|END trans_opt */ - 192, /* (9) cmd ::= ROLLBACK trans_opt */ - 192, /* (10) cmd ::= SAVEPOINT nm */ - 192, /* (11) cmd ::= RELEASE savepoint_opt nm */ - 192, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - 197, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - 199, /* (14) createkw ::= CREATE */ - 201, /* (15) ifnotexists ::= */ - 201, /* (16) ifnotexists ::= IF NOT EXISTS */ - 200, /* (17) temp ::= TEMP */ - 200, /* (18) temp ::= */ - 198, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - 198, /* (20) create_table_args ::= AS select */ - 205, /* (21) table_option_set ::= */ - 205, /* (22) table_option_set ::= table_option_set COMMA table_option */ - 207, /* (23) table_option ::= WITHOUT nm */ - 207, /* (24) table_option ::= nm */ - 208, /* (25) columnname ::= nm typetoken */ - 210, /* (26) typetoken ::= */ - 210, /* (27) typetoken ::= typename LP signed RP */ - 210, /* (28) typetoken ::= typename LP signed COMMA signed RP */ - 211, /* (29) typename ::= typename ID|STRING */ - 215, /* (30) scanpt ::= */ - 216, /* (31) scantok ::= */ - 217, /* (32) ccons ::= CONSTRAINT nm */ - 217, /* (33) ccons ::= DEFAULT scantok term */ - 217, /* (34) ccons ::= DEFAULT LP expr RP */ - 217, /* (35) ccons ::= DEFAULT PLUS scantok term */ - 217, /* (36) ccons ::= DEFAULT MINUS scantok term */ - 217, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ - 217, /* (38) ccons ::= NOT NULL onconf */ - 217, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - 217, /* (40) ccons ::= UNIQUE onconf */ - 217, /* (41) ccons ::= CHECK LP expr RP */ - 217, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ - 217, /* (43) ccons ::= defer_subclause */ - 217, /* (44) ccons ::= COLLATE ID|STRING */ - 226, /* (45) generated ::= LP expr RP */ - 226, /* (46) generated ::= LP expr RP ID */ - 222, /* (47) autoinc ::= */ - 222, /* (48) autoinc ::= AUTOINCR */ - 224, /* (49) refargs ::= */ - 224, /* (50) refargs ::= refargs refarg */ - 227, /* (51) refarg ::= MATCH nm */ - 227, /* (52) refarg ::= ON INSERT refact */ - 227, /* (53) refarg ::= ON DELETE refact */ - 227, /* (54) refarg ::= ON UPDATE refact */ - 228, /* (55) refact ::= SET NULL */ - 228, /* (56) refact ::= SET DEFAULT */ - 228, /* (57) refact ::= CASCADE */ - 228, /* (58) refact ::= RESTRICT */ - 228, /* (59) refact ::= NO ACTION */ - 225, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - 225, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 229, /* (62) init_deferred_pred_opt ::= */ - 229, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - 229, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 204, /* (65) conslist_opt ::= */ - 231, /* (66) tconscomma ::= COMMA */ - 232, /* (67) tcons ::= CONSTRAINT nm */ - 232, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - 232, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ - 232, /* (70) tcons ::= CHECK LP expr RP onconf */ - 232, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 235, /* (72) defer_subclause_opt ::= */ - 220, /* (73) onconf ::= */ - 220, /* (74) onconf ::= ON CONFLICT resolvetype */ - 236, /* (75) orconf ::= */ - 236, /* (76) orconf ::= OR resolvetype */ - 237, /* (77) resolvetype ::= IGNORE */ - 237, /* (78) resolvetype ::= REPLACE */ - 192, /* (79) cmd ::= DROP TABLE ifexists fullname */ - 239, /* (80) ifexists ::= IF EXISTS */ - 239, /* (81) ifexists ::= */ - 192, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - 192, /* (83) cmd ::= DROP VIEW ifexists fullname */ - 192, /* (84) cmd ::= select */ - 206, /* (85) select ::= WITH wqlist selectnowith */ - 206, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ - 206, /* (87) select ::= selectnowith */ - 241, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ - 244, /* (89) multiselect_op ::= UNION */ - 244, /* (90) multiselect_op ::= UNION ALL */ - 244, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ - 242, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - 254, /* (94) values ::= VALUES LP nexprlist RP */ - 242, /* (95) oneselect ::= mvalues */ - 256, /* (96) mvalues ::= values COMMA LP nexprlist RP */ - 256, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ - 245, /* (98) distinct ::= DISTINCT */ - 245, /* (99) distinct ::= ALL */ - 245, /* (100) distinct ::= */ - 257, /* (101) sclp ::= */ - 246, /* (102) selcollist ::= sclp scanpt expr scanpt as */ - 246, /* (103) selcollist ::= sclp scanpt STAR */ - 246, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ - 258, /* (105) as ::= AS nm */ - 258, /* (106) as ::= */ - 247, /* (107) from ::= */ - 247, /* (108) from ::= FROM seltablist */ - 260, /* (109) stl_prefix ::= seltablist joinop */ - 260, /* (110) stl_prefix ::= */ - 259, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ - 259, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - 259, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - 259, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ - 259, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 202, /* (116) dbnm ::= */ - 202, /* (117) dbnm ::= DOT nm */ - 240, /* (118) fullname ::= nm */ - 240, /* (119) fullname ::= nm DOT nm */ - 265, /* (120) xfullname ::= nm */ - 265, /* (121) xfullname ::= nm DOT nm */ - 265, /* (122) xfullname ::= nm DOT nm AS nm */ - 265, /* (123) xfullname ::= nm AS nm */ - 261, /* (124) joinop ::= COMMA|JOIN */ - 261, /* (125) joinop ::= JOIN_KW JOIN */ - 261, /* (126) joinop ::= JOIN_KW nm JOIN */ - 261, /* (127) joinop ::= JOIN_KW nm nm JOIN */ - 262, /* (128) on_using ::= ON expr */ - 262, /* (129) on_using ::= USING LP idlist RP */ - 262, /* (130) on_using ::= */ - 267, /* (131) indexed_opt ::= */ - 263, /* (132) indexed_by ::= INDEXED BY nm */ - 263, /* (133) indexed_by ::= NOT INDEXED */ - 251, /* (134) orderby_opt ::= */ - 251, /* (135) orderby_opt ::= ORDER BY sortlist */ - 233, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ - 233, /* (137) sortlist ::= expr sortorder nulls */ - 221, /* (138) sortorder ::= ASC */ - 221, /* (139) sortorder ::= DESC */ - 221, /* (140) sortorder ::= */ - 268, /* (141) nulls ::= NULLS FIRST */ - 268, /* (142) nulls ::= NULLS LAST */ - 268, /* (143) nulls ::= */ - 249, /* (144) groupby_opt ::= */ - 249, /* (145) groupby_opt ::= GROUP BY nexprlist */ - 250, /* (146) having_opt ::= */ - 250, /* (147) having_opt ::= HAVING expr */ - 252, /* (148) limit_opt ::= */ - 252, /* (149) limit_opt ::= LIMIT expr */ - 252, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ - 252, /* (151) limit_opt ::= LIMIT expr COMMA expr */ - 192, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ - 248, /* (153) where_opt ::= */ - 248, /* (154) where_opt ::= WHERE expr */ - 270, /* (155) where_opt_ret ::= */ - 270, /* (156) where_opt_ret ::= WHERE expr */ - 270, /* (157) where_opt_ret ::= RETURNING selcollist */ - 270, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ - 192, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ - 271, /* (160) setlist ::= setlist COMMA nm EQ expr */ - 271, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ - 271, /* (162) setlist ::= nm EQ expr */ - 271, /* (163) setlist ::= LP idlist RP EQ expr */ - 192, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 274, /* (166) upsert ::= */ - 274, /* (167) upsert ::= RETURNING selcollist */ - 274, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - 274, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ - 274, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - 275, /* (172) returning ::= RETURNING selcollist */ - 272, /* (173) insert_cmd ::= INSERT orconf */ - 272, /* (174) insert_cmd ::= REPLACE */ - 273, /* (175) idlist_opt ::= */ - 273, /* (176) idlist_opt ::= LP idlist RP */ - 266, /* (177) idlist ::= idlist COMMA nm */ - 266, /* (178) idlist ::= nm */ - 219, /* (179) expr ::= LP expr RP */ - 219, /* (180) expr ::= ID|INDEXED|JOIN_KW */ - 219, /* (181) expr ::= nm DOT nm */ - 219, /* (182) expr ::= nm DOT nm DOT nm */ - 218, /* (183) term ::= NULL|FLOAT|BLOB */ - 218, /* (184) term ::= STRING */ - 218, /* (185) term ::= INTEGER */ - 219, /* (186) expr ::= VARIABLE */ - 219, /* (187) expr ::= expr COLLATE ID|STRING */ - 219, /* (188) expr ::= CAST LP expr AS typetoken RP */ - 219, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - 218, /* (195) term ::= CTIME_KW */ - 219, /* (196) expr ::= LP nexprlist COMMA expr RP */ - 219, /* (197) expr ::= expr AND expr */ - 219, /* (198) expr ::= expr OR expr */ - 219, /* (199) expr ::= expr LT|GT|GE|LE expr */ - 219, /* (200) expr ::= expr EQ|NE expr */ - 219, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 219, /* (202) expr ::= expr PLUS|MINUS expr */ - 219, /* (203) expr ::= expr STAR|SLASH|REM expr */ - 219, /* (204) expr ::= expr CONCAT expr */ - 277, /* (205) likeop ::= NOT LIKE_KW|MATCH */ - 219, /* (206) expr ::= expr likeop expr */ - 219, /* (207) expr ::= expr likeop expr ESCAPE expr */ - 219, /* (208) expr ::= expr ISNULL|NOTNULL */ - 219, /* (209) expr ::= expr NOT NULL */ - 219, /* (210) expr ::= expr IS expr */ - 219, /* (211) expr ::= expr IS NOT expr */ - 219, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ - 219, /* (213) expr ::= expr IS DISTINCT FROM expr */ - 219, /* (214) expr ::= NOT expr */ - 219, /* (215) expr ::= BITNOT expr */ - 219, /* (216) expr ::= PLUS|MINUS expr */ - 219, /* (217) expr ::= expr PTR expr */ - 278, /* (218) between_op ::= BETWEEN */ - 278, /* (219) between_op ::= NOT BETWEEN */ - 219, /* (220) expr ::= expr between_op expr AND expr */ - 279, /* (221) in_op ::= IN */ - 279, /* (222) in_op ::= NOT IN */ - 219, /* (223) expr ::= expr in_op LP exprlist RP */ - 219, /* (224) expr ::= LP select RP */ - 219, /* (225) expr ::= expr in_op LP select RP */ - 219, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ - 219, /* (227) expr ::= EXISTS LP select RP */ - 219, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ - 282, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 282, /* (230) case_exprlist ::= WHEN expr THEN expr */ - 283, /* (231) case_else ::= ELSE expr */ - 283, /* (232) case_else ::= */ - 281, /* (233) case_operand ::= */ - 264, /* (234) exprlist ::= */ - 255, /* (235) nexprlist ::= nexprlist COMMA expr */ - 255, /* (236) nexprlist ::= expr */ - 280, /* (237) paren_exprlist ::= */ - 280, /* (238) paren_exprlist ::= LP exprlist RP */ - 192, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 284, /* (240) uniqueflag ::= UNIQUE */ - 284, /* (241) uniqueflag ::= */ - 223, /* (242) eidlist_opt ::= */ - 223, /* (243) eidlist_opt ::= LP eidlist RP */ - 234, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ - 234, /* (245) eidlist ::= nm collate sortorder */ - 285, /* (246) collate ::= */ - 285, /* (247) collate ::= COLLATE ID|STRING */ - 192, /* (248) cmd ::= DROP INDEX ifexists fullname */ - 192, /* (249) cmd ::= VACUUM vinto */ - 192, /* (250) cmd ::= VACUUM nm vinto */ - 286, /* (251) vinto ::= INTO expr */ - 286, /* (252) vinto ::= */ - 192, /* (253) cmd ::= PRAGMA nm dbnm */ - 192, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 192, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 192, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 192, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 213, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ - 214, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ - 192, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 288, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 290, /* (262) trigger_time ::= BEFORE|AFTER */ - 290, /* (263) trigger_time ::= INSTEAD OF */ - 290, /* (264) trigger_time ::= */ - 291, /* (265) trigger_event ::= DELETE|INSERT */ - 291, /* (266) trigger_event ::= UPDATE */ - 291, /* (267) trigger_event ::= UPDATE OF idlist */ - 293, /* (268) when_clause ::= */ - 293, /* (269) when_clause ::= WHEN expr */ - 289, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 289, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - 295, /* (272) trnm ::= nm DOT nm */ - 296, /* (273) tridxby ::= INDEXED BY nm */ - 296, /* (274) tridxby ::= NOT INDEXED */ - 294, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 294, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 294, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 294, /* (278) trigger_cmd ::= scanpt select scanpt */ - 219, /* (279) expr ::= RAISE LP IGNORE RP */ - 219, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - 238, /* (281) raisetype ::= ROLLBACK */ - 238, /* (282) raisetype ::= ABORT */ - 238, /* (283) raisetype ::= FAIL */ - 192, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - 192, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 192, /* (286) cmd ::= DETACH database_kw_opt expr */ - 298, /* (287) key_opt ::= */ - 298, /* (288) key_opt ::= KEY expr */ - 192, /* (289) cmd ::= REINDEX */ - 192, /* (290) cmd ::= REINDEX nm dbnm */ - 192, /* (291) cmd ::= ANALYZE */ - 192, /* (292) cmd ::= ANALYZE nm dbnm */ - 192, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 192, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 192, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 299, /* (296) add_column_fullname ::= fullname */ - 192, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 192, /* (298) cmd ::= create_vtab */ - 192, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - 301, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 303, /* (301) vtabarg ::= */ - 304, /* (302) vtabargtoken ::= ANY */ - 304, /* (303) vtabargtoken ::= lp anylist RP */ - 305, /* (304) lp ::= LP */ - 269, /* (305) with ::= WITH wqlist */ - 269, /* (306) with ::= WITH RECURSIVE wqlist */ - 308, /* (307) wqas ::= AS */ - 308, /* (308) wqas ::= AS MATERIALIZED */ - 308, /* (309) wqas ::= AS NOT MATERIALIZED */ - 307, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - 309, /* (311) withnm ::= nm */ - 243, /* (312) wqlist ::= wqitem */ - 243, /* (313) wqlist ::= wqlist COMMA wqitem */ - 310, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 311, /* (315) windowdefn ::= nm AS LP window RP */ - 312, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (318) window ::= ORDER BY sortlist frame_opt */ - 312, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - 312, /* (320) window ::= nm frame_opt */ - 313, /* (321) frame_opt ::= */ - 313, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 313, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 317, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - 319, /* (325) frame_bound_s ::= frame_bound */ - 319, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - 320, /* (327) frame_bound_e ::= frame_bound */ - 320, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 318, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - 318, /* (330) frame_bound ::= CURRENT ROW */ - 321, /* (331) frame_exclude_opt ::= */ - 321, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 322, /* (333) frame_exclude ::= NO OTHERS */ - 322, /* (334) frame_exclude ::= CURRENT ROW */ - 322, /* (335) frame_exclude ::= GROUP|TIES */ - 253, /* (336) window_clause ::= WINDOW windowdefn_list */ - 276, /* (337) filter_over ::= filter_clause over_clause */ - 276, /* (338) filter_over ::= over_clause */ - 276, /* (339) filter_over ::= filter_clause */ - 316, /* (340) over_clause ::= OVER LP window RP */ - 316, /* (341) over_clause ::= OVER nm */ - 315, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - 218, /* (343) term ::= QNUMBER */ - 187, /* (344) input ::= cmdlist */ - 188, /* (345) cmdlist ::= cmdlist ecmd */ - 188, /* (346) cmdlist ::= ecmd */ - 189, /* (347) ecmd ::= SEMI */ - 189, /* (348) ecmd ::= cmdx SEMI */ - 189, /* (349) ecmd ::= explain cmdx SEMI */ - 194, /* (350) trans_opt ::= */ - 194, /* (351) trans_opt ::= TRANSACTION */ - 194, /* (352) trans_opt ::= TRANSACTION nm */ - 196, /* (353) savepoint_opt ::= SAVEPOINT */ - 196, /* (354) savepoint_opt ::= */ - 192, /* (355) cmd ::= create_table create_table_args */ - 205, /* (356) table_option_set ::= table_option */ - 203, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - 203, /* (358) columnlist ::= columnname carglist */ - 195, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - 195, /* (360) nm ::= STRING */ - 210, /* (361) typetoken ::= typename */ - 211, /* (362) typename ::= ID|STRING */ - 212, /* (363) signed ::= plus_num */ - 212, /* (364) signed ::= minus_num */ - 209, /* (365) carglist ::= carglist ccons */ - 209, /* (366) carglist ::= */ - 217, /* (367) ccons ::= NULL onconf */ - 217, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - 217, /* (369) ccons ::= AS generated */ - 204, /* (370) conslist_opt ::= COMMA conslist */ - 230, /* (371) conslist ::= conslist tconscomma tcons */ - 230, /* (372) conslist ::= tcons */ - 231, /* (373) tconscomma ::= */ - 235, /* (374) defer_subclause_opt ::= defer_subclause */ - 237, /* (375) resolvetype ::= raisetype */ - 241, /* (376) selectnowith ::= oneselect */ - 242, /* (377) oneselect ::= values */ - 257, /* (378) sclp ::= selcollist COMMA */ - 258, /* (379) as ::= ID|STRING */ - 267, /* (380) indexed_opt ::= indexed_by */ - 275, /* (381) returning ::= */ - 219, /* (382) expr ::= term */ - 277, /* (383) likeop ::= LIKE_KW|MATCH */ - 281, /* (384) case_operand ::= expr */ - 264, /* (385) exprlist ::= nexprlist */ - 287, /* (386) nmnum ::= plus_num */ - 287, /* (387) nmnum ::= nm */ - 287, /* (388) nmnum ::= ON */ - 287, /* (389) nmnum ::= DELETE */ - 287, /* (390) nmnum ::= DEFAULT */ - 213, /* (391) plus_num ::= INTEGER|FLOAT */ - 292, /* (392) foreach_clause ::= */ - 292, /* (393) foreach_clause ::= FOR EACH ROW */ - 295, /* (394) trnm ::= nm */ - 296, /* (395) tridxby ::= */ - 297, /* (396) database_kw_opt ::= DATABASE */ - 297, /* (397) database_kw_opt ::= */ - 300, /* (398) kwcolumn_opt ::= */ - 300, /* (399) kwcolumn_opt ::= COLUMNKW */ - 302, /* (400) vtabarglist ::= vtabarg */ - 302, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - 303, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 306, /* (403) anylist ::= */ - 306, /* (404) anylist ::= anylist LP anylist RP */ - 306, /* (405) anylist ::= anylist ANY */ - 269, /* (406) with ::= */ - 310, /* (407) windowdefn_list ::= windowdefn */ - 312, /* (408) window ::= frame_opt */ + 193, /* (8) transtype ::= CONCURRENT */ + 192, /* (9) cmd ::= COMMIT|END trans_opt */ + 192, /* (10) cmd ::= ROLLBACK trans_opt */ + 192, /* (11) cmd ::= SAVEPOINT nm */ + 192, /* (12) cmd ::= RELEASE savepoint_opt nm */ + 192, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 197, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 199, /* (15) createkw ::= CREATE */ + 201, /* (16) ifnotexists ::= */ + 201, /* (17) ifnotexists ::= IF NOT EXISTS */ + 200, /* (18) temp ::= TEMP */ + 200, /* (19) temp ::= */ + 198, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + 198, /* (21) create_table_args ::= AS select */ + 205, /* (22) table_option_set ::= */ + 205, /* (23) table_option_set ::= table_option_set COMMA table_option */ + 207, /* (24) table_option ::= WITHOUT nm */ + 207, /* (25) table_option ::= nm */ + 208, /* (26) columnname ::= nm typetoken */ + 210, /* (27) typetoken ::= */ + 210, /* (28) typetoken ::= typename LP signed RP */ + 210, /* (29) typetoken ::= typename LP signed COMMA signed RP */ + 211, /* (30) typename ::= typename ID|STRING */ + 215, /* (31) scanpt ::= */ + 216, /* (32) scantok ::= */ + 217, /* (33) ccons ::= CONSTRAINT nm */ + 217, /* (34) ccons ::= DEFAULT scantok term */ + 217, /* (35) ccons ::= DEFAULT LP expr RP */ + 217, /* (36) ccons ::= DEFAULT PLUS scantok term */ + 217, /* (37) ccons ::= DEFAULT MINUS scantok term */ + 217, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */ + 217, /* (39) ccons ::= NOT NULL onconf */ + 217, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 217, /* (41) ccons ::= UNIQUE onconf */ + 217, /* (42) ccons ::= CHECK LP expr RP */ + 217, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */ + 217, /* (44) ccons ::= defer_subclause */ + 217, /* (45) ccons ::= COLLATE ID|STRING */ + 226, /* (46) generated ::= LP expr RP */ + 226, /* (47) generated ::= LP expr RP ID */ + 222, /* (48) autoinc ::= */ + 222, /* (49) autoinc ::= AUTOINCR */ + 224, /* (50) refargs ::= */ + 224, /* (51) refargs ::= refargs refarg */ + 227, /* (52) refarg ::= MATCH nm */ + 227, /* (53) refarg ::= ON INSERT refact */ + 227, /* (54) refarg ::= ON DELETE refact */ + 227, /* (55) refarg ::= ON UPDATE refact */ + 228, /* (56) refact ::= SET NULL */ + 228, /* (57) refact ::= SET DEFAULT */ + 228, /* (58) refact ::= CASCADE */ + 228, /* (59) refact ::= RESTRICT */ + 228, /* (60) refact ::= NO ACTION */ + 225, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 225, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 229, /* (63) init_deferred_pred_opt ::= */ + 229, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 229, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 204, /* (66) conslist_opt ::= */ + 231, /* (67) tconscomma ::= COMMA */ + 232, /* (68) tcons ::= CONSTRAINT nm */ + 232, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 232, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */ + 232, /* (71) tcons ::= CHECK LP expr RP onconf */ + 232, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 235, /* (73) defer_subclause_opt ::= */ + 220, /* (74) onconf ::= */ + 220, /* (75) onconf ::= ON CONFLICT resolvetype */ + 236, /* (76) orconf ::= */ + 236, /* (77) orconf ::= OR resolvetype */ + 237, /* (78) resolvetype ::= IGNORE */ + 237, /* (79) resolvetype ::= REPLACE */ + 192, /* (80) cmd ::= DROP TABLE ifexists fullname */ + 239, /* (81) ifexists ::= IF EXISTS */ + 239, /* (82) ifexists ::= */ + 192, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 192, /* (84) cmd ::= DROP VIEW ifexists fullname */ + 192, /* (85) cmd ::= select */ + 206, /* (86) select ::= WITH wqlist selectnowith */ + 206, /* (87) select ::= WITH RECURSIVE wqlist selectnowith */ + 206, /* (88) select ::= selectnowith */ + 241, /* (89) selectnowith ::= selectnowith multiselect_op oneselect */ + 244, /* (90) multiselect_op ::= UNION */ + 244, /* (91) multiselect_op ::= UNION ALL */ + 244, /* (92) multiselect_op ::= EXCEPT|INTERSECT */ + 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 242, /* (94) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 254, /* (95) values ::= VALUES LP nexprlist RP */ + 242, /* (96) oneselect ::= mvalues */ + 256, /* (97) mvalues ::= values COMMA LP nexprlist RP */ + 256, /* (98) mvalues ::= mvalues COMMA LP nexprlist RP */ + 245, /* (99) distinct ::= DISTINCT */ + 245, /* (100) distinct ::= ALL */ + 245, /* (101) distinct ::= */ + 257, /* (102) sclp ::= */ + 246, /* (103) selcollist ::= sclp scanpt expr scanpt as */ + 246, /* (104) selcollist ::= sclp scanpt STAR */ + 246, /* (105) selcollist ::= sclp scanpt nm DOT STAR */ + 258, /* (106) as ::= AS nm */ + 258, /* (107) as ::= */ + 247, /* (108) from ::= */ + 247, /* (109) from ::= FROM seltablist */ + 260, /* (110) stl_prefix ::= seltablist joinop */ + 260, /* (111) stl_prefix ::= */ + 259, /* (112) seltablist ::= stl_prefix nm dbnm as on_using */ + 259, /* (113) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + 259, /* (114) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + 259, /* (115) seltablist ::= stl_prefix LP select RP as on_using */ + 259, /* (116) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 202, /* (117) dbnm ::= */ + 202, /* (118) dbnm ::= DOT nm */ + 240, /* (119) fullname ::= nm */ + 240, /* (120) fullname ::= nm DOT nm */ + 265, /* (121) xfullname ::= nm */ + 265, /* (122) xfullname ::= nm DOT nm */ + 265, /* (123) xfullname ::= nm DOT nm AS nm */ + 265, /* (124) xfullname ::= nm AS nm */ + 261, /* (125) joinop ::= COMMA|JOIN */ + 261, /* (126) joinop ::= JOIN_KW JOIN */ + 261, /* (127) joinop ::= JOIN_KW nm JOIN */ + 261, /* (128) joinop ::= JOIN_KW nm nm JOIN */ + 262, /* (129) on_using ::= ON expr */ + 262, /* (130) on_using ::= USING LP idlist RP */ + 262, /* (131) on_using ::= */ + 267, /* (132) indexed_opt ::= */ + 263, /* (133) indexed_by ::= INDEXED BY nm */ + 263, /* (134) indexed_by ::= NOT INDEXED */ + 251, /* (135) orderby_opt ::= */ + 251, /* (136) orderby_opt ::= ORDER BY sortlist */ + 233, /* (137) sortlist ::= sortlist COMMA expr sortorder nulls */ + 233, /* (138) sortlist ::= expr sortorder nulls */ + 221, /* (139) sortorder ::= ASC */ + 221, /* (140) sortorder ::= DESC */ + 221, /* (141) sortorder ::= */ + 268, /* (142) nulls ::= NULLS FIRST */ + 268, /* (143) nulls ::= NULLS LAST */ + 268, /* (144) nulls ::= */ + 249, /* (145) groupby_opt ::= */ + 249, /* (146) groupby_opt ::= GROUP BY nexprlist */ + 250, /* (147) having_opt ::= */ + 250, /* (148) having_opt ::= HAVING expr */ + 252, /* (149) limit_opt ::= */ + 252, /* (150) limit_opt ::= LIMIT expr */ + 252, /* (151) limit_opt ::= LIMIT expr OFFSET expr */ + 252, /* (152) limit_opt ::= LIMIT expr COMMA expr */ + 192, /* (153) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + 248, /* (154) where_opt ::= */ + 248, /* (155) where_opt ::= WHERE expr */ + 270, /* (156) where_opt_ret ::= */ + 270, /* (157) where_opt_ret ::= WHERE expr */ + 270, /* (158) where_opt_ret ::= RETURNING selcollist */ + 270, /* (159) where_opt_ret ::= WHERE expr RETURNING selcollist */ + 192, /* (160) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + 271, /* (161) setlist ::= setlist COMMA nm EQ expr */ + 271, /* (162) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 271, /* (163) setlist ::= nm EQ expr */ + 271, /* (164) setlist ::= LP idlist RP EQ expr */ + 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 192, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 274, /* (167) upsert ::= */ + 274, /* (168) upsert ::= RETURNING selcollist */ + 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + 274, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + 274, /* (171) upsert ::= ON CONFLICT DO NOTHING returning */ + 274, /* (172) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + 275, /* (173) returning ::= RETURNING selcollist */ + 272, /* (174) insert_cmd ::= INSERT orconf */ + 272, /* (175) insert_cmd ::= REPLACE */ + 273, /* (176) idlist_opt ::= */ + 273, /* (177) idlist_opt ::= LP idlist RP */ + 266, /* (178) idlist ::= idlist COMMA nm */ + 266, /* (179) idlist ::= nm */ + 219, /* (180) expr ::= LP expr RP */ + 219, /* (181) expr ::= ID|INDEXED|JOIN_KW */ + 219, /* (182) expr ::= nm DOT nm */ + 219, /* (183) expr ::= nm DOT nm DOT nm */ + 218, /* (184) term ::= NULL|FLOAT|BLOB */ + 218, /* (185) term ::= STRING */ + 218, /* (186) term ::= INTEGER */ + 219, /* (187) expr ::= VARIABLE */ + 219, /* (188) expr ::= expr COLLATE ID|STRING */ + 219, /* (189) expr ::= CAST LP expr AS typetoken RP */ + 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + 219, /* (195) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + 218, /* (196) term ::= CTIME_KW */ + 219, /* (197) expr ::= LP nexprlist COMMA expr RP */ + 219, /* (198) expr ::= expr AND expr */ + 219, /* (199) expr ::= expr OR expr */ + 219, /* (200) expr ::= expr LT|GT|GE|LE expr */ + 219, /* (201) expr ::= expr EQ|NE expr */ + 219, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 219, /* (203) expr ::= expr PLUS|MINUS expr */ + 219, /* (204) expr ::= expr STAR|SLASH|REM expr */ + 219, /* (205) expr ::= expr CONCAT expr */ + 277, /* (206) likeop ::= NOT LIKE_KW|MATCH */ + 219, /* (207) expr ::= expr likeop expr */ + 219, /* (208) expr ::= expr likeop expr ESCAPE expr */ + 219, /* (209) expr ::= expr ISNULL|NOTNULL */ + 219, /* (210) expr ::= expr NOT NULL */ + 219, /* (211) expr ::= expr IS expr */ + 219, /* (212) expr ::= expr IS NOT expr */ + 219, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */ + 219, /* (214) expr ::= expr IS DISTINCT FROM expr */ + 219, /* (215) expr ::= NOT expr */ + 219, /* (216) expr ::= BITNOT expr */ + 219, /* (217) expr ::= PLUS|MINUS expr */ + 219, /* (218) expr ::= expr PTR expr */ + 278, /* (219) between_op ::= BETWEEN */ + 278, /* (220) between_op ::= NOT BETWEEN */ + 219, /* (221) expr ::= expr between_op expr AND expr */ + 279, /* (222) in_op ::= IN */ + 279, /* (223) in_op ::= NOT IN */ + 219, /* (224) expr ::= expr in_op LP exprlist RP */ + 219, /* (225) expr ::= LP select RP */ + 219, /* (226) expr ::= expr in_op LP select RP */ + 219, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */ + 219, /* (228) expr ::= EXISTS LP select RP */ + 219, /* (229) expr ::= CASE case_operand case_exprlist case_else END */ + 282, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 282, /* (231) case_exprlist ::= WHEN expr THEN expr */ + 283, /* (232) case_else ::= ELSE expr */ + 283, /* (233) case_else ::= */ + 281, /* (234) case_operand ::= */ + 264, /* (235) exprlist ::= */ + 255, /* (236) nexprlist ::= nexprlist COMMA expr */ + 255, /* (237) nexprlist ::= expr */ + 280, /* (238) paren_exprlist ::= */ + 280, /* (239) paren_exprlist ::= LP exprlist RP */ + 192, /* (240) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 284, /* (241) uniqueflag ::= UNIQUE */ + 284, /* (242) uniqueflag ::= */ + 223, /* (243) eidlist_opt ::= */ + 223, /* (244) eidlist_opt ::= LP eidlist RP */ + 234, /* (245) eidlist ::= eidlist COMMA nm collate sortorder */ + 234, /* (246) eidlist ::= nm collate sortorder */ + 285, /* (247) collate ::= */ + 285, /* (248) collate ::= COLLATE ID|STRING */ + 192, /* (249) cmd ::= DROP INDEX ifexists fullname */ + 192, /* (250) cmd ::= VACUUM vinto */ + 192, /* (251) cmd ::= VACUUM nm vinto */ + 286, /* (252) vinto ::= INTO expr */ + 286, /* (253) vinto ::= */ + 192, /* (254) cmd ::= PRAGMA nm dbnm */ + 192, /* (255) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 192, /* (256) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 192, /* (257) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 192, /* (258) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 213, /* (259) plus_num ::= PLUS INTEGER|FLOAT */ + 214, /* (260) minus_num ::= MINUS INTEGER|FLOAT */ + 192, /* (261) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 288, /* (262) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 290, /* (263) trigger_time ::= BEFORE|AFTER */ + 290, /* (264) trigger_time ::= INSTEAD OF */ + 290, /* (265) trigger_time ::= */ + 291, /* (266) trigger_event ::= DELETE|INSERT */ + 291, /* (267) trigger_event ::= UPDATE */ + 291, /* (268) trigger_event ::= UPDATE OF idlist */ + 293, /* (269) when_clause ::= */ + 293, /* (270) when_clause ::= WHEN expr */ + 289, /* (271) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 289, /* (272) trigger_cmd_list ::= trigger_cmd SEMI */ + 295, /* (273) trnm ::= nm DOT nm */ + 296, /* (274) tridxby ::= INDEXED BY nm */ + 296, /* (275) tridxby ::= NOT INDEXED */ + 294, /* (276) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + 294, /* (277) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 294, /* (278) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 294, /* (279) trigger_cmd ::= scanpt select scanpt */ + 219, /* (280) expr ::= RAISE LP IGNORE RP */ + 219, /* (281) expr ::= RAISE LP raisetype COMMA expr RP */ + 238, /* (282) raisetype ::= ROLLBACK */ + 238, /* (283) raisetype ::= ABORT */ + 238, /* (284) raisetype ::= FAIL */ + 192, /* (285) cmd ::= DROP TRIGGER ifexists fullname */ + 192, /* (286) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 192, /* (287) cmd ::= DETACH database_kw_opt expr */ + 298, /* (288) key_opt ::= */ + 298, /* (289) key_opt ::= KEY expr */ + 192, /* (290) cmd ::= REINDEX */ + 192, /* (291) cmd ::= REINDEX nm dbnm */ + 192, /* (292) cmd ::= ANALYZE */ + 192, /* (293) cmd ::= ANALYZE nm dbnm */ + 192, /* (294) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 192, /* (295) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 192, /* (296) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 299, /* (297) add_column_fullname ::= fullname */ + 192, /* (298) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 192, /* (299) cmd ::= create_vtab */ + 192, /* (300) cmd ::= create_vtab LP vtabarglist RP */ + 301, /* (301) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 303, /* (302) vtabarg ::= */ + 304, /* (303) vtabargtoken ::= ANY */ + 304, /* (304) vtabargtoken ::= lp anylist RP */ + 305, /* (305) lp ::= LP */ + 269, /* (306) with ::= WITH wqlist */ + 269, /* (307) with ::= WITH RECURSIVE wqlist */ + 308, /* (308) wqas ::= AS */ + 308, /* (309) wqas ::= AS MATERIALIZED */ + 308, /* (310) wqas ::= AS NOT MATERIALIZED */ + 307, /* (311) wqitem ::= withnm eidlist_opt wqas LP select RP */ + 309, /* (312) withnm ::= nm */ + 243, /* (313) wqlist ::= wqitem */ + 243, /* (314) wqlist ::= wqlist COMMA wqitem */ + 310, /* (315) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 311, /* (316) windowdefn ::= nm AS LP window RP */ + 312, /* (317) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 312, /* (318) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 312, /* (319) window ::= ORDER BY sortlist frame_opt */ + 312, /* (320) window ::= nm ORDER BY sortlist frame_opt */ + 312, /* (321) window ::= nm frame_opt */ + 313, /* (322) frame_opt ::= */ + 313, /* (323) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 313, /* (324) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 317, /* (325) range_or_rows ::= RANGE|ROWS|GROUPS */ + 319, /* (326) frame_bound_s ::= frame_bound */ + 319, /* (327) frame_bound_s ::= UNBOUNDED PRECEDING */ + 320, /* (328) frame_bound_e ::= frame_bound */ + 320, /* (329) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 318, /* (330) frame_bound ::= expr PRECEDING|FOLLOWING */ + 318, /* (331) frame_bound ::= CURRENT ROW */ + 321, /* (332) frame_exclude_opt ::= */ + 321, /* (333) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 322, /* (334) frame_exclude ::= NO OTHERS */ + 322, /* (335) frame_exclude ::= CURRENT ROW */ + 322, /* (336) frame_exclude ::= GROUP|TIES */ + 253, /* (337) window_clause ::= WINDOW windowdefn_list */ + 276, /* (338) filter_over ::= filter_clause over_clause */ + 276, /* (339) filter_over ::= over_clause */ + 276, /* (340) filter_over ::= filter_clause */ + 316, /* (341) over_clause ::= OVER LP window RP */ + 316, /* (342) over_clause ::= OVER nm */ + 315, /* (343) filter_clause ::= FILTER LP WHERE expr RP */ + 218, /* (344) term ::= QNUMBER */ + 187, /* (345) input ::= cmdlist */ + 188, /* (346) cmdlist ::= cmdlist ecmd */ + 188, /* (347) cmdlist ::= ecmd */ + 189, /* (348) ecmd ::= SEMI */ + 189, /* (349) ecmd ::= cmdx SEMI */ + 189, /* (350) ecmd ::= explain cmdx SEMI */ + 194, /* (351) trans_opt ::= */ + 194, /* (352) trans_opt ::= TRANSACTION */ + 194, /* (353) trans_opt ::= TRANSACTION nm */ + 196, /* (354) savepoint_opt ::= SAVEPOINT */ + 196, /* (355) savepoint_opt ::= */ + 192, /* (356) cmd ::= create_table create_table_args */ + 205, /* (357) table_option_set ::= table_option */ + 203, /* (358) columnlist ::= columnlist COMMA columnname carglist */ + 203, /* (359) columnlist ::= columnname carglist */ + 195, /* (360) nm ::= ID|INDEXED|JOIN_KW */ + 195, /* (361) nm ::= STRING */ + 210, /* (362) typetoken ::= typename */ + 211, /* (363) typename ::= ID|STRING */ + 212, /* (364) signed ::= plus_num */ + 212, /* (365) signed ::= minus_num */ + 209, /* (366) carglist ::= carglist ccons */ + 209, /* (367) carglist ::= */ + 217, /* (368) ccons ::= NULL onconf */ + 217, /* (369) ccons ::= GENERATED ALWAYS AS generated */ + 217, /* (370) ccons ::= AS generated */ + 204, /* (371) conslist_opt ::= COMMA conslist */ + 230, /* (372) conslist ::= conslist tconscomma tcons */ + 230, /* (373) conslist ::= tcons */ + 231, /* (374) tconscomma ::= */ + 235, /* (375) defer_subclause_opt ::= defer_subclause */ + 237, /* (376) resolvetype ::= raisetype */ + 241, /* (377) selectnowith ::= oneselect */ + 242, /* (378) oneselect ::= values */ + 257, /* (379) sclp ::= selcollist COMMA */ + 258, /* (380) as ::= ID|STRING */ + 267, /* (381) indexed_opt ::= indexed_by */ + 275, /* (382) returning ::= */ + 219, /* (383) expr ::= term */ + 277, /* (384) likeop ::= LIKE_KW|MATCH */ + 281, /* (385) case_operand ::= expr */ + 264, /* (386) exprlist ::= nexprlist */ + 287, /* (387) nmnum ::= plus_num */ + 287, /* (388) nmnum ::= nm */ + 287, /* (389) nmnum ::= ON */ + 287, /* (390) nmnum ::= DELETE */ + 287, /* (391) nmnum ::= DEFAULT */ + 213, /* (392) plus_num ::= INTEGER|FLOAT */ + 292, /* (393) foreach_clause ::= */ + 292, /* (394) foreach_clause ::= FOR EACH ROW */ + 295, /* (395) trnm ::= nm */ + 296, /* (396) tridxby ::= */ + 297, /* (397) database_kw_opt ::= DATABASE */ + 297, /* (398) database_kw_opt ::= */ + 300, /* (399) kwcolumn_opt ::= */ + 300, /* (400) kwcolumn_opt ::= COLUMNKW */ + 302, /* (401) vtabarglist ::= vtabarg */ + 302, /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ + 303, /* (403) vtabarg ::= vtabarg vtabargtoken */ + 306, /* (404) anylist ::= */ + 306, /* (405) anylist ::= anylist LP anylist RP */ + 306, /* (406) anylist ::= anylist ANY */ + 269, /* (407) with ::= */ + 310, /* (408) windowdefn_list ::= windowdefn */ + 312, /* (409) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -179804,407 +179874,408 @@ static const signed char yyRuleInfoNRhs[] = { -1, /* (5) transtype ::= DEFERRED */ -1, /* (6) transtype ::= IMMEDIATE */ -1, /* (7) transtype ::= ID */ - -2, /* (8) cmd ::= COMMIT|END trans_opt */ - -2, /* (9) cmd ::= ROLLBACK trans_opt */ - -2, /* (10) cmd ::= SAVEPOINT nm */ - -3, /* (11) cmd ::= RELEASE savepoint_opt nm */ - -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - -1, /* (14) createkw ::= CREATE */ - 0, /* (15) ifnotexists ::= */ - -3, /* (16) ifnotexists ::= IF NOT EXISTS */ - -1, /* (17) temp ::= TEMP */ - 0, /* (18) temp ::= */ - -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - -2, /* (20) create_table_args ::= AS select */ - 0, /* (21) table_option_set ::= */ - -3, /* (22) table_option_set ::= table_option_set COMMA table_option */ - -2, /* (23) table_option ::= WITHOUT nm */ - -1, /* (24) table_option ::= nm */ - -2, /* (25) columnname ::= nm typetoken */ - 0, /* (26) typetoken ::= */ - -4, /* (27) typetoken ::= typename LP signed RP */ - -6, /* (28) typetoken ::= typename LP signed COMMA signed RP */ - -2, /* (29) typename ::= typename ID|STRING */ - 0, /* (30) scanpt ::= */ - 0, /* (31) scantok ::= */ - -2, /* (32) ccons ::= CONSTRAINT nm */ - -3, /* (33) ccons ::= DEFAULT scantok term */ - -4, /* (34) ccons ::= DEFAULT LP expr RP */ - -4, /* (35) ccons ::= DEFAULT PLUS scantok term */ - -4, /* (36) ccons ::= DEFAULT MINUS scantok term */ - -3, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ - -3, /* (38) ccons ::= NOT NULL onconf */ - -5, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - -2, /* (40) ccons ::= UNIQUE onconf */ - -4, /* (41) ccons ::= CHECK LP expr RP */ - -4, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ - -1, /* (43) ccons ::= defer_subclause */ - -2, /* (44) ccons ::= COLLATE ID|STRING */ - -3, /* (45) generated ::= LP expr RP */ - -4, /* (46) generated ::= LP expr RP ID */ - 0, /* (47) autoinc ::= */ - -1, /* (48) autoinc ::= AUTOINCR */ - 0, /* (49) refargs ::= */ - -2, /* (50) refargs ::= refargs refarg */ - -2, /* (51) refarg ::= MATCH nm */ - -3, /* (52) refarg ::= ON INSERT refact */ - -3, /* (53) refarg ::= ON DELETE refact */ - -3, /* (54) refarg ::= ON UPDATE refact */ - -2, /* (55) refact ::= SET NULL */ - -2, /* (56) refact ::= SET DEFAULT */ - -1, /* (57) refact ::= CASCADE */ - -1, /* (58) refact ::= RESTRICT */ - -2, /* (59) refact ::= NO ACTION */ - -3, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - -2, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 0, /* (62) init_deferred_pred_opt ::= */ - -2, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - -2, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 0, /* (65) conslist_opt ::= */ - -1, /* (66) tconscomma ::= COMMA */ - -2, /* (67) tcons ::= CONSTRAINT nm */ - -7, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - -5, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ - -5, /* (70) tcons ::= CHECK LP expr RP onconf */ - -10, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 0, /* (72) defer_subclause_opt ::= */ - 0, /* (73) onconf ::= */ - -3, /* (74) onconf ::= ON CONFLICT resolvetype */ - 0, /* (75) orconf ::= */ - -2, /* (76) orconf ::= OR resolvetype */ - -1, /* (77) resolvetype ::= IGNORE */ - -1, /* (78) resolvetype ::= REPLACE */ - -4, /* (79) cmd ::= DROP TABLE ifexists fullname */ - -2, /* (80) ifexists ::= IF EXISTS */ - 0, /* (81) ifexists ::= */ - -9, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - -4, /* (83) cmd ::= DROP VIEW ifexists fullname */ - -1, /* (84) cmd ::= select */ - -3, /* (85) select ::= WITH wqlist selectnowith */ - -4, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ - -1, /* (87) select ::= selectnowith */ - -3, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ - -1, /* (89) multiselect_op ::= UNION */ - -2, /* (90) multiselect_op ::= UNION ALL */ - -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ - -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - -4, /* (94) values ::= VALUES LP nexprlist RP */ - -1, /* (95) oneselect ::= mvalues */ - -5, /* (96) mvalues ::= values COMMA LP nexprlist RP */ - -5, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ - -1, /* (98) distinct ::= DISTINCT */ - -1, /* (99) distinct ::= ALL */ - 0, /* (100) distinct ::= */ - 0, /* (101) sclp ::= */ - -5, /* (102) selcollist ::= sclp scanpt expr scanpt as */ - -3, /* (103) selcollist ::= sclp scanpt STAR */ - -5, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ - -2, /* (105) as ::= AS nm */ - 0, /* (106) as ::= */ - 0, /* (107) from ::= */ - -2, /* (108) from ::= FROM seltablist */ - -2, /* (109) stl_prefix ::= seltablist joinop */ - 0, /* (110) stl_prefix ::= */ - -5, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ - -6, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - -8, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - -6, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ - -6, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 0, /* (116) dbnm ::= */ - -2, /* (117) dbnm ::= DOT nm */ - -1, /* (118) fullname ::= nm */ - -3, /* (119) fullname ::= nm DOT nm */ - -1, /* (120) xfullname ::= nm */ - -3, /* (121) xfullname ::= nm DOT nm */ - -5, /* (122) xfullname ::= nm DOT nm AS nm */ - -3, /* (123) xfullname ::= nm AS nm */ - -1, /* (124) joinop ::= COMMA|JOIN */ - -2, /* (125) joinop ::= JOIN_KW JOIN */ - -3, /* (126) joinop ::= JOIN_KW nm JOIN */ - -4, /* (127) joinop ::= JOIN_KW nm nm JOIN */ - -2, /* (128) on_using ::= ON expr */ - -4, /* (129) on_using ::= USING LP idlist RP */ - 0, /* (130) on_using ::= */ - 0, /* (131) indexed_opt ::= */ - -3, /* (132) indexed_by ::= INDEXED BY nm */ - -2, /* (133) indexed_by ::= NOT INDEXED */ - 0, /* (134) orderby_opt ::= */ - -3, /* (135) orderby_opt ::= ORDER BY sortlist */ - -5, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ - -3, /* (137) sortlist ::= expr sortorder nulls */ - -1, /* (138) sortorder ::= ASC */ - -1, /* (139) sortorder ::= DESC */ - 0, /* (140) sortorder ::= */ - -2, /* (141) nulls ::= NULLS FIRST */ - -2, /* (142) nulls ::= NULLS LAST */ - 0, /* (143) nulls ::= */ - 0, /* (144) groupby_opt ::= */ - -3, /* (145) groupby_opt ::= GROUP BY nexprlist */ - 0, /* (146) having_opt ::= */ - -2, /* (147) having_opt ::= HAVING expr */ - 0, /* (148) limit_opt ::= */ - -2, /* (149) limit_opt ::= LIMIT expr */ - -4, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ - -4, /* (151) limit_opt ::= LIMIT expr COMMA expr */ - -8, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ - 0, /* (153) where_opt ::= */ - -2, /* (154) where_opt ::= WHERE expr */ - 0, /* (155) where_opt_ret ::= */ - -2, /* (156) where_opt_ret ::= WHERE expr */ - -2, /* (157) where_opt_ret ::= RETURNING selcollist */ - -4, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ - -11, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ - -5, /* (160) setlist ::= setlist COMMA nm EQ expr */ - -7, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ - -3, /* (162) setlist ::= nm EQ expr */ - -5, /* (163) setlist ::= LP idlist RP EQ expr */ - -7, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - -8, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 0, /* (166) upsert ::= */ - -2, /* (167) upsert ::= RETURNING selcollist */ - -12, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - -9, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - -5, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ - -8, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - -2, /* (172) returning ::= RETURNING selcollist */ - -2, /* (173) insert_cmd ::= INSERT orconf */ - -1, /* (174) insert_cmd ::= REPLACE */ - 0, /* (175) idlist_opt ::= */ - -3, /* (176) idlist_opt ::= LP idlist RP */ - -3, /* (177) idlist ::= idlist COMMA nm */ - -1, /* (178) idlist ::= nm */ - -3, /* (179) expr ::= LP expr RP */ - -1, /* (180) expr ::= ID|INDEXED|JOIN_KW */ - -3, /* (181) expr ::= nm DOT nm */ - -5, /* (182) expr ::= nm DOT nm DOT nm */ - -1, /* (183) term ::= NULL|FLOAT|BLOB */ - -1, /* (184) term ::= STRING */ - -1, /* (185) term ::= INTEGER */ - -1, /* (186) expr ::= VARIABLE */ - -3, /* (187) expr ::= expr COLLATE ID|STRING */ - -6, /* (188) expr ::= CAST LP expr AS typetoken RP */ - -5, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - -8, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - -4, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - -6, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - -9, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - -5, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - -1, /* (195) term ::= CTIME_KW */ - -5, /* (196) expr ::= LP nexprlist COMMA expr RP */ - -3, /* (197) expr ::= expr AND expr */ - -3, /* (198) expr ::= expr OR expr */ - -3, /* (199) expr ::= expr LT|GT|GE|LE expr */ - -3, /* (200) expr ::= expr EQ|NE expr */ - -3, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - -3, /* (202) expr ::= expr PLUS|MINUS expr */ - -3, /* (203) expr ::= expr STAR|SLASH|REM expr */ - -3, /* (204) expr ::= expr CONCAT expr */ - -2, /* (205) likeop ::= NOT LIKE_KW|MATCH */ - -3, /* (206) expr ::= expr likeop expr */ - -5, /* (207) expr ::= expr likeop expr ESCAPE expr */ - -2, /* (208) expr ::= expr ISNULL|NOTNULL */ - -3, /* (209) expr ::= expr NOT NULL */ - -3, /* (210) expr ::= expr IS expr */ - -4, /* (211) expr ::= expr IS NOT expr */ - -6, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ - -5, /* (213) expr ::= expr IS DISTINCT FROM expr */ - -2, /* (214) expr ::= NOT expr */ - -2, /* (215) expr ::= BITNOT expr */ - -2, /* (216) expr ::= PLUS|MINUS expr */ - -3, /* (217) expr ::= expr PTR expr */ - -1, /* (218) between_op ::= BETWEEN */ - -2, /* (219) between_op ::= NOT BETWEEN */ - -5, /* (220) expr ::= expr between_op expr AND expr */ - -1, /* (221) in_op ::= IN */ - -2, /* (222) in_op ::= NOT IN */ - -5, /* (223) expr ::= expr in_op LP exprlist RP */ - -3, /* (224) expr ::= LP select RP */ - -5, /* (225) expr ::= expr in_op LP select RP */ - -5, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ - -4, /* (227) expr ::= EXISTS LP select RP */ - -5, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ - -5, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - -4, /* (230) case_exprlist ::= WHEN expr THEN expr */ - -2, /* (231) case_else ::= ELSE expr */ - 0, /* (232) case_else ::= */ - 0, /* (233) case_operand ::= */ - 0, /* (234) exprlist ::= */ - -3, /* (235) nexprlist ::= nexprlist COMMA expr */ - -1, /* (236) nexprlist ::= expr */ - 0, /* (237) paren_exprlist ::= */ - -3, /* (238) paren_exprlist ::= LP exprlist RP */ - -12, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - -1, /* (240) uniqueflag ::= UNIQUE */ - 0, /* (241) uniqueflag ::= */ - 0, /* (242) eidlist_opt ::= */ - -3, /* (243) eidlist_opt ::= LP eidlist RP */ - -5, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ - -3, /* (245) eidlist ::= nm collate sortorder */ - 0, /* (246) collate ::= */ - -2, /* (247) collate ::= COLLATE ID|STRING */ - -4, /* (248) cmd ::= DROP INDEX ifexists fullname */ - -2, /* (249) cmd ::= VACUUM vinto */ - -3, /* (250) cmd ::= VACUUM nm vinto */ - -2, /* (251) vinto ::= INTO expr */ - 0, /* (252) vinto ::= */ - -3, /* (253) cmd ::= PRAGMA nm dbnm */ - -5, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ - -6, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - -5, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ - -6, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - -2, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ - -2, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ - -5, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - -11, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - -1, /* (262) trigger_time ::= BEFORE|AFTER */ - -2, /* (263) trigger_time ::= INSTEAD OF */ - 0, /* (264) trigger_time ::= */ - -1, /* (265) trigger_event ::= DELETE|INSERT */ - -1, /* (266) trigger_event ::= UPDATE */ - -3, /* (267) trigger_event ::= UPDATE OF idlist */ - 0, /* (268) when_clause ::= */ - -2, /* (269) when_clause ::= WHEN expr */ - -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (272) trnm ::= nm DOT nm */ - -3, /* (273) tridxby ::= INDEXED BY nm */ - -2, /* (274) tridxby ::= NOT INDEXED */ - -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (278) trigger_cmd ::= scanpt select scanpt */ - -4, /* (279) expr ::= RAISE LP IGNORE RP */ - -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - -1, /* (281) raisetype ::= ROLLBACK */ - -1, /* (282) raisetype ::= ABORT */ - -1, /* (283) raisetype ::= FAIL */ - -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (286) cmd ::= DETACH database_kw_opt expr */ - 0, /* (287) key_opt ::= */ - -2, /* (288) key_opt ::= KEY expr */ - -1, /* (289) cmd ::= REINDEX */ - -3, /* (290) cmd ::= REINDEX nm dbnm */ - -1, /* (291) cmd ::= ANALYZE */ - -3, /* (292) cmd ::= ANALYZE nm dbnm */ - -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (296) add_column_fullname ::= fullname */ - -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (298) cmd ::= create_vtab */ - -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (301) vtabarg ::= */ - -1, /* (302) vtabargtoken ::= ANY */ - -3, /* (303) vtabargtoken ::= lp anylist RP */ - -1, /* (304) lp ::= LP */ - -2, /* (305) with ::= WITH wqlist */ - -3, /* (306) with ::= WITH RECURSIVE wqlist */ - -1, /* (307) wqas ::= AS */ - -2, /* (308) wqas ::= AS MATERIALIZED */ - -3, /* (309) wqas ::= AS NOT MATERIALIZED */ - -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - -1, /* (311) withnm ::= nm */ - -1, /* (312) wqlist ::= wqitem */ - -3, /* (313) wqlist ::= wqlist COMMA wqitem */ - -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (315) windowdefn ::= nm AS LP window RP */ - -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (318) window ::= ORDER BY sortlist frame_opt */ - -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (320) window ::= nm frame_opt */ - 0, /* (321) frame_opt ::= */ - -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (325) frame_bound_s ::= frame_bound */ - -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (327) frame_bound_e ::= frame_bound */ - -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (330) frame_bound ::= CURRENT ROW */ - 0, /* (331) frame_exclude_opt ::= */ - -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (333) frame_exclude ::= NO OTHERS */ - -2, /* (334) frame_exclude ::= CURRENT ROW */ - -1, /* (335) frame_exclude ::= GROUP|TIES */ - -2, /* (336) window_clause ::= WINDOW windowdefn_list */ - -2, /* (337) filter_over ::= filter_clause over_clause */ - -1, /* (338) filter_over ::= over_clause */ - -1, /* (339) filter_over ::= filter_clause */ - -4, /* (340) over_clause ::= OVER LP window RP */ - -2, /* (341) over_clause ::= OVER nm */ - -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (343) term ::= QNUMBER */ - -1, /* (344) input ::= cmdlist */ - -2, /* (345) cmdlist ::= cmdlist ecmd */ - -1, /* (346) cmdlist ::= ecmd */ - -1, /* (347) ecmd ::= SEMI */ - -2, /* (348) ecmd ::= cmdx SEMI */ - -3, /* (349) ecmd ::= explain cmdx SEMI */ - 0, /* (350) trans_opt ::= */ - -1, /* (351) trans_opt ::= TRANSACTION */ - -2, /* (352) trans_opt ::= TRANSACTION nm */ - -1, /* (353) savepoint_opt ::= SAVEPOINT */ - 0, /* (354) savepoint_opt ::= */ - -2, /* (355) cmd ::= create_table create_table_args */ - -1, /* (356) table_option_set ::= table_option */ - -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (358) columnlist ::= columnname carglist */ - -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (360) nm ::= STRING */ - -1, /* (361) typetoken ::= typename */ - -1, /* (362) typename ::= ID|STRING */ - -1, /* (363) signed ::= plus_num */ - -1, /* (364) signed ::= minus_num */ - -2, /* (365) carglist ::= carglist ccons */ - 0, /* (366) carglist ::= */ - -2, /* (367) ccons ::= NULL onconf */ - -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (369) ccons ::= AS generated */ - -2, /* (370) conslist_opt ::= COMMA conslist */ - -3, /* (371) conslist ::= conslist tconscomma tcons */ - -1, /* (372) conslist ::= tcons */ - 0, /* (373) tconscomma ::= */ - -1, /* (374) defer_subclause_opt ::= defer_subclause */ - -1, /* (375) resolvetype ::= raisetype */ - -1, /* (376) selectnowith ::= oneselect */ - -1, /* (377) oneselect ::= values */ - -2, /* (378) sclp ::= selcollist COMMA */ - -1, /* (379) as ::= ID|STRING */ - -1, /* (380) indexed_opt ::= indexed_by */ - 0, /* (381) returning ::= */ - -1, /* (382) expr ::= term */ - -1, /* (383) likeop ::= LIKE_KW|MATCH */ - -1, /* (384) case_operand ::= expr */ - -1, /* (385) exprlist ::= nexprlist */ - -1, /* (386) nmnum ::= plus_num */ - -1, /* (387) nmnum ::= nm */ - -1, /* (388) nmnum ::= ON */ - -1, /* (389) nmnum ::= DELETE */ - -1, /* (390) nmnum ::= DEFAULT */ - -1, /* (391) plus_num ::= INTEGER|FLOAT */ - 0, /* (392) foreach_clause ::= */ - -3, /* (393) foreach_clause ::= FOR EACH ROW */ - -1, /* (394) trnm ::= nm */ - 0, /* (395) tridxby ::= */ - -1, /* (396) database_kw_opt ::= DATABASE */ - 0, /* (397) database_kw_opt ::= */ - 0, /* (398) kwcolumn_opt ::= */ - -1, /* (399) kwcolumn_opt ::= COLUMNKW */ - -1, /* (400) vtabarglist ::= vtabarg */ - -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (403) anylist ::= */ - -4, /* (404) anylist ::= anylist LP anylist RP */ - -2, /* (405) anylist ::= anylist ANY */ - 0, /* (406) with ::= */ - -1, /* (407) windowdefn_list ::= windowdefn */ - -1, /* (408) window ::= frame_opt */ + -1, /* (8) transtype ::= CONCURRENT */ + -2, /* (9) cmd ::= COMMIT|END trans_opt */ + -2, /* (10) cmd ::= ROLLBACK trans_opt */ + -2, /* (11) cmd ::= SAVEPOINT nm */ + -3, /* (12) cmd ::= RELEASE savepoint_opt nm */ + -5, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + -6, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + -1, /* (15) createkw ::= CREATE */ + 0, /* (16) ifnotexists ::= */ + -3, /* (17) ifnotexists ::= IF NOT EXISTS */ + -1, /* (18) temp ::= TEMP */ + 0, /* (19) temp ::= */ + -5, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + -2, /* (21) create_table_args ::= AS select */ + 0, /* (22) table_option_set ::= */ + -3, /* (23) table_option_set ::= table_option_set COMMA table_option */ + -2, /* (24) table_option ::= WITHOUT nm */ + -1, /* (25) table_option ::= nm */ + -2, /* (26) columnname ::= nm typetoken */ + 0, /* (27) typetoken ::= */ + -4, /* (28) typetoken ::= typename LP signed RP */ + -6, /* (29) typetoken ::= typename LP signed COMMA signed RP */ + -2, /* (30) typename ::= typename ID|STRING */ + 0, /* (31) scanpt ::= */ + 0, /* (32) scantok ::= */ + -2, /* (33) ccons ::= CONSTRAINT nm */ + -3, /* (34) ccons ::= DEFAULT scantok term */ + -4, /* (35) ccons ::= DEFAULT LP expr RP */ + -4, /* (36) ccons ::= DEFAULT PLUS scantok term */ + -4, /* (37) ccons ::= DEFAULT MINUS scantok term */ + -3, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */ + -3, /* (39) ccons ::= NOT NULL onconf */ + -5, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + -2, /* (41) ccons ::= UNIQUE onconf */ + -4, /* (42) ccons ::= CHECK LP expr RP */ + -4, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */ + -1, /* (44) ccons ::= defer_subclause */ + -2, /* (45) ccons ::= COLLATE ID|STRING */ + -3, /* (46) generated ::= LP expr RP */ + -4, /* (47) generated ::= LP expr RP ID */ + 0, /* (48) autoinc ::= */ + -1, /* (49) autoinc ::= AUTOINCR */ + 0, /* (50) refargs ::= */ + -2, /* (51) refargs ::= refargs refarg */ + -2, /* (52) refarg ::= MATCH nm */ + -3, /* (53) refarg ::= ON INSERT refact */ + -3, /* (54) refarg ::= ON DELETE refact */ + -3, /* (55) refarg ::= ON UPDATE refact */ + -2, /* (56) refact ::= SET NULL */ + -2, /* (57) refact ::= SET DEFAULT */ + -1, /* (58) refact ::= CASCADE */ + -1, /* (59) refact ::= RESTRICT */ + -2, /* (60) refact ::= NO ACTION */ + -3, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + -2, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 0, /* (63) init_deferred_pred_opt ::= */ + -2, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + -2, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 0, /* (66) conslist_opt ::= */ + -1, /* (67) tconscomma ::= COMMA */ + -2, /* (68) tcons ::= CONSTRAINT nm */ + -7, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + -5, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */ + -5, /* (71) tcons ::= CHECK LP expr RP onconf */ + -10, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 0, /* (73) defer_subclause_opt ::= */ + 0, /* (74) onconf ::= */ + -3, /* (75) onconf ::= ON CONFLICT resolvetype */ + 0, /* (76) orconf ::= */ + -2, /* (77) orconf ::= OR resolvetype */ + -1, /* (78) resolvetype ::= IGNORE */ + -1, /* (79) resolvetype ::= REPLACE */ + -4, /* (80) cmd ::= DROP TABLE ifexists fullname */ + -2, /* (81) ifexists ::= IF EXISTS */ + 0, /* (82) ifexists ::= */ + -9, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + -4, /* (84) cmd ::= DROP VIEW ifexists fullname */ + -1, /* (85) cmd ::= select */ + -3, /* (86) select ::= WITH wqlist selectnowith */ + -4, /* (87) select ::= WITH RECURSIVE wqlist selectnowith */ + -1, /* (88) select ::= selectnowith */ + -3, /* (89) selectnowith ::= selectnowith multiselect_op oneselect */ + -1, /* (90) multiselect_op ::= UNION */ + -2, /* (91) multiselect_op ::= UNION ALL */ + -1, /* (92) multiselect_op ::= EXCEPT|INTERSECT */ + -9, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + -10, /* (94) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + -4, /* (95) values ::= VALUES LP nexprlist RP */ + -1, /* (96) oneselect ::= mvalues */ + -5, /* (97) mvalues ::= values COMMA LP nexprlist RP */ + -5, /* (98) mvalues ::= mvalues COMMA LP nexprlist RP */ + -1, /* (99) distinct ::= DISTINCT */ + -1, /* (100) distinct ::= ALL */ + 0, /* (101) distinct ::= */ + 0, /* (102) sclp ::= */ + -5, /* (103) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (104) selcollist ::= sclp scanpt STAR */ + -5, /* (105) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (106) as ::= AS nm */ + 0, /* (107) as ::= */ + 0, /* (108) from ::= */ + -2, /* (109) from ::= FROM seltablist */ + -2, /* (110) stl_prefix ::= seltablist joinop */ + 0, /* (111) stl_prefix ::= */ + -5, /* (112) seltablist ::= stl_prefix nm dbnm as on_using */ + -6, /* (113) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + -8, /* (114) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + -6, /* (115) seltablist ::= stl_prefix LP select RP as on_using */ + -6, /* (116) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 0, /* (117) dbnm ::= */ + -2, /* (118) dbnm ::= DOT nm */ + -1, /* (119) fullname ::= nm */ + -3, /* (120) fullname ::= nm DOT nm */ + -1, /* (121) xfullname ::= nm */ + -3, /* (122) xfullname ::= nm DOT nm */ + -5, /* (123) xfullname ::= nm DOT nm AS nm */ + -3, /* (124) xfullname ::= nm AS nm */ + -1, /* (125) joinop ::= COMMA|JOIN */ + -2, /* (126) joinop ::= JOIN_KW JOIN */ + -3, /* (127) joinop ::= JOIN_KW nm JOIN */ + -4, /* (128) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (129) on_using ::= ON expr */ + -4, /* (130) on_using ::= USING LP idlist RP */ + 0, /* (131) on_using ::= */ + 0, /* (132) indexed_opt ::= */ + -3, /* (133) indexed_by ::= INDEXED BY nm */ + -2, /* (134) indexed_by ::= NOT INDEXED */ + 0, /* (135) orderby_opt ::= */ + -3, /* (136) orderby_opt ::= ORDER BY sortlist */ + -5, /* (137) sortlist ::= sortlist COMMA expr sortorder nulls */ + -3, /* (138) sortlist ::= expr sortorder nulls */ + -1, /* (139) sortorder ::= ASC */ + -1, /* (140) sortorder ::= DESC */ + 0, /* (141) sortorder ::= */ + -2, /* (142) nulls ::= NULLS FIRST */ + -2, /* (143) nulls ::= NULLS LAST */ + 0, /* (144) nulls ::= */ + 0, /* (145) groupby_opt ::= */ + -3, /* (146) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (147) having_opt ::= */ + -2, /* (148) having_opt ::= HAVING expr */ + 0, /* (149) limit_opt ::= */ + -2, /* (150) limit_opt ::= LIMIT expr */ + -4, /* (151) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (152) limit_opt ::= LIMIT expr COMMA expr */ + -8, /* (153) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + 0, /* (154) where_opt ::= */ + -2, /* (155) where_opt ::= WHERE expr */ + 0, /* (156) where_opt_ret ::= */ + -2, /* (157) where_opt_ret ::= WHERE expr */ + -2, /* (158) where_opt_ret ::= RETURNING selcollist */ + -4, /* (159) where_opt_ret ::= WHERE expr RETURNING selcollist */ + -11, /* (160) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + -5, /* (161) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (162) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (163) setlist ::= nm EQ expr */ + -5, /* (164) setlist ::= LP idlist RP EQ expr */ + -7, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -8, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 0, /* (167) upsert ::= */ + -2, /* (168) upsert ::= RETURNING selcollist */ + -12, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + -9, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + -5, /* (171) upsert ::= ON CONFLICT DO NOTHING returning */ + -8, /* (172) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + -2, /* (173) returning ::= RETURNING selcollist */ + -2, /* (174) insert_cmd ::= INSERT orconf */ + -1, /* (175) insert_cmd ::= REPLACE */ + 0, /* (176) idlist_opt ::= */ + -3, /* (177) idlist_opt ::= LP idlist RP */ + -3, /* (178) idlist ::= idlist COMMA nm */ + -1, /* (179) idlist ::= nm */ + -3, /* (180) expr ::= LP expr RP */ + -1, /* (181) expr ::= ID|INDEXED|JOIN_KW */ + -3, /* (182) expr ::= nm DOT nm */ + -5, /* (183) expr ::= nm DOT nm DOT nm */ + -1, /* (184) term ::= NULL|FLOAT|BLOB */ + -1, /* (185) term ::= STRING */ + -1, /* (186) term ::= INTEGER */ + -1, /* (187) expr ::= VARIABLE */ + -3, /* (188) expr ::= expr COLLATE ID|STRING */ + -6, /* (189) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + -8, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + -4, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + -6, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + -9, /* (194) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + -5, /* (195) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + -1, /* (196) term ::= CTIME_KW */ + -5, /* (197) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (198) expr ::= expr AND expr */ + -3, /* (199) expr ::= expr OR expr */ + -3, /* (200) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (201) expr ::= expr EQ|NE expr */ + -3, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (203) expr ::= expr PLUS|MINUS expr */ + -3, /* (204) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (205) expr ::= expr CONCAT expr */ + -2, /* (206) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (207) expr ::= expr likeop expr */ + -5, /* (208) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (209) expr ::= expr ISNULL|NOTNULL */ + -3, /* (210) expr ::= expr NOT NULL */ + -3, /* (211) expr ::= expr IS expr */ + -4, /* (212) expr ::= expr IS NOT expr */ + -6, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */ + -5, /* (214) expr ::= expr IS DISTINCT FROM expr */ + -2, /* (215) expr ::= NOT expr */ + -2, /* (216) expr ::= BITNOT expr */ + -2, /* (217) expr ::= PLUS|MINUS expr */ + -3, /* (218) expr ::= expr PTR expr */ + -1, /* (219) between_op ::= BETWEEN */ + -2, /* (220) between_op ::= NOT BETWEEN */ + -5, /* (221) expr ::= expr between_op expr AND expr */ + -1, /* (222) in_op ::= IN */ + -2, /* (223) in_op ::= NOT IN */ + -5, /* (224) expr ::= expr in_op LP exprlist RP */ + -3, /* (225) expr ::= LP select RP */ + -5, /* (226) expr ::= expr in_op LP select RP */ + -5, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (228) expr ::= EXISTS LP select RP */ + -5, /* (229) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (231) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (232) case_else ::= ELSE expr */ + 0, /* (233) case_else ::= */ + 0, /* (234) case_operand ::= */ + 0, /* (235) exprlist ::= */ + -3, /* (236) nexprlist ::= nexprlist COMMA expr */ + -1, /* (237) nexprlist ::= expr */ + 0, /* (238) paren_exprlist ::= */ + -3, /* (239) paren_exprlist ::= LP exprlist RP */ + -12, /* (240) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (241) uniqueflag ::= UNIQUE */ + 0, /* (242) uniqueflag ::= */ + 0, /* (243) eidlist_opt ::= */ + -3, /* (244) eidlist_opt ::= LP eidlist RP */ + -5, /* (245) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (246) eidlist ::= nm collate sortorder */ + 0, /* (247) collate ::= */ + -2, /* (248) collate ::= COLLATE ID|STRING */ + -4, /* (249) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (250) cmd ::= VACUUM vinto */ + -3, /* (251) cmd ::= VACUUM nm vinto */ + -2, /* (252) vinto ::= INTO expr */ + 0, /* (253) vinto ::= */ + -3, /* (254) cmd ::= PRAGMA nm dbnm */ + -5, /* (255) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (256) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (257) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (258) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (259) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (260) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (261) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (262) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (263) trigger_time ::= BEFORE|AFTER */ + -2, /* (264) trigger_time ::= INSTEAD OF */ + 0, /* (265) trigger_time ::= */ + -1, /* (266) trigger_event ::= DELETE|INSERT */ + -1, /* (267) trigger_event ::= UPDATE */ + -3, /* (268) trigger_event ::= UPDATE OF idlist */ + 0, /* (269) when_clause ::= */ + -2, /* (270) when_clause ::= WHEN expr */ + -3, /* (271) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (272) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (273) trnm ::= nm DOT nm */ + -3, /* (274) tridxby ::= INDEXED BY nm */ + -2, /* (275) tridxby ::= NOT INDEXED */ + -9, /* (276) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + -8, /* (277) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (278) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (279) trigger_cmd ::= scanpt select scanpt */ + -4, /* (280) expr ::= RAISE LP IGNORE RP */ + -6, /* (281) expr ::= RAISE LP raisetype COMMA expr RP */ + -1, /* (282) raisetype ::= ROLLBACK */ + -1, /* (283) raisetype ::= ABORT */ + -1, /* (284) raisetype ::= FAIL */ + -4, /* (285) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (286) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (287) cmd ::= DETACH database_kw_opt expr */ + 0, /* (288) key_opt ::= */ + -2, /* (289) key_opt ::= KEY expr */ + -1, /* (290) cmd ::= REINDEX */ + -3, /* (291) cmd ::= REINDEX nm dbnm */ + -1, /* (292) cmd ::= ANALYZE */ + -3, /* (293) cmd ::= ANALYZE nm dbnm */ + -6, /* (294) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (295) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -6, /* (296) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + -1, /* (297) add_column_fullname ::= fullname */ + -8, /* (298) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (299) cmd ::= create_vtab */ + -4, /* (300) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (301) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (302) vtabarg ::= */ + -1, /* (303) vtabargtoken ::= ANY */ + -3, /* (304) vtabargtoken ::= lp anylist RP */ + -1, /* (305) lp ::= LP */ + -2, /* (306) with ::= WITH wqlist */ + -3, /* (307) with ::= WITH RECURSIVE wqlist */ + -1, /* (308) wqas ::= AS */ + -2, /* (309) wqas ::= AS MATERIALIZED */ + -3, /* (310) wqas ::= AS NOT MATERIALIZED */ + -6, /* (311) wqitem ::= withnm eidlist_opt wqas LP select RP */ + -1, /* (312) withnm ::= nm */ + -1, /* (313) wqlist ::= wqitem */ + -3, /* (314) wqlist ::= wqlist COMMA wqitem */ + -3, /* (315) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (316) windowdefn ::= nm AS LP window RP */ + -5, /* (317) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (318) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (319) window ::= ORDER BY sortlist frame_opt */ + -5, /* (320) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (321) window ::= nm frame_opt */ + 0, /* (322) frame_opt ::= */ + -3, /* (323) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (324) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (325) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (326) frame_bound_s ::= frame_bound */ + -2, /* (327) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (328) frame_bound_e ::= frame_bound */ + -2, /* (329) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (330) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (331) frame_bound ::= CURRENT ROW */ + 0, /* (332) frame_exclude_opt ::= */ + -2, /* (333) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (334) frame_exclude ::= NO OTHERS */ + -2, /* (335) frame_exclude ::= CURRENT ROW */ + -1, /* (336) frame_exclude ::= GROUP|TIES */ + -2, /* (337) window_clause ::= WINDOW windowdefn_list */ + -2, /* (338) filter_over ::= filter_clause over_clause */ + -1, /* (339) filter_over ::= over_clause */ + -1, /* (340) filter_over ::= filter_clause */ + -4, /* (341) over_clause ::= OVER LP window RP */ + -2, /* (342) over_clause ::= OVER nm */ + -5, /* (343) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (344) term ::= QNUMBER */ + -1, /* (345) input ::= cmdlist */ + -2, /* (346) cmdlist ::= cmdlist ecmd */ + -1, /* (347) cmdlist ::= ecmd */ + -1, /* (348) ecmd ::= SEMI */ + -2, /* (349) ecmd ::= cmdx SEMI */ + -3, /* (350) ecmd ::= explain cmdx SEMI */ + 0, /* (351) trans_opt ::= */ + -1, /* (352) trans_opt ::= TRANSACTION */ + -2, /* (353) trans_opt ::= TRANSACTION nm */ + -1, /* (354) savepoint_opt ::= SAVEPOINT */ + 0, /* (355) savepoint_opt ::= */ + -2, /* (356) cmd ::= create_table create_table_args */ + -1, /* (357) table_option_set ::= table_option */ + -4, /* (358) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (359) columnlist ::= columnname carglist */ + -1, /* (360) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (361) nm ::= STRING */ + -1, /* (362) typetoken ::= typename */ + -1, /* (363) typename ::= ID|STRING */ + -1, /* (364) signed ::= plus_num */ + -1, /* (365) signed ::= minus_num */ + -2, /* (366) carglist ::= carglist ccons */ + 0, /* (367) carglist ::= */ + -2, /* (368) ccons ::= NULL onconf */ + -4, /* (369) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (370) ccons ::= AS generated */ + -2, /* (371) conslist_opt ::= COMMA conslist */ + -3, /* (372) conslist ::= conslist tconscomma tcons */ + -1, /* (373) conslist ::= tcons */ + 0, /* (374) tconscomma ::= */ + -1, /* (375) defer_subclause_opt ::= defer_subclause */ + -1, /* (376) resolvetype ::= raisetype */ + -1, /* (377) selectnowith ::= oneselect */ + -1, /* (378) oneselect ::= values */ + -2, /* (379) sclp ::= selcollist COMMA */ + -1, /* (380) as ::= ID|STRING */ + -1, /* (381) indexed_opt ::= indexed_by */ + 0, /* (382) returning ::= */ + -1, /* (383) expr ::= term */ + -1, /* (384) likeop ::= LIKE_KW|MATCH */ + -1, /* (385) case_operand ::= expr */ + -1, /* (386) exprlist ::= nexprlist */ + -1, /* (387) nmnum ::= plus_num */ + -1, /* (388) nmnum ::= nm */ + -1, /* (389) nmnum ::= ON */ + -1, /* (390) nmnum ::= DELETE */ + -1, /* (391) nmnum ::= DEFAULT */ + -1, /* (392) plus_num ::= INTEGER|FLOAT */ + 0, /* (393) foreach_clause ::= */ + -3, /* (394) foreach_clause ::= FOR EACH ROW */ + -1, /* (395) trnm ::= nm */ + 0, /* (396) tridxby ::= */ + -1, /* (397) database_kw_opt ::= DATABASE */ + 0, /* (398) database_kw_opt ::= */ + 0, /* (399) kwcolumn_opt ::= */ + -1, /* (400) kwcolumn_opt ::= COLUMNKW */ + -1, /* (401) vtabarglist ::= vtabarg */ + -3, /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (403) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (404) anylist ::= */ + -4, /* (405) anylist ::= anylist LP anylist RP */ + -2, /* (406) anylist ::= anylist ANY */ + 0, /* (407) with ::= */ + -1, /* (408) windowdefn_list ::= windowdefn */ + -1, /* (409) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -180263,7 +180334,8 @@ static YYACTIONTYPE yy_reduce( break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); - case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); + case 8: /* transtype ::= CONCURRENT */ yytestcase(yyruleno==8); + case 325: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==325); {yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/} break; case 7: /* transtype ::= ID */ @@ -180278,68 +180350,68 @@ static YYACTIONTYPE yy_reduce( } } break; - case 8: /* cmd ::= COMMIT|END trans_opt */ - case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); + case 9: /* cmd ::= COMMIT|END trans_opt */ + case 10: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==10); {sqlite3EndTransaction(pParse,yymsp[-1].major);} break; - case 10: /* cmd ::= SAVEPOINT nm */ + case 11: /* cmd ::= SAVEPOINT nm */ { sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); } break; - case 11: /* cmd ::= RELEASE savepoint_opt nm */ + case 12: /* cmd ::= RELEASE savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); } break; - case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; - case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy502,0,0,yymsp[-2].minor.yy502); } break; - case 14: /* createkw ::= CREATE */ + case 15: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; - case 15: /* ifnotexists ::= */ - case 18: /* temp ::= */ yytestcase(yyruleno==18); - case 47: /* autoinc ::= */ yytestcase(yyruleno==47); - case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62); - case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); - case 81: /* ifexists ::= */ yytestcase(yyruleno==81); - case 100: /* distinct ::= */ yytestcase(yyruleno==100); - case 246: /* collate ::= */ yytestcase(yyruleno==246); + case 16: /* ifnotexists ::= */ + case 19: /* temp ::= */ yytestcase(yyruleno==19); + case 48: /* autoinc ::= */ yytestcase(yyruleno==48); + case 63: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==63); + case 73: /* defer_subclause_opt ::= */ yytestcase(yyruleno==73); + case 82: /* ifexists ::= */ yytestcase(yyruleno==82); + case 101: /* distinct ::= */ yytestcase(yyruleno==101); + case 247: /* collate ::= */ yytestcase(yyruleno==247); {yymsp[1].minor.yy502 = 0;} break; - case 16: /* ifnotexists ::= IF NOT EXISTS */ + case 17: /* ifnotexists ::= IF NOT EXISTS */ {yymsp[-2].minor.yy502 = 1;} break; - case 17: /* temp ::= TEMP */ + case 18: /* temp ::= TEMP */ {yymsp[0].minor.yy502 = pParse->db->init.busy==0;} break; - case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy9,0); } break; - case 20: /* create_table_args ::= AS select */ + case 21: /* create_table_args ::= AS select */ { sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy637); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); } break; - case 21: /* table_option_set ::= */ + case 22: /* table_option_set ::= */ {yymsp[1].minor.yy9 = 0;} break; - case 22: /* table_option_set ::= table_option_set COMMA table_option */ + case 23: /* table_option_set ::= table_option_set COMMA table_option */ {yylhsminor.yy9 = yymsp[-2].minor.yy9|yymsp[0].minor.yy9;} yymsp[-2].minor.yy9 = yylhsminor.yy9; break; - case 23: /* table_option ::= WITHOUT nm */ + case 24: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ yymsp[-1].minor.yy9 = TF_WithoutRowid | TF_NoVisibleRowid; @@ -180349,7 +180421,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 24: /* table_option ::= nm */ + case 25: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ yylhsminor.yy9 = TF_Strict; @@ -180360,59 +180432,59 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy9 = yylhsminor.yy9; break; - case 25: /* columnname ::= nm typetoken */ + case 26: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} break; - case 26: /* typetoken ::= */ - case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); - case 106: /* as ::= */ yytestcase(yyruleno==106); + case 27: /* typetoken ::= */ + case 66: /* conslist_opt ::= */ yytestcase(yyruleno==66); + case 107: /* as ::= */ yytestcase(yyruleno==107); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; - case 27: /* typetoken ::= typename LP signed RP */ + case 28: /* typetoken ::= typename LP signed RP */ { yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); } break; - case 28: /* typetoken ::= typename LP signed COMMA signed RP */ + case 29: /* typetoken ::= typename LP signed COMMA signed RP */ { yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); } break; - case 29: /* typename ::= typename ID|STRING */ + case 30: /* typename ::= typename ID|STRING */ {yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; - case 30: /* scanpt ::= */ + case 31: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy342 = yyLookaheadToken.z; } break; - case 31: /* scantok ::= */ + case 32: /* scantok ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy0 = yyLookaheadToken; } break; - case 32: /* ccons ::= CONSTRAINT nm */ - case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); + case 33: /* ccons ::= CONSTRAINT nm */ + case 68: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==68); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 33: /* ccons ::= DEFAULT scantok term */ + case 34: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 34: /* ccons ::= DEFAULT LP expr RP */ + case 35: /* ccons ::= DEFAULT LP expr RP */ {sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; - case 35: /* ccons ::= DEFAULT PLUS scantok term */ + case 36: /* ccons ::= DEFAULT PLUS scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 36: /* ccons ::= DEFAULT MINUS scantok term */ + case 37: /* ccons ::= DEFAULT MINUS scantok term */ { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy590, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; - case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */ + case 38: /* ccons ::= DEFAULT scantok ID|INDEXED */ { Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); if( p ){ @@ -180422,150 +180494,150 @@ static YYACTIONTYPE yy_reduce( sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; - case 38: /* ccons ::= NOT NULL onconf */ + case 39: /* ccons ::= NOT NULL onconf */ {sqlite3AddNotNull(pParse, yymsp[0].minor.yy502);} break; - case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ + case 40: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy502,yymsp[0].minor.yy502,yymsp[-2].minor.yy502);} break; - case 40: /* ccons ::= UNIQUE onconf */ + case 41: /* ccons ::= UNIQUE onconf */ {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy502,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 41: /* ccons ::= CHECK LP expr RP */ + case 42: /* ccons ::= CHECK LP expr RP */ {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; - case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ + case 43: /* ccons ::= REFERENCES nm eidlist_opt refargs */ {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy402,yymsp[0].minor.yy502);} break; - case 43: /* ccons ::= defer_subclause */ + case 44: /* ccons ::= defer_subclause */ {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy502);} break; - case 44: /* ccons ::= COLLATE ID|STRING */ + case 45: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 45: /* generated ::= LP expr RP */ + case 46: /* generated ::= LP expr RP */ {sqlite3AddGenerated(pParse,yymsp[-1].minor.yy590,0);} break; - case 46: /* generated ::= LP expr RP ID */ + case 47: /* generated ::= LP expr RP ID */ {sqlite3AddGenerated(pParse,yymsp[-2].minor.yy590,&yymsp[0].minor.yy0);} break; - case 48: /* autoinc ::= AUTOINCR */ + case 49: /* autoinc ::= AUTOINCR */ {yymsp[0].minor.yy502 = 1;} break; - case 49: /* refargs ::= */ + case 50: /* refargs ::= */ { yymsp[1].minor.yy502 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 50: /* refargs ::= refargs refarg */ + case 51: /* refargs ::= refargs refarg */ { yymsp[-1].minor.yy502 = (yymsp[-1].minor.yy502 & ~yymsp[0].minor.yy481.mask) | yymsp[0].minor.yy481.value; } break; - case 51: /* refarg ::= MATCH nm */ + case 52: /* refarg ::= MATCH nm */ { yymsp[-1].minor.yy481.value = 0; yymsp[-1].minor.yy481.mask = 0x000000; } break; - case 52: /* refarg ::= ON INSERT refact */ + case 53: /* refarg ::= ON INSERT refact */ { yymsp[-2].minor.yy481.value = 0; yymsp[-2].minor.yy481.mask = 0x000000; } break; - case 53: /* refarg ::= ON DELETE refact */ + case 54: /* refarg ::= ON DELETE refact */ { yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502; yymsp[-2].minor.yy481.mask = 0x0000ff; } break; - case 54: /* refarg ::= ON UPDATE refact */ + case 55: /* refarg ::= ON UPDATE refact */ { yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502<<8; yymsp[-2].minor.yy481.mask = 0x00ff00; } break; - case 55: /* refact ::= SET NULL */ + case 56: /* refact ::= SET NULL */ { yymsp[-1].minor.yy502 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 56: /* refact ::= SET DEFAULT */ + case 57: /* refact ::= SET DEFAULT */ { yymsp[-1].minor.yy502 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 57: /* refact ::= CASCADE */ + case 58: /* refact ::= CASCADE */ { yymsp[0].minor.yy502 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 58: /* refact ::= RESTRICT */ + case 59: /* refact ::= RESTRICT */ { yymsp[0].minor.yy502 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 59: /* refact ::= NO ACTION */ + case 60: /* refact ::= NO ACTION */ { yymsp[-1].minor.yy502 = OE_None; /* EV: R-33326-45252 */} break; - case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + case 61: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ {yymsp[-2].minor.yy502 = 0;} break; - case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); - case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173); + case 62: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 77: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==77); + case 174: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==174); {yymsp[-1].minor.yy502 = yymsp[0].minor.yy502;} break; - case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); - case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219); - case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222); - case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247); + case 64: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 81: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==81); + case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220); + case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223); + case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248); {yymsp[-1].minor.yy502 = 1;} break; - case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + case 65: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ {yymsp[-1].minor.yy502 = 0;} break; - case 66: /* tconscomma ::= COMMA */ + case 67: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + case 69: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);} break; - case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ + case 70: /* tcons ::= UNIQUE LP sortlist RP onconf */ {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy402,yymsp[0].minor.yy502,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 70: /* tcons ::= CHECK LP expr RP onconf */ + case 71: /* tcons ::= CHECK LP expr RP onconf */ {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy590,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; - case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 72: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy402, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[-1].minor.yy502); sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy502); } break; - case 73: /* onconf ::= */ - case 75: /* orconf ::= */ yytestcase(yyruleno==75); + case 74: /* onconf ::= */ + case 76: /* orconf ::= */ yytestcase(yyruleno==76); {yymsp[1].minor.yy502 = OE_Default;} break; - case 74: /* onconf ::= ON CONFLICT resolvetype */ + case 75: /* onconf ::= ON CONFLICT resolvetype */ {yymsp[-2].minor.yy502 = yymsp[0].minor.yy502;} break; - case 77: /* resolvetype ::= IGNORE */ + case 78: /* resolvetype ::= IGNORE */ {yymsp[0].minor.yy502 = OE_Ignore;} break; - case 78: /* resolvetype ::= REPLACE */ - case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174); + case 79: /* resolvetype ::= REPLACE */ + case 175: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==175); {yymsp[0].minor.yy502 = OE_Replace;} break; - case 79: /* cmd ::= DROP TABLE ifexists fullname */ + case 80: /* cmd ::= DROP TABLE ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy563, 0, yymsp[-1].minor.yy502); } break; - case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 83: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[0].minor.yy637, yymsp[-7].minor.yy502, yymsp[-5].minor.yy502); } break; - case 83: /* cmd ::= DROP VIEW ifexists fullname */ + case 84: /* cmd ::= DROP VIEW ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy563, 1, yymsp[-1].minor.yy502); } break; - case 84: /* cmd ::= select */ + case 85: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); } break; - case 85: /* select ::= WITH wqlist selectnowith */ + case 86: /* select ::= WITH wqlist selectnowith */ {yymsp[-2].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} break; - case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ + case 87: /* select ::= WITH RECURSIVE wqlist selectnowith */ {yymsp[-3].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} break; - case 87: /* select ::= selectnowith */ + case 88: /* select ::= selectnowith */ { Select *p = yymsp[0].minor.yy637; if( p ){ @@ -180573,7 +180645,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 89: /* selectnowith ::= selectnowith multiselect_op oneselect */ { Select *pRhs = yymsp[0].minor.yy637; Select *pLhs = yymsp[-2].minor.yy637; @@ -180597,19 +180669,19 @@ static YYACTIONTYPE yy_reduce( yymsp[-2].minor.yy637 = pRhs; } break; - case 89: /* multiselect_op ::= UNION */ - case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); + case 90: /* multiselect_op ::= UNION */ + case 92: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==92); {yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 90: /* multiselect_op ::= UNION ALL */ + case 91: /* multiselect_op ::= UNION ALL */ {yymsp[-1].minor.yy502 = TK_ALL;} break; - case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { yymsp[-8].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy402,yymsp[-5].minor.yy563,yymsp[-4].minor.yy590,yymsp[-3].minor.yy402,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[-7].minor.yy502,yymsp[0].minor.yy590); } break; - case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + case 94: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { yymsp[-9].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy402,yymsp[-6].minor.yy563,yymsp[-5].minor.yy590,yymsp[-4].minor.yy402,yymsp[-3].minor.yy590,yymsp[-1].minor.yy402,yymsp[-8].minor.yy502,yymsp[0].minor.yy590); if( yymsp[-9].minor.yy637 ){ @@ -180619,51 +180691,51 @@ static YYACTIONTYPE yy_reduce( } } break; - case 94: /* values ::= VALUES LP nexprlist RP */ + case 95: /* values ::= VALUES LP nexprlist RP */ { yymsp[-3].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy402,0,0,0,0,0,SF_Values,0); } break; - case 95: /* oneselect ::= mvalues */ + case 96: /* oneselect ::= mvalues */ { sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy637); } break; - case 96: /* mvalues ::= values COMMA LP nexprlist RP */ - case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97); + case 97: /* mvalues ::= values COMMA LP nexprlist RP */ + case 98: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==98); { yymsp[-4].minor.yy637 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy637, yymsp[-1].minor.yy402); } break; - case 98: /* distinct ::= DISTINCT */ + case 99: /* distinct ::= DISTINCT */ {yymsp[0].minor.yy502 = SF_Distinct;} break; - case 99: /* distinct ::= ALL */ + case 100: /* distinct ::= ALL */ {yymsp[0].minor.yy502 = SF_All;} break; - case 101: /* sclp ::= */ - case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134); - case 144: /* groupby_opt ::= */ yytestcase(yyruleno==144); - case 234: /* exprlist ::= */ yytestcase(yyruleno==234); - case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237); - case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242); + case 102: /* sclp ::= */ + case 135: /* orderby_opt ::= */ yytestcase(yyruleno==135); + case 145: /* groupby_opt ::= */ yytestcase(yyruleno==145); + case 235: /* exprlist ::= */ yytestcase(yyruleno==235); + case 238: /* paren_exprlist ::= */ yytestcase(yyruleno==238); + case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243); {yymsp[1].minor.yy402 = 0;} break; - case 102: /* selcollist ::= sclp scanpt expr scanpt as */ + case 103: /* selcollist ::= sclp scanpt expr scanpt as */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[0].minor.yy0, 1); sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy402,yymsp[-3].minor.yy342,yymsp[-1].minor.yy342); } break; - case 103: /* selcollist ::= sclp scanpt STAR */ + case 104: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy402, p); } break; - case 104: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 105: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight, *pLeft, *pDot; pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); @@ -180673,50 +180745,50 @@ static YYACTIONTYPE yy_reduce( yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, pDot); } break; - case 105: /* as ::= AS nm */ - case 117: /* dbnm ::= DOT nm */ yytestcase(yyruleno==117); - case 258: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==258); - case 259: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==259); + case 106: /* as ::= AS nm */ + case 118: /* dbnm ::= DOT nm */ yytestcase(yyruleno==118); + case 259: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==259); + case 260: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==260); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 107: /* from ::= */ - case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110); + case 108: /* from ::= */ + case 111: /* stl_prefix ::= */ yytestcase(yyruleno==111); {yymsp[1].minor.yy563 = 0;} break; - case 108: /* from ::= FROM seltablist */ + case 109: /* from ::= FROM seltablist */ { yymsp[-1].minor.yy563 = yymsp[0].minor.yy563; sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy563); } break; - case 109: /* stl_prefix ::= seltablist joinop */ + case 110: /* stl_prefix ::= seltablist joinop */ { if( ALWAYS(yymsp[-1].minor.yy563 && yymsp[-1].minor.yy563->nSrc>0) ) yymsp[-1].minor.yy563->a[yymsp[-1].minor.yy563->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy502; } break; - case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */ + case 112: /* seltablist ::= stl_prefix nm dbnm as on_using */ { yymsp[-4].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy563,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); } break; - case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + case 113: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ { yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy421); sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-1].minor.yy0); } break; - case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + case 114: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ { yymsp[-7].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy563,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy563, yymsp[-3].minor.yy402); } break; - case 114: /* seltablist ::= stl_prefix LP select RP as on_using */ + case 115: /* seltablist ::= stl_prefix LP select RP as on_using */ { yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy637,&yymsp[0].minor.yy421); } break; - case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ + case 116: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ { if( yymsp[-5].minor.yy563==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy421.pOn==0 && yymsp[0].minor.yy421.pUsing==0 ){ yymsp[-5].minor.yy563 = yymsp[-3].minor.yy563; @@ -180725,21 +180797,11 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-5].minor.yy563 ){ SrcItem *pNew = &yymsp[-5].minor.yy563->a[yymsp[-5].minor.yy563->nSrc-1]; SrcItem *pOld = yymsp[-3].minor.yy563->a; - assert( pOld->fg.fixedSchema==0 ); pNew->zName = pOld->zName; - assert( pOld->fg.fixedSchema==0 ); - if( pOld->fg.isSubquery ){ - pNew->fg.isSubquery = 1; - pNew->u4.pSubq = pOld->u4.pSubq; - pOld->u4.pSubq = 0; - pOld->fg.isSubquery = 0; - assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 ); - if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){ - pNew->fg.isNestedFrom = 1; - } - }else{ - pNew->u4.zDatabase = pOld->u4.zDatabase; - pOld->u4.zDatabase = 0; + pNew->zDatabase = pOld->zDatabase; + pNew->pSelect = pOld->pSelect; + if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ + pNew->fg.isNestedFrom = 1; } if( pOld->fg.isTabFunc ){ pNew->u1.pFuncArg = pOld->u1.pFuncArg; @@ -180747,7 +180809,8 @@ static YYACTIONTYPE yy_reduce( pOld->fg.isTabFunc = 0; pNew->fg.isTabFunc = 1; } - pOld->zName = 0; + pOld->zName = pOld->zDatabase = 0; + pOld->pSelect = 0; } sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy563); }else{ @@ -180758,127 +180821,127 @@ static YYACTIONTYPE yy_reduce( } } break; - case 116: /* dbnm ::= */ - case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131); + case 117: /* dbnm ::= */ + case 132: /* indexed_opt ::= */ yytestcase(yyruleno==132); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 118: /* fullname ::= nm */ + case 119: /* fullname ::= nm */ { yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); } yymsp[0].minor.yy563 = yylhsminor.yy563; break; - case 119: /* fullname ::= nm DOT nm */ + case 120: /* fullname ::= nm DOT nm */ { yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); } yymsp[-2].minor.yy563 = yylhsminor.yy563; break; - case 120: /* xfullname ::= nm */ + case 121: /* xfullname ::= nm */ {yymsp[0].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 121: /* xfullname ::= nm DOT nm */ + case 122: /* xfullname ::= nm DOT nm */ {yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 122: /* xfullname ::= nm DOT nm AS nm */ + case 123: /* xfullname ::= nm DOT nm AS nm */ { yymsp[-4].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ if( yymsp[-4].minor.yy563 ) yymsp[-4].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 123: /* xfullname ::= nm AS nm */ + case 124: /* xfullname ::= nm AS nm */ { yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ if( yymsp[-2].minor.yy563 ) yymsp[-2].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 124: /* joinop ::= COMMA|JOIN */ + case 125: /* joinop ::= COMMA|JOIN */ { yymsp[0].minor.yy502 = JT_INNER; } break; - case 125: /* joinop ::= JOIN_KW JOIN */ + case 126: /* joinop ::= JOIN_KW JOIN */ {yymsp[-1].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 126: /* joinop ::= JOIN_KW nm JOIN */ + case 127: /* joinop ::= JOIN_KW nm JOIN */ {yymsp[-2].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 127: /* joinop ::= JOIN_KW nm nm JOIN */ + case 128: /* joinop ::= JOIN_KW nm nm JOIN */ {yymsp[-3].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 128: /* on_using ::= ON expr */ + case 129: /* on_using ::= ON expr */ {yymsp[-1].minor.yy421.pOn = yymsp[0].minor.yy590; yymsp[-1].minor.yy421.pUsing = 0;} break; - case 129: /* on_using ::= USING LP idlist RP */ + case 130: /* on_using ::= USING LP idlist RP */ {yymsp[-3].minor.yy421.pOn = 0; yymsp[-3].minor.yy421.pUsing = yymsp[-1].minor.yy204;} break; - case 130: /* on_using ::= */ + case 131: /* on_using ::= */ {yymsp[1].minor.yy421.pOn = 0; yymsp[1].minor.yy421.pUsing = 0;} break; - case 132: /* indexed_by ::= INDEXED BY nm */ + case 133: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 133: /* indexed_by ::= NOT INDEXED */ + case 134: /* indexed_by ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 135: /* orderby_opt ::= ORDER BY sortlist */ - case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145); + case 136: /* orderby_opt ::= ORDER BY sortlist */ + case 146: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==146); {yymsp[-2].minor.yy402 = yymsp[0].minor.yy402;} break; - case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */ + case 137: /* sortlist ::= sortlist COMMA expr sortorder nulls */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590); sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); } break; - case 137: /* sortlist ::= expr sortorder nulls */ + case 138: /* sortlist ::= expr sortorder nulls */ { yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy590); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); } break; - case 138: /* sortorder ::= ASC */ + case 139: /* sortorder ::= ASC */ {yymsp[0].minor.yy502 = SQLITE_SO_ASC;} break; - case 139: /* sortorder ::= DESC */ + case 140: /* sortorder ::= DESC */ {yymsp[0].minor.yy502 = SQLITE_SO_DESC;} break; - case 140: /* sortorder ::= */ - case 143: /* nulls ::= */ yytestcase(yyruleno==143); + case 141: /* sortorder ::= */ + case 144: /* nulls ::= */ yytestcase(yyruleno==144); {yymsp[1].minor.yy502 = SQLITE_SO_UNDEFINED;} break; - case 141: /* nulls ::= NULLS FIRST */ + case 142: /* nulls ::= NULLS FIRST */ {yymsp[-1].minor.yy502 = SQLITE_SO_ASC;} break; - case 142: /* nulls ::= NULLS LAST */ + case 143: /* nulls ::= NULLS LAST */ {yymsp[-1].minor.yy502 = SQLITE_SO_DESC;} break; - case 146: /* having_opt ::= */ - case 148: /* limit_opt ::= */ yytestcase(yyruleno==148); - case 153: /* where_opt ::= */ yytestcase(yyruleno==153); - case 155: /* where_opt_ret ::= */ yytestcase(yyruleno==155); - case 232: /* case_else ::= */ yytestcase(yyruleno==232); - case 233: /* case_operand ::= */ yytestcase(yyruleno==233); - case 252: /* vinto ::= */ yytestcase(yyruleno==252); + case 147: /* having_opt ::= */ + case 149: /* limit_opt ::= */ yytestcase(yyruleno==149); + case 154: /* where_opt ::= */ yytestcase(yyruleno==154); + case 156: /* where_opt_ret ::= */ yytestcase(yyruleno==156); + case 233: /* case_else ::= */ yytestcase(yyruleno==233); + case 234: /* case_operand ::= */ yytestcase(yyruleno==234); + case 253: /* vinto ::= */ yytestcase(yyruleno==253); {yymsp[1].minor.yy590 = 0;} break; - case 147: /* having_opt ::= HAVING expr */ - case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154); - case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156); - case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231); - case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251); + case 148: /* having_opt ::= HAVING expr */ + case 155: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==155); + case 157: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==157); + case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232); + case 252: /* vinto ::= INTO expr */ yytestcase(yyruleno==252); {yymsp[-1].minor.yy590 = yymsp[0].minor.yy590;} break; - case 149: /* limit_opt ::= LIMIT expr */ + case 150: /* limit_opt ::= LIMIT expr */ {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,0);} break; - case 150: /* limit_opt ::= LIMIT expr OFFSET expr */ + case 151: /* limit_opt ::= LIMIT expr OFFSET expr */ {yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 151: /* limit_opt ::= LIMIT expr COMMA expr */ + case 152: /* limit_opt ::= LIMIT expr COMMA expr */ {yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,yymsp[-2].minor.yy590);} break; - case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + case 153: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ { sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy563, &yymsp[-3].minor.yy0); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT @@ -180891,13 +180954,13 @@ static YYACTIONTYPE yy_reduce( sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy563,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[0].minor.yy590); } break; - case 157: /* where_opt_ret ::= RETURNING selcollist */ + case 158: /* where_opt_ret ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-1].minor.yy590 = 0;} break; - case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ + case 159: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-3].minor.yy590 = yymsp[-2].minor.yy590;} break; - case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + case 160: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ { sqlite3SrcListIndexedBy(pParse, yymsp[-7].minor.yy563, &yymsp[-6].minor.yy0); if( yymsp[-3].minor.yy563 ){ @@ -180923,79 +180986,79 @@ static YYACTIONTYPE yy_reduce( sqlite3Update(pParse,yymsp[-7].minor.yy563,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590,yymsp[-8].minor.yy502,yymsp[-1].minor.yy402,yymsp[0].minor.yy590,0); } break; - case 160: /* setlist ::= setlist COMMA nm EQ expr */ + case 161: /* setlist ::= setlist COMMA nm EQ expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[0].minor.yy590); sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, 1); } break; - case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 162: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { yymsp[-6].minor.yy402 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy402, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); } break; - case 162: /* setlist ::= nm EQ expr */ + case 163: /* setlist ::= nm EQ expr */ { yylhsminor.yy402 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy590); sqlite3ExprListSetName(pParse, yylhsminor.yy402, &yymsp[-2].minor.yy0, 1); } yymsp[-2].minor.yy402 = yylhsminor.yy402; break; - case 163: /* setlist ::= LP idlist RP EQ expr */ + case 164: /* setlist ::= LP idlist RP EQ expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); } break; - case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { sqlite3Insert(pParse, yymsp[-3].minor.yy563, yymsp[-1].minor.yy637, yymsp[-2].minor.yy204, yymsp[-5].minor.yy502, yymsp[0].minor.yy403); } break; - case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + case 166: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ { sqlite3Insert(pParse, yymsp[-4].minor.yy563, 0, yymsp[-3].minor.yy204, yymsp[-6].minor.yy502, 0); } break; - case 166: /* upsert ::= */ + case 167: /* upsert ::= */ { yymsp[1].minor.yy403 = 0; } break; - case 167: /* upsert ::= RETURNING selcollist */ + case 168: /* upsert ::= RETURNING selcollist */ { yymsp[-1].minor.yy403 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy402); } break; - case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ { yymsp[-11].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy402,yymsp[-6].minor.yy590,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,yymsp[0].minor.yy403);} break; - case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + case 170: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ { yymsp[-8].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy402,yymsp[-3].minor.yy590,0,0,yymsp[0].minor.yy403); } break; - case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */ + case 171: /* upsert ::= ON CONFLICT DO NOTHING returning */ { yymsp[-4].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } break; - case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + case 172: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ { yymsp[-7].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,0);} break; - case 172: /* returning ::= RETURNING selcollist */ + case 173: /* returning ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402);} break; - case 175: /* idlist_opt ::= */ + case 176: /* idlist_opt ::= */ {yymsp[1].minor.yy204 = 0;} break; - case 176: /* idlist_opt ::= LP idlist RP */ + case 177: /* idlist_opt ::= LP idlist RP */ {yymsp[-2].minor.yy204 = yymsp[-1].minor.yy204;} break; - case 177: /* idlist ::= idlist COMMA nm */ + case 178: /* idlist ::= idlist COMMA nm */ {yymsp[-2].minor.yy204 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy204,&yymsp[0].minor.yy0);} break; - case 178: /* idlist ::= nm */ + case 179: /* idlist ::= nm */ {yymsp[0].minor.yy204 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 179: /* expr ::= LP expr RP */ + case 180: /* expr ::= LP expr RP */ {yymsp[-2].minor.yy590 = yymsp[-1].minor.yy590;} break; - case 180: /* expr ::= ID|INDEXED|JOIN_KW */ + case 181: /* expr ::= ID|INDEXED|JOIN_KW */ {yymsp[0].minor.yy590=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 181: /* expr ::= nm DOT nm */ + case 182: /* expr ::= nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); @@ -181003,7 +181066,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy590 = yylhsminor.yy590; break; - case 182: /* expr ::= nm DOT nm DOT nm */ + case 183: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); @@ -181016,18 +181079,18 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 183: /* term ::= NULL|FLOAT|BLOB */ - case 184: /* term ::= STRING */ yytestcase(yyruleno==184); + case 184: /* term ::= NULL|FLOAT|BLOB */ + case 185: /* term ::= STRING */ yytestcase(yyruleno==185); {yymsp[0].minor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 185: /* term ::= INTEGER */ + case 186: /* term ::= INTEGER */ { yylhsminor.yy590 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); if( yylhsminor.yy590 ) yylhsminor.yy590->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); } yymsp[0].minor.yy590 = yylhsminor.yy590; break; - case 186: /* expr ::= VARIABLE */ + case 187: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; @@ -181049,44 +181112,44 @@ static YYACTIONTYPE yy_reduce( } } break; - case 187: /* expr ::= expr COLLATE ID|STRING */ + case 188: /* expr ::= expr COLLATE ID|STRING */ { yymsp[-2].minor.yy590 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy590, &yymsp[0].minor.yy0, 1); } break; - case 188: /* expr ::= CAST LP expr AS typetoken RP */ + case 189: /* expr ::= CAST LP expr AS typetoken RP */ { yymsp[-5].minor.yy590 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy590, yymsp[-3].minor.yy590, 0); } break; - case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy502); } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy402, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy502); sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-1].minor.yy402); } yymsp[-7].minor.yy590 = yylhsminor.yy590; break; - case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } yymsp[-3].minor.yy590 = yylhsminor.yy590; break; - case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy402, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy502); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); } yymsp[-5].minor.yy590 = yylhsminor.yy590; break; - case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + case 194: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy402, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy502); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); @@ -181094,20 +181157,20 @@ static YYACTIONTYPE yy_reduce( } yymsp[-8].minor.yy590 = yylhsminor.yy590; break; - case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + case 195: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 195: /* term ::= CTIME_KW */ + case 196: /* term ::= CTIME_KW */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } yymsp[0].minor.yy590 = yylhsminor.yy590; break; - case 196: /* expr ::= LP nexprlist COMMA expr RP */ + case 197: /* expr ::= LP nexprlist COMMA expr RP */ { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590); yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -181121,22 +181184,22 @@ static YYACTIONTYPE yy_reduce( } } break; - case 197: /* expr ::= expr AND expr */ + case 198: /* expr ::= expr AND expr */ {yymsp[-2].minor.yy590=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 198: /* expr ::= expr OR expr */ - case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199); - case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200); - case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201); - case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202); - case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203); - case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204); + case 199: /* expr ::= expr OR expr */ + case 200: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==200); + case 201: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==201); + case 202: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==202); + case 203: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==203); + case 204: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==204); + case 205: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==205); {yymsp[-2].minor.yy590=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 205: /* likeop ::= NOT LIKE_KW|MATCH */ + case 206: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 206: /* expr ::= expr likeop expr */ + case 207: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; @@ -181148,7 +181211,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-2].minor.yy590 ) yymsp[-2].minor.yy590->flags |= EP_InfixFunc; } break; - case 207: /* expr ::= expr likeop expr ESCAPE expr */ + case 208: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; @@ -181161,41 +181224,41 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-4].minor.yy590 ) yymsp[-4].minor.yy590->flags |= EP_InfixFunc; } break; - case 208: /* expr ::= expr ISNULL|NOTNULL */ + case 209: /* expr ::= expr ISNULL|NOTNULL */ {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy590,0);} break; - case 209: /* expr ::= expr NOT NULL */ + case 210: /* expr ::= expr NOT NULL */ {yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy590,0);} break; - case 210: /* expr ::= expr IS expr */ + case 211: /* expr ::= expr IS expr */ { yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-2].minor.yy590, TK_ISNULL); } break; - case 211: /* expr ::= expr IS NOT expr */ + case 212: /* expr ::= expr IS NOT expr */ { yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-3].minor.yy590, TK_NOTNULL); } break; - case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ + case 213: /* expr ::= expr IS NOT DISTINCT FROM expr */ { yymsp[-5].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-5].minor.yy590, TK_ISNULL); } break; - case 213: /* expr ::= expr IS DISTINCT FROM expr */ + case 214: /* expr ::= expr IS DISTINCT FROM expr */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-4].minor.yy590, TK_NOTNULL); } break; - case 214: /* expr ::= NOT expr */ - case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215); + case 215: /* expr ::= NOT expr */ + case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216); {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy590, 0);/*A-overwrites-B*/} break; - case 216: /* expr ::= PLUS|MINUS expr */ + case 217: /* expr ::= PLUS|MINUS expr */ { Expr *p = yymsp[0].minor.yy590; u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS); @@ -181210,7 +181273,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 217: /* expr ::= expr PTR expr */ + case 218: /* expr ::= expr PTR expr */ { ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy590); pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy590); @@ -181218,11 +181281,11 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy590 = yylhsminor.yy590; break; - case 218: /* between_op ::= BETWEEN */ - case 221: /* in_op ::= IN */ yytestcase(yyruleno==221); + case 219: /* between_op ::= BETWEEN */ + case 222: /* in_op ::= IN */ yytestcase(yyruleno==222); {yymsp[0].minor.yy502 = 0;} break; - case 220: /* expr ::= expr between_op expr AND expr */ + case 221: /* expr ::= expr between_op expr AND expr */ { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590); @@ -181235,7 +181298,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 223: /* expr ::= expr in_op LP exprlist RP */ + case 224: /* expr ::= expr in_op LP exprlist RP */ { if( yymsp[-1].minor.yy402==0 ){ /* Expressions of the form @@ -181281,20 +181344,20 @@ static YYACTIONTYPE yy_reduce( } } break; - case 224: /* expr ::= LP select RP */ + case 225: /* expr ::= LP select RP */ { yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy590, yymsp[-1].minor.yy637); } break; - case 225: /* expr ::= expr in_op LP select RP */ + case 226: /* expr ::= expr in_op LP select RP */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, yymsp[-1].minor.yy637); if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 227: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); @@ -181304,14 +181367,14 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 227: /* expr ::= EXISTS LP select RP */ + case 228: /* expr ::= EXISTS LP select RP */ { Expr *p; p = yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy637); } break; - case 228: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 229: /* expr ::= CASE case_operand case_exprlist case_else END */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy590, 0); if( yymsp[-4].minor.yy590 ){ @@ -181323,29 +181386,29 @@ static YYACTIONTYPE yy_reduce( } } break; - case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[0].minor.yy590); } break; - case 230: /* case_exprlist ::= WHEN expr THEN expr */ + case 231: /* case_exprlist ::= WHEN expr THEN expr */ { yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy402, yymsp[0].minor.yy590); } break; - case 235: /* nexprlist ::= nexprlist COMMA expr */ + case 236: /* nexprlist ::= nexprlist COMMA expr */ {yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[0].minor.yy590);} break; - case 236: /* nexprlist ::= expr */ + case 237: /* nexprlist ::= expr */ {yymsp[0].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy590); /*A-overwrites-Y*/} break; - case 238: /* paren_exprlist ::= LP exprlist RP */ - case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243); + case 239: /* paren_exprlist ::= LP exprlist RP */ + case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244); {yymsp[-2].minor.yy402 = yymsp[-1].minor.yy402;} break; - case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy402, yymsp[-10].minor.yy502, @@ -181355,48 +181418,48 @@ static YYACTIONTYPE yy_reduce( } } break; - case 240: /* uniqueflag ::= UNIQUE */ - case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); + case 241: /* uniqueflag ::= UNIQUE */ + case 283: /* raisetype ::= ABORT */ yytestcase(yyruleno==283); {yymsp[0].minor.yy502 = OE_Abort;} break; - case 241: /* uniqueflag ::= */ + case 242: /* uniqueflag ::= */ {yymsp[1].minor.yy502 = OE_None;} break; - case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */ { yymsp[-4].minor.yy402 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); } break; - case 245: /* eidlist ::= nm collate sortorder */ + case 246: /* eidlist ::= nm collate sortorder */ { yymsp[-2].minor.yy402 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); /*A-overwrites-Y*/ } break; - case 248: /* cmd ::= DROP INDEX ifexists fullname */ + case 249: /* cmd ::= DROP INDEX ifexists fullname */ {sqlite3DropIndex(pParse, yymsp[0].minor.yy563, yymsp[-1].minor.yy502);} break; - case 249: /* cmd ::= VACUUM vinto */ + case 250: /* cmd ::= VACUUM vinto */ {sqlite3Vacuum(pParse,0,yymsp[0].minor.yy590);} break; - case 250: /* cmd ::= VACUUM nm vinto */ + case 251: /* cmd ::= VACUUM nm vinto */ {sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy590);} break; - case 253: /* cmd ::= PRAGMA nm dbnm */ + case 254: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 255: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 256: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 257: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 258: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 260: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 261: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; @@ -181404,50 +181467,50 @@ static YYACTIONTYPE yy_reduce( sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy319, &all); } break; - case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 262: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 262: /* trigger_time ::= BEFORE|AFTER */ + case 263: /* trigger_time ::= BEFORE|AFTER */ { yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 263: /* trigger_time ::= INSTEAD OF */ + case 264: /* trigger_time ::= INSTEAD OF */ { yymsp[-1].minor.yy502 = TK_INSTEAD;} break; - case 264: /* trigger_time ::= */ + case 265: /* trigger_time ::= */ { yymsp[1].minor.yy502 = TK_BEFORE; } break; - case 265: /* trigger_event ::= DELETE|INSERT */ - case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266); + case 266: /* trigger_event ::= DELETE|INSERT */ + case 267: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==267); {yymsp[0].minor.yy28.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy28.b = 0;} break; - case 267: /* trigger_event ::= UPDATE OF idlist */ + case 268: /* trigger_event ::= UPDATE OF idlist */ {yymsp[-2].minor.yy28.a = TK_UPDATE; yymsp[-2].minor.yy28.b = yymsp[0].minor.yy204;} break; - case 268: /* when_clause ::= */ - case 287: /* key_opt ::= */ yytestcase(yyruleno==287); + case 269: /* when_clause ::= */ + case 288: /* key_opt ::= */ yytestcase(yyruleno==288); { yymsp[1].minor.yy590 = 0; } break; - case 269: /* when_clause ::= WHEN expr */ - case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); + case 270: /* when_clause ::= WHEN expr */ + case 289: /* key_opt ::= KEY expr */ yytestcase(yyruleno==289); { yymsp[-1].minor.yy590 = yymsp[0].minor.yy590; } break; - case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 271: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { assert( yymsp[-2].minor.yy319!=0 ); yymsp[-2].minor.yy319->pLast->pNext = yymsp[-1].minor.yy319; yymsp[-2].minor.yy319->pLast = yymsp[-1].minor.yy319; } break; - case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 272: /* trigger_cmd_list ::= trigger_cmd SEMI */ { assert( yymsp[-1].minor.yy319!=0 ); yymsp[-1].minor.yy319->pLast = yymsp[-1].minor.yy319; } break; - case 272: /* trnm ::= nm DOT nm */ + case 273: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -181455,39 +181518,39 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 273: /* tridxby ::= INDEXED BY nm */ + case 274: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 274: /* tridxby ::= NOT INDEXED */ + case 275: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + case 276: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ {yylhsminor.yy319 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy563, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590, yymsp[-7].minor.yy502, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy342);} yymsp[-8].minor.yy319 = yylhsminor.yy319; break; - case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 277: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { yylhsminor.yy319 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy204,yymsp[-2].minor.yy637,yymsp[-6].minor.yy502,yymsp[-1].minor.yy403,yymsp[-7].minor.yy342,yymsp[0].minor.yy342);/*yylhsminor.yy319-overwrites-yymsp[-6].minor.yy502*/ } yymsp[-7].minor.yy319 = yylhsminor.yy319; break; - case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + case 278: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ {yylhsminor.yy319 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy590, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy342);} yymsp[-5].minor.yy319 = yylhsminor.yy319; break; - case 278: /* trigger_cmd ::= scanpt select scanpt */ + case 279: /* trigger_cmd ::= scanpt select scanpt */ {yylhsminor.yy319 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy637, yymsp[-2].minor.yy342, yymsp[0].minor.yy342); /*yylhsminor.yy319-overwrites-yymsp[-1].minor.yy637*/} yymsp[-2].minor.yy319 = yylhsminor.yy319; break; - case 279: /* expr ::= RAISE LP IGNORE RP */ + case 280: /* expr ::= RAISE LP IGNORE RP */ { yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( yymsp[-3].minor.yy590 ){ @@ -181495,7 +181558,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */ + case 281: /* expr ::= RAISE LP raisetype COMMA expr RP */ { yymsp[-5].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy590, 0); if( yymsp[-5].minor.yy590 ) { @@ -181503,117 +181566,117 @@ static YYACTIONTYPE yy_reduce( } } break; - case 281: /* raisetype ::= ROLLBACK */ + case 282: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy502 = OE_Rollback;} break; - case 283: /* raisetype ::= FAIL */ + case 284: /* raisetype ::= FAIL */ {yymsp[0].minor.yy502 = OE_Fail;} break; - case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 285: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy563,yymsp[-1].minor.yy502); } break; - case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 286: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy590, yymsp[-1].minor.yy590, yymsp[0].minor.yy590); } break; - case 286: /* cmd ::= DETACH database_kw_opt expr */ + case 287: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy590); } break; - case 289: /* cmd ::= REINDEX */ + case 290: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 290: /* cmd ::= REINDEX nm dbnm */ + case 291: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 291: /* cmd ::= ANALYZE */ + case 292: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 292: /* cmd ::= ANALYZE nm dbnm */ + case 293: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 294: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy563,&yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 295: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + case 296: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy563, &yymsp[0].minor.yy0); } break; - case 296: /* add_column_fullname ::= fullname */ + case 297: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy563); } break; - case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 298: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy563, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 298: /* cmd ::= create_vtab */ + case 299: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 299: /* cmd ::= create_vtab LP vtabarglist RP */ + case 300: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 301: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy502); } break; - case 301: /* vtabarg ::= */ + case 302: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 302: /* vtabargtoken ::= ANY */ - case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); - case 304: /* lp ::= LP */ yytestcase(yyruleno==304); + case 303: /* vtabargtoken ::= ANY */ + case 304: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==304); + case 305: /* lp ::= LP */ yytestcase(yyruleno==305); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 305: /* with ::= WITH wqlist */ - case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); + case 306: /* with ::= WITH wqlist */ + case 307: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==307); { sqlite3WithPush(pParse, yymsp[0].minor.yy125, 1); } break; - case 307: /* wqas ::= AS */ + case 308: /* wqas ::= AS */ {yymsp[0].minor.yy444 = M10d_Any;} break; - case 308: /* wqas ::= AS MATERIALIZED */ + case 309: /* wqas ::= AS MATERIALIZED */ {yymsp[-1].minor.yy444 = M10d_Yes;} break; - case 309: /* wqas ::= AS NOT MATERIALIZED */ + case 310: /* wqas ::= AS NOT MATERIALIZED */ {yymsp[-2].minor.yy444 = M10d_No;} break; - case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ + case 311: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ { yymsp[-5].minor.yy361 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy402, yymsp[-1].minor.yy637, yymsp[-3].minor.yy444); /*A-overwrites-X*/ } break; - case 311: /* withnm ::= nm */ + case 312: /* withnm ::= nm */ {pParse->bHasWith = 1;} break; - case 312: /* wqlist ::= wqitem */ + case 313: /* wqlist ::= wqitem */ { yymsp[0].minor.yy125 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy361); /*A-overwrites-X*/ } break; - case 313: /* wqlist ::= wqlist COMMA wqitem */ + case 314: /* wqlist ::= wqlist COMMA wqitem */ { yymsp[-2].minor.yy125 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy125, yymsp[0].minor.yy361); } break; - case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 315: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { assert( yymsp[0].minor.yy483!=0 ); sqlite3WindowChain(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy483); @@ -181622,7 +181685,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy483 = yylhsminor.yy483; break; - case 315: /* windowdefn ::= nm AS LP window RP */ + case 316: /* windowdefn ::= nm AS LP window RP */ { if( ALWAYS(yymsp[-1].minor.yy483) ){ yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); @@ -181631,83 +181694,83 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy483 = yylhsminor.yy483; break; - case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 317: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { yymsp[-4].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, 0); } break; - case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 318: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, &yymsp[-5].minor.yy0); } yymsp[-5].minor.yy483 = yylhsminor.yy483; break; - case 318: /* window ::= ORDER BY sortlist frame_opt */ + case 319: /* window ::= ORDER BY sortlist frame_opt */ { yymsp[-3].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, 0); } break; - case 319: /* window ::= nm ORDER BY sortlist frame_opt */ + case 320: /* window ::= nm ORDER BY sortlist frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy483 = yylhsminor.yy483; break; - case 320: /* window ::= nm frame_opt */ + case 321: /* window ::= nm frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, 0, &yymsp[-1].minor.yy0); } yymsp[-1].minor.yy483 = yylhsminor.yy483; break; - case 321: /* frame_opt ::= */ + case 322: /* frame_opt ::= */ { yymsp[1].minor.yy483 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 323: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy502, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy444); } yymsp[-2].minor.yy483 = yylhsminor.yy483; break; - case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 324: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy502, yymsp[-3].minor.yy205.eType, yymsp[-3].minor.yy205.pExpr, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, yymsp[0].minor.yy444); } yymsp[-5].minor.yy483 = yylhsminor.yy483; break; - case 325: /* frame_bound_s ::= frame_bound */ - case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327); + case 326: /* frame_bound_s ::= frame_bound */ + case 328: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==328); {yylhsminor.yy205 = yymsp[0].minor.yy205;} yymsp[0].minor.yy205 = yylhsminor.yy205; break; - case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328); - case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330); + case 327: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 329: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==329); + case 331: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==331); {yylhsminor.yy205.eType = yymsp[-1].major; yylhsminor.yy205.pExpr = 0;} yymsp[-1].minor.yy205 = yylhsminor.yy205; break; - case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */ + case 330: /* frame_bound ::= expr PRECEDING|FOLLOWING */ {yylhsminor.yy205.eType = yymsp[0].major; yylhsminor.yy205.pExpr = yymsp[-1].minor.yy590;} yymsp[-1].minor.yy205 = yylhsminor.yy205; break; - case 331: /* frame_exclude_opt ::= */ + case 332: /* frame_exclude_opt ::= */ {yymsp[1].minor.yy444 = 0;} break; - case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ + case 333: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ {yymsp[-1].minor.yy444 = yymsp[0].minor.yy444;} break; - case 333: /* frame_exclude ::= NO OTHERS */ - case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334); + case 334: /* frame_exclude ::= NO OTHERS */ + case 335: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==335); {yymsp[-1].minor.yy444 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 335: /* frame_exclude ::= GROUP|TIES */ + case 336: /* frame_exclude ::= GROUP|TIES */ {yymsp[0].minor.yy444 = yymsp[0].major; /*A-overwrites-X*/} break; - case 336: /* window_clause ::= WINDOW windowdefn_list */ + case 337: /* window_clause ::= WINDOW windowdefn_list */ { yymsp[-1].minor.yy483 = yymsp[0].minor.yy483; } break; - case 337: /* filter_over ::= filter_clause over_clause */ + case 338: /* filter_over ::= filter_clause over_clause */ { if( yymsp[0].minor.yy483 ){ yymsp[0].minor.yy483->pFilter = yymsp[-1].minor.yy590; @@ -181718,13 +181781,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[-1].minor.yy483 = yylhsminor.yy483; break; - case 338: /* filter_over ::= over_clause */ + case 339: /* filter_over ::= over_clause */ { yylhsminor.yy483 = yymsp[0].minor.yy483; } yymsp[0].minor.yy483 = yylhsminor.yy483; break; - case 339: /* filter_over ::= filter_clause */ + case 340: /* filter_over ::= filter_clause */ { yylhsminor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yylhsminor.yy483 ){ @@ -181736,13 +181799,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy483 = yylhsminor.yy483; break; - case 340: /* over_clause ::= OVER LP window RP */ + case 341: /* over_clause ::= OVER LP window RP */ { yymsp[-3].minor.yy483 = yymsp[-1].minor.yy483; assert( yymsp[-3].minor.yy483!=0 ); } break; - case 341: /* over_clause ::= OVER nm */ + case 342: /* over_clause ::= OVER nm */ { yymsp[-1].minor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yymsp[-1].minor.yy483 ){ @@ -181750,10 +181813,10 @@ static YYACTIONTYPE yy_reduce( } } break; - case 342: /* filter_clause ::= FILTER LP WHERE expr RP */ + case 343: /* filter_clause ::= FILTER LP WHERE expr RP */ { yymsp[-4].minor.yy590 = yymsp[-1].minor.yy590; } break; - case 343: /* term ::= QNUMBER */ + case 344: /* term ::= QNUMBER */ { yylhsminor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); sqlite3DequoteNumber(pParse, yylhsminor.yy590); @@ -181761,71 +181824,71 @@ static YYACTIONTYPE yy_reduce( yymsp[0].minor.yy590 = yylhsminor.yy590; break; default: - /* (344) input ::= cmdlist */ yytestcase(yyruleno==344); - /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345); - /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346); - /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347); - /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348); - /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349); - /* (350) trans_opt ::= */ yytestcase(yyruleno==350); - /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351); - /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352); - /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353); - /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354); - /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355); - /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356); - /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357); - /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358); - /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359); - /* (360) nm ::= STRING */ yytestcase(yyruleno==360); - /* (361) typetoken ::= typename */ yytestcase(yyruleno==361); - /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362); - /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363); - /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); - /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365); - /* (366) carglist ::= */ yytestcase(yyruleno==366); - /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367); - /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368); - /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369); - /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370); - /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371); - /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372); - /* (373) tconscomma ::= */ yytestcase(yyruleno==373); - /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374); - /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375); - /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) oneselect ::= values */ yytestcase(yyruleno==377); - /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378); - /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379); - /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380); - /* (381) returning ::= */ yytestcase(yyruleno==381); - /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382); - /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383); - /* (384) case_operand ::= expr */ yytestcase(yyruleno==384); - /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385); - /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386); - /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387); - /* (388) nmnum ::= ON */ yytestcase(yyruleno==388); - /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389); - /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390); - /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391); - /* (392) foreach_clause ::= */ yytestcase(yyruleno==392); - /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393); - /* (394) trnm ::= nm */ yytestcase(yyruleno==394); - /* (395) tridxby ::= */ yytestcase(yyruleno==395); - /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396); - /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397); - /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398); - /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399); - /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400); - /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401); - /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402); - /* (403) anylist ::= */ yytestcase(yyruleno==403); - /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404); - /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405); - /* (406) with ::= */ yytestcase(yyruleno==406); - /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407); - /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408); + /* (345) input ::= cmdlist */ yytestcase(yyruleno==345); + /* (346) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==346); + /* (347) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=347); + /* (348) ecmd ::= SEMI */ yytestcase(yyruleno==348); + /* (349) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==349); + /* (350) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=350); + /* (351) trans_opt ::= */ yytestcase(yyruleno==351); + /* (352) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==352); + /* (353) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==353); + /* (354) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==354); + /* (355) savepoint_opt ::= */ yytestcase(yyruleno==355); + /* (356) cmd ::= create_table create_table_args */ yytestcase(yyruleno==356); + /* (357) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=357); + /* (358) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==358); + /* (359) columnlist ::= columnname carglist */ yytestcase(yyruleno==359); + /* (360) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==360); + /* (361) nm ::= STRING */ yytestcase(yyruleno==361); + /* (362) typetoken ::= typename */ yytestcase(yyruleno==362); + /* (363) typename ::= ID|STRING */ yytestcase(yyruleno==363); + /* (364) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); + /* (365) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=365); + /* (366) carglist ::= carglist ccons */ yytestcase(yyruleno==366); + /* (367) carglist ::= */ yytestcase(yyruleno==367); + /* (368) ccons ::= NULL onconf */ yytestcase(yyruleno==368); + /* (369) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==369); + /* (370) ccons ::= AS generated */ yytestcase(yyruleno==370); + /* (371) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==371); + /* (372) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==372); + /* (373) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=373); + /* (374) tconscomma ::= */ yytestcase(yyruleno==374); + /* (375) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=375); + /* (376) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=377); + /* (378) oneselect ::= values */ yytestcase(yyruleno==378); + /* (379) sclp ::= selcollist COMMA */ yytestcase(yyruleno==379); + /* (380) as ::= ID|STRING */ yytestcase(yyruleno==380); + /* (381) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=381); + /* (382) returning ::= */ yytestcase(yyruleno==382); + /* (383) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=383); + /* (384) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==384); + /* (385) case_operand ::= expr */ yytestcase(yyruleno==385); + /* (386) exprlist ::= nexprlist */ yytestcase(yyruleno==386); + /* (387) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=387); + /* (388) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=388); + /* (389) nmnum ::= ON */ yytestcase(yyruleno==389); + /* (390) nmnum ::= DELETE */ yytestcase(yyruleno==390); + /* (391) nmnum ::= DEFAULT */ yytestcase(yyruleno==391); + /* (392) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==392); + /* (393) foreach_clause ::= */ yytestcase(yyruleno==393); + /* (394) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==394); + /* (395) trnm ::= nm */ yytestcase(yyruleno==395); + /* (396) tridxby ::= */ yytestcase(yyruleno==396); + /* (397) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==397); + /* (398) database_kw_opt ::= */ yytestcase(yyruleno==398); + /* (399) kwcolumn_opt ::= */ yytestcase(yyruleno==399); + /* (400) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==400); + /* (401) vtabarglist ::= vtabarg */ yytestcase(yyruleno==401); + /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==402); + /* (403) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==403); + /* (404) anylist ::= */ yytestcase(yyruleno==404); + /* (405) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==405); + /* (406) anylist ::= anylist ANY */ yytestcase(yyruleno==406); + /* (407) with ::= */ yytestcase(yyruleno==407); + /* (408) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=408); + /* (409) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=409); break; /********** End reduce actions ************************************************/ }; @@ -182325,152 +182388,153 @@ const unsigned char ebcdicToAscii[] = { ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ -/* Hash score: 231 */ -/* zKWText[] encodes 1007 bytes of keyword text in 667 bytes */ -/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ -/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */ -/* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */ -/* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */ -/* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */ -/* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */ -/* PRAGMATERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENWHERE */ -/* CURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCASTCOLUMN */ -/* COMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILASTFILTER */ -/* EPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ +/* Hash score: 233 */ +/* zKWText[] encodes 1018 bytes of keyword text in 669 bytes */ +/* CONCURRENT_DATEMPORARYREINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXP */ +/* LAINSTEADDATABASELECTABLEFTHENDEFERRABLELSEXCLUDELETEXCEPTIES */ +/* AVEPOINTERSECTRANSACTIONOTNULLSISNULLIKEXCLUSIVEXISTS */ +/* CONSTRAINTOFFSETRIGGERAISEUNIQUERYWITHOUTERANGENERATEDETACH */ +/* AVINGLOBEGINNEREFERENCESATTACHBETWEENATURALTERELEASECASCADE */ +/* FAULTCASECOLLATECREATEIMMEDIATEJOINSERTMATCHPLANALYZEPRAGMA */ +/* TERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENOTHINGROUPS */ +/* WHERECURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCAST */ +/* COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILAST */ +/* FILTEREPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ /* ETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBY */ /* INITIALLYPRIMARY */ -static const char zKWText[666] = { - 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', - 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', - 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', - 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', - 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', - 'T','E','M','P','O','R','A','R','Y','I','S','N','U','L','L','S','A','V', - 'E','P','O','I','N','T','E','R','S','E','C','T','I','E','S','N','O','T', - 'N','U','L','L','I','K','E','X','C','E','P','T','R','A','N','S','A','C', - 'T','I','O','N','A','T','U','R','A','L','T','E','R','A','I','S','E','X', - 'C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T','R', - 'A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A','N', - 'G','E','N','E','R','A','T','E','D','E','T','A','C','H','A','V','I','N', - 'G','L','O','B','E','G','I','N','N','E','R','E','F','E','R','E','N','C', - 'E','S','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T','E', - 'R','E','L','E','A','S','E','A','T','T','A','C','H','B','E','T','W','E', - 'E','N','O','T','H','I','N','G','R','O','U','P','S','C','A','S','C','A', - 'D','E','F','A','U','L','T','C','A','S','E','C','O','L','L','A','T','E', - 'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E', - 'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M', - 'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M', - 'A','T','E','R','I','A','L','I','Z','E','D','E','F','E','R','R','E','D', - 'I','S','T','I','N','C','T','U','P','D','A','T','E','V','A','L','U','E', - 'S','V','I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H', - 'E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A','F','T', - 'E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T','I','T', - 'I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T','C','A', - 'S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O','N','F', - 'L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T','_','T', - 'I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G','F','A', - 'I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C','E','F', - 'I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O','M','F', - 'U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S','T','R', - 'I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U','R','N', - 'I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O', - 'W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S', - 'I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W', - 'B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', +static const char zKWText[668] = { + 'C','O','N','C','U','R','R','E','N','T','_','D','A','T','E','M','P','O', + 'R','A','R','Y','R','E','I','N','D','E','X','E','D','E','S','C','A','P', + 'E','A','C','H','E','C','K','E','Y','B','E','F','O','R','E','I','G','N', + 'O','R','E','G','E','X','P','L','A','I','N','S','T','E','A','D','D','A', + 'T','A','B','A','S','E','L','E','C','T','A','B','L','E','F','T','H','E', + 'N','D','E','F','E','R','R','A','B','L','E','L','S','E','X','C','L','U', + 'D','E','L','E','T','E','X','C','E','P','T','I','E','S','A','V','E','P', + 'O','I','N','T','E','R','S','E','C','T','R','A','N','S','A','C','T','I', + 'O','N','O','T','N','U','L','L','S','I','S','N','U','L','L','I','K','E', + 'X','C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T', + 'R','A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A', + 'I','S','E','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T', + 'E','R','A','N','G','E','N','E','R','A','T','E','D','E','T','A','C','H', + 'A','V','I','N','G','L','O','B','E','G','I','N','N','E','R','E','F','E', + 'R','E','N','C','E','S','A','T','T','A','C','H','B','E','T','W','E','E', + 'N','A','T','U','R','A','L','T','E','R','E','L','E','A','S','E','C','A', + 'S','C','A','D','E','F','A','U','L','T','C','A','S','E','C','O','L','L', + 'A','T','E','C','R','E','A','T','E','I','M','M','E','D','I','A','T','E', + 'J','O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A', + 'L','Y','Z','E','P','R','A','G','M','A','T','E','R','I','A','L','I','Z', + 'E','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','U','P', + 'D','A','T','E','V','A','L','U','E','S','V','I','R','T','U','A','L','W', + 'A','Y','S','W','H','E','N','O','T','H','I','N','G','R','O','U','P','S', + 'W','H','E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A', + 'F','T','E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T', + 'I','T','I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T', + 'C','A','S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O', + 'N','F','L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T', + '_','T','I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G', + 'F','A','I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C', + 'E','F','I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O', + 'M','F','U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S', + 'T','R','I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U', + 'R','N','I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K', + 'R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N', + 'U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D', + 'O','W','B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A', + 'R','Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { - 84, 92, 134, 82, 105, 29, 0, 0, 94, 0, 85, 72, 0, - 53, 35, 86, 15, 0, 42, 97, 54, 89, 135, 19, 0, 0, - 140, 0, 40, 129, 0, 22, 107, 0, 9, 0, 0, 123, 80, - 0, 78, 6, 0, 65, 103, 147, 0, 136, 115, 0, 0, 48, - 0, 90, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 142, - 110, 122, 0, 73, 91, 71, 145, 61, 120, 74, 0, 49, 0, - 11, 41, 0, 113, 0, 0, 0, 109, 10, 111, 116, 125, 14, - 50, 124, 0, 100, 0, 18, 121, 144, 56, 130, 139, 88, 83, - 37, 30, 126, 0, 0, 108, 51, 131, 128, 0, 34, 0, 0, - 132, 0, 98, 38, 39, 0, 20, 45, 117, 93, + 82, 90, 135, 80, 106, 4, 0, 0, 92, 0, 83, 96, 0, + 52, 34, 84, 20, 0, 37, 95, 53, 87, 136, 24, 0, 0, + 141, 0, 46, 130, 0, 27, 108, 0, 14, 0, 0, 124, 79, + 0, 77, 11, 0, 57, 104, 148, 0, 137, 116, 0, 0, 47, + 0, 88, 29, 0, 22, 0, 32, 69, 28, 31, 10, 65, 143, + 111, 123, 0, 97, 89, 70, 146, 66, 121, 98, 0, 48, 0, + 16, 33, 0, 114, 0, 0, 0, 110, 15, 112, 117, 126, 19, + 49, 125, 0, 101, 0, 23, 122, 145, 61, 131, 140, 86, 81, + 41, 5, 127, 0, 0, 109, 50, 132, 129, 0, 36, 0, 0, + 133, 0, 99, 42, 44, 0, 25, 71, 118, 91, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ -static const unsigned char aKWNext[148] = {0, - 0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0, - 0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0, - 141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0, - 138, 0, 133, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0, - 0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 69, 0, 0, 0, 0, 0, 146, 3, 0, 58, 0, 1, - 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 127, 0, 104, - 0, 64, 66, 63, 0, 0, 0, 0, 0, 46, 0, 16, 8, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 101, 0, - 112, 21, 7, 67, 0, 79, 96, 118, 0, 0, 68, 0, 0, - 99, 44, 0, 55, 0, 76, 0, 95, 32, 33, 57, 25, 0, - 102, 0, 0, 87, +static const unsigned char aKWNext[149] = {0, + 0, 0, 0, 0, 120, 0, 0, 0, 0, 9, 0, 38, 0, + 0, 107, 115, 0, 0, 0, 7, 0, 0, 144, 0, 0, 0, + 18, 0, 0, 0, 0, 142, 0, 17, 0, 138, 134, 0, 0, + 0, 0, 67, 0, 0, 51, 139, 3, 76, 1, 0, 0, 0, + 64, 0, 0, 0, 0, 0, 73, 0, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 40, 0, 0, 0, 63, 0, 6, 74, + 0, 0, 45, 0, 0, 0, 0, 0, 128, 0, 105, 0, 56, + 58, 68, 0, 0, 0, 147, 8, 0, 0, 0, 72, 0, 21, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 102, + 0, 113, 26, 12, 59, 0, 78, 94, 119, 0, 0, 60, 0, + 0, 100, 39, 0, 54, 0, 75, 0, 93, 43, 35, 62, 30, + 0, 103, 0, 0, 85, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[148] = {0, - 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, - 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, - 6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4, - 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6, - 2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5, - 7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4, - 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, - 2, 6, 6, 7, 6, 4, 5, 9, 5, 5, 6, 3, 4, - 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, - 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, - 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, - 2, 9, 3, 7, +static const unsigned char aKWLen[149] = {0, + 10, 12, 9, 4, 2, 7, 7, 5, 4, 6, 4, 5, 3, + 6, 7, 3, 6, 6, 7, 7, 3, 8, 2, 6, 5, 4, + 4, 3, 10, 4, 7, 6, 6, 4, 9, 9, 11, 6, 2, + 7, 3, 2, 5, 4, 6, 4, 9, 6, 10, 4, 6, 2, + 3, 7, 5, 6, 5, 7, 4, 5, 5, 9, 6, 6, 4, + 5, 5, 10, 6, 7, 7, 5, 7, 7, 3, 7, 4, 7, + 6, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, 2, 6, + 6, 7, 6, 4, 7, 6, 5, 5, 9, 5, 5, 6, 3, + 4, 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, + 9, 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, + 6, 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, + 2, 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[148] = {0, - 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, - 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, - 86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126, - 129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184, - 184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239, - 244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295, - 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 359, 370, 377, - 378, 385, 391, 397, 402, 408, 412, 415, 424, 429, 433, 439, 441, - 444, 453, 455, 457, 466, 470, 476, 482, 490, 495, 495, 495, 511, - 520, 523, 527, 532, 539, 544, 553, 557, 560, 565, 567, 571, 579, - 585, 588, 597, 602, 610, 610, 614, 623, 628, 633, 639, 642, 645, - 648, 650, 655, 659, +static const unsigned short int aKWOffset[149] = {0, + 0, 3, 13, 13, 17, 22, 24, 24, 30, 31, 36, 38, 42, + 45, 47, 47, 51, 55, 58, 63, 68, 70, 75, 76, 81, 84, + 87, 89, 91, 100, 103, 108, 113, 118, 121, 127, 135, 140, 144, + 145, 145, 145, 148, 148, 153, 158, 161, 169, 175, 182, 185, 185, + 188, 190, 196, 201, 204, 209, 209, 213, 217, 220, 228, 233, 238, + 241, 244, 248, 258, 264, 270, 275, 279, 286, 287, 291, 298, 302, + 309, 315, 324, 326, 332, 337, 339, 346, 350, 361, 368, 369, 376, + 382, 388, 393, 399, 402, 408, 408, 414, 417, 426, 431, 435, 441, + 443, 446, 455, 457, 459, 468, 472, 478, 484, 492, 497, 497, 497, + 513, 522, 525, 529, 534, 541, 546, 555, 559, 562, 567, 569, 573, + 581, 587, 590, 599, 604, 612, 612, 616, 625, 630, 635, 641, 644, + 647, 650, 652, 657, 661, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[148] = {0, +static const unsigned char aKWCode[149] = {0, + TK_CONCURRENT, TK_CTIME_KW, TK_TEMP, TK_TEMP, TK_OR, TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, - TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES, - TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, - TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, - TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, - TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, + TK_EXCLUDE, TK_DELETE, TK_EXCEPT, TK_TIES, TK_SAVEPOINT, + TK_INTERSECT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_NOTNULL, + TK_NOT, TK_NO, TK_NULLS, TK_NULL, TK_ISNULL, + TK_LIKE_KW, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, TK_RAISE, + TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW, - TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY, - TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH, - TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE, - TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, - TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, - TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, - TK_DISTINCT, TK_IS, TK_UPDATE, TK_VALUES, TK_VIRTUAL, - TK_ALWAYS, TK_WHEN, TK_WHERE, TK_RECURSIVE, TK_ABORT, - TK_AFTER, TK_RENAME, TK_AND, TK_DROP, TK_PARTITION, - TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, - TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, - TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, - TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, - TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, - TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, - TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, - TK_VIEW, TK_WINDOW, TK_DO, TK_BY, TK_INITIALLY, - TK_ALL, TK_PRIMARY, + TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_ATTACH, TK_BETWEEN, + TK_JOIN_KW, TK_ALTER, TK_RELEASE, TK_CASCADE, TK_ASC, + TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, TK_IMMEDIATE, + TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, + TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, TK_DISTINCT, TK_IS, + TK_UPDATE, TK_VALUES, TK_VIRTUAL, TK_ALWAYS, TK_WHEN, + TK_NOTHING, TK_GROUPS, TK_GROUP, TK_WHERE, TK_RECURSIVE, + TK_ABORT, TK_AFTER, TK_RENAME, TK_AND, TK_DROP, + TK_PARTITION, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, + TK_FILTER, TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, + TK_JOIN_KW, TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, + TK_OTHERS, TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, + TK_ROWS, TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, + TK_VACUUM, TK_VIEW, TK_WINDOW, TK_DO, TK_BY, + TK_INITIALLY, TK_ALL, TK_PRIMARY, }; /* Hash table decoded: ** 0: INSERT @@ -182564,7 +182628,7 @@ static const unsigned char aKWCode[148] = {0, ** 88: CURRENT AFTER ALTER ** 89: FULL FAIL CONFLICT ** 90: EXPLAIN -** 91: CONSTRAINT +** 91: CONSTRAINT CONCURRENT ** 92: FROM ALWAYS ** 93: ** 94: ABORT @@ -182625,153 +182689,154 @@ static int keywordCode(const char *z, int n, int *pType){ while( j=2 ) keywordCode((char*)z, n, &id); return id; } -#define SQLITE_N_KEYWORD 147 +#define SQLITE_N_KEYWORD 148 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; i++; @@ -184015,6 +184080,9 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_EXTRA_AUTOEXT SQLITE_EXTRA_AUTOEXT, #endif +#ifdef SQLITE_ENABLE_HCT + sqlite3HctVtabInit, +#endif }; #ifndef SQLITE_AMALGAMATION @@ -185855,8 +185923,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS| - SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But @@ -188323,18 +188390,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } - /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N) - ** - ** Write the current optimization settings into *N. A zero bit means that - ** the optimization is on, and a 1 bit means that the optimization is off. - */ - case SQLITE_TESTCTRL_GETOPT: { - sqlite3 *db = va_arg(ap, sqlite3*); - int *pN = va_arg(ap, int*); - *pN = db->dbOptFlags; - break; - } - /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt); ** ** If parameter onoff is 1, subsequent calls to localtime() fail. @@ -188565,6 +188620,21 @@ SQLITE_API int sqlite3_test_control(int op, ...){ *pI2 = sqlite3LogEst(*pU64); break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_HCT_MTCOMMIT, + ** sqlite3 *db, + ** void(*xMtCommit)(void*, int), + ** void *pCtx + ** ); + ** + ** Install xMtCommit hook on "main" hct database. + */ + case SQLITE_TESTCTRL_HCT_MTCOMMIT: { + typedef void (*mt_commit_hook)(void*,int); + sqlite3 *db = va_arg(ap, sqlite3*); + db->xMtCommit = va_arg(ap, mt_commit_hook); + db->pMtCommitCtx = va_arg(ap, void*); + break; + }; #if !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X); @@ -188583,7 +188653,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ } #endif - #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** @@ -199691,7 +199760,11 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( #ifdef SQLITE_TEST -#include "tclsqlite.h" +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif /* #include */ /* @@ -206918,7 +206991,6 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){ return 1; } - assert( pIter->nSnippet>=0 ); pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; @@ -211912,9 +211984,7 @@ static u32 jsonLookupStep( zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; - for(i=1; zPath[i] && zPath[i]!='"'; i++){ - if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++; - } + for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; if( zPath[i] ){ i++; @@ -228039,7 +228109,6 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ pIdxInfo->orderByConsumed = 1; pIdxInfo->idxNum |= 0x08; } - pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX; return SQLITE_OK; } @@ -235912,10 +235981,6 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** -** In all cases, matches are visited in (column ASC, offset ASC) order. -** i.e. all those in column 0, sorted by offset, followed by those in -** column 1, etc. -** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -235982,32 +236047,9 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. -** -** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the locale associated -** with column iCol of the current row. Usually, there is no associated -** locale, and output parameters (*pzLocale) and (*pnLocale) are set -** to NULL and 0, respectively. However, if the fts5_locale() function -** was used to associate a locale with the value when it was inserted -** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated -** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) -** is set to the size in bytes of the buffer, not including the -** nul-terminator. -** -** If successful, SQLITE_OK is returned. Or, if an error occurs, an -** SQLite error code is returned. The final value of the output parameters -** is undefined in this case. -** -** xTokenize_v2: -** Tokenize text using the tokenizer belonging to the FTS5 table. This -** API is the same as the xTokenize() API, except that it allows a tokenizer -** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 4 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -236049,15 +236091,6 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); - - /* Below this point are iVersion>=4 only */ - int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); - int (*xTokenize_v2)(Fts5Context*, - const char *pText, int nText, /* Text to tokenize */ - const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ - void *pCtx, /* Context passed to xToken() */ - int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ - ); }; /* @@ -236070,7 +236103,6 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting -** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -236079,7 +236111,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer_v2 object +** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -236103,7 +236135,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The third argument indicates the reason that FTS5 is requesting +** The second argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -236127,13 +236159,6 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** -** The sixth and seventh arguments passed to xTokenize() - pLocale and -** nLocale - are a pointer to a buffer containing the locale to use for -** tokenization (e.g. "en_US") and its size in bytes, respectively. The -** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in -** which case nLocale is always 0) to indicate that the tokenizer should -** use its default locale. -** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -236157,30 +236182,6 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** -** If the tokenizer is registered using an fts5_tokenizer_v2 object, -** then the xTokenize() method has two additional arguments - pLocale -** and nLocale. These specify the locale that the tokenizer should use -** for the current request. If pLocale and nLocale are both 0, then the -** tokenizer should use its default locale. Otherwise, pLocale points to -** an nLocale byte buffer containing the name of the locale to use as utf-8 -** text. pLocale is not nul-terminated. -** -** FTS5_TOKENIZER -** -** There is also an fts5_tokenizer object. This is an older, deprecated, -** version of fts5_tokenizer_v2. It is similar except that: -** -**
    -**
  • There is no "iVersion" field, and -**
  • The xTokenize() method does not take a locale argument. -**
-** -** Legacy fts5_tokenizer tokenizers must be registered using the -** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). -** -** Tokenizer implementations registered using either API may be retrieved -** using both xFindTokenizer() and xFindTokenizer_v2(). -** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -236289,33 +236290,6 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; -typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; -struct fts5_tokenizer_v2 { - int iVersion; /* Currently always 2 */ - - int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); - void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, - void *pCtx, - int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, - const char *pLocale, int nLocale, - int (*xToken)( - void *pCtx, /* Copy of 2nd argument to xTokenize() */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Pointer to buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Byte offset of token within input text */ - int iEnd /* Byte offset of end of token within input text */ - ) - ); -}; - -/* -** New code should use the fts5_tokenizer_v2 type to define tokenizer -** implementations. The following type is included for legacy applications -** that still use it. -*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -236335,7 +236309,6 @@ struct fts5_tokenizer { ); }; - /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -236355,7 +236328,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -236382,25 +236355,6 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); - - /* APIs below this point are only available if iVersion>=3 */ - - /* Create a new tokenizer */ - int (*xCreateTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void *pUserData, - fts5_tokenizer_v2 *pTokenizer, - void (*xDestroy)(void*) - ); - - /* Find an existing tokenizer */ - int (*xFindTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void **ppUserData, - fts5_tokenizer_v2 **ppTokenizer - ); }; /* @@ -236474,22 +236428,6 @@ typedef sqlite3_uint64 u64; # define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) # define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) -/* The uptr type is an unsigned integer large enough to hold a pointer -*/ -#if defined(HAVE_STDINT_H) - typedef uintptr_t uptr; -#elif SQLITE_PTRSIZE==4 - typedef u32 uptr; -#else - typedef u64 uptr; -#endif - -#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC -# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) -#else -# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) -#endif - #endif /* Truncate very long tokens to this many bytes. Hard limit is @@ -236577,13 +236515,10 @@ typedef struct Fts5TokenizerConfig Fts5TokenizerConfig; struct Fts5TokenizerConfig { Fts5Tokenizer *pTok; - fts5_tokenizer_v2 *pApi2; - fts5_tokenizer *pApi1; + fts5_tokenizer *pTokApi; const char **azArg; int nArg; int ePattern; /* FTS_PATTERN_XXX constant */ - const char *pLocale; /* Current locale to use */ - int nLocale; /* Size of pLocale in bytes */ }; /* @@ -236624,8 +236559,6 @@ struct Fts5TokenizerConfig { ** ** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex); ** -** bLocale: -** Set to true if locale=1 was specified when the table was created. */ struct Fts5Config { sqlite3 *db; /* Database handle */ @@ -236643,13 +236576,11 @@ struct Fts5Config { char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ int bTokendata; /* "tokendata=" option value (dflt==0) */ - int bLocale; /* "locale=" option value (dflt==0) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5TokenizerConfig t; int bLock; /* True when table is preparing statement */ - /* Values loaded from the %_config table */ int iVersion; /* fts5 file format 'version' */ int iCookie; /* Incremented when %_config is modified */ @@ -236714,8 +236645,6 @@ static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, i static int sqlite3Fts5ConfigParseRank(const char*, char**, char**); -static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...); - /* ** End of interface to code in fts5_config.c. **************************************************************************/ @@ -236760,7 +236689,7 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); static void sqlite3Fts5Put32(u8*, int); static int sqlite3Fts5Get32(const u8*); -#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF) +#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; @@ -237051,17 +236980,6 @@ static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); static int sqlite3Fts5FlushToDisk(Fts5Table*); -static int sqlite3Fts5ExtractText( - Fts5Config *pConfig, - sqlite3_value *pVal, /* Value to extract text from */ - int bContent, /* Loaded from content table */ - int *pbResetTokenizer, /* OUT: True if ClearLocale() required */ - const char **ppText, /* OUT: Pointer to text buffer */ - int *pnText /* OUT: Size of (*ppText) in bytes */ -); - -static void sqlite3Fts5ClearLocale(Fts5Config *pConfig); - /* ** End of interface to code in fts5.c. **************************************************************************/ @@ -237141,7 +237059,7 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); static int sqlite3Fts5DropAll(Fts5Config*); static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int); +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); @@ -237167,9 +237085,6 @@ static int sqlite3Fts5StorageOptimize(Fts5Storage *p); static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); static int sqlite3Fts5StorageReset(Fts5Storage *p); -static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*); -static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel); - /* ** End of interface to code in fts5_storage.c. **************************************************************************/ @@ -239100,7 +239015,6 @@ static int fts5HighlightCb( return rc; } - /* ** Implementation of highlight() function. */ @@ -239131,19 +239045,12 @@ static void fts5HighlightFunction( sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); rc = SQLITE_OK; }else if( ctx.zIn ){ - const char *pLoc = 0; /* Locale of column iCol */ - int nLoc = 0; /* Size of pLoc in bytes */ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } if( rc==SQLITE_OK ){ - rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc); - } - if( rc==SQLITE_OK ){ - rc = pApi->xTokenize_v2( - pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb - ); + rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } if( ctx.bOpen ){ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); @@ -239340,8 +239247,6 @@ static void fts5SnippetFunction( memset(&sFinder, 0, sizeof(Fts5SFinder)); for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc); if( rc!=SQLITE_OK ) break; - rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc); - if( rc!=SQLITE_OK ) break; - rc = pApi->xTokenize_v2(pFts, - sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb + rc = pApi->xTokenize(pFts, + sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb ); if( rc!=SQLITE_OK ) break; rc = pApi->xColumnSize(pFts, i, &nDocsize); @@ -239410,9 +239313,6 @@ static void fts5SnippetFunction( rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); } if( ctx.zIn ){ - const char *pLoc = 0; /* Locale of column iBestCol */ - int nLoc = 0; /* Bytes in pLoc */ - if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); } @@ -239431,12 +239331,7 @@ static void fts5SnippetFunction( } if( rc==SQLITE_OK ){ - rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc); - } - if( rc==SQLITE_OK ){ - rc = pApi->xTokenize_v2( - pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb - ); + rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } if( ctx.bOpen ){ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); @@ -239620,53 +239515,6 @@ static void fts5Bm25Function( } } -/* -** Implementation of fts5_get_locale() function. -*/ -static void fts5GetLocaleFunction( - const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ - Fts5Context *pFts, /* First arg to pass to pApi functions */ - sqlite3_context *pCtx, /* Context for returning result/error */ - int nVal, /* Number of values in apVal[] array */ - sqlite3_value **apVal /* Array of trailing arguments */ -){ - int iCol = 0; - int eType = 0; - int rc = SQLITE_OK; - const char *zLocale = 0; - int nLocale = 0; - - /* xColumnLocale() must be available */ - assert( pApi->iVersion>=4 ); - - if( nVal!=1 ){ - const char *z = "wrong number of arguments to function fts5_get_locale()"; - sqlite3_result_error(pCtx, z, -1); - return; - } - - eType = sqlite3_value_numeric_type(apVal[0]); - if( eType!=SQLITE_INTEGER ){ - const char *z = "non-integer argument passed to function fts5_get_locale()"; - sqlite3_result_error(pCtx, z, -1); - return; - } - - iCol = sqlite3_value_int(apVal[0]); - if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){ - sqlite3_result_error_code(pCtx, SQLITE_RANGE); - return; - } - - rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale); - if( rc!=SQLITE_OK ){ - sqlite3_result_error_code(pCtx, rc); - return; - } - - sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT); -} - static int sqlite3Fts5AuxInit(fts5_api *pApi){ struct Builtin { const char *zFunc; /* Function name (nul-terminated) */ @@ -239674,10 +239522,9 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ fts5_extension_function xFunc;/* Callback function */ void (*xDestroy)(void*); /* Destructor function */ } aBuiltin [] = { - { "snippet", 0, fts5SnippetFunction, 0 }, - { "highlight", 0, fts5HighlightFunction, 0 }, - { "bm25", 0, fts5Bm25Function, 0 }, - { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 }, + { "snippet", 0, fts5SnippetFunction, 0 }, + { "highlight", 0, fts5HighlightFunction, 0 }, + { "bm25", 0, fts5Bm25Function, 0 }, }; int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ @@ -240488,16 +240335,6 @@ static int fts5ConfigParseSpecial( return rc; } - if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){ - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ - *pzErr = sqlite3_mprintf("malformed locale=... directive"); - rc = SQLITE_ERROR; - }else{ - pConfig->bLocale = (zArg[0]=='1'); - } - return rc; - } - if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ const Fts5Enum aDetail[] = { { "none", FTS5_DETAIL_NONE }, @@ -240787,11 +240624,7 @@ static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ if( pConfig ){ int i; if( pConfig->t.pTok ){ - if( pConfig->t.pApi1 ){ - pConfig->t.pApi1->xDelete(pConfig->t.pTok); - }else{ - pConfig->t.pApi2->xDelete(pConfig->t.pTok); - } + pConfig->t.pTokApi->xDelete(pConfig->t.pTok); } sqlite3_free((char*)pConfig->t.azArg); sqlite3_free(pConfig->zDb); @@ -240874,15 +240707,9 @@ static int sqlite3Fts5Tokenize( rc = sqlite3Fts5LoadTokenizer(pConfig); } if( rc==SQLITE_OK ){ - if( pConfig->t.pApi1 ){ - rc = pConfig->t.pApi1->xTokenize( - pConfig->t.pTok, pCtx, flags, pText, nText, xToken - ); - }else{ - rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags, - pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken - ); - } + rc = pConfig->t.pTokApi->xTokenize( + pConfig->t.pTok, pCtx, flags, pText, nText, xToken + ); } } return rc; @@ -241139,10 +240966,13 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){ rc = SQLITE_ERROR; - sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format " - "(found %d, expected %d or %d) - run 'rebuild'", - iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE - ); + if( pConfig->pzErrmsg ){ + assert( 0==*pConfig->pzErrmsg ); + *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format " + "(found %d, expected %d or %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE + ); + } }else{ pConfig->iVersion = iVersion; } @@ -241153,29 +240983,6 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ return rc; } -/* -** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer -** containing the error message created using printf() style formatting -** string zFmt and its trailing arguments. -*/ -static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ - va_list ap; /* ... printf arguments */ - char *zMsg = 0; - - va_start(ap, zFmt); - zMsg = sqlite3_vmprintf(zFmt, ap); - if( pConfig->pzErrmsg ){ - assert( *pConfig->pzErrmsg==0 ); - *pConfig->pzErrmsg = zMsg; - }else{ - sqlite3_free(zMsg); - } - - va_end(ap); -} - - - /* ** 2014 May 31 ** @@ -241232,7 +241039,7 @@ struct Fts5Expr { /* ** eType: -** Expression node type. Usually one of: +** Expression node type. Always one of: ** ** FTS5_AND (nChild, apChild valid) ** FTS5_OR (nChild, apChild valid) @@ -241240,10 +241047,6 @@ struct Fts5Expr { ** FTS5_STRING (pNear valid) ** FTS5_TERM (pNear valid) ** -** An expression node with eType==0 may also exist. It always matches zero -** rows. This is created when a phrase containing no tokens is parsed. -** e.g. "". -** ** iHeight: ** Distance from this node to furthest leaf. This is always 0 for nodes ** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one @@ -241464,12 +241267,11 @@ static int sqlite3Fts5ExprNew( }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); sqlite3Fts5ParserFree(pEngine, fts5ParseFree); - assert( sParse.pExpr || sParse.rc!=SQLITE_OK ); assert_expr_depth_ok(sParse.rc, sParse.pExpr); /* If the LHS of the MATCH expression was a user column, apply the ** implicit column-filter. */ - if( sParse.rc==SQLITE_OK && iColnCol ){ + if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ int n = sizeof(Fts5Colset); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); if( pColset ){ @@ -241486,7 +241288,15 @@ static int sqlite3Fts5ExprNew( sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); }else{ - pNew->pRoot = sParse.pExpr; + if( !sParse.pExpr ){ + const int nByte = sizeof(Fts5ExprNode); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); + if( pNew->pRoot ){ + pNew->pRoot->bEof = 1; + } + }else{ + pNew->pRoot = sParse.pExpr; + } pNew->pIndex = 0; pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; @@ -242304,7 +242114,7 @@ static int fts5ExprNodeTest_STRING( } }else{ Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; - if( pIter->iRowid==iLast ) continue; + if( pIter->iRowid==iLast || pIter->bEof ) continue; bMatch = 0; if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ return rc; @@ -242826,6 +242636,9 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( Fts5ExprNearset *pRet = 0; if( pParse->rc==SQLITE_OK ){ + if( pPhrase==0 ){ + return pNear; + } if( pNear==0 ){ sqlite3_int64 nByte; nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); @@ -243047,7 +242860,6 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( }else if( sCtx.pPhrase->nTerm ){ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } - assert( pParse->apPhrase!=0 ); pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; } @@ -243435,9 +243247,6 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ } } -/* -** Add pSub as a child of p. -*/ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ int ii = p->nChild; if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ @@ -243582,23 +243391,19 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( "fts5: %s queries are not supported (detail!=full)", pNear->nPhrase==1 ? "phrase": "NEAR" ); - sqlite3Fts5ParseNodeFree(pRet); + sqlite3_free(pRet); pRet = 0; - pNear = 0; - assert( pLeft==0 && pRight==0 ); } } }else{ - assert( pNear==0 ); fts5ExprAddChildren(pRet, pLeft); fts5ExprAddChildren(pRet, pRight); - pLeft = pRight = 0; if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){ sqlite3Fts5ParseError(pParse, "fts5 expression tree is too large (maximum depth %d)", SQLITE_FTS5_MAX_EXPR_DEPTH ); - sqlite3Fts5ParseNodeFree(pRet); + sqlite3_free(pRet); pRet = 0; } } @@ -243636,7 +243441,6 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( assert( pRight->eType==FTS5_STRING || pRight->eType==FTS5_TERM || pRight->eType==FTS5_EOF - || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd) ); if( pLeft->eType==FTS5_AND ){ @@ -243650,8 +243454,6 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( ); if( pRight->eType==FTS5_EOF ){ - assert( pParse->apPhrase!=0 ); - assert( pParse->nPhrase>0 ); assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); sqlite3Fts5ParseNodeFree(pRight); pRet = pLeft; @@ -244284,7 +244086,6 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ pNode->iRowid = iRowid; pNode->bEof = 0; switch( pNode->eType ){ - case 0: case FTS5_TERM: case FTS5_STRING: return (pNode->pNear->apPhrase[0]->poslist.n>0); @@ -245868,12 +245669,11 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); - int szData = (sizeof(Fts5Data) + 7) & ~7; - sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING; + sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; - aOut = pRet->p = (u8*)pRet + szData; + aOut = pRet->p = (u8*)&pRet[1]; }else{ rc = SQLITE_NOMEM; } @@ -245896,7 +245696,6 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ } assert( (pRet==0)==(p->rc!=SQLITE_OK) ); - assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) ); return pRet; } @@ -246294,7 +246093,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){ if( p->pDataVersion==0 ){ p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb) - ); + ); if( p->rc ) return 0; } @@ -247222,7 +247021,7 @@ static void fts5SegIterNext_None( if( iOffiEndofDoclist ){ /* Next entry is on the current page */ - u64 iDelta; + i64 iDelta; iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); pIter->iLeafOffset = iOff; pIter->iRowid += iDelta; @@ -254212,28 +254011,11 @@ struct Fts5Auxiliary { ** Each tokenizer module registered with the FTS5 module is represented ** by an object of the following type. All such objects are stored as part ** of the Fts5Global.pTok list. -** -** bV2Native: -** True if the tokenizer was registered using xCreateTokenizer_v2(), false -** for xCreateTokenizer(). If this variable is true, then x2 is populated -** with the routines as supplied by the caller and x1 contains synthesized -** wrapper routines. In this case the user-data pointer passed to -** x1.xCreate should be a pointer to the Fts5TokenizerModule structure, -** not a copy of pUserData. -** -** Of course, if bV2Native is false, then x1 contains the real routines and -** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule -** object should be passed to x2.xCreate. -** -** The synthesized wrapper routines are necessary for xFindTokenizer(_v2) -** calls. */ struct Fts5TokenizerModule { char *zName; /* Name of tokenizer */ void *pUserData; /* User pointer passed to xCreate() */ - int bV2Native; /* True if v2 native tokenizer */ - fts5_tokenizer x1; /* Tokenizer functions */ - fts5_tokenizer_v2 x2; /* V2 tokenizer functions */ + fts5_tokenizer x; /* Tokenizer functions */ void (*xDestroy)(void*); /* Destructor function */ Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; @@ -254321,7 +254103,7 @@ struct Fts5Cursor { Fts5Auxiliary *pAux; /* Currently executing extension function */ Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ - /* Cache used by auxiliary API functions xInst() and xInstCount() */ + /* Cache used by auxiliary functions xInst() and xInstCount() */ Fts5PoslistReader *aInstIter; /* One for each phrase */ int nInstAlloc; /* Size of aInst[] array (entries / 3) */ int nInstCount; /* Number of phrase instances */ @@ -254356,12 +254138,6 @@ struct Fts5Cursor { #define BitFlagAllTest(x,y) (((x) & (y))==(y)) #define BitFlagTest(x,y) (((x) & (y))!=0) -/* -** The subtype value and header bytes used by fts5_locale(). -*/ -#define FTS5_LOCALE_SUBTYPE ((unsigned int)'L') -#define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB" - /* ** Macros to Set(), Clear() and Test() cursor flags. @@ -254536,7 +254312,8 @@ static int fts5InitVtab( /* Load the initial configuration */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1); + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + sqlite3Fts5IndexRollback(pTab->p.pIndex); } if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ @@ -254738,7 +254515,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ if( bSeenRank ) continue; idxStr[iIdxStr++] = 'r'; bSeenRank = 1; - }else{ + }else if( iCol>=0 ){ nSeenMatch++; idxStr[iIdxStr++] = 'M'; sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); @@ -255124,7 +254901,7 @@ static int fts5PrepareStatement( rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, &pRet, 0); if( rc!=SQLITE_OK ){ - sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db)); + *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); } sqlite3_free(zSql); } @@ -255348,200 +255125,6 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ return iDefault; } -/* -** Set the error message on the virtual table passed as the first argument. -*/ -static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ - va_list ap; /* ... printf arguments */ - va_start(ap, zFormat); - sqlite3_free(p->p.base.zErrMsg); - p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); - va_end(ap); -} - -/* -** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale -** specified by pLocale/nLocale. The buffer indicated by pLocale must remain -** valid until after the final call to sqlite3Fts5Tokenize() that will use -** the locale. -*/ -static void fts5SetLocale( - Fts5Config *pConfig, - const char *zLocale, - int nLocale -){ - Fts5TokenizerConfig *pT = &pConfig->t; - pT->pLocale = zLocale; - pT->nLocale = nLocale; -} - -/* -** Clear any locale configured by an earlier call to fts5SetLocale() or -** sqlite3Fts5ExtractText(). -*/ -static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){ - fts5SetLocale(pConfig, 0, 0); -} - -/* -** This function is used to extract utf-8 text from an sqlite3_value. This -** is usually done in order to tokenize it. For example, when: -** -** * a value is written to an fts5 table, -** * a value is deleted from an FTS5_CONTENT_NORMAL table, -** * a value containing a query expression is passed to xFilter() -** -** and so on. -** -** This function handles 2 cases: -** -** 1) Ordinary values. The text can be extracted from these using -** sqlite3_value_text(). -** -** 2) Combination text/locale blobs created by fts5_locale(). There -** are several cases for these: -** -** * Blobs tagged with FTS5_LOCALE_SUBTYPE. -** * Blobs read from the content table of a locale=1 external-content -** table, and -** * Blobs read from the content table of a locale=1 regular -** content table. -** -** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER -** header. It is an error if a blob with the subtype or a blob read -** from the content table of an external content table does not have -** the required header. A blob read from the content table of a regular -** locale=1 table does not have the header. This is to save space. -** -** If successful, SQLITE_OK is returned and output parameters (*ppText) -** and (*pnText) are set to point to a buffer containing the extracted utf-8 -** text and its length in bytes, respectively. The buffer is not -** nul-terminated. It has the same lifetime as the sqlite3_value object -** from which it is extracted. -** -** Parameter bContent must be true if the value was read from an indexed -** column (i.e. not UNINDEXED) of the on disk content. -** -** If pbResetTokenizer is not NULL and if case (2) is used, then -** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls -** use the locale. In this case (*pbResetTokenizer) is set to true before -** returning, to indicate that the caller must call sqlite3Fts5ClearLocale() -** to clear the locale after tokenizing the text. -*/ -static int sqlite3Fts5ExtractText( - Fts5Config *pConfig, - sqlite3_value *pVal, /* Value to extract text from */ - int bContent, /* True if indexed table content */ - int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */ - const char **ppText, /* OUT: Pointer to text buffer */ - int *pnText /* OUT: Size of (*ppText) in bytes */ -){ - const char *pText = 0; - int nText = 0; - int rc = SQLITE_OK; - int bDecodeBlob = 0; - - assert( pbResetTokenizer==0 || *pbResetTokenizer==0 ); - assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE ); - assert( bContent==0 || sqlite3_value_subtype(pVal)==0 ); - - if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ - if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE - || (bContent && pConfig->bLocale) - ){ - bDecodeBlob = 1; - } - } - - if( bDecodeBlob ){ - const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; - const u8 *pBlob = sqlite3_value_blob(pVal); - int nBlob = sqlite3_value_bytes(pVal); - - /* Unless this blob was read from the %_content table of an - ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale() - ** header. Check for this. If it is not found, return an error. */ - if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){ - if( nBlobbLock==0 ); + if( pConfig->bLock ){ + pTab->p.base.zErrMsg = sqlite3_mprintf( + "recursively defined fts5 content table" + ); + return SQLITE_ERROR; + } + if( pCsr->ePlan ){ fts5FreeCursorComponents(pCsr); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); @@ -255600,14 +255189,8 @@ static int fts5FilterMethod( pRank = apVal[i]; break; case 'M': { - char *zText = 0; - int bFreeAndReset = 0; - int bInternal = 0; - - rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset); - if( rc!=SQLITE_OK ) goto filter_out; + const char *zText = (const char*)sqlite3_value_text(apVal[i]); if( zText==0 ) zText = ""; - iCol = 0; do{ iCol = iCol*10 + (idxStr[iIdxStr]-'0'); @@ -255619,7 +255202,7 @@ static int fts5FilterMethod( ** indicates that the MATCH expression is not a full text query, ** but a request for an internal parameter. */ rc = fts5SpecialMatch(pTab, pCsr, &zText[1]); - bInternal = 1; + goto filter_out; }else{ char **pzErr = &pTab->p.base.zErrMsg; rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); @@ -255627,15 +255210,9 @@ static int fts5FilterMethod( rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); pExpr = 0; } + if( rc!=SQLITE_OK ) goto filter_out; } - if( bFreeAndReset ){ - sqlite3_free(zText); - sqlite3Fts5ClearLocale(pConfig); - } - - if( bInternal || rc!=SQLITE_OK ) goto filter_out; - break; } case 'L': @@ -255723,7 +255300,9 @@ static int fts5FilterMethod( } } }else if( pConfig->zContent==0 ){ - fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName); + *pConfig->pzErrmsg = sqlite3_mprintf( + "%s: table does not support scanning", pConfig->zName + ); rc = SQLITE_ERROR; }else{ /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup @@ -255798,7 +255377,6 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ return SQLITE_OK; } - /* ** If the cursor requires seeking (bSeekRequired flag is set), seek it. ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. @@ -255835,13 +255413,8 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK ){ rc = FTS5_CORRUPT; - fts5SetVtabError((Fts5FullTable*)pTab, - "fts5: missing row %lld from content table %s", - fts5CursorRowid(pCsr), - pTab->pConfig->zContent - ); }else if( pTab->pConfig->pzErrmsg ){ - fts5SetVtabError((Fts5FullTable*)pTab, + *pTab->pConfig->pzErrmsg = sqlite3_mprintf( "%s", sqlite3_errmsg(pTab->pConfig->db) ); } @@ -255850,6 +255423,14 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ return rc; } +static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + assert( p->p.base.zErrMsg==0 ); + p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + /* ** This function is called to handle an FTS INSERT command. In other words, ** an INSERT statement of the form: @@ -255943,7 +255524,7 @@ static int fts5SpecialDelete( int eType1 = sqlite3_value_type(apVal[1]); if( eType1==SQLITE_INTEGER ){ sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); } return rc; } @@ -256067,7 +255648,7 @@ static int fts5UpdateMethod( /* DELETE */ else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); bUpdateOrDelete = 1; } @@ -256075,31 +255656,16 @@ static int fts5UpdateMethod( else{ int eType1 = sqlite3_value_numeric_type(apVal[1]); - /* Ensure that no fts5_locale() values are written to locale=0 tables. - ** And that no blobs except fts5_locale() blobs are written to indexed - ** (i.e. not UNINDEXED) columns of locale=1 tables. */ - int ii; - for(ii=0; iinCol; ii++){ - if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){ - int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE); - if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0) - || (pConfig->bLocale==0 && bSub) - ){ - if( pConfig->bLocale==0 ){ - fts5SetVtabError(pTab, "fts5_locale() requires locale=1"); - } - rc = SQLITE_MISMATCH; - goto update_out; - } - } + if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ + rc = SQLITE_MISMATCH; } - if( eType0!=SQLITE_INTEGER ){ + else if( eType0!=SQLITE_INTEGER ){ /* An INSERT statement. If the conflict-mode is REPLACE, first remove ** the current entry (if any). */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); bUpdateOrDelete = 1; } fts5StorageInsert(&rc, pTab, apVal, pRowid); @@ -256109,35 +255675,28 @@ static int fts5UpdateMethod( else{ i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ - if( eType1!=SQLITE_INTEGER ){ - rc = SQLITE_MISMATCH; - }else if( iOld!=iNew ){ + if( eType1==SQLITE_INTEGER && iOld!=iNew ){ if( eConflict==SQLITE_REPLACE ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); }else{ - rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld); + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid); - } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); } } }else{ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); fts5StorageInsert(&rc, pTab, apVal, pRowid); } bUpdateOrDelete = 1; - sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage); } - } } @@ -256154,7 +255713,6 @@ static int fts5UpdateMethod( } } - update_out: sqlite3Fts5IndexCloseReader(pTab->p.pIndex); pTab->p.pConfig->pzErrmsg = 0; return rc; @@ -256177,11 +255735,9 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ ** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ - int rc = fts5NewTransaction((Fts5FullTable*)pVtab); - if( rc==SQLITE_OK ){ - fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); - } - return rc; + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); + fts5NewTransaction((Fts5FullTable*)pVtab); + return SQLITE_OK; } /* @@ -256235,40 +255791,17 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); } -/* -** Implementation of xTokenize_v2() API. -*/ -static int fts5ApiTokenize_v2( +static int fts5ApiTokenize( Fts5Context *pCtx, const char *pText, int nText, - const char *pLoc, int nLoc, void *pUserData, int (*xToken)(void*, int, const char*, int, int, int) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - int rc = SQLITE_OK; - - fts5SetLocale(pTab->pConfig, pLoc, nLoc); - rc = sqlite3Fts5Tokenize(pTab->pConfig, - FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken + return sqlite3Fts5Tokenize( + pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken ); - fts5SetLocale(pTab->pConfig, 0, 0); - - return rc; -} - -/* -** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0 -** passed as the locale. -*/ -static int fts5ApiTokenize( - Fts5Context *pCtx, - const char *pText, int nText, - void *pUserData, - int (*xToken)(void*, int, const char*, int, int, int) -){ - return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken); } static int fts5ApiPhraseCount(Fts5Context *pCtx){ @@ -256290,37 +255823,28 @@ static int fts5ApiColumnText( int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - - assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); if( iCol<0 || iCol>=pTab->pConfig->nCol ){ rc = SQLITE_RANGE; - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){ + }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) + || pCsr->ePlan==FTS5_PLAN_SPECIAL + ){ *pz = 0; *pn = 0; }else{ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ - Fts5Config *pConfig = pTab->pConfig; - int bContent = (pConfig->abUnindexed[iCol]==0); - sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); - sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn); + *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); + *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); } } return rc; } -/* -** This is called by various API functions - xInst, xPhraseFirst, -** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase -** of the current row. This function works for both detail=full tables (in -** which case the position-list was read from the fts index) or for other -** detail= modes if the row content is available. -*/ static int fts5CsrPoslist( - Fts5Cursor *pCsr, /* Fts5 cursor object */ - int iPhrase, /* Phrase to find position list for */ - const u8 **pa, /* OUT: Pointer to position list buffer */ - int *pn /* OUT: Size of (*pa) in bytes */ + Fts5Cursor *pCsr, + int iPhrase, + const u8 **pa, + int *pn ){ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; int rc = SQLITE_OK; @@ -256328,34 +255852,20 @@ static int fts5CsrPoslist( if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ rc = SQLITE_RANGE; - }else if( pConfig->eDetail!=FTS5_DETAIL_FULL - && pConfig->eContent==FTS5_CONTENT_NONE - ){ - *pa = 0; - *pn = 0; - return SQLITE_OK; }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ Fts5PoslistPopulator *aPopulator; int i; - aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); if( aPopulator==0 ) rc = SQLITE_NOMEM; - if( rc==SQLITE_OK ){ - rc = fts5SeekCursor(pCsr, 0); - } for(i=0; inCol && rc==SQLITE_OK; i++){ - sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); - const char *z = 0; - int n = 0; - int bReset = 0; - rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); + int n; const char *z; + rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprPopulatePoslists( pConfig, pCsr->pExpr, aPopulator, i, z, n ); } - if( bReset ) sqlite3Fts5ClearLocale(pConfig); } sqlite3_free(aPopulator); @@ -256380,6 +255890,7 @@ static int fts5CsrPoslist( *pn = 0; } + return rc; } @@ -256448,8 +255959,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); - assert( aInst[1]>=0 ); - if( aInst[1]>=nCol ){ + if( aInst[1]<0 || aInst[1]>=nCol ){ rc = FTS5_CORRUPT; break; } @@ -256536,21 +256046,16 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ } }else{ int i; - rc = fts5SeekCursor(pCsr, 0); for(i=0; rc==SQLITE_OK && inCol; i++){ if( pConfig->abUnindexed[i]==0 ){ - const char *z = 0; - int n = 0; - int bReset = 0; - sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); - + const char *z; int n; + void *p = (void*)(&pCsr->aColumnSize[i]); pCsr->aColumnSize[i] = 0; - rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); + rc = fts5ApiColumnText(pCtx, i, &z, &n); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX, - z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb + rc = sqlite3Fts5Tokenize( + pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb ); - if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } } @@ -256631,10 +256136,11 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ } static void fts5ApiPhraseNext( - Fts5Context *pCtx, + Fts5Context *pUnused, Fts5PhraseIter *pIter, int *piCol, int *piOff ){ + UNUSED_PARAM(pUnused); if( pIter->a>=pIter->b ){ *piCol = -1; *piOff = -1; @@ -256642,12 +256148,8 @@ static void fts5ApiPhraseNext( int iVal; pIter->a += fts5GetVarint32(pIter->a, iVal); if( iVal==1 ){ - /* Avoid returning a (*piCol) value that is too large for the table, - ** even if the position-list is corrupt. The caller might not be - ** expecting it. */ - int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol; pIter->a += fts5GetVarint32(pIter->a, iVal); - *piCol = (iVal>=nCol ? nCol-1 : iVal); + *piCol = iVal; *piOff = 0; pIter->a += fts5GetVarint32(pIter->a, iVal); } @@ -256797,71 +256299,8 @@ static int fts5ApiQueryPhrase(Fts5Context*, int, void*, int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) ); -/* -** The xColumnLocale() API. -*/ -static int fts5ApiColumnLocale( - Fts5Context *pCtx, - int iCol, - const char **pzLocale, - int *pnLocale -){ - int rc = SQLITE_OK; - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; - - *pzLocale = 0; - *pnLocale = 0; - - assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); - if( iCol<0 || iCol>=pConfig->nCol ){ - rc = SQLITE_RANGE; - }else if( - pConfig->abUnindexed[iCol]==0 - && pConfig->eContent!=FTS5_CONTENT_NONE - && pConfig->bLocale - ){ - rc = fts5SeekCursor(pCsr, 0); - if( rc==SQLITE_OK ){ - /* Load the value into pVal. pVal is a locale/text pair iff: - ** - ** 1) It is an SQLITE_BLOB, and - ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the - ** value was loaded from an FTS5_CONTENT_NORMAL table, and - ** 3) It does not begin with an 0x00 byte. - */ - sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); - if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ - const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); - int nBlob = sqlite3_value_bytes(pVal); - if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ - const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; - if( nBlobpAux==0 ); - assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); pCsr->pAux = pAux; pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv); pCsr->pAux = 0; @@ -256949,21 +256385,6 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){ return pCsr; } -/* -** Parameter zFmt is a printf() style formatting string. This function -** formats it using the trailing arguments and returns the result as -** an error message to the context passed as the first argument. -*/ -static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){ - char *zErr = 0; - va_list ap; - va_start(ap, zFmt); - zErr = sqlite3_vmprintf(zFmt, ap); - sqlite3_result_error(pCtx, zErr, -1); - sqlite3_free(zErr); - va_end(ap); -} - static void fts5ApiCallback( sqlite3_context *context, int argc, @@ -256979,13 +256400,12 @@ static void fts5ApiCallback( iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); - if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){ - fts5ResultError(context, "no such cursor: %lld", iCsrId); + if( pCsr==0 || pCsr->ePlan==0 ){ + char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); }else{ - sqlite3_vtab *pTab = pCsr->base.pVtab; fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); - sqlite3_free(pTab->zErrMsg); - pTab->zErrMsg = 0; } } @@ -257074,57 +256494,6 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ return rc; } -/* -** Value pVal was read from column iCol of the FTS5 table. This function -** returns it to the owner of pCtx via a call to an sqlite3_result_xxx() -** function. This function deals with the same cases as -** sqlite3Fts5ExtractText(): -** -** 1) Ordinary values. These can be returned using sqlite3_result_value(). -** -** 2) Blobs from fts5_locale(). The text is extracted from these and -** returned via sqlite3_result_text(). The locale is discarded. -*/ -static void fts5ExtractValueFromColumn( - sqlite3_context *pCtx, - Fts5Config *pConfig, - int iCol, - sqlite3_value *pVal -){ - assert( pConfig->eContent!=FTS5_CONTENT_NONE ); - - if( pConfig->bLocale - && sqlite3_value_type(pVal)==SQLITE_BLOB - && pConfig->abUnindexed[iCol]==0 - ){ - const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; - const u8 *pBlob = sqlite3_value_blob(pVal); - int nBlob = sqlite3_value_bytes(pVal); - int ii; - - if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ - if( nBlobiCsrId); }else if( iCol==pConfig->nCol+1 ){ - /* The value of the "rank" column. */ + /* The value of the "rank" column. */ if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ fts5PoslistBlob(pCtx, pCsr); }else if( @@ -257166,27 +256535,20 @@ static int fts5ColumnMethod( fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } - }else{ - /* A column created by the user containing values. */ - int bNochange = sqlite3_vtab_nochange(pCtx); - - if( fts5IsContentless(pTab) ){ - if( bNochange && pConfig->bContentlessDelete ){ - fts5ResultError(pCtx, "cannot UPDATE a subset of " - "columns on fts5 contentless-delete table: %s", pConfig->zName - ); - } - }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){ - pConfig->pzErrmsg = &pTab->p.base.zErrMsg; - rc = fts5SeekCursor(pCsr, 1); - if( rc==SQLITE_OK ){ - sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); - fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal); - } - pConfig->pzErrmsg = 0; + }else if( !fts5IsContentless(pTab) ){ + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; + rc = fts5SeekCursor(pCsr, 1); + if( rc==SQLITE_OK ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } + pConfig->pzErrmsg = 0; + }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){ + char *zErr = sqlite3_mprintf("cannot UPDATE a subset of " + "columns on fts5 contentless-delete table: %s", pConfig->zName + ); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); } - return rc; } @@ -257326,210 +256688,47 @@ static int fts5CreateAux( } /* -** This function is used by xCreateTokenizer_v2() and xCreateTokenizer(). -** It allocates and partially populates a new Fts5TokenizerModule object. -** The new object is already linked into the Fts5Global context before -** returning. -** -** If successful, SQLITE_OK is returned and a pointer to the new -** Fts5TokenizerModule object returned via output parameter (*ppNew). All -** that is required is for the caller to fill in the methods in -** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native -** as appropriate. -** -** If an error occurs, an SQLite error code is returned and the final value -** of (*ppNew) undefined. +** Register a new tokenizer. This is the implementation of the +** fts5_api.xCreateTokenizer() method. */ -static int fts5NewTokenizerModule( - Fts5Global *pGlobal, /* Global context (one per db handle) */ +static int fts5CreateTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ const char *zName, /* Name of new function */ void *pUserData, /* User data for aux. function */ - void(*xDestroy)(void*), /* Destructor for pUserData */ - Fts5TokenizerModule **ppNew + fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ ){ - int rc = SQLITE_OK; + Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; - sqlite3_int64 nName; /* Size of zName and its \0 terminator */ - sqlite3_int64 nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ + int rc = SQLITE_OK; nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; - *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte); + pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); if( pNew ){ + memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; + pNew->x = *pTokenizer; pNew->xDestroy = xDestroy; pNew->pNext = pGlobal->pTok; pGlobal->pTok = pNew; if( pNew->pNext==0 ){ pGlobal->pDfltTok = pNew; } - } - - return rc; -} - -/* -** An instance of this type is used as the Fts5Tokenizer object for -** wrapper tokenizers - those that provide access to a v1 tokenizer via -** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer -** via the fts5_tokenizer API. -*/ -typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer; -struct Fts5VtoVTokenizer { - int bV2Native; /* True if v2 native tokenizer */ - fts5_tokenizer x1; /* Tokenizer functions */ - fts5_tokenizer_v2 x2; /* V2 tokenizer functions */ - Fts5Tokenizer *pReal; -}; - -/* -** Create a wrapper tokenizer. The context argument pCtx points to the -** Fts5TokenizerModule object. -*/ -static int fts5VtoVCreate( - void *pCtx, - const char **azArg, - int nArg, - Fts5Tokenizer **ppOut -){ - Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx; - Fts5VtoVTokenizer *pNew = 0; - int rc = SQLITE_OK; - - pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew)); - if( rc==SQLITE_OK ){ - pNew->x1 = pMod->x1; - pNew->x2 = pMod->x2; - pNew->bV2Native = pMod->bV2Native; - if( pMod->bV2Native ){ - rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); - }else{ - rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); - } - if( rc!=SQLITE_OK ){ - sqlite3_free(pNew); - pNew = 0; - } - } - - *ppOut = (Fts5Tokenizer*)pNew; - return rc; -} - -/* -** Delete an Fts5VtoVTokenizer wrapper tokenizer. -*/ -static void fts5VtoVDelete(Fts5Tokenizer *pTok){ - Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; - if( p ){ - if( p->bV2Native ){ - p->x2.xDelete(p->pReal); - }else{ - p->x1.xDelete(p->pReal); - } - sqlite3_free(p); - } -} - - -/* -** xTokenizer method for a wrapper tokenizer that offers the v1 interface -** (no support for locales). -*/ -static int fts5V1toV2Tokenize( - Fts5Tokenizer *pTok, - void *pCtx, int flags, - const char *pText, int nText, - int (*xToken)(void*, int, const char*, int, int, int) -){ - Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; - assert( p->bV2Native ); - return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken); -} - -/* -** xTokenizer method for a wrapper tokenizer that offers the v2 interface -** (with locale support). -*/ -static int fts5V2toV1Tokenize( - Fts5Tokenizer *pTok, - void *pCtx, int flags, - const char *pText, int nText, - const char *pLocale, int nLocale, - int (*xToken)(void*, int, const char*, int, int, int) -){ - Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; - assert( p->bV2Native==0 ); - UNUSED_PARAM2(pLocale,nLocale); - return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken); -} - -/* -** Register a new tokenizer. This is the implementation of the -** fts5_api.xCreateTokenizer_v2() method. -*/ -static int fts5CreateTokenizer_v2( - fts5_api *pApi, /* Global context (one per db handle) */ - const char *zName, /* Name of new function */ - void *pUserData, /* User data for aux. function */ - fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */ - void(*xDestroy)(void*) /* Destructor for pUserData */ -){ - Fts5Global *pGlobal = (Fts5Global*)pApi; - int rc = SQLITE_OK; - - if( pTokenizer->iVersion>2 ){ - rc = SQLITE_ERROR; }else{ - Fts5TokenizerModule *pNew = 0; - rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew); - if( pNew ){ - pNew->x2 = *pTokenizer; - pNew->bV2Native = 1; - pNew->x1.xCreate = fts5VtoVCreate; - pNew->x1.xTokenize = fts5V1toV2Tokenize; - pNew->x1.xDelete = fts5VtoVDelete; - } + rc = SQLITE_NOMEM; } return rc; } -/* -** The fts5_api.xCreateTokenizer() method. -*/ -static int fts5CreateTokenizer( - fts5_api *pApi, /* Global context (one per db handle) */ - const char *zName, /* Name of new function */ - void *pUserData, /* User data for aux. function */ - fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ - void(*xDestroy)(void*) /* Destructor for pUserData */ -){ - Fts5TokenizerModule *pNew = 0; - int rc = SQLITE_OK; - - rc = fts5NewTokenizerModule( - (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew - ); - if( pNew ){ - pNew->x1 = *pTokenizer; - pNew->x2.xCreate = fts5VtoVCreate; - pNew->x2.xTokenize = fts5V2toV1Tokenize; - pNew->x2.xDelete = fts5VtoVDelete; - } - return rc; -} - -/* -** Search the global context passed as the first argument for a tokenizer -** module named zName. If found, return a pointer to the Fts5TokenizerModule -** object. Otherwise, return NULL. -*/ static Fts5TokenizerModule *fts5LocateTokenizer( - Fts5Global *pGlobal, /* Global (one per db handle) object */ - const char *zName /* Name of tokenizer module to find */ + Fts5Global *pGlobal, + const char *zName ){ Fts5TokenizerModule *pMod = 0; @@ -257544,36 +256743,6 @@ static Fts5TokenizerModule *fts5LocateTokenizer( return pMod; } -/* -** Find a tokenizer. This is the implementation of the -** fts5_api.xFindTokenizer_v2() method. -*/ -static int fts5FindTokenizer_v2( - fts5_api *pApi, /* Global context (one per db handle) */ - const char *zName, /* Name of tokenizer */ - void **ppUserData, - fts5_tokenizer_v2 **ppTokenizer /* Populate this object */ -){ - int rc = SQLITE_OK; - Fts5TokenizerModule *pMod; - - pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); - if( pMod ){ - if( pMod->bV2Native ){ - *ppUserData = pMod->pUserData; - }else{ - *ppUserData = (void*)pMod; - } - *ppTokenizer = &pMod->x2; - }else{ - *ppTokenizer = 0; - *ppUserData = 0; - rc = SQLITE_ERROR; - } - - return rc; -} - /* ** Find a tokenizer. This is the implementation of the ** fts5_api.xFindTokenizer() method. @@ -257589,75 +256758,66 @@ static int fts5FindTokenizer( pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); if( pMod ){ - if( pMod->bV2Native==0 ){ - *ppUserData = pMod->pUserData; - }else{ - *ppUserData = (void*)pMod; - } - *pTokenizer = pMod->x1; + *pTokenizer = pMod->x; + *ppUserData = pMod->pUserData; }else{ - memset(pTokenizer, 0, sizeof(*pTokenizer)); - *ppUserData = 0; + memset(pTokenizer, 0, sizeof(fts5_tokenizer)); rc = SQLITE_ERROR; } return rc; } -/* -** Attempt to instantiate the tokenizer. -*/ -static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){ - const char **azArg = pConfig->t.azArg; - const int nArg = pConfig->t.nArg; - Fts5TokenizerModule *pMod = 0; +int fts5GetTokenizer( + Fts5Global *pGlobal, + const char **azArg, + int nArg, + Fts5Config *pConfig, + char **pzErr +){ + Fts5TokenizerModule *pMod; int rc = SQLITE_OK; - pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]); + pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); if( pMod==0 ){ assert( nArg>0 ); rc = SQLITE_ERROR; - sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]); + if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); }else{ - int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0; - if( pMod->bV2Native ){ - xCreate = pMod->x2.xCreate; - pConfig->t.pApi2 = &pMod->x2; - }else{ - pConfig->t.pApi1 = &pMod->x1; - xCreate = pMod->x1.xCreate; - } - - rc = xCreate(pMod->pUserData, - (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok + rc = pMod->x.xCreate( + pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok ); - + pConfig->t.pTokApi = &pMod->x; if( rc!=SQLITE_OK ){ - if( rc!=SQLITE_NOMEM ){ - sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor"); + if( pzErr && rc!=SQLITE_NOMEM ){ + *pzErr = sqlite3_mprintf("error in tokenizer constructor"); } - }else if( pMod->bV2Native==0 ){ + }else{ pConfig->t.ePattern = sqlite3Fts5TokenizerPattern( - pMod->x1.xCreate, pConfig->t.pTok + pMod->x.xCreate, pConfig->t.pTok ); } } if( rc!=SQLITE_OK ){ - pConfig->t.pApi1 = 0; - pConfig->t.pApi2 = 0; + pConfig->t.pTokApi = 0; pConfig->t.pTok = 0; } return rc; } - /* -** xDestroy callback passed to sqlite3_create_module(). This is invoked -** when the db handle is being closed. Free memory associated with -** tokenizers and aux functions registered with this db handle. +** Attempt to instantiate the tokenizer. */ +static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){ + return fts5GetTokenizer( + pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg, + pConfig, pConfig->pzErrmsg + ); +} + + static void fts5ModuleDestroy(void *pCtx){ Fts5TokenizerModule *pTok, *pNextTok; Fts5Auxiliary *pAux, *pNextAux; @@ -257678,10 +256838,6 @@ static void fts5ModuleDestroy(void *pCtx){ sqlite3_free(pGlobal); } -/* -** Implementation of the fts5() function used by clients to obtain the -** API pointer. -*/ static void fts5Fts5Func( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ @@ -257705,70 +256861,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-11-01 15:25:34 492a0a85438586a8ccd9629239304f4df3f2c6391ec05dd9837b7a553313d632", -1, SQLITE_TRANSIENT); -} - -/* -** Implementation of fts5_locale(LOCALE, TEXT) function. -** -** If parameter LOCALE is NULL, or a zero-length string, then a copy of -** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as -** text, and the value returned is a blob consisting of: -** -** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER). -** * The LOCALE, as utf-8 text, followed by -** * 0x00, followed by -** * The TEXT, as utf-8 text. -** -** There is no final nul-terminator following the TEXT value. -*/ -static void fts5LocaleFunc( - sqlite3_context *pCtx, /* Function call context */ - int nArg, /* Number of args */ - sqlite3_value **apArg /* Function arguments */ -){ - const char *zLocale = 0; - int nLocale = 0; - const char *zText = 0; - int nText = 0; - - assert( nArg==2 ); - UNUSED_PARAM(nArg); - - zLocale = (const char*)sqlite3_value_text(apArg[0]); - nLocale = sqlite3_value_bytes(apArg[0]); - - zText = (const char*)sqlite3_value_text(apArg[1]); - nText = sqlite3_value_bytes(apArg[1]); - - if( zLocale==0 || zLocale[0]=='\0' ){ - sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT); - }else{ - u8 *pBlob = 0; - u8 *pCsr = 0; - int nBlob = 0; - const int nHdr = 4; - assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 ); - - nBlob = nHdr + nLocale + 1 + nText; - pBlob = (u8*)sqlite3_malloc(nBlob); - if( pBlob==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - - pCsr = pBlob; - memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr); - pCsr += nHdr; - memcpy(pCsr, zLocale, nLocale); - pCsr += nLocale; - (*pCsr++) = 0x00; - if( zText ) memcpy(pCsr, zText, nText); - assert( &pCsr[nText]==&pBlob[nBlob] ); - - sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free); - sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE); - } + sqlite3_result_text(pCtx, "fts5: 2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f", -1, SQLITE_TRANSIENT); } /* @@ -257863,12 +256956,10 @@ static int fts5Init(sqlite3 *db){ void *p = (void*)pGlobal; memset(pGlobal, 0, sizeof(Fts5Global)); pGlobal->db = db; - pGlobal->api.iVersion = 3; + pGlobal->api.iVersion = 2; pGlobal->api.xCreateFunction = fts5CreateAux; pGlobal->api.xCreateTokenizer = fts5CreateTokenizer; pGlobal->api.xFindTokenizer = fts5FindTokenizer; - pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2; - pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2; rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); @@ -257887,13 +256978,6 @@ static int fts5Init(sqlite3 *db){ p, fts5SourceIdFunc, 0, 0 ); } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function( - db, "fts5_locale", 2, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE, - p, fts5LocaleFunc, 0, 0 - ); - } } /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file @@ -257968,40 +257052,13 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){ /* #include "fts5Int.h" */ -/* -** pSavedRow: -** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it -** does a by-rowid lookup to retrieve a single row from the %_content -** table or equivalent external-content table/view. -** -** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original -** values for a row being UPDATEd. In that case, the SQL statement is -** not reset and pSavedRow is set to point at it. This is so that the -** insert operation that follows the delete may access the original -** row values for any new values for which sqlite3_value_nochange() returns -** true. i.e. if the user executes: -** -** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1); -** ... -** UPDATE fts SET a=?, b=? WHERE rowid=?; -** -** then the value passed to the xUpdate() method of this table as the -** new.c value is an sqlite3_value_nochange() value. So in this case it -** must be read from the saved row stored in Fts5Storage.pSavedRow. -** -** This is necessary - using sqlite3_value_nochange() instead of just having -** SQLite pass the original value back via xUpdate() - so as not to discard -** any locale information associated with such values. -** -*/ struct Fts5Storage { Fts5Config *pConfig; Fts5Index *pIndex; int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */ i64 nTotalRow; /* Total number of rows in FTS table */ i64 *aTotalSize; /* Total sizes of each column */ - sqlite3_stmt *pSavedRow; - sqlite3_stmt *aStmt[12]; + sqlite3_stmt *aStmt[11]; }; @@ -258015,15 +257072,14 @@ struct Fts5Storage { # error "FTS5_STMT_LOOKUP mismatch" #endif -#define FTS5_STMT_LOOKUP2 3 -#define FTS5_STMT_INSERT_CONTENT 4 -#define FTS5_STMT_REPLACE_CONTENT 5 -#define FTS5_STMT_DELETE_CONTENT 6 -#define FTS5_STMT_REPLACE_DOCSIZE 7 -#define FTS5_STMT_DELETE_DOCSIZE 8 -#define FTS5_STMT_LOOKUP_DOCSIZE 9 -#define FTS5_STMT_REPLACE_CONFIG 10 -#define FTS5_STMT_SCAN 11 +#define FTS5_STMT_INSERT_CONTENT 3 +#define FTS5_STMT_REPLACE_CONTENT 4 +#define FTS5_STMT_DELETE_CONTENT 5 +#define FTS5_STMT_REPLACE_DOCSIZE 6 +#define FTS5_STMT_DELETE_DOCSIZE 7 +#define FTS5_STMT_LOOKUP_DOCSIZE 8 +#define FTS5_STMT_REPLACE_CONFIG 9 +#define FTS5_STMT_SCAN 10 /* ** Prepare the two insert statements - Fts5Storage.pInsertContent and @@ -258053,7 +257109,6 @@ static int fts5StorageGetStmt( "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC", "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC", "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */ - "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */ "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */ @@ -258069,8 +257124,6 @@ static int fts5StorageGetStmt( Fts5Config *pC = p->pConfig; char *zSql = 0; - assert( ArraySize(azStmt)==ArraySize(p->aStmt) ); - switch( eStmt ){ case FTS5_STMT_SCAN: zSql = sqlite3_mprintf(azStmt[eStmt], @@ -258087,7 +257140,6 @@ static int fts5StorageGetStmt( break; case FTS5_STMT_LOOKUP: - case FTS5_STMT_LOOKUP2: zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, pC->zContent, pC->zContentRowid ); @@ -258134,7 +257186,7 @@ static int fts5StorageGetStmt( rc = SQLITE_NOMEM; }else{ int f = SQLITE_PREPARE_PERSISTENT; - if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB; + if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; p->pConfig->bLock++; rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); p->pConfig->bLock--; @@ -258383,49 +257435,15 @@ static int fts5StorageInsertCallback( return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); } -/* -** This function is used as part of an UPDATE statement that modifies the -** rowid of a row. In that case, this function is called first to set -** Fts5Storage.pSavedRow to point to a statement that may be used to -** access the original values of the row being deleted - iDel. -** -** SQLITE_OK is returned if successful, or an SQLite error code otherwise. -** It is not considered an error if row iDel does not exist. In this case -** pSavedRow is not set and SQLITE_OK returned. -*/ -static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){ - int rc = SQLITE_OK; - sqlite3_stmt *pSeek = 0; - - assert( p->pSavedRow==0 ); - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pSeek, 1, iDel); - if( sqlite3_step(pSeek)!=SQLITE_ROW ){ - rc = sqlite3_reset(pSeek); - }else{ - p->pSavedRow = pSeek; - } - } - - return rc; -} - /* ** If a row with rowid iDel is present in the %_content table, add the ** delete-markers to the FTS index necessary to delete it. Do not actually ** remove the %_content row at this time though. -** -** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left -** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access -** the original values of the row being deleted. This is used by UPDATE -** statements. */ static int fts5StorageDeleteFromIndex( Fts5Storage *p, i64 iDel, - sqlite3_value **apVal, - int bSaveRow /* True to set pSavedRow */ + sqlite3_value **apVal ){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ @@ -258434,21 +257452,12 @@ static int fts5StorageDeleteFromIndex( int iCol; Fts5InsertCtx ctx; - assert( bSaveRow==0 || apVal==0 ); - assert( bSaveRow==0 || bSaveRow==1 ); - assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 ); - if( apVal==0 ){ - if( p->pSavedRow && bSaveRow ){ - pSeek = p->pSavedRow; - p->pSavedRow = 0; - }else{ - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_int64(pSeek, 1, iDel); - if( sqlite3_step(pSeek)!=SQLITE_ROW ){ - return sqlite3_reset(pSeek); - } + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pSeek, 1, iDel); + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + return sqlite3_reset(pSeek); } } @@ -258456,32 +257465,26 @@ static int fts5StorageDeleteFromIndex( ctx.iCol = -1; for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ - sqlite3_value *pVal = 0; - const char *pText = 0; - int nText = 0; - int bReset = 0; - + const char *zText; + int nText; assert( pSeek==0 || apVal==0 ); assert( pSeek!=0 || apVal!=0 ); if( pSeek ){ - pVal = sqlite3_column_value(pSeek, iCol); + zText = (const char*)sqlite3_column_text(pSeek, iCol); + nText = sqlite3_column_bytes(pSeek, iCol); + }else if( ALWAYS(apVal) ){ + zText = (const char*)sqlite3_value_text(apVal[iCol-1]); + nText = sqlite3_value_bytes(apVal[iCol-1]); }else{ - pVal = apVal[iCol-1]; + continue; } - - rc = sqlite3Fts5ExtractText( - pConfig, pVal, pSeek!=0, &bReset, &pText, &nText + ctx.szCol = 0; + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + zText, nText, (void*)&ctx, fts5StorageInsertCallback ); - if( rc==SQLITE_OK ){ - ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, - pText, nText, (void*)&ctx, fts5StorageInsertCallback - ); - p->aTotalSize[iCol-1] -= (i64)ctx.szCol; - if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){ - rc = FTS5_CORRUPT; - } - if( bReset ) sqlite3Fts5ClearLocale(pConfig); + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + if( p->aTotalSize[iCol-1]<0 ){ + rc = FTS5_CORRUPT; } } } @@ -258491,29 +257494,11 @@ static int fts5StorageDeleteFromIndex( p->nTotalRow--; } - if( rc==SQLITE_OK && bSaveRow ){ - assert( p->pSavedRow==0 ); - p->pSavedRow = pSeek; - }else{ - rc2 = sqlite3_reset(pSeek); - if( rc==SQLITE_OK ) rc = rc2; - } + rc2 = sqlite3_reset(pSeek); + if( rc==SQLITE_OK ) rc = rc2; return rc; } -/* -** Reset any saved statement pSavedRow. Zero pSavedRow as well. This -** should be called by the xUpdate() method of the fts5 table before -** returning from any operation that may have set Fts5Storage.pSavedRow. -*/ -static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){ - assert( pStorage->pSavedRow==0 - || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2] - ); - sqlite3_reset(pStorage->pSavedRow); - pStorage->pSavedRow = 0; -} - /* ** This function is called to process a DELETE on a contentless_delete=1 ** table. It adds the tombstone required to delete the entry with rowid @@ -258570,12 +257555,12 @@ static int fts5StorageInsertDocsize( rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin); sqlite3_bind_int64(pReplace, 3, iOrigin); } - } - if( rc==SQLITE_OK ){ - sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); - sqlite3_step(pReplace); - rc = sqlite3_reset(pReplace); - sqlite3_bind_null(pReplace, 2); + if( rc==SQLITE_OK ){ + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 2); + } } } return rc; @@ -258629,12 +257614,7 @@ static int fts5StorageSaveTotals(Fts5Storage *p){ /* ** Remove a row from the FTS table. */ -static int sqlite3Fts5StorageDelete( - Fts5Storage *p, /* Storage object */ - i64 iDel, /* Rowid to delete from table */ - sqlite3_value **apVal, /* Optional - values to remove from index */ - int bSaveRow /* If true, set pSavedRow for deleted row */ -){ +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ Fts5Config *pConfig = p->pConfig; int rc; sqlite3_stmt *pDel = 0; @@ -258651,7 +257631,7 @@ static int sqlite3Fts5StorageDelete( if( p->pConfig->bContentlessDelete ){ rc = fts5StorageContentlessDelete(p, iDel); }else{ - rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow); + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); } } @@ -258740,21 +257720,14 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - int bReset = 0; /* True if tokenizer locale must be reset */ - int nText = 0; /* Size of pText in bytes */ - const char *pText = 0; /* Pointer to buffer containing text value */ - sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1); - - rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - pText, nText, - (void*)&ctx, - fts5StorageInsertCallback - ); - if( bReset ) sqlite3Fts5ClearLocale(pConfig); - } + const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1); + int nText = sqlite3_column_bytes(pScan, ctx.iCol+1); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + zText, nText, + (void*)&ctx, + fts5StorageInsertCallback + ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; @@ -258838,31 +257811,7 @@ static int sqlite3Fts5StorageContentInsert( int i; /* Counter variable */ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ - sqlite3_value *pVal = apVal[i]; - if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ - /* This is an UPDATE statement, and column (i-2) was not modified. - ** Retrieve the value from Fts5Storage.pSavedRow instead. */ - pVal = sqlite3_column_value(p->pSavedRow, i-1); - }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){ - assert( pConfig->bLocale ); - assert( i>1 ); - if( pConfig->abUnindexed[i-2] ){ - /* At attempt to insert an fts5_locale() value into an UNINDEXED - ** column. Strip the locale away and just bind the text. */ - const char *pText = 0; - int nText = 0; - rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText); - sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT); - }else{ - const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); - int nBlob = sqlite3_value_bytes(pVal); - assert( nBlob>4 ); - sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT); - } - continue; - } - - rc = sqlite3_bind_value(pInsert, i, pVal); + rc = sqlite3_bind_value(pInsert, i, apVal[i]); } if( rc==SQLITE_OK ){ sqlite3_step(pInsert); @@ -258897,24 +257846,14 @@ static int sqlite3Fts5StorageIndexInsert( for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - int bReset = 0; /* True if tokenizer locale must be reset */ - int nText = 0; /* Size of pText in bytes */ - const char *pText = 0; /* Pointer to buffer containing text value */ - sqlite3_value *pVal = apVal[ctx.iCol+2]; - int bDisk = 0; - if( p->pSavedRow && sqlite3_value_nochange(pVal) ){ - pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1); - bDisk = 1; - } - rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText); - if( rc==SQLITE_OK ){ - assert( bReset==0 || pConfig->bLocale ); - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, - fts5StorageInsertCallback - ); - if( bReset ) sqlite3Fts5ClearLocale(pConfig); - } + const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]); + int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + zText, nText, + (void*)&ctx, + fts5StorageInsertCallback + ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; @@ -259085,22 +258024,14 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } if( rc==SQLITE_OK ){ - int bReset = 0; /* True if tokenizer locale must be reset */ - int nText = 0; /* Size of pText in bytes */ - const char *pText = 0; /* Pointer to buffer containing text value */ - - rc = sqlite3Fts5ExtractText(pConfig, - sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText + const char *zText = (const char*)sqlite3_column_text(pScan, i+1); + int nText = sqlite3_column_bytes(pScan, i+1); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + zText, nText, + (void*)&ctx, + fts5StorageIntegrityCallback ); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - pText, nText, - (void*)&ctx, - fts5StorageIntegrityCallback - ); - if( bReset ) sqlite3Fts5ClearLocale(pConfig); - } } if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ rc = FTS5_CORRUPT; @@ -259722,6 +258653,7 @@ static int fts5UnicodeCreate( zCat = azArg[i+1]; } } + if( rc==SQLITE_OK ){ rc = unicodeSetCategories(p, zCat); } @@ -259751,6 +258683,7 @@ static int fts5UnicodeCreate( rc = SQLITE_ERROR; } } + }else{ rc = SQLITE_NOMEM; } @@ -259889,7 +258822,7 @@ static int fts5UnicodeTokenize( typedef struct PorterTokenizer PorterTokenizer; struct PorterTokenizer { - fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */ + fts5_tokenizer tokenizer; /* Parent tokenizer module */ Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */ char aBuf[FTS5_PORTER_MAX_TOKEN + 64]; }; @@ -259901,7 +258834,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){ if( pTok ){ PorterTokenizer *p = (PorterTokenizer*)pTok; if( p->pTokenizer ){ - p->tokenizer_v2.xDelete(p->pTokenizer); + p->tokenizer.xDelete(p->pTokenizer); } sqlite3_free(p); } @@ -259920,7 +258853,6 @@ static int fts5PorterCreate( PorterTokenizer *pRet; void *pUserdata = 0; const char *zBase = "unicode61"; - fts5_tokenizer_v2 *pV2 = 0; if( nArg>0 ){ zBase = azArg[0]; @@ -259929,15 +258861,14 @@ static int fts5PorterCreate( pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); if( pRet ){ memset(pRet, 0, sizeof(PorterTokenizer)); - rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); + rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer); }else{ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ int nArg2 = (nArg>0 ? nArg-1 : 0); - const char **az2 = (nArg2 ? &azArg[1] : 0); - memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2)); - rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer); + const char **azArg2 = (nArg2 ? &azArg[1] : 0); + rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer); } if( rc!=SQLITE_OK ){ @@ -260588,7 +259519,6 @@ static int fts5PorterTokenize( void *pCtx, int flags, const char *pText, int nText, - const char *pLoc, int nLoc, int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) ){ PorterTokenizer *p = (PorterTokenizer*)pTokenizer; @@ -260596,8 +259526,8 @@ static int fts5PorterTokenize( sCtx.xToken = xToken; sCtx.pCtx = pCtx; sCtx.aBuf = p->aBuf; - return p->tokenizer_v2.xTokenize( - p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb + return p->tokenizer.xTokenize( + p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb ); } @@ -260627,46 +259557,40 @@ static int fts5TriCreate( Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; - TrigramTokenizer *pNew = 0; + TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); UNUSED_PARAM(pUnused); - if( nArg%2 ){ - rc = SQLITE_ERROR; + if( pNew==0 ){ + rc = SQLITE_NOMEM; }else{ int i; - pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pNew->bFold = 1; - pNew->iFoldParam = 0; - - for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); - } - }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ - if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ - rc = SQLITE_ERROR; - }else{ - pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; - } + pNew->bFold = 1; + pNew->iFoldParam = 0; + for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); + } + }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ + if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ rc = SQLITE_ERROR; + }else{ + pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; } - } - - if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ + }else{ rc = SQLITE_ERROR; } + } - if( rc!=SQLITE_OK ){ - fts5TriDelete((Fts5Tokenizer*)pNew); - pNew = 0; - } + if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ + rc = SQLITE_ERROR; + } + + if( rc!=SQLITE_OK ){ + fts5TriDelete((Fts5Tokenizer*)pNew); + pNew = 0; } } *ppOut = (Fts5Tokenizer*)pNew; @@ -260791,6 +259715,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ } aBuiltin[] = { { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, + { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, }; @@ -260805,20 +259730,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ 0 ); } - if( rc==SQLITE_OK ){ - fts5_tokenizer_v2 sPorter = { - 2, - fts5PorterCreate, - fts5PorterDelete, - fts5PorterTokenize - }; - rc = pApi->xCreateTokenizer_v2(pApi, - "porter", - (void*)pApi, - &sPorter, - 0 - ); - } + return rc; } @@ -261188,9 +260100,6 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ default: return 1; } break; - - default: - return 1; } return 0; } @@ -263113,6 +262022,21237 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ +/************** Begin file hct_pman.c ****************************************/ +/* +** 2022 April 10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + + +/************** Include hctInt.h in the middle of hct_pman.c *****************/ +/************** Begin file hctInt.h ******************************************/ + +/* #include */ +/************** Include sqlite3hct.h in the middle of hctInt.h ***************/ +/************** Begin file sqlite3hct.h **************************************/ +/* +** 2023 May 16 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + + + +#ifndef SQLITE3HCT_H +#define SQLITE3HCT_H + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +extern "C" { +#endif + +#define SQLITE_HCT_JOURNAL_HASHSIZE 16 + +/* +** Initialize the main database for replication. +*/ +SQLITE_API int sqlite3_hct_journal_init(sqlite3 *db); + +/* +** Write a transaction into the database. +*/ +SQLITE_API int sqlite3_hct_journal_write( + sqlite3 *db, /* Write to "main" db of this handle */ + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid +); + +SQLITE_API int sqlite3_hct_journal_truncate(sqlite3 *db, sqlite3_int64 iMinCid); + +/* +** Candidate values for second arg to sqlite3_hct_journal_setmode() +*/ +#define SQLITE_HCT_JOURNAL_MODE_FOLLOWER 0 +#define SQLITE_HCT_JOURNAL_MODE_LEADER 1 + +/* +** Query the LEADER/FOLLOWER setting of the db passed as the only argument. +*/ +SQLITE_API int sqlite3_hct_journal_mode(sqlite3 *db); + +/* +** Set the LEADER/FOLLOWER setting of the db passed as the first argument. +** Return SQLITE_OK if successful. Otherwise, return an SQLite error code +** and leave an English language error message (accessible using +** sqlite3_errmsg()) in the database handle. +*/ +SQLITE_API int sqlite3_hct_journal_setmode(sqlite3 *db, int eMode); + +/* +** Rollback transactions that follow the first hole in the journal. +*/ +SQLITE_API int sqlite3_hct_journal_rollback(sqlite3 *db, sqlite3_int64 iCid); + +/* +** Special values that may be passed as second argument to +** sqlite3_hct_journal_rollback(). +*/ +#define SQLITE_HCT_ROLLBACK_MAXIMUM 0 +#define SQLITE_HCT_ROLLBACK_PRESERVE -1 + +/* +** Set output variable (*piCid) to the CID of the newest available +** database snapshot. Return SQLITE_OK if successful, or an SQLite +** error code if something goes wrong. +*/ +SQLITE_API int sqlite3_hct_journal_snapshot(sqlite3 *db, sqlite3_int64 *piCid); + +/* +** Register a custom validation callback with the database handle. +*/ +SQLITE_API int sqlite3_hct_journal_hook( + sqlite3 *db, + void *pArg, + int(*xValidate)( + void *pCopyOfArg, + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid + ) +); + +/* +** Both arguments are assumed to point to SQLITE_HCT_JOURNAL_HASHSIZE +** byte buffers. This function updates the hash stored in buffer pHash +** based on the contents of buffer pData. +*/ +SQLITE_API void sqlite3_hct_journal_hash(void *pHash, const void *pData); + +/* +** It is assumed that buffer pHash points to a buffer +** SQLITE_HCT_JOURNAL_HASHSIZE bytes in size. This function populates this +** buffer with a hash based on the remaining arguments. +*/ +SQLITE_API void sqlite3_hct_journal_hashentry( + void *pHash, /* OUT: Hash of other arguments */ + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid +); + +SQLITE_API void sqlite3_hct_migrate_mode(sqlite3 *db, int bActivate); + +#if 0 +} +#endif +#endif /* SQLITE3HCT_H */ + +/************** End of sqlite3hct.h ******************************************/ +/************** Continuing where we left off in hctInt.h *********************/ + +typedef sqlite3_int64 i64; +typedef unsigned char u8; +typedef unsigned int u32; + +/* +** Primitives for atomic load and store. +*/ +#define HctAtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL), __ATOMIC_SEQ_CST) +#define HctAtomicLoad(PTR) __atomic_load_n((PTR), __ATOMIC_SEQ_CST) + +#define HctCASBool(PTR,OLD,NEW) \ + (int)__sync_bool_compare_and_swap((PTR),(OLD),(NEW)) + + +/* +*/ +typedef struct HctConfig HctConfig; +struct HctConfig { + int nDbFile; /* Number of files (hct_file.c) */ + int nPageSet; /* Used by hct_pman.c */ + int nPageScan; /* Used by hct_pman.c */ + int szLogChunk; /* Used by hctree.c */ + int nTryBeforeUnevict; + int bQuiescentIntegrityCheck; /* PRAGMA hct_quiescent_integrity_check */ + int pgsz; + sqlite3 *db; +}; + +#define HCT_TID_MASK ((((u64)0x00FFFFFF) << 32)|0xFFFFFFFF) +#define HCT_PGNO_MASK ((u64)0xFFFFFFFF) + +#define HCT_MAX_NDBFILE 128 + +#define HCT_DEFAULT_NDBFILE 1 +#define HCT_DEFAULT_NPAGESET 256 +#define HCT_DEFAULT_NTRYBEFOREUNEVICT 100 +#define HCT_DEFAULT_NPAGESCAN 1024 +#define HCT_DEFAULT_SZLOGCHUNK 16384 +#define HCT_DEFAULT_PAGESIZE 4096 + + + +/************** Include hctTMapInt.h in the middle of hctInt.h ***************/ +/************** Begin file hctTMapInt.h **************************************/ +/* +** 2021 February 24 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This header file describes the transaction map implementation. It +** serves two tasks: +** +** * Provides the transaction map itself, a mapping from 56-bit TID values +** to a combination of a CID value (also 56 bits) and some flags. +** +** * Provides the read-lock system required by readers to ensure that old +** database pages and other resources are not reused before they +** are guaranteed to be finished with them. +*/ + +/* +*/ + +/* #define HCT_TMAP_PAGESIZE 1024 */ + +#define HCT_TMAP_PGSZBITS 10 +#define HCT_TMAP_PAGESIZE (1 << HCT_TMAP_PGSZBITS) + +#define HCT_TMAP_ENTRYSLOT(iEntry) \ + (((iEntry) >> 3) + (((iEntry) & 0x07) << (HCT_TMAP_PGSZBITS-3))) +// #define HCT_TMAP_ENTRYSLOT(iEntry) (((iEntry) >> 3) + (((iEntry) & 0x07) << 10)) + +/* +** Transaction state - stored in the MSB of the 8-byte transaction map entry. +*/ +#define HCT_TMAP_WRITING (((u64)0x00) << 56) +#define HCT_TMAP_VALIDATING (((u64)0x01) << 56) +#define HCT_TMAP_ROLLBACK (((u64)0x02) << 56) +#define HCT_TMAP_COMMITTED (((u64)0x03) << 56) + +#define HCT_TMAP_STATE_MASK (((u64)0x07) << 56) +#define HCT_TMAP_CID_MASK ~(((u64)0xFF) << 56) + +/* +** There is a single object of this type for each distinct database +** opened within the process. All connections to said database have +** a pointer to the same HctTMapServer object. +*/ +typedef struct HctTMapServer HctTMapServer; + +/* +** Each separate database connection holds a handle of this type for +** the lifetime of the connection. Obtained and later released using +** functions: +** +** sqlite3HctTMapServerNew() +** sqlite3HctTMapServerFree() +*/ +typedef struct HctTMapClient HctTMapClient; + +/* +*/ +typedef struct HctTMap HctTMap; + +/* +** A transaction-map object. +** +** iMinTid: +** This, and all smaller TID values have been finalized (fully committed +** or rolled back). The client may not query the map for any TID values +** less than or equal to this one. +** +** iMinCid: +** This an all smaller CID values were committed +*/ +struct HctTMap { + /* Snapshot locking values */ +#if 0 + u64 iMinCid; /* This + all smaller CIDs fully committed */ + u64 iMinTid; /* This + all smaller TIDs fully committed */ +#endif + + /* Transaction map */ + u64 iFirstTid; /* TID corresponding to aaMap[0][0] */ + int nMap; /* Number of mapping pages in aaMap[] */ + u64 **aaMap; /* Array of u64[HCT_TMAP_PAGESIZE] arrays */ +}; + +/* +** Create or delete a tmap server object. +*/ +SQLITE_PRIVATE int sqlite3HctTMapServerNew(u64 iFirstTid, u64 iLastTid, HctTMapServer **pp); +SQLITE_PRIVATE void sqlite3HctTMapServerFree(HctTMapServer *p); + +/* +** Connect/disconnect a tmap client object. +*/ +SQLITE_PRIVATE int sqlite3HctTMapClientNew(HctTMapServer*, HctConfig*, HctTMapClient**); +SQLITE_PRIVATE void sqlite3HctTMapClientFree(HctTMapClient *pClient); + +/* +** Obtain, update or release a reference to a transaction map object. +*/ +SQLITE_PRIVATE int sqlite3HctTMapBegin(HctTMapClient *p, u64 iSnapshot, HctTMap **ppMap); +SQLITE_PRIVATE int sqlite3HctTMapUpdate(HctTMapClient *p, HctTMap **ppMap); +SQLITE_PRIVATE int sqlite3HctTMapEnd(HctTMapClient *p, u64 iCID); + +/* +** Return a TID value for which: +** +** 1. the transactions associated with it and all smaller TID values +** have been finalized (marked as committed or rolled back), and +** +** 2. the transactions associated with it and all smaller TID values +** are included in the snapshots accessed by all current and future +** readers. +** +** All physical and logical pages freed by transactions with TIDs equal to +** or smaller than the returned value may now be reused without disturbing +** current or future readers. +*/ +SQLITE_PRIVATE u64 sqlite3HctTMapSafeTID(HctTMapClient*); + +SQLITE_PRIVATE int sqlite3HctTMapNewTID(HctTMapClient *p, u64 iTid, HctTMap **ppMap); + +/* +** Return TID value T for all transactions with tid values less than or +** equal to T were finished (marked as committed or rolled back), last +** time sqlite3HctTMapBegin() was called. +*/ +SQLITE_PRIVATE u64 sqlite3HctTMapCommitedTID(HctTMapClient*); + +SQLITE_PRIVATE i64 sqlite3HctTMapStats(sqlite3 *db, int iStat, const char **pzStat); + +SQLITE_PRIVATE void sqlite3HctTMapScan(HctTMapClient*); + + +/* +** The following API is used when recovering a replication-enabled database. +** In that case, a new HctTMap object must be created during recovery to +** reflect the contents of the sqlite_hct_journal table. +*/ +SQLITE_PRIVATE int sqlite3HctTMapRecoverySet(HctTMapClient*, u64 iTid, u64 iCid); +SQLITE_PRIVATE void sqlite3HctTMapRecoveryFinish(HctTMapClient*, int rc); + +SQLITE_PRIVATE int sqlite3HctTMapServerSet(HctTMapServer *pServer, u64 iTid, u64 iCid); + + + + +/************** End of hctTMapInt.h ******************************************/ +/************** Continuing where we left off in hctInt.h *********************/ +/************** Include hctFileInt.h in the middle of hctInt.h ***************/ +/************** Begin file hctFileInt.h **************************************/ +/* +** 2023 January 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ + +typedef struct HctFileServer HctFileServer; +typedef struct HctFile HctFile; + +SQLITE_PRIVATE HctFile *sqlite3HctFileOpen( + int *pRc, + const char *zFile, + HctConfig *pConfig +); +SQLITE_PRIVATE void sqlite3HctFileClose(HctFile *pFile); + +/* +** If the database has not yet been created on disk, create it. Or, if +** the db has already been created, then this function is a no-op. +*/ +SQLITE_PRIVATE int sqlite3HctFileNewDb(HctFile *pFile); + +/* +** Return true if the db has not yet been created on disk. Or false +** if it already has. +*/ +SQLITE_PRIVATE int sqlite3HctFileIsNewDb(HctFile *pFile); + +SQLITE_PRIVATE u32 sqlite3HctFileMaxpage(HctFile *pFile); + +typedef struct HctFilePage HctFilePage; +struct HctFilePage { + u8 *aOld; /* Current buffer, or NULL */ + u8 *aNew; /* New buffer (to be populated) */ + + /* Used internally by hct_file.c. Mostly... */ + u32 iPg; /* logical page number */ + u32 iNewPg; /* New physical page number */ + u32 iOldPg; /* Original physical page number */ + HctFile *pFile; +}; + +/* +** Allocate logical root page numbers. And free the same (required if the +** transaction is rolled back). +*/ +SQLITE_PRIVATE int sqlite3HctFileRootPgno(HctFile *pFile, u32 *piRoot); +SQLITE_PRIVATE int sqlite3HctFileRootFree(HctFile *pFile, u32 iRoot); +SQLITE_PRIVATE int sqlite3HctFileRootNew(HctFile *pFile, u32 iRoot, HctFilePage*); + + +SQLITE_PRIVATE int sqlite3HctFilePageNew(HctFile *pFile, HctFilePage *pPg); + +/* +** Obtain a read-only reference to logical page iPg. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageGet(HctFile *pFile, u32 iPg, HctFilePage *pPg); + +/* +** If the page is not already writable (if pPg->aNew==0), make it writable. +** This involves allocating a new physical page and setting pPg->aNew +** to point to the buffer. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageWrite(HctFilePage *pPg); + +/* +** This is a no-op if the page is not writable. +** +** If the page is already writable, reverse this so that will not be +** written out when PageRelease() or PageCommit() is called. This reclaims +** the physical page that was allocated by the earlier PageWrite() call +** and sets pPg->aNew to NULL. +*/ +SQLITE_PRIVATE void sqlite3HctFilePageUnwrite(HctFilePage *pPg); + +/* +** This is a no-op if the page is not writable. +** +** Commit the new version of the page to disk (i.e. set the page-map entry +** so that the logical page number now maps to the new version of the page +** in pPg->aNew). Then make pPg a non-writable reference to the logical +** page (so that pPg->aOld points to the new version of the page and +** pPg->aNew is NULL). +*/ +SQLITE_PRIVATE int sqlite3HctFilePageCommit(HctFilePage *pPg); + +/* +** Evict the page from the data structure - i.e. set the LOGICAL_EVICTED +** flag for it. This operation fails if the LOGICAL_EVICTED flag has +** already been set, or if the page has been written since it was read. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageEvict(HctFilePage *pPg, int bIrrevocable); + +SQLITE_PRIVATE void sqlite3HctFilePageUnevict(HctFilePage *pPg); + +SQLITE_PRIVATE int sqlite3HctFilePageIsEvicted(HctFile *pFile, u32 iPgno); +SQLITE_PRIVATE int sqlite3HctFilePageIsFree(HctFile *pFile, u32 iPgno, int bLogical); + +/* +** Release a page reference obtained via an earlier call to +** sqlite3HctFilePageGet() or sqlite3HctFilePageNew(). After this call +** pPg->aOld is NULL. +** +** If the page is writable, it is committed (see sqlite3HctFilePageCommit) +** before the reference is released. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageRelease(HctFilePage *pPg); + + +SQLITE_PRIVATE int sqlite3HctFilePageGetPhysical(HctFile *pFile, u32 iPg, HctFilePage *pPg); +SQLITE_PRIVATE int sqlite3HctFilePageNewPhysical(HctFile *pFile, HctFilePage *pPg); + +SQLITE_PRIVATE u64 sqlite3HctFileAllocateTransid(HctFile *pFile); +SQLITE_PRIVATE u64 sqlite3HctFileAllocateCID(HctFile *pFile, int); +SQLITE_PRIVATE u64 sqlite3HctFileGetSnapshotid(HctFile *pFile); + +SQLITE_PRIVATE void sqlite3HctFileSetCID(HctFile *pFile, u64); + +/* +** Increment the global write-count by nIncr, and return the final value. +*/ +SQLITE_PRIVATE u64 sqlite3HctFileIncrWriteCount(HctFile *pFile, int nIncr); + +SQLITE_PRIVATE HctTMapClient *sqlite3HctFileTMapClient(HctFile*); + +SQLITE_PRIVATE int sqlite3HctFilePgsz(HctFile *pFile); +SQLITE_PRIVATE int sqlite3HctFileVtabInit(sqlite3 *db); + +SQLITE_PRIVATE u64 sqlite3HctFileSafeTID(HctFile*); +SQLITE_PRIVATE u32 sqlite3HctFilePageRangeAlloc(HctFile*, int bLogical, int nPg); + +SQLITE_PRIVATE int sqlite3HctFileClearInUse(HctFilePage *pPg, int bReuseNow); +SQLITE_PRIVATE int sqlite3HctFileClearPhysInUse(HctFile *pFile, u32 pgno, int bReuseNow); + +SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...); + +SQLITE_PRIVATE char *sqlite3HctFileLogFile(HctFile *pFile); +SQLITE_PRIVATE int sqlite3HctFileStartRecovery(HctFile *pFile, int iStage); +SQLITE_PRIVATE int sqlite3HctFileFinishRecovery(HctFile *pFile, int iStage, int rc); +SQLITE_PRIVATE int sqlite3HctFileRecoverFreelists( + HctFile *pFile, /* File to recover freelists for */ + int nRoot, i64 *aRoot, /* Array of root page numbers */ + int nPhys, i64 *aPhys /* Sorted array of phys. pages to preserve */ +); + +SQLITE_PRIVATE int sqlite3HctFileFindLogs(HctFile*, void*, int(*)(void*, const char*)); + +SQLITE_PRIVATE u32 sqlite3HctFilePageMapping(HctFile *pFile, u32 iLogical, int *pbEvicted); + +SQLITE_PRIVATE void sqlite3HctFileICArrays(HctFile*, u8**, u32*, u8**, u32*); +SQLITE_PRIVATE int sqlite3HctFileTreeFree(HctFile *, u32, int); +SQLITE_PRIVATE int sqlite3HctFilePageClearIsRoot(HctFile*, u32); +SQLITE_PRIVATE int sqlite3HctFilePageClearInUse(HctFile *pFile, u32 iPg, int bLogic); + +/************** Include hctPManInt.h in the middle of hctFileInt.h ***********/ +/************** Begin file hctPManInt.h **************************************/ +/* +** 2022 March 20 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ + +/* +** There is a single object of this type for each distinct database opened +** by the process. Allocated and later freed using the following functions. +** +** sqlite3HctPManServerNew() +** sqlite3HctPManServerFree() +** +** Once an HctPManServer object has been created, it is configured with +** the set of free logical and physical pages, which the caller presumably +** discovers by scanning the page-map. +*/ +typedef struct HctPManServer HctPManServer; +typedef struct HctFile HctFile; + +SQLITE_PRIVATE HctPManServer *sqlite3HctPManServerNew( + int *pRc, /* IN/OUT: Error code */ + HctFileServer *pFileServer /* Associated file-server object */ +); +SQLITE_PRIVATE void sqlite3HctPManServerFree(HctPManServer*); + +/* +** This function is called multiple times while scanning the page-map +** during initialization. To load the initial set of free physical and +** logical pages. +*/ +SQLITE_PRIVATE void sqlite3HctPManServerInit( + int *pRc, HctPManServer*, u64 iTid, u32 iPg, int bLogical +); + +/* +** Each separate database connection holds a handle of this type for +** the lifetime of the connection. +*/ +typedef struct HctPManClient HctPManClient; + +SQLITE_PRIVATE HctPManClient *sqlite3HctPManClientNew( + int *pRc, + HctConfig*, + HctPManServer*, + HctFile* +); +SQLITE_PRIVATE void sqlite3HctPManClientFree(HctPManClient*); + +/* +** Allocate a new logical or physical page. +*/ +SQLITE_PRIVATE u32 sqlite3HctPManAllocPg( + int *pRc, /* IN/OUT: Error code */ + HctPManClient *p, /* page-manager client handle */ + HctFile *pFile, + int bLogical +); + +/* +** Mark a logical or physical page as no longer in use. Parameter iTid +** is the transaction-id associated with the transaction that freed the +** page. The page may be reused once all clients are accessing a +** snapshot that includes this transaction. In other words, once the +** snapshot id of all readers is greater than or equal to the commit id +** that maps to transaction id iTid. +** +** Sometimes this function is called with iTid==0, to indicate that the +** page in question may be reused immediately. +*/ +SQLITE_PRIVATE void sqlite3HctPManFreePg( + int *pRc, /* IN/OUT: Error code */ + HctPManClient *p, /* page-manager client handle */ + i64 iTid, /* Associated TID value */ + u32 iPg, /* Page number */ + int bLogical /* True for logical, false for physical */ +); + +SQLITE_PRIVATE void sqlite3HctPManClientHandoff(HctPManClient *p); + +SQLITE_PRIVATE void sqlite3HctPManServerReset(HctPManServer *pServer); + +SQLITE_PRIVATE int sqlite3HctPManVtabInit(sqlite3 *db); + +/* +** Mark an entire tree of logical and physical pages as free. The iTid +** parameter works just as it does for sqlite3HctPManFreePg(). +** +** SQLITE_OK is returned if successful, or an error code (e.g. SQLITE_NOMEM) +** otherwise. +*/ +SQLITE_PRIVATE int sqlite3HctPManFreeTree(HctPManClient *p, HctFile*, u32 iRoot, u64 iTid); + +SQLITE_PRIVATE int sqlite3HctPManServerInitRoot(int *pRc, HctPManServer*, u64, HctFile*, u32); +SQLITE_PRIVATE i64 sqlite3HctPManStats(sqlite3 *db, int iStat, const char **pzStat); + +/************** End of hctPManInt.h ******************************************/ +/************** Continuing where we left off in hctFileInt.h *****************/ +SQLITE_PRIVATE HctPManClient *sqlite3HctFilePManClient(HctFile*); + +SQLITE_PRIVATE int sqlite3HctFileRootArray(HctFile*, u32**, int*); + +/* Interface used by hct_stats virtual table */ +SQLITE_PRIVATE i64 sqlite3HctFileStats(sqlite3*, int, const char**); + +/* +** Return the total number of physical page allocations made during +** the entire lifetime of this object. +*/ +SQLITE_PRIVATE u64 sqlite3HctFileWriteCount(HctFile *pFile); + +/* +** Return the number of files used to store data within the database (the +** value to return for "PRAGMA hct_ndbfile"). Before returning, set output +** parameter *pbFixed if the database has been created and the number +** of files is therefore fixed, or clear it if the db has yet to be created. +*/ +SQLITE_PRIVATE int sqlite3HctFileNFile(HctFile *pFile, int *pbFixed); + +SQLITE_PRIVATE void sqlite3HctFileSetJrnlPtr(HctFile *pFile, void *pPtr, void(*xDel)(void*)); +SQLITE_PRIVATE void *sqlite3HctFileGetJrnlPtr(HctFile *pFile); + +SQLITE_PRIVATE int sqlite3HctIoerr(int rc); + + +/************** End of hctFileInt.h ******************************************/ +/************** Continuing where we left off in hctInt.h *********************/ + +#ifdef SQLITE_DEBUG +# define SQLITE_LOCKED_ERR(x,y) sqlite3HctLockedErr(x,y) +SQLITE_PRIVATE int sqlite3HctLockedErr(u32 pgno, const char *zReason); +#else +# define SQLITE_LOCKED_ERR(x,y) SQLITE_LOCKED +#endif + +#define HCT_TREE_SCHEMAOP_ROOT 3 + +/* +** Growable buffer type used for various things. +*/ +typedef struct HctBuffer HctBuffer; +struct HctBuffer { + u8 *aBuf; + int nBuf; + int nAlloc; +}; +SQLITE_PRIVATE int sqlite3HctBufferGrow(HctBuffer *pBuf, int nSize); +SQLITE_PRIVATE void sqlite3HctBufferFree(HctBuffer *pBuf); + + + +/************************************************************************* +** Interface to code in hct_tree.c +*/ +typedef struct HctTree HctTree; +typedef struct HctTreeCsr HctTreeCsr; + +SQLITE_PRIVATE int sqlite3HctTreeNew(HctTree **ppTree); +SQLITE_PRIVATE void sqlite3HctTreeFree(HctTree *pTree); + +SQLITE_PRIVATE int sqlite3HctTreeInsert(HctTreeCsr*, UnpackedRecord*, i64, int, const u8*,int); +SQLITE_PRIVATE int sqlite3HctTreeAppend(HctTreeCsr*, KeyInfo*, i64, int, const u8*,int); +SQLITE_PRIVATE int sqlite3HctTreeDelete(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeDeleteKey(HctTreeCsr *, UnpackedRecord *, i64, int,const u8*); + +/* +** These functions are used to open and close transactions and nested +** sub-transactions. +** +** The Begin() function is used to open transactions and sub-transactions. +** A successful call to Begin() ensures that there are at least iLevel +** nested transactions open. To open a top-level transaction, pass iLevel=1. +** To open a sub-transaction within the top-level transaction, iLevel=2. +** Passing iLevel=0 is a no-op. +** +** Release() is used to commit transactions and sub-transactions. A +** successful call to Release() ensures that there are at most iLevel +** nested transactions open. To commit a top-level transaction, pass iLevel=0. +** To commit all sub-transactions inside the main transaction, pass iLevel=1. +** +** Function lsm_rollback() is used to roll back transactions and +** sub-transactions. A successful call to lsm_rollback() restores the database +** to the state it was in when the iLevel'th nested sub-transaction (if any) +** was first opened. And then closes transactions to ensure that there are +** at most iLevel nested transactions open. Passing iLevel=0 rolls back and +** closes the top-level transaction. iLevel=1 also rolls back the top-level +** transaction, but leaves it open. iLevel=2 rolls back the sub-transaction +** nested directly inside the top-level transaction (and leaves it open). +*/ +SQLITE_PRIVATE int sqlite3HctTreeBegin(HctTree *pTree, int iStmt); +SQLITE_PRIVATE int sqlite3HctTreeRelease(HctTree *pTree, int iStmt); +SQLITE_PRIVATE int sqlite3HctTreeRollbackTo(HctTree *pTree, int iStmt); + +SQLITE_PRIVATE int sqlite3HctTreeClearOne(HctTree *pTree, u32 iRoot, i64 *pnRow); + +SQLITE_PRIVATE int sqlite3HctTreeCsrOpen(HctTree *pTree, u32 iRoot, HctTreeCsr **ppCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrClose(HctTreeCsr *pCsr); + +SQLITE_PRIVATE int sqlite3HctTreeCsrNext(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrPrev(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrEof(HctTreeCsr *pCsr); + +SQLITE_PRIVATE int sqlite3HctTreeCsrSeek(HctTreeCsr*, UnpackedRecord*, i64 iKey, int *pRes); +SQLITE_PRIVATE int sqlite3HctTreeCsrFirst(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrLast(HctTreeCsr *pCsr); + +SQLITE_PRIVATE int sqlite3HctTreeCsrKey(HctTreeCsr *pCsr, i64 *piKey); +SQLITE_PRIVATE int sqlite3HctTreeCsrData(HctTreeCsr *pCsr, int *pnData, const u8 **paData); +SQLITE_PRIVATE int sqlite3HctTreeCsrIsDelete(HctTreeCsr *pCsr); + +SQLITE_PRIVATE void sqlite3HctTreeCsrPin(HctTreeCsr *pCsr); +SQLITE_PRIVATE void sqlite3HctTreeCsrUnpin(HctTreeCsr *pCsr); + +SQLITE_PRIVATE int sqlite3HctTreeCsrHasMoved(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrRestore(HctTreeCsr *pCsr, int *pIsDifferent); +SQLITE_PRIVATE void sqlite3HctTreeCsrClear(HctTreeCsr *pCsr); + +SQLITE_PRIVATE u32 sqlite3HctTreeCsrRoot(HctTreeCsr *pCsr); + + +/* +** Iterate through non-empty tables/indexes within an HctTree structure. Used +** when flushing contents to disk. +** +** If parameter bSchemaOp is false, then no callback is issued for the table +** with root page number HCT_TREE_SCHEMAOP_ROOT. If bSchemaOp is non-zero, +** then HCT_TREE_SCHEMAOP_ROOT is treated like any other table. +*/ + +SQLITE_PRIVATE int sqlite3HctTreeForeach( + HctTree *pTree, + int bSchemOp, + void *pCtx, + int (*x)(void *, u32, KeyInfo*) +); +SQLITE_PRIVATE void sqlite3HctTreeClear(HctTree *pTree); + +SQLITE_PRIVATE void sqlite3HctTreeCsrIncrblob(HctTreeCsr *pCsr); +SQLITE_PRIVATE int sqlite3HctTreeCsrReseek(HctTreeCsr *pCsr, int*); + +SQLITE_PRIVATE int sqlite3HctTreeUpdateMeta(HctTree*, const u8*, int); + +/************************************************************************* +** Interface to code in hct_database.c +*/ +typedef struct HctDatabase HctDatabase; +typedef struct HctDbCsr HctDbCsr; + +typedef struct HctJournal HctJournal; + +SQLITE_PRIVATE HctDatabase *sqlite3HctDbFind(sqlite3*, int); +SQLITE_PRIVATE int sqlite3HctDetectJournals(sqlite3 *db); + +SQLITE_PRIVATE HctDatabase *sqlite3HctDbOpen(int*, const char *zFile, HctConfig*); +SQLITE_PRIVATE void sqlite3HctDbClose(HctDatabase *pDb); + +SQLITE_PRIVATE int sqlite3HctDbRootNew(HctDatabase *p, u32 *piRoot); +SQLITE_PRIVATE int sqlite3HctDbRootFree(HctDatabase *p, u32 iRoot); + +SQLITE_PRIVATE int sqlite3HctDbRootInit(HctDatabase *p, int bIndex, u32 iRoot); +SQLITE_PRIVATE void sqlite3HctDbRootPageInit(int bIndex, u8 *aPage, int szPage); +SQLITE_PRIVATE int sqlite3HctDbGetMeta(HctDatabase *p, u8 *aBuf, int nBuf); + +SQLITE_PRIVATE int sqlite3HctDbInsert( + HctDatabase *pDb, + u32 iRoot, + UnpackedRecord *pRec, i64 iKey, + int bDel, int nData, const u8 *aData, + int *pnRetry +); +SQLITE_PRIVATE int sqlite3HctDbInsertFlush(HctDatabase *pDb, int *pnRetry); +SQLITE_PRIVATE int sqlite3HctDbStartRead(HctDatabase*,HctJournal*); +SQLITE_PRIVATE int sqlite3HctDbStartWrite(HctDatabase*, u64*); +SQLITE_PRIVATE int sqlite3HctDbEndWrite(HctDatabase*, u64, int); +SQLITE_PRIVATE int sqlite3HctDbEndRead(HctDatabase*); +SQLITE_PRIVATE int sqlite3HctDbValidate(sqlite3*, HctDatabase*, u64 *piCid, int*); + +SQLITE_PRIVATE i64 sqlite3HctDbTid(HctDatabase *); + +SQLITE_PRIVATE void sqlite3HctDbRollbackMode(HctDatabase*,int); + +SQLITE_PRIVATE int sqlite3HctDbCsrOpen(HctDatabase*, struct KeyInfo*, u32 iRoot, HctDbCsr**); +SQLITE_PRIVATE void sqlite3HctDbCsrClose(HctDbCsr *pCsr); + +SQLITE_PRIVATE void sqlite3HctDbCsrNosnap(HctDbCsr *pCsr, int bNosnap); + +SQLITE_PRIVATE void sqlite3HctDbCsrDir(HctDbCsr*, int eDir); +SQLITE_PRIVATE int sqlite3HctDbCsrSeek(HctDbCsr*, UnpackedRecord*, i64 iKey, int *pRes); + +SQLITE_PRIVATE int sqlite3HctDbCsrEof(HctDbCsr*); +SQLITE_PRIVATE int sqlite3HctDbCsrFirst(HctDbCsr*); +SQLITE_PRIVATE int sqlite3HctDbCsrLast(HctDbCsr*); +SQLITE_PRIVATE int sqlite3HctDbCsrNext(HctDbCsr*); +SQLITE_PRIVATE int sqlite3HctDbCsrPrev(HctDbCsr*); +SQLITE_PRIVATE void sqlite3HctDbCsrClear(HctDbCsr*); + +SQLITE_PRIVATE void sqlite3HctDbCsrKey(HctDbCsr*, i64 *piKey); +SQLITE_PRIVATE int sqlite3HctDbCsrData(HctDbCsr *pCsr, int *pnData, const u8 **paData); +SQLITE_PRIVATE int sqlite3HctDbCsrLoadAndDecode(HctDbCsr *pCsr, UnpackedRecord **ppRec); + +SQLITE_PRIVATE int sqlite3HctDbIsIndex(HctDatabase *pDb, u32 iRoot, int *pbIndex); + +SQLITE_PRIVATE int sqlite3HctDbStartRecovery(HctDatabase *pDb, int iStage); +SQLITE_PRIVATE int sqlite3HctDbFinishRecovery(HctDatabase *db, int iStage, int rc); +SQLITE_PRIVATE void sqlite3HctDbRecoverTid(HctDatabase *db, u64 iTid); + +SQLITE_PRIVATE char *sqlite3HctDbLogFile(HctDatabase*); + +SQLITE_PRIVATE i64 sqlite3HctDbNCasFail(HctDatabase*); + +SQLITE_PRIVATE char *sqlite3HctDbIntegrityCheck(HctDatabase*, u32 *aRoot,Mem*,int nRoot, int*); +SQLITE_PRIVATE i64 sqlite3HctDbStats(sqlite3 *db, int iStat, const char **pzStat); + +SQLITE_PRIVATE int sqlite3HctDbCsrRollbackSeek(HctDbCsr*, UnpackedRecord*, i64, int *pOp); + +SQLITE_PRIVATE void sqlite3HctDbSetSavePhysical( + HctDatabase *pDb, + int (*xSave)(void*, i64 iPhys), + void *pSave +); + +SQLITE_PRIVATE char *sqlite3HctDbRecordToText(sqlite3 *db, const u8 *aRec, int nRec); + +SQLITE_PRIVATE void sqlite3HctDbTMapScan(HctDatabase *pDb); + +SQLITE_PRIVATE void sqlite3HctDbTransIsConcurrent(HctDatabase *pDb, int bConcurrent); + +SQLITE_PRIVATE HctFile *sqlite3HctDbFile(HctDatabase *pDb); + +SQLITE_PRIVATE int sqlite3HctDbWalkTree( + HctFile *pFile, /* File tree resides in */ + u32 iRoot, /* Root page of tree */ + int (*x)(void*, u32, u32), /* Callback function */ + void *pCtx /* First argument to pass to x() */ +); + +SQLITE_PRIVATE int sqlite3HctDbPagesize(HctDatabase *pDb); + +SQLITE_PRIVATE void sqlite3HctDbRecordTrim(UnpackedRecord *pRec); + +/* +** This function returns the current snapshot-id. It may only be called +** when a read transaction is active. +*/ +SQLITE_PRIVATE i64 sqlite3HctDbSnapshotId(HctDatabase *pDb); + +SQLITE_PRIVATE int sqlite3HctDbCsrFindLastWrite( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index/without rowid tables */ + i64 iKey, /* Key for intkey tables */ + u64 *piCid /* Last CID to write to this key */ +); + +SQLITE_PRIVATE void sqlite3HctDbJrnlWriteCid(HctDatabase *pDb, u64 iVal); + +/************************************************************************* +** Interface to code in hct_file.c +*/ + +/************************************************************************* +** Interface to code in hct_record.c +*/ +SQLITE_PRIVATE int sqlite3HctSerializeRecord( + UnpackedRecord *pRec, /* Record to serialize */ + u8 **ppRec, /* OUT: buffer containing serialization */ + int *pnRec /* OUT: size of (*ppRec) in bytes */ +); + +/************************************************************************* +** Interface to code in hct_stats.c +*/ +SQLITE_PRIVATE int sqlite3HctStatsInit(sqlite3*); + +/************************************************************************* +** Utility functions: +*/ +SQLITE_PRIVATE void *sqlite3HctMalloc(int *pRc, i64 nByte); + +/************************************************************************* +** hctree.c: +**/ + +/************** Include hctJrnlInt.h in the middle of hctInt.h ***************/ +/************** Begin file hctJrnlInt.h **************************************/ +/* +** 2023 January 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ + +typedef struct HctJournal HctJournal; + +/* +** If schema pSchema contains the special tables sqlite_hct_journal and +** sqlite_hct_baseline, allocate a new HctJournal object, set (*pp) +** to point to it and return SQLITE_OK. Or, if neither table can be +** found, set (*pp) to NULL and return SQLITE_OK. +** +** If only one of the required tables is found (SQLITE_CORRUPT), or if an +** OOM error occurs (SQLITE_NOMEM), return an SQLite error code. The final +** value of (*pp) is NULL in this case. +*/ +SQLITE_PRIVATE int sqlite3HctJournalNewIf(Schema*, HctTree*, HctDatabase*, HctJournal **pp); + +SQLITE_PRIVATE void sqlite3HctJournalClose(HctJournal*); + + +SQLITE_PRIVATE int sqlite3HctJrnlLog( + HctJournal *pJrnl, + sqlite3 *db, + Schema *pSchema, + u64 iCid, + u64 iTid, + int *pbCustomValid +); + +/* +** This is called as part of stage 1 recovery (the bit after the upper layer +** has loaded the database schema). The recovery mutex is held, so the client +** has exclusive access to the database on disk. +*/ +SQLITE_PRIVATE int sqlite3HctJrnlRecovery(HctJournal *pJrnl, HctDatabase *pDb); + +SQLITE_PRIVATE int sqlite3HctJrnlSavePhysical(sqlite3 *db, HctJournal *pJrnl, + int (*xSave)(void*, i64 iPhys), void *pSave +); + +/* +** Register the hct_journal_entry() SQL user-function with the database +** handle. For decoding the "data" column of the sqlite_hct_journal table. +*/ +SQLITE_PRIVATE int sqlite3HctJrnlInit(sqlite3 *db); + +/* +** Return non-zero if (1) argument pJrnl is not NULL, and either (2a) argument +** iTable is the logical root page of either the journal or baseline table +** represented by pJrnl, or (2b) the connection is in follower mode. +** +** Before returning, set output variable (*pbNosnap) to non-zero if condition +** (2a) was true. To indicate that the table does not use snapshots - all +** committed rows are visible. +*/ +SQLITE_PRIVATE int sqlite3HctJournalIsReadonly(HctJournal *pJrnl, u64 iTable, int *pbNosnap); + +SQLITE_PRIVATE int sqlite3HctJrnlRollbackEntry(HctJournal *pJrnl, i64 iTid); + +SQLITE_PRIVATE int sqlite3HctJrnlWriteEmpty(HctJournal *Jrnl, u64 iCid, u64 iTid, sqlite3 *db); + +SQLITE_PRIVATE u64 sqlite3HctJrnlWriteTid(HctJournal *pJrnl, u64 *piCid); + +SQLITE_PRIVATE u64 sqlite3HctJournalSnapshot(HctJournal *pJrnl); + +SQLITE_PRIVATE void sqlite3HctJournalFixSchema(HctJournal *pJrnl, sqlite3*, void *pSchema); + +SQLITE_PRIVATE void sqlite3HctJournalSchemaVersion(HctJournal *pJrnl, u32 *pSchemaVersion); + +SQLITE_PRIVATE void sqlite3HctJrnlInvokeHook(HctJournal *pJrnl, sqlite3 *db); + +/************** End of hctJrnlInt.h ******************************************/ +/************** Continuing where we left off in hctInt.h *********************/ +SQLITE_PRIVATE HctJournal *sqlite3HctJrnlFind(sqlite3*); + +SQLITE_PRIVATE int sqlite3HctBtreeIsNewTable(Btree *pBt, u64 iRoot); +SQLITE_PRIVATE u64 sqlite3HctBtreeSnapshotId(Btree *pBt); + +SQLITE_PRIVATE i64 sqlite3HctMainStats(sqlite3 *db, int iStat, const char **pzStat); + + + +/************** End of hctInt.h **********************************************/ +/************** Continuing where we left off in hct_pman.c *******************/ + +typedef struct HctPManPageset HctPManPageset; +typedef struct HctPManTree HctPManTree; + +#define PAGESET_INIT_SIZE 1000 + +typedef struct HctPManFreePg HctPManFreePg; +typedef struct HctPManFreePgSet HctPManFreePgSet; + +struct HctPManFreePg { + i64 pgno; /* The free page number */ + i64 iTid; /* TID of transaction that freed page */ +}; + +struct HctPManFreePgSet { + HctPManFreePg *aPg; /* Page buffer */ + int nAlloc; /* Allocated size of aPg[] */ + int iFirst; /* Index of first entry in aPg[] */ + int nPg; /* Number of valid pages in aPg[] */ +}; + + + + +/****************************************************************/ + +/* +** A basket of free page ids - a pageset - is represented by an instance +** of the following type. +** +** nAlloc: +** Allocated size of aPg[] array, in entries (not bytes). +** +** nPg: +** Number of valid entries in aPg[]. +** +** aPg: +** Array of free logical or physical page ids. +** +** iMaxTid: +** When a page is freed, it is associated with a TID. Such that the page +** may be reused once it is guaranteed that all current and future readers +** include in their snapshots all transactions with TID values less than +** the associated TID. The maximum of all these values for pages in the +** page set is stored in this variable. +** +** pNext: +** Used to link the HctPManServer.apList[] lists together. +*/ +struct HctPManPageset { + i64 iMaxTid; /* Max associated TID of aPg[] entries */ + int nAlloc; /* Allocated size of aPg[] array */ + int nPg; /* Number of valid entries in aPg[] */ + u32 *aPg; /* Array of page numbers */ + HctPManPageset *pNext; /* Next in list */ +}; + +/* +** A tree of free logical and physical pages. +*/ +struct HctPManTree { + u32 iRoot; /* Logical root of free tree */ + i64 iTid; /* Associated TID value */ +}; + +/* +** Indexes into HctPManServer.apList[], HctPManClient.apAcc[] and +** HctPManClient.apUse[] arrays. +*/ +#define PAGESET_PHYSICAL 0 +#define PAGESET_LOGICAL 1 + +/* +** aList[]: +** aList[0].pHead is a pointer to the first element of a singly-linked +** list of pagesets containing free physical page ids. aList[0].pTail +** always points to the last element of this list. The list is sorted +** in order of HctPManPageset.iMaxTid values. +** +** aList[1] is similar, but for logical page ids. +** +** aTree[]: +** Array of tree structures to eventually walk and free +*/ +struct HctPManServer { + sqlite3_mutex *pMutex; /* Mutex to protect this object */ + HctFileServer *pFileServer; /* Associated file-server object */ + struct HctPManServerList { + HctPManPageset *pHead; + HctPManPageset *pTail; + } aList[2]; + + int nTree; + HctPManTree *aTree; +}; + +/* +** Event counters used by the hctstats virtual table. +*/ +typedef struct HctPManStats HctPManStats; +struct HctPManStats { + i64 nMutex; + i64 nMutexBlock; +}; + +/* +** apAcc[]: +** These two pagesets are used to accumulate physical (apAcc[0]) and +** logical (apAcc[1]) page ids as they are freed by the client. Once +** sufficient page ids have been accumulated the pageset will be handed +** to the server object. +** +** apUse[]: +** These two pagesets are guaranteed to contain page ids that can be +** reused immediately. For the client to use as it requires. +*/ +struct HctPManClient { + HctConfig *pConfig; + HctPManServer *pServer; + HctFile *pFile; + + HctPManFreePgSet aPgSet[2]; /* Free physical and logical pages */ + + HctPManStats stats; +}; + +static void hctPManMutexEnter(HctPManClient *pClient){ + sqlite3_mutex *pMutex = pClient->pServer->pMutex; + pClient->stats.nMutex++; + if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ + pClient->stats.nMutexBlock++; + sqlite3_mutex_enter(pMutex); + } +} + + +#define ENTER_PMAN_MUTEX(pClient) hctPManMutexEnter(pClient) +#define LEAVE_PMAN_MUTEX(pClient) sqlite3_mutex_leave(pClient->pServer->pMutex) + +/* +** Utility malloc function for hct. Allocate nByte bytes of zeroed memory. +*/ +SQLITE_PRIVATE void *sqlite3HctMalloc(int *pRc, i64 nByte){ + void *pRet = 0; + assert( nByte!=0 ); + if( *pRc==SQLITE_OK ){ + pRet = sqlite3MallocZero(nByte); + if( pRet==0 ){ + *pRc = SQLITE_NOMEM_BKPT; + } + } + return pRet; +} + + +/* +** Allocate and return a new HctPManServer object. +*/ +SQLITE_PRIVATE HctPManServer *sqlite3HctPManServerNew( + int *pRc, + HctFileServer *pFileServer +){ + int rc = *pRc; + HctPManServer *pRet = 0; + pRet = sqlite3HctMalloc(&rc, sizeof(*pRet)); + if( pRet ){ + pRet->pFileServer = pFileServer; + pRet->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); + if( pRet->pMutex==0 ){ + rc = SQLITE_NOMEM_BKPT; + } + } + + if( rc!=SQLITE_OK ){ + sqlite3HctPManServerFree(pRet); + pRet = 0; + } + *pRc = rc; + return pRet; +} + + +SQLITE_PRIVATE void sqlite3HctPManServerReset(HctPManServer *pServer){ + int ii = 0; + for(ii=0; ii<2; ii++){ + HctPManPageset *pNext = pServer->aList[ii].pHead; + while( pNext ){ + HctPManPageset *pDel = pNext; + pNext = pNext->pNext; + sqlite3_free(pDel); + } + memset(&pServer->aList[ii], 0, sizeof(struct HctPManServerList)); + } +} + +/* +** Free an HctPManServer object allocated by an earlier call to +** sqlite3HctPManServerNew(). +*/ +SQLITE_PRIVATE void sqlite3HctPManServerFree(HctPManServer *pServer){ + if( pServer ){ + sqlite3HctPManServerReset(pServer); + sqlite3_mutex_free(pServer->pMutex); + sqlite3_free(pServer->aTree); + sqlite3_free(pServer); + } +} + +/* +** Allocate and return a pointer to a new pageset object with enough +** space for up to nAlloc page ids. +*/ +static HctPManPageset *hctPManPagesetNew(int *pRc, int nAlloc){ + const int nByte = sizeof(HctPManPageset) + nAlloc*sizeof(u32); + HctPManPageset *pRet = 0; + + pRet = (HctPManPageset*)sqlite3HctMalloc(pRc, nByte); + if( pRet ){ + pRet->aPg = (u32*)&pRet[1]; + pRet->nAlloc = nAlloc; + } + + return pRet; +} + +/* +** Add page iPg directly to the list of free pages managed by server pServer. +** iPg may be either a logical (if bLogical==1) or a physical (if bLogical==0) +** page id. It is available for reuse immediately. +** +** This function is not threadsafe. It is only called during initialization, +** when there is only one thread that may be accessing object pServer. +*/ +SQLITE_PRIVATE void sqlite3HctPManServerInit( + int *pRc, + HctPManServer *pServer, + u64 iTid, + u32 iPg, + int bLogical +){ + struct HctPManServerList *p = &pServer->aList[bLogical]; + assert( bLogical==0 || bLogical==1 ); + + if( p->pHead==0 || p->pHead->nPg==p->pHead->nAlloc ){ + HctPManPageset *pNew = hctPManPagesetNew(pRc, PAGESET_INIT_SIZE); + if( pNew==0 ) return; + pNew->pNext = p->pHead; + pNew->iMaxTid = iTid; + p->pHead = pNew; + if( p->pTail==0 ) p->pTail = pNew; + } + p->pHead->aPg[p->pHead->nPg++] = iPg; +} + +/* +** Allocate a new page-manager client. +*/ +SQLITE_PRIVATE HctPManClient *sqlite3HctPManClientNew( + int *pRc, /* IN/OUT: Error code */ + HctConfig *pConfig, /* Connection configuration object */ + HctPManServer *pServer, /* Page-manager server to connect to */ + HctFile *pFile /* File object */ +){ + HctPManClient *pClient = 0; + pClient = (HctPManClient*)sqlite3HctMalloc(pRc, sizeof(HctPManClient)); + if( pClient ){ + pClient->pConfig = pConfig; + pClient->pServer = pServer; + pClient->pFile = pFile; + } + return pClient; +} + +/* +** Hand off a page-set object to the server passed as the first argument. +*/ +static void hctPManServerHandoff( + HctPManServer *p, /* Server object */ + HctPManPageset *pPageSet, /* Pageset to pass to the server */ + int bLogical, /* True for logical, false for physical ids */ + int bUsable /* Page ids are immediately usable */ +){ + if( pPageSet ){ + struct HctPManServerList *pList = &p->aList[bLogical]; + if( bUsable ){ + pPageSet->pNext = pList->pHead; + pList->pHead = pPageSet; + if( pList->pTail==0 ) pList->pTail = pPageSet; + }else{ + pPageSet->pNext = 0; + if( pList->pTail==0 ){ + pList->pTail = pList->pHead = pPageSet; + }else{ + pList->pTail->pNext = pPageSet; + pList->pTail = pPageSet; + } + } + } +} + +/* +** +*/ +static int hctPManHandback( + HctPManClient *pClient, /* Client to hand pages back from */ + int bLogical, /* True for logical pages, false for phys. */ + int nPg /* Number of pages to hand back */ +){ + u64 iSafeTid = sqlite3HctFileSafeTID(pClient->pFile); + const int nPageSet = pClient->pConfig->nPageSet; + HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; + int nRem = nPg; + int rc = SQLITE_OK; + + HctPManPageset *pList = 0; + + assert( bLogical==0 || bLogical==1 ); + assert( nPg<=pSet->nPg ); + + while( nRem>0 ){ + int ii = 0; + HctPManPageset *pNew = 0; + int nCopy = MIN(nRem, nPageSet); + + nRem -= nCopy; + pNew = hctPManPagesetNew(&rc, nCopy); + if( !pNew ) break; + for(ii=0; iiiFirst + ii) % pSet->nAlloc; + pNew->aPg[pNew->nPg++] = (u32)(pSet->aPg[iPg].pgno); + pNew->iMaxTid = pSet->aPg[iPg].iTid; + } + pSet->iFirst = (pSet->iFirst+nCopy) % pSet->nAlloc; + pSet->nPg -= nCopy; + + pNew->pNext = pList; + pList = pNew; + } + assert( pList || nPg==0 || rc!=SQLITE_OK ); + + ENTER_PMAN_MUTEX(pClient); + while( pList ){ + int bSafe = (pList->iMaxTid<=iSafeTid); + HctPManPageset *pNext = pList->pNext; + pList->pNext = 0; + hctPManServerHandoff(pClient->pServer, pList, bLogical, bSafe); + pList = pNext; + } + LEAVE_PMAN_MUTEX(pClient); + + return rc; +} + +/* +** Free a page-manager client. +*/ +SQLITE_PRIVATE void sqlite3HctPManClientFree(HctPManClient *pClient){ + if( pClient ){ + /* Return all pages to the server object */ + hctPManHandback(pClient, 0, pClient->aPgSet[0].nPg); + hctPManHandback(pClient, 1, pClient->aPgSet[1].nPg); + + /* Free allocations */ + sqlite3_free(pClient->aPgSet[0].aPg); + sqlite3_free(pClient->aPgSet[1].aPg); + sqlite3_free(pClient); + } +} + + +typedef struct FreeTreeCtx FreeTreeCtx; +struct FreeTreeCtx { + HctFile *pFile; + HctPManClient *pPManClient; +}; + +static int pmanFreeTreeCb(void *pCtx, u32 iLogic, u32 iPhys){ + FreeTreeCtx *p = (FreeTreeCtx*)pCtx; + int rc = SQLITE_OK; + + if( iLogic && !sqlite3HctFilePageIsFree(p->pFile, iLogic, 1) ){ + rc = sqlite3HctFilePageClearInUse(p->pFile, iLogic, 1); + sqlite3HctPManFreePg(&rc, p->pPManClient, 0, iLogic, 1); + } + if( iPhys && !sqlite3HctFilePageIsFree(p->pFile, iPhys, 0) && rc==SQLITE_OK ){ + rc = sqlite3HctFilePageClearInUse(p->pFile, iPhys, 0); + sqlite3HctPManFreePg(&rc, p->pPManClient, 0, iPhys, 0); + } + + return rc; +} + +static int hctPManFreeTreeNow( + HctPManClient *p, + HctFile *pFile, + u32 iRoot +){ + int rc = SQLITE_OK; + FreeTreeCtx ctx; + ctx.pPManClient = p; + ctx.pFile = pFile; + rc = sqlite3HctDbWalkTree(pFile, iRoot, pmanFreeTreeCb, (void*)&ctx); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageClearIsRoot(pFile, iRoot); + } + return rc; +} + +#if 0 +static void pman_debug( + HctPManClient *pClient, + const char *zOp, + int bLogical, + u32 iPg, + i64 iTid +){ + printf("pman: (%p) %s %s page %d - tid=%lld\n", pClient, + zOp, bLogical ? "LOGICAL" : "PHYSICAL", (int)iPg, iTid + ); + fflush(stdout); +} + +static void pman_debug_new_pageset( + HctPManPageset *pPageSet, + int bLogical, + u64 iSafeTid, + u64 iServerTid +){ + printf( + "pman: new %s pageset - safetid=%lld servertid=%lld\n", + bLogical ? "LOGICAL" : "PHYSICAL", iSafeTid, iServerTid + ); + fflush(stdout); +} +#else + +# define pman_debug(a,b,c,d,e) +# define pman_debug_new_pageset(a,b,c,d) + +#endif + +/* +** Ensure that the circular buffer identified by bLogical has at least +** nPg free slots in it. +*/ +static int hctPManMakeSpace( + HctPManClient *pClient, + int bLogical, + int nPg +){ + int rc = SQLITE_OK; + HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; + + if( (pSet->nAlloc-pSet->nPg)nPg + nPg; + int nByte = nNew * sizeof(HctPManFreePg); + HctPManFreePg *aNew = (HctPManFreePg*)sqlite3_realloc(pSet->aPg, nByte); + + if( aNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pSet->aPg = aNew; + if( (pSet->iFirst + pSet->nPg)>pSet->nAlloc ){ + int nExtra = nNew - pSet->nAlloc; + int nStart = pSet->nPg - (pSet->nAlloc - pSet->iFirst); + + if( nExtra>=nStart ){ + memcpy(&aNew[pSet->nAlloc], aNew, nStart*sizeof(HctPManFreePg)); + }else{ + memcpy(&aNew[pSet->nAlloc], aNew, nExtra*sizeof(HctPManFreePg)); + memmove(aNew, &aNew[nExtra], (nStart-nExtra)*sizeof(HctPManFreePg)); + } + } + pSet->nAlloc = nNew; + } + } + + return rc; +} + +static void hctPManAddFree( + HctPManClient *pClient, + int bLogical, + i64 iPg, + i64 iTid +){ + HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; + int iIdx = 0; + + assert( pSet->nPgnAlloc ); + if( iTid==0 ){ + if( pSet->iFirst==0 ) pSet->iFirst = pSet->nAlloc; + pSet->iFirst--; + iIdx = pSet->iFirst; + }else{ + iIdx = (pSet->iFirst + pSet->nPg) % pSet->nAlloc; + } + + pSet->nPg++; + pSet->aPg[iIdx].pgno = iPg; + pSet->aPg[iIdx].iTid = iTid; +} + + +/* +** Allocate a new logical or physical page. +*/ +SQLITE_PRIVATE u32 sqlite3HctPManAllocPg( + int *pRc, /* IN/OUT: Error code */ + HctPManClient *pClient, /* page-manager client handle */ + HctFile *pFile, + int bLogical +){ + HctPManServer *p = pClient->pServer; + u64 iSafeTid = sqlite3HctFileSafeTID(pFile); + HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; + u32 iRoot = 0; + HctPManPageset *pPgset = 0; + int rc = SQLITE_OK; + + /* Check if the client has a usable page already. If so, return early. */ + if( pSet->nPg>0 && pSet->aPg[pSet->iFirst].iTid<=iSafeTid ){ + u32 pgno = pSet->aPg[pSet->iFirst].pgno; + + pman_debug(pClient, "alloc", bLogical, pgno, pSet->aPg[pSet->iFirst].iTid); + + pSet->iFirst = (pSet->iFirst+1) % pSet->nAlloc; + pSet->nPg--; + return pgno; + } + + do{ + iRoot = 0; + + /* Attempt to allocate a page from the page-manager server. */ + ENTER_PMAN_MUTEX(pClient); + if( p->nTree>0 && p->aTree[0].iTid<=iSafeTid ){ + /* A tree structure that can be traversed to find free pages. */ + iRoot = p->aTree[0].iRoot; + p->nTree--; + memmove(&p->aTree[0], &p->aTree[1], (p->nTree)*sizeof(HctPManTree)); + }else{ + struct HctPManServerList *pList = &p->aList[bLogical]; + if( pList->pHead && pList->pHead->iMaxTid<=iSafeTid ){ + /* A page-set object full of usable pages */ + pPgset = pList->pHead; + pList->pHead = pList->pHead->pNext; + if( pList->pHead==0 ) pList->pTail = 0; + } + } + LEAVE_PMAN_MUTEX(pClient); + + /* If a free tree structure was found, iterate through it, returning + ** all physical and logical pages to the server. Then retry the above. + */ + if( iRoot ){ + rc = hctPManFreeTreeNow(pClient, pFile, iRoot); + } + }while( iRoot ); + + if( rc==SQLITE_OK ){ + int ii; + if( pPgset ){ + pman_debug_new_pageset(pPgset, bLogical, iSafeTid, pPgset->iMaxTid); + rc = hctPManMakeSpace(pClient, bLogical, pPgset->nPg); + if( rc==SQLITE_OK ){ + for(ii=pPgset->nPg-1; ii>=0; ii--){ + hctPManAddFree(pClient, bLogical, pPgset->aPg[ii], 0); + } + } + }else{ + const int nPageSet = pClient->pConfig->nPageSet; + rc = hctPManMakeSpace(pClient, bLogical, nPageSet); + if( rc==SQLITE_OK ){ + u32 iPg = sqlite3HctFilePageRangeAlloc(pFile, bLogical, nPageSet); + pman_debug_new_pageset(0, bLogical, iSafeTid, -1); + for(ii=nPageSet-1; ii>=0; ii--){ + hctPManAddFree(pClient, bLogical, iPg+ii, 0); + } + } + } + } + sqlite3_free(pPgset); + + if( rc==SQLITE_OK ){ + assert( pSet->nPg>0 && pSet->aPg[pSet->iFirst].iTid<=iSafeTid ); + return sqlite3HctPManAllocPg(pRc, pClient, pFile, bLogical); + } + + /* An error has occurred. Return 0. */ + *pRc = rc; + return 0; +} + +/* +** Free a physical or logical page. +*/ +SQLITE_PRIVATE void sqlite3HctPManFreePg( + int *pRc, /* IN/OUT: Error code */ + HctPManClient *pClient, /* page-manager client handle */ + i64 iTid, /* Associated TID value */ + u32 iPg, /* Page number */ + int bLogical /* True for logical, false for physical */ +){ + int rc = SQLITE_OK; + pman_debug(pClient, "free", bLogical, iPg, iTid); + assert( iPg>0 ); + rc = hctPManMakeSpace(pClient, bLogical, 1); + if( rc==SQLITE_OK ){ + hctPManAddFree(pClient, bLogical, iPg, iTid); + } +} + +SQLITE_PRIVATE void sqlite3HctPManClientHandoff(HctPManClient *pClient){ + hctPManHandback(pClient, 0, pClient->aPgSet[0].nPg); + hctPManHandback(pClient, 1, pClient->aPgSet[1].nPg); +} + +SQLITE_PRIVATE int sqlite3HctPManFreeTree( + HctPManClient *p, + HctFile *pFile, + u32 iRoot, + u64 iTid +){ + int rc = SQLITE_OK; + if( iTid==0 ){ + rc = hctPManFreeTreeNow(p, pFile, iRoot); + }else{ + HctPManServer *pServer = p->pServer; + int nNew; + HctPManTree *aNew; + + ENTER_PMAN_MUTEX(p); + nNew = pServer->nTree + 1; + aNew = (HctPManTree*)sqlite3_realloc( + pServer->aTree, nNew*sizeof(HctPManTree) + ); + if( aNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + aNew[pServer->nTree].iRoot = iRoot; + aNew[pServer->nTree].iTid = iTid; + pServer->nTree++; + pServer->aTree = aNew; + } + LEAVE_PMAN_MUTEX(p); + } + return rc; +} + +typedef struct InitRootCtx InitRootCtx; +struct InitRootCtx { + HctFile *pFile; + HctPManServer *pServer; + u64 iTid; + u64 iRoot; /* Logical root page of this tree */ +}; + +static int pmanInitRootCb(void *pCtx, u32 iLogic, u32 iPhys){ + InitRootCtx *p = (InitRootCtx*)pCtx; + int rc = SQLITE_OK; + + if( iLogic && !sqlite3HctFilePageIsFree(p->pFile, iLogic, 1) ){ + rc = sqlite3HctFilePageClearInUse(p->pFile, iLogic, 1); + if( iLogiciRoot ){ + sqlite3HctPManServerInit(&rc, p->pServer, p->iTid, iLogic, 1); + } + } + if( iPhys && !sqlite3HctFilePageIsFree(p->pFile, iPhys, 0) && rc==SQLITE_OK ){ + rc = sqlite3HctFilePageClearInUse(p->pFile, iPhys, 0); + if( iPhysiRoot ){ + sqlite3HctPManServerInit(&rc, p->pServer, p->iTid, iPhys, 0); + } + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctPManServerInitRoot( + int *pRc, + HctPManServer *pServer, + u64 iTid, + HctFile *pFile, + u32 iRoot +){ + int rc = SQLITE_OK; + InitRootCtx ctx; + ctx.pServer = pServer; + ctx.pFile = pFile; + ctx.iTid = iTid; + ctx.iRoot = iRoot; + rc = sqlite3HctDbWalkTree(pFile, iRoot, pmanInitRootCb, (void*)&ctx); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageClearIsRoot(pFile, iRoot); + } + return rc; +} + +/************************************************************************* +** Beginning of vtab implemetation. +*************************************************************************/ + +#define HCT_PMAN_SCHEMA \ +" CREATE TABLE hctpman(" \ +" type TEXT," \ +" location TEXT," \ +" pgno INTEGER," \ +" tid INTEGER" \ +" );" + +typedef struct pman_vtab pman_vtab; +typedef struct pman_cursor pman_cursor; +typedef struct HctPmanRow HctPmanRow; + +/* +** Virtual table type for "hctpman". +*/ +struct pman_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; + +/* +** Virtual cursor type for "hctpman". +*/ +struct pman_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + int nRow; + int iRow; + HctPmanRow *aRow; +}; + +/* +** Values to return for a single row of the hctpman table. +*/ +struct HctPmanRow { + u8 eType; /* HCT_PMAN_TYPE_* value */ + u8 eLoc; /* HCT_PMAN_LOC_* value */ + u32 pgno; /* Page number */ + i64 iTid; /* Associated TID */ +}; + +#define HCT_PMAN_TYPE_PHYSICAL 0 +#define HCT_PMAN_TYPE_LOGICAL 1 + +#define HCT_PMAN_LOC_USE 0 +#define HCT_PMAN_LOC_ACC 1 +#define HCT_PMAN_LOC_SERVER 2 + +/* +** This xConnect() method is invoked to create a new hctpman virtual table. +*/ +static int pmanConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + pman_vtab *pNew; + int rc; + + rc = sqlite3_declare_vtab(db, HCT_PMAN_SCHEMA); + pNew = (pman_vtab*)sqlite3HctMalloc(&rc, sizeof(*pNew)); + if( pNew ){ + pNew->db = db; + } + + *ppVtab = (sqlite3_vtab*)pNew; + return rc; +} + +/* +** This method is the destructor for pman_vtab objects. +*/ +static int pmanDisconnect(sqlite3_vtab *pVtab){ + pman_vtab *p = (pman_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new pman_cursor object. +*/ +static int pmanOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + pman_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a pman_cursor. +*/ +static int pmanClose(sqlite3_vtab_cursor *cur){ + pman_cursor *pCur = (pman_cursor*)cur; + sqlite3_free(pCur->aRow); + sqlite3_free(pCur); + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last row of output. +*/ +static int pmanEof(sqlite3_vtab_cursor *cur){ + pman_cursor *pCur = (pman_cursor*)cur; + return pCur->iRow>=pCur->nRow; +} + +/* +** Advance a pman_cursor to its next row of output. +*/ +static int pmanNext(sqlite3_vtab_cursor *cur){ + pman_cursor *pCur = (pman_cursor*)cur; + pCur->iRow++; + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the pgmap_cursor +** is currently pointing. +*/ +static int pmanColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + const char *aType[] = {"physical", "logical"}; + const char *aLoc[] = {"use", "acc", "server"}; + pman_cursor *pCur = (pman_cursor*)cur; + + HctPmanRow *pRow = &pCur->aRow[pCur->iRow]; + switch( i ){ + case 0: { /* type */ + sqlite3_result_text(ctx, aType[pRow->eType], -1, SQLITE_STATIC); + break; + } + case 1: { /* location */ + sqlite3_result_text(ctx, aLoc[pRow->eLoc], -1, SQLITE_STATIC); + break; + } + case 2: { /* pgno */ + sqlite3_result_int64(ctx, pRow->pgno); + break; + } + case 3: { /* tid */ + sqlite3_result_int64(ctx, pRow->iTid); + break; + } + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the slotno value. +*/ +static int pmanRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + pman_cursor *pCur = (pman_cursor*)cur; + *pRowid = pCur->iRow+1; + return SQLITE_OK; +} + +static int hctPagesetSize(HctPManPageset *pPageset){ + return pPageset ? pPageset->nPg : 0; +} + +static void hctPagesetRows( + pman_cursor *pCur, + HctPManPageset *pPageset, + u8 eType, + u8 eLoc +){ + if( pPageset ){ + int ii; + for(ii=0; iinPg; ii++){ + HctPmanRow *pRow = &pCur->aRow[pCur->nRow++]; + pRow->eType = eType; + pRow->eLoc = eLoc; + pRow->pgno = pPageset->aPg[ii]; + pRow->iTid = pPageset->iMaxTid; + } + } +} + +/* +** This method is called to "rewind" the pman_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to pmanColumn() or pmanRowid() or +** pmanEof(). +*/ +static int pmanFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + pman_cursor *pCur = (pman_cursor*)pVtabCursor; + pman_vtab *pTab = (pman_vtab*)(pCur->base.pVtab); + HctPManClient *pClient = 0; + int nRow = 0; + int ii = 0; + HctPManPageset *pSet = 0; + int rc = SQLITE_OK; + + pCur->iRow = 0; + pCur->nRow = 0; + sqlite3_free(pCur->aRow); + pCur->aRow = 0; + + pClient = sqlite3HctFilePManClient( + sqlite3HctDbFile(sqlite3HctDbFind(pTab->db, 0)) + ); + + ENTER_PMAN_MUTEX(pClient); + for(ii=0; ii<2; ii++){ + nRow += pClient->aPgSet[ii].nPg; + for(pSet=pClient->pServer->aList[ii].pHead; pSet; pSet=pSet->pNext){ + nRow += hctPagesetSize(pSet); + } + } + pCur->aRow = sqlite3HctMalloc(&rc, sizeof(HctPmanRow) * nRow); + if( pCur->aRow ){ + for(ii=0; ii<2; ii++){ + int i2; + HctPManFreePgSet *pPgSet = &pClient->aPgSet[ii]; + for(i2=0; i2nPg; i2++){ + HctPmanRow *pRow = &pCur->aRow[pCur->nRow++]; + int idx = (pPgSet->iFirst + i2) % pPgSet->nAlloc; + pRow->eType = ii; + pRow->eLoc = HCT_PMAN_LOC_USE; + pRow->pgno = pPgSet->aPg[idx].pgno; + pRow->iTid = pPgSet->aPg[idx].iTid; + } + for(pSet=pClient->pServer->aList[ii].pHead; pSet; pSet=pSet->pNext){ + hctPagesetRows(pCur, pSet, ii, HCT_PMAN_LOC_SERVER); + } + } + } + LEAVE_PMAN_MUTEX(pClient); + + return rc; +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int pmanBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)10; + pIdxInfo->estimatedRows = 10; + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctPManVtabInit(sqlite3 *db){ + static sqlite3_module pmanModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ pmanConnect, + /* xBestIndex */ pmanBestIndex, + /* xDisconnect */ pmanDisconnect, + /* xDestroy */ 0, + /* xOpen */ pmanOpen, + /* xClose */ pmanClose, + /* xFilter */ pmanFilter, + /* xNext */ pmanNext, + /* xEof */ pmanEof, + /* xColumn */ pmanColumn, + /* xRowid */ pmanRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + return sqlite3_create_module(db, "hctpman", &pmanModule, 0); +} + + +SQLITE_PRIVATE i64 sqlite3HctPManStats(sqlite3 *db, int iStat, const char **pzStat){ + HctPManClient *pClient = 0; + i64 iVal = -1; + + pClient = sqlite3HctFilePManClient(sqlite3HctDbFile(sqlite3HctDbFind(db, 0))); + switch( iStat ){ + case 0: + *pzStat = "mutex_attempt"; + iVal = pClient->stats.nMutex; + break; + case 1: + *pzStat = "mutex_block"; + iVal = pClient->stats.nMutexBlock; + break; + default: + break; + } + + return iVal; +} + + + +/************** End of hct_pman.c ********************************************/ +/************** Begin file hctree.c ******************************************/ +/* +** 2004 April 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ + +/* #include "sqliteInt.h" */ +/* #include "hctInt.h" */ + +/* #include */ +/* #include */ +/* #include */ +/* #include */ +#include + +#ifdef SQLITE_ENABLE_HCT + +typedef struct BtSchemaOp BtSchemaOp; + +typedef struct HBtree HBtree; +typedef struct HBtCursor HBtCursor; +typedef struct HctLogFile HctLogFile; +typedef struct HctMainStats HctMainStats; + + +/* +** An object to help with writing a log file. +*/ +struct HctLogFile { + int fd; /* File descriptor open on log file */ + char *zLogFile; /* Full path to log file */ + u8 *aBuf; /* malloc'd buffer for writing log file */ + int nBuf; /* Size of aBuf[] in bytes */ + i64 iFileOff; /* Current write offset in file */ + int iBufferOff; /* Current write offset in buffer */ +}; + +struct HctMainStats { + i64 nRetry; + i64 nRetryKey; + i64 nKeyOp; +}; + +/* +** aSchemaOp[]: +** Array of nSchemaOp BtSchemaOp structures. Each such structure represents +** a new table or index created by the current transaction. +** aSchemaOp[x].iSavepoint contains the open savepoint count when the table +** with root page aSchemaOp[x].pgnoRoot was created. The value +** HBtree.db->nSavepoint. +** +** eTrans: +** Set to SQLITE_TXN_NONE, READ or WRITE to indicate the type of +** transaction that is open. This is set by the following functions: +** +** sqlite3HctBtreeBeginTrans() +** sqlite3HctBtreeCommitPhaseTwo() +** sqlite3HctBtreeRollback() +*/ +struct HBtree { + BtreeMethods *pMethods; + + HctConfig config; /* Configuration for this connection */ + HctTree *pHctTree; /* In-memory part of database */ + HctDatabase *pHctDb; /* On-disk part of db, if any */ + void *pSchema; /* Memory from sqlite3HctBtreeSchema() */ + void(*xSchemaFree)(void*); /* Function to free pSchema */ + int eTrans; /* SQLITE_TXN_NONE, READ or WRITE */ + HBtCursor *pCsrList; /* List of all open cursors */ + + int nSchemaOp; + BtSchemaOp *aSchemaOp; + int nRollbackOp; + + int openFlags; + HctLogFile *pLog; /* Object for writing to log file */ + u32 iNextRoot; /* Next root page to allocate if pHctDb==0 */ + u32 aMeta[SQLITE_N_BTREE_META]; /* 16 database meta values */ + int eMetaState; + + int bRecoveryDone; +#if 0 + u64 iJrnlRoot; /* Root of sqlite_hct_journal */ + u64 iBaseRoot; /* Root of sqlite_hct_baseline */ +#endif + HctJournal *pHctJrnl; + + Pager *pFakePager; + HctMainStats stats; +}; + +/* +** Another candidate value for HBtree.eTrans. Must be different from +** SQLITE_TXN_NONE, SQLITE_TXN_READ and SQLITE_TXN_WRITE. +*/ +#define SQLITE_TXN_ERROR 4 + +/* +** Candidate values for HBtree.eMetaState. +*/ +#define HCT_METASTATE_NONE 0 +#define HCT_METASTATE_READ 1 + +/* +** A schema op. +*/ +struct BtSchemaOp { + int iSavepoint; + int eSchemaOp; + u32 pgnoRoot; +}; + +/* +** Candidate values for BtSchemaOp.eSchemaOp +*/ +#define HCT_SCHEMAOP_DROP 1 +#define HCT_SCHEMAOP_CREATE_INTKEY 2 +#define HCT_SCHEMAOP_CREATE_INDEX 3 + + +struct HBtCursor { + BtCursorMethods *pMethods; + + HBtree *pBtree; + HctTreeCsr *pHctTreeCsr; + HctDbCsr *pHctDbCsr; + int bUseTree; /* 1 if tree-csr is current entry, else 0 */ + int eDir; /* One of BTREE_DIR_NONE, FORWARD, REVERSE */ + + int isLast; /* Csr has not moved since BtreeLast() */ + + KeyInfo *pKeyInfo; /* For non-intkey tables */ + int errCode; + int wrFlag; /* Value of wrFlag when cursor opened */ + HBtCursor *pCsrNext; /* Next element in Btree.pCsrList list */ +}; + + +#ifdef SQLITE_TEST +SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; +#endif + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Enable or disable the shared pager and schema features. +** +** This routine has no effect on existing database connections. +** The shared cache setting effects only future calls to +** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). +*/ +SQLITE_API int sqlite3_enable_shared_cache(int enable){ + sqlite3GlobalConfig.sharedCacheEnabled = enable; + return SQLITE_OK; +} +#endif + + +/* +** Return an reset the seek counter for a Btree object. +*/ +SQLITE_PRIVATE sqlite3_uint64 sqlite3HctBtreeSeekCount(Btree *pBt){ + assert( 0 ); + return 0; +} + +/* +** Clear the current cursor position. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeClearCursor(BtCursor *pCur){ + HBtCursor *pCsr = (HBtCursor*)pCur; + sqlite3HctDbCsrClear(pCsr->pHctDbCsr); + sqlite3HctTreeCsrClear(pCsr->pHctTreeCsr); +} + +/* +** Determine whether or not a cursor has moved from the position where +** it was last placed, or has been invalidated for any other reason. +** Cursors can move when the row they are pointing at is deleted out +** from under them, for example. Cursor might also move if a btree +** is rebalanced. +** +** Calling this routine with a NULL cursor pointer returns false. +** +** Use the separate sqlite3HctBtreeCursorRestore() routine to restore a cursor +** back to where it ought to be if this routine returns true. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursorHasMoved(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + return sqlite3HctTreeCsrHasMoved(pCur->pHctTreeCsr); +} + +/* +** Return a pointer to a fake BtCursor object that will always answer +** false to the sqlite3HctBtreeCursorHasMoved() routine above. The fake +** cursor returned must not be used with any other Btree interface. +*/ +#if 0 +SQLITE_PRIVATE BtCursor *sqlite3HctBtreeFakeValidCursor(void){ + static BtCursor csr = {0,0,0}; + return &csr; +} +#endif + +/* +** This routine restores a cursor back to its original position after it +** has been moved by some outside activity (such as a btree rebalance or +** a row having been deleted out from under the cursor). +** +** On success, the *pDifferentRow parameter is false if the cursor is left +** pointing at exactly the same row. *pDifferntRow is the row the cursor +** was pointing to has been deleted, forcing the cursor to point to some +** nearby row. +** +** This routine should only be called for a cursor that just returned +** TRUE from sqlite3HctBtreeCursorHasMoved(). +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursorRestore(BtCursor *pCursor, int *pDifferentRow){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + return sqlite3HctTreeCsrRestore(pCur->pHctTreeCsr, pDifferentRow); +} + +/* +** Return the size of the database file in pages. If there is any kind of +** error, return ((unsigned int)-1). +*/ +SQLITE_PRIVATE Pgno sqlite3HctBtreeLastPage(Btree *p){ + return 0xFFFFFFFF; +} + +/* +** Provide flag hints to the cursor. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeCursorHintFlags(BtCursor *pCur, unsigned x){ + /* no-op */ + assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); +} + +typedef struct RecoverCsr RecoverCsr; +struct RecoverCsr { + HctDbCsr *pCsr; /* Cursor to read from database on disk */ + HctTreeCsr *pTreeCsr; /* Cursor to write to in-memory tree */ + UnpackedRecord *pRec; /* Used to seek both cursors */ + KeyInfo *pKeyInfo; +}; + +static void hctRecoverCursorClose(HBtree *p, RecoverCsr *pCsr){ + sqlite3HctDbCsrClose(pCsr->pCsr); + sqlite3HctTreeCsrClose(pCsr->pTreeCsr); + sqlite3DbFree(p->config.db, pCsr->pRec); + sqlite3KeyInfoUnref(pCsr->pKeyInfo); + memset(pCsr, 0, sizeof(RecoverCsr)); +} + +static int hctFindKeyInfo(HBtree *p, u32 iRoot, KeyInfo **ppKeyInfo){ + Schema *pSchema = (Schema*)p->pSchema; + int rc = SQLITE_OK; + HashElem *pE = 0; + KeyInfo *pKeyInfo = 0; + + /* Search the database schema for an index with root page iRoot. If + ** one is found, extract a KeyInfo reference. */ + for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ + Index *pIdx = 0; + Table *pTab = (Table*)sqliteHashData(pE); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->tnum==iRoot ){ + Parse sParse; + Parse *pSave = 0; + memset(&sParse, 0, sizeof(sParse)); + sParse.db = p->config.db; + pSave = sParse.db->pParse; + sParse.db->pParse = &sParse; + pKeyInfo = sqlite3KeyInfoOfIndex(&sParse, pIdx); + sParse.db->pParse = pSave; + rc = sParse.rc; + sqlite3DbFree(sParse.db, sParse.zErrMsg); + break; + } + } + if( pTab->tnum==iRoot ) break; + } + + *ppKeyInfo = pKeyInfo; + return rc; +} + +/* +** +*/ +static int hctRecoverCursorOpen( + HBtree *p, + u32 iRoot, + RecoverCsr *pCsr +){ + int rc = SQLITE_OK; + memset(pCsr, 0, sizeof(RecoverCsr)); + + rc = hctFindKeyInfo(p, iRoot, &pCsr->pKeyInfo); + assert( rc==SQLITE_OK || pCsr->pKeyInfo==0 ); + if( pCsr->pKeyInfo ){ + pCsr->pRec = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo); + if( pCsr->pRec==0 ) rc = SQLITE_NOMEM_BKPT; + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrOpen(p->pHctDb, pCsr->pKeyInfo, iRoot, &pCsr->pCsr); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr->pTreeCsr); + } + + return rc; +} + +#if 1 +# define hctRecoverDebug(v,w,x,y,z) +#else +static void hctRecoverDebug( + RecoverCsr *p, + const char *zType, + i64 iKey, + const u8 *aKey, + int nKey +){ + if( p->pRec==0 ){ + printf("recover-%s: %lld\n", zType, iKey); + }else{ + char *zText = sqlite3HctDbRecordToText(0, aKey, nKey); + printf("recover-%s: %s\n", zType, zText); + sqlite3_free(zText); + } + fflush(stdout); +} +#endif + +/* +** This object is used to read a log file from disk. It is manipulated using +** the following API: +** +** hctLogReaderOpen() +** hctLogReaderNext() +** hctLogReaderClose() +** +** Log file format consists of an 8-byte TID value followed by one or more +** records. Each record is: +** +** * 32-bit root page number, +** * 32-bit size of key field (nKey), +** * if( nKey==0 ) 64-bit rowid key, +** * if( nKey!=0 ) nKey byte blob key. +*/ +typedef struct HctLogReader HctLogReader; +struct HctLogReader { + u8 *aFile; /* Buffer containing log file contents */ + int nFile; /* Size of aFile[] in bytes */ + int iFile; /* Offset of next record in aFile[] */ + + i64 iTid; /* TID value for log file */ + int bEof; /* True if reader has hit EOF */ + + /* Valid only if bEof==0 */ + i64 iRoot; /* Root page for current entry */ + i64 iKey; /* Integer key for current entry (aKey==0) */ + int nKey; /* Size of aKey[] buffer */ + u8 *aKey; /* Blob key for current entry */ +}; + +static void hctLogReaderNext(HctLogReader *pReader){ + u32 aInt[2]; + + if( (pReader->iFile + sizeof(aInt))>pReader->nFile ){ + pReader->bEof = 1; + }else{ + memcpy(aInt, &pReader->aFile[pReader->iFile], sizeof(aInt)); + pReader->iRoot = (i64)aInt[0]; + if( pReader->iRoot==0 ){ + pReader->bEof = 1; + }else{ + pReader->nKey = (int)aInt[1]; + pReader->iFile += sizeof(aInt); + if( pReader->nKey==0 ){ + pReader->aKey = 0; + if( pReader->iFile+sizeof(i64)>pReader->nFile ){ + pReader->bEof = 1; + }else{ + memcpy(&pReader->iKey, &pReader->aFile[pReader->iFile], sizeof(i64)); + pReader->iFile += sizeof(i64); + } + }else{ + pReader->iKey = 0; + if( pReader->iFile+pReader->nKey>pReader->nFile ){ + pReader->bEof = 1; + }else{ + pReader->aKey = &pReader->aFile[pReader->iFile]; + pReader->iFile += pReader->nKey; + } + } + } + } +} + +static void hctLogReaderClose(HctLogReader *pReader){ + sqlite3_free(pReader->aFile); + memset(pReader, 0, sizeof(*pReader)); +} + +static int hctLogReaderOpen(const char *zFile, HctLogReader *pReader){ + int rc = SQLITE_OK; + int fd = -1; + + memset(pReader, 0, sizeof(*pReader)); + fd = open(zFile, O_RDONLY); + if( fd<0 ){ + rc = sqlite3HctIoerr(SQLITE_IOERR); + }else{ + struct stat sStat; + + memset(&sStat, 0, sizeof(sStat)); + fstat(fd, &sStat); + pReader->nFile = (int)sStat.st_size; + pReader->aFile = (u8*)sqlite3HctMalloc(&rc, pReader->nFile + 8); + if( pReader->aFile ){ + int nRead = read(fd, pReader->aFile, pReader->nFile); + if( nRead!=pReader->nFile ){ + rc = sqlite3HctIoerr(SQLITE_IOERR); + }else{ + memcpy(&pReader->iTid, pReader->aFile, sizeof(i64)); + pReader->iFile = sizeof(i64); + if( pReader->iTid==0 ){ + pReader->bEof = 1; + }else{ + hctLogReaderNext(pReader); + } + } + } + + close(fd); + } + + return rc; +} + + +static int btreeFlushData(HBtree *p, int bRollback); + +static int hctRecoverOne(void *pCtx, const char *zFile){ + HBtree *p = (HBtree*)pCtx; + int rc = SQLITE_OK; + u32 iPrevRoot = 0; + RecoverCsr csr; + HctLogReader rdr; + + memset(&csr, 0, sizeof(csr)); + rc = hctLogReaderOpen(zFile, &rdr); + if( rc==SQLITE_OK && rdr.bEof==0 ){ + + assert( rdr.iTid!=0 ); + sqlite3HctDbRollbackMode(p->pHctDb, 2); + sqlite3HctDbRecoverTid(p->pHctDb, rdr.iTid); + for(/* no-op */; rdr.bEof==0; hctLogReaderNext(&rdr)){ + int op = 0; + + if( rdr.iRoot!=iPrevRoot ){ + iPrevRoot = rdr.iRoot; + hctRecoverCursorClose(p, &csr); + rc = hctRecoverCursorOpen(p, rdr.iRoot, &csr); + } + + if( rdr.nKey ){ + sqlite3VdbeRecordUnpack(csr.pKeyInfo, rdr.nKey, rdr.aKey, csr.pRec); + } + rc = sqlite3HctDbCsrRollbackSeek(csr.pCsr, csr.pRec, rdr.iKey, &op); + + if( rc==SQLITE_OK && op!=0 ){ + HctTreeCsr *pTCsr = csr.pTreeCsr; + if( op<0 ){ + /* rollback requires deleting the key */ + hctRecoverDebug(&csr, "delete", rdr.iKey, rdr.aKey, rdr.nKey); + rc = sqlite3HctTreeDeleteKey( + pTCsr, csr.pRec, rdr.iKey, rdr.nKey, rdr.aKey + ); + }else if( op>0 ){ + const u8 *aOld = 0; + int nOld = 0; + rc = sqlite3HctDbCsrData(csr.pCsr, &nOld, &aOld); + if( rc==SQLITE_OK ){ + hctRecoverDebug(&csr, "insert", rdr.iKey, aOld, nOld); + rc = sqlite3HctTreeInsert(pTCsr, csr.pRec, rdr.iKey, nOld, aOld, 0); + } + } + } + } + hctRecoverCursorClose(p, &csr); + + if( rc==SQLITE_OK ){ + rc = btreeFlushData(p, 0); + } + sqlite3HctDbRollbackMode(p->pHctDb, 0); + if( rc==SQLITE_OK && p->pHctJrnl ){ + rc = sqlite3HctJrnlRollbackEntry(p->pHctJrnl, rdr.iTid); + } + sqlite3HctDbRecoverTid(p->pHctDb, 0); + } + + if( rc==SQLITE_OK ){ + /* TODO!!! */ + unlink(zFile); + } + hctLogReaderClose(&rdr); + return rc; +} + +static int hctRecoverLogs(HBtree *p){ + HctFile *pFile = sqlite3HctDbFile(p->pHctDb); + return sqlite3HctFileFindLogs(pFile, (void*)p, hctRecoverOne); +} + + +/* +** Free a pLog object and close the associated log file handle. If parameter +** bUnlink is true, also unlink() the log file. +*/ +static void hctLogFileClose(HctLogFile *pLog, int bUnlink){ + if( pLog ){ + close(pLog->fd); + if( bUnlink ) unlink(pLog->zLogFile); + sqlite3_free(pLog->zLogFile); + sqlite3_free(pLog->aBuf); + sqlite3_free(pLog); + } +} + +/* +** Open a log file object. +*/ +static int hctLogFileOpen(char *zLogFile, int nBuf, HctLogFile **ppLog){ + int rc = SQLITE_OK; + HctLogFile *pLog; + + pLog = (HctLogFile*)sqlite3HctMalloc(&rc, sizeof(HctLogFile)); + if( pLog ){ + pLog->zLogFile = zLogFile; + pLog->fd = open(zLogFile, O_CREAT|O_RDWR, 0644); + if( pLog->fd<0 ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + pLog->nBuf = nBuf; + pLog->aBuf = sqlite3HctMalloc(&rc, nBuf); + } + } + + if( rc!=SQLITE_OK ){ + hctLogFileClose(pLog, 0); + pLog = 0; + } + + *ppLog = pLog; + return rc; +} + +static int hctLogFileWrite(HctLogFile *pLog, const void *aData, int nData){ + int nRem = nData; + const u8 *aRem = (u8*)aData; + + assert( pLog->iBufferOff<=pLog->nBuf ); + while( 1 ){ + + int nCopy = MIN(pLog->nBuf - pLog->iBufferOff, nRem); + if( nCopy>0 ){ + memcpy(&pLog->aBuf[pLog->iBufferOff], aRem, nCopy); + pLog->iBufferOff += nCopy; + nRem -= nCopy; + if( nRem==0 ) break; + aRem += nCopy; + } + + if( write(pLog->fd, pLog->aBuf, pLog->nBuf)!=pLog->nBuf ){ + return sqlite3HctIoerr(SQLITE_IOERR_WRITE); + } + pLog->iFileOff += pLog->nBuf; + pLog->iBufferOff = 0; + } + + return SQLITE_OK; +} + + +static void hctLogFileRestart(HctLogFile *pLog){ + memset(pLog->aBuf, 0, 8); + lseek(pLog->fd, 0, SEEK_SET); + pLog->iFileOff = 0; + pLog->iBufferOff = 8; +} + + +static int hctLogFileWriteTid(HctLogFile *pLog, u64 iTid){ + lseek(pLog->fd, 0, SEEK_SET); + if( write(pLog->fd, &iTid, sizeof(iTid))!=sizeof(iTid) ){ + return sqlite3HctIoerr(SQLITE_IOERR_WRITE); + } + return SQLITE_OK; +} + +static int hctLogFileFinish(HctLogFile *pLog, u64 iTid){ + int rc = SQLITE_OK; + int bDone = 0; + if( pLog->iFileOff==0 ){ + bDone = 1; + memcpy(pLog->aBuf, &iTid, sizeof(iTid)); + } + if( rc==SQLITE_OK ){ + static const u8 aZero[8] = {0,0,0,0, 0,0,0,0}; + rc = hctLogFileWrite(pLog, aZero, sizeof(aZero)); + if( rc==SQLITE_OK ){ + assert( pLog->iBufferOff>0 ); + if( write(pLog->fd, pLog->aBuf, pLog->iBufferOff)!=pLog->iBufferOff ){ + rc = sqlite3HctIoerr(SQLITE_IOERR_WRITE); + } + } + } + if( bDone==0 && rc==SQLITE_OK ){ + rc = hctLogFileWriteTid(pLog, iTid); + } + return rc; +} + +static int btreeLogFileZero(HctLogFile *pLog){ + return hctLogFileWriteTid(pLog, 0); +} + + +/* +** Open a database file. +** +** zFilename is the name of the database file. If zFilename is NULL +** then an ephemeral database is created. The ephemeral database might +** be exclusively in memory, or it might use a disk-based memory cache. +** Either way, the ephemeral database will be automatically deleted +** when sqlite3HctBtreeClose() is called. +** +** If zFilename is ":memory:" then an in-memory database is created +** that is automatically destroyed when it is closed. +** +** The "flags" parameter is a bitmask that might contain bits like +** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY. +** +** If the database is already opened in the same database connection +** and we are in shared cache mode, then the open will fail with an +** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared +** objects in the same database connection since doing so will lead +** to problems with locking. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ + const char *zFilename, /* Name of the file containing the BTree database */ + sqlite3 *db, /* Associated database handle */ + Btree **ppBtree, /* Pointer to new Btree object written here */ + int flags, /* Options */ + int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ +){ + int rc = SQLITE_OK; + HBtree *pNew; + + assert( (flags & BTREE_SINGLE)==0 && zFilename && zFilename[0] ); + + pNew = (HBtree*)sqlite3_malloc(sizeof(HBtree)); + if( pNew ){ + memset(pNew, 0, sizeof(HBtree)); + pNew->iNextRoot = 2; + pNew->config.db = db; + pNew->openFlags = flags; + pNew->config.nDbFile = HCT_DEFAULT_NDBFILE; + pNew->config.nPageSet = HCT_DEFAULT_NPAGESET; + pNew->config.nTryBeforeUnevict = HCT_DEFAULT_NTRYBEFOREUNEVICT; + pNew->config.nPageScan = HCT_DEFAULT_NPAGESCAN; + pNew->config.szLogChunk = HCT_DEFAULT_SZLOGCHUNK; + pNew->config.pgsz = HCT_DEFAULT_PAGESIZE; + rc = sqlite3HctTreeNew(&pNew->pHctTree); + pNew->pFakePager = (Pager*)sqlite3HctMalloc(&rc, 4096); + }else{ + rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK && zFilename && zFilename[0] ){ + pNew->pHctDb = sqlite3HctDbOpen(&rc, zFilename, &pNew->config); + } + + if( rc!=SQLITE_OK ){ + sqlite3HctBtreeClose((Btree*)pNew); + pNew = 0; + } + *ppBtree = (Btree*)pNew; + return rc; +} + +/* +** Close an open database and invalidate all cursors. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeClose(Btree *pBt){ + HBtree *const p = (HBtree*)pBt; + if( p ){ + while(p->pCsrList){ + sqlite3HctBtreeCloseCursor((BtCursor*)p->pCsrList); + } + hctLogFileClose(p->pLog, 1); + sqlite3HctBtreeRollback((Btree*)p, SQLITE_OK, 0); + sqlite3HctBtreeCommit((Btree*)p); + if( p->xSchemaFree ){ + p->xSchemaFree(p->pSchema); + } + sqlite3_free(p->pSchema); + sqlite3HctJournalClose(p->pHctJrnl); + sqlite3HctTreeFree(p->pHctTree); + sqlite3HctDbClose(p->pHctDb); + sqlite3_free(p->aSchemaOp); + sqlite3_free(p->pFakePager); + sqlite3_free(p); + } + return SQLITE_OK; +} + +/* +** Change the "soft" limit on the number of pages in the cache. +** Unused and unmodified pages will be recycled when the number of +** pages in the cache exceeds this soft limit. But the size of the +** cache is allowed to grow larger than this limit if it contains +** dirty pages or pages still in active use. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetCacheSize(Btree *p, int mxPage){ + /* no-op in hct */ + return SQLITE_OK; +} + +/* +** Change the "spill" limit on the number of pages in the cache. +** If the number of pages exceeds this limit during a write transaction, +** the pager might attempt to "spill" pages to the journal early in +** order to free up memory. +** +** The value returned is the current spill size. If zero is passed +** as an argument, no changes are made to the spill size setting, so +** using mxPage of 0 is a way to query the current spill size. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetSpillSize(Btree *p, int mxPage){ + return 1024; +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** Change the limit on the amount of the database file that may be +** memory mapped. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ + /* assert( 0 ); */ + return SQLITE_OK; +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* +** Change the way data is synced to disk in order to increase or decrease +** how well the database resists damage due to OS crashes and power +** failures. Level 1 is the same as asynchronous (no syncs() occur and +** there is a high probability of damage) Level 2 is the default. There +** is a very low but non-zero probability of damage. Level 3 reduces the +** probability of damage to near zero but with a write performance reduction. +*/ +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +SQLITE_PRIVATE int sqlite3HctBtreeSetPagerFlags( + Btree *p, /* The btree to set the safety level on */ + unsigned pgFlags /* Various PAGER_* flags */ +){ + /* HCT - does this need fixing? */ + return SQLITE_OK; +} +#endif + +/* +** Change the default pages size and the number of reserved bytes per page. +** Or, if the page size has already been fixed, return SQLITE_READONLY +** without changing anything. +** +** The page size must be a power of 2 between 512 and 65536. If the page +** size supplied does not meet this constraint then the page size is not +** changed. +** +** Page sizes are constrained to be a power of two so that the region +** of the database file used for locking (beginning at PENDING_BYTE, +** the first byte past the 1GB boundary, 0x40000000) needs to occur +** at the beginning of a page. +** +** If parameter nReserve is less than zero, then the number of reserved +** bytes per page is left unchanged. +** +** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size +** and autovacuum mode can no longer be changed. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetPageSize(Btree *pBt, int pgsz, int nReserve, int iFix){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_READONLY; + if( p->pHctDb && pgsz>=512 && pgsz<=32768 && 0==(pgsz & (pgsz-1)) ){ + int orig = sqlite3HctDbPagesize(p->pHctDb); + if( orig==0 ){ + p->config.pgsz = pgsz; + rc = SQLITE_OK; + } + } + return rc; +} + +/* +** Return the currently defined page size +*/ +SQLITE_PRIVATE int sqlite3HctBtreeGetPageSize(Btree *pBt){ + HBtree *const p = (HBtree*)pBt; + int pgsz = 1024; + if( p->pHctDb ){ + pgsz = sqlite3HctDbPagesize(p->pHctDb); + if( pgsz==0 ){ + pgsz = p->config.pgsz; + } + } + p->config.pgsz = pgsz; + return pgsz; +} + +/* +** This function is similar to sqlite3HctBtreeGetReserve(), except that it +** may only be called if it is guaranteed that the b-tree mutex is already +** held. +** +** This is useful in one special case in the backup API code where it is +** known that the shared b-tree mutex is held, but the mutex on the +** database handle that owns *p is not. In this case if sqlite3HctBtreeEnter() +** were to be called, it might collide with some other operation on the +** database handle that owns *p, causing undefined behavior. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeGetReserveNoMutex(Btree *p){ + assert( 0 ); + return 0; +} + +/* +** Return the number of bytes of space at the end of every page that +** are intentually left unused. This is the "reserved" space that is +** sometimes used by extensions. +** +** The value returned is the larger of the current reserve size and +** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES. +** The amount of reserve can only grow - never shrink. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeGetRequestedReserve(Btree *p){ + return 0; +} + + +/* +** Set the maximum page count for a database if mxPage is positive. +** No changes are made if mxPage is 0 or negative. +** Regardless of the value of mxPage, return the maximum page count. +*/ +SQLITE_PRIVATE Pgno sqlite3HctBtreeMaxPageCount(Btree *p, Pgno mxPage){ + return 0xFFFFFFFF; +} + +/* +** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: +** +** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared +** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared +** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set +** newFlag==(-1) No changes +** +** This routine acts as a query if newFlag is less than zero +** +** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but +** freelist leaf pages are not written back to the database. Thus in-page +** deleted content is cleared, but freelist deleted content is not. +** +** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition +** that freelist leaf pages are written back into the database, increasing +** the amount of disk I/O. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSecureDelete(Btree *p, int newFlag){ + return 0; +} + +/* +** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' +** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it +** is disabled. The default value for the auto-vacuum property is +** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetAutoVacuum(Btree *p, int autoVacuum){ + return SQLITE_OK; +} + +/* +** Return the value of the 'auto-vacuum' property. If auto-vacuum is +** enabled 1 is returned. Otherwise 0. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeGetAutoVacuum(Btree *p){ + /* hct is never in auto-vacuum mode */ + return 0; +} + +/* +** Initialize the first page of the database file (creating a database +** consisting of a single page and no schema objects). Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeNewDb(Btree *p){ + int rc = SQLITE_OK; + assert( 0 ); + return rc; +} + +static int hctDetectJournals(HBtree *p){ + int rc = SQLITE_OK; + if( p->pHctJrnl==0 ){ + rc = sqlite3HctJournalNewIf( + (Schema*)p->pSchema, p->pHctTree, p->pHctDb, &p->pHctJrnl + ); + } + return rc; +} + +/* +** This is called by sqlite3_hct_journal_init() after the journal and +** baseline tables have been created in the database to initialize the +** journal sub-system. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +SQLITE_PRIVATE int sqlite3HctDetectJournals(sqlite3 *db){ + HBtree *p = (HBtree*)db->aDb[0].pBt; + int rc = hctDetectJournals(p); + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbStartRead(p->pHctDb, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctJrnlRecovery(p->pHctJrnl, p->pHctDb); + } + sqlite3HctDbEndRead(p->pHctDb); + return rc; +} + +typedef struct HctFreelistCtx HctFreelistCtx; +struct HctFreelistCtx { + /* Physical pages that need to be preserved for log and journal rollback */ + int nAlloc; + int nPg; + i64 *aPg; + + /* Root pages in the current schema */ + int nRootAlloc; + int nRoot; + i64 *aRoot; + + HBtree *p; +}; + +static int hctTopDownMerge( + i64 *aB, + int iBegin1, int iEnd1, + int iBegin2, int iEnd2, + i64 *aA +){ + int i = iBegin1; + int j = iBegin2; + int k; + for(k=iBegin1; i=iEnd2 || aA[i]<=aA[j]) ){ + if( j1 ){ + int iMid = (iEnd + iBegin) / 2; + int i1 = hctTopDownSplitMerge(aA, iBegin, iMid, aB); + int i2 = hctTopDownSplitMerge(aA, iMid, iEnd, aB); + return hctTopDownMerge(aB, iBegin, i1, iMid, i2, aA); + } + return iEnd; +} + +/* +** Sort the array of aPg[] page numbers in ascending order. Discard +** any duplicates. +*/ +static void hctFreelistSort(int *pRc, HctFreelistCtx *p){ + if( *pRc==SQLITE_OK && p->nPg>1 ){ + i64 *aWork = (i64*)sqlite3HctMalloc(pRc, p->nPg * sizeof(i64)); + if( aWork ){ + memcpy(aWork, p->aPg, p->nPg * sizeof(i64)); + p->nPg = hctTopDownSplitMerge(p->aPg, 0, p->nPg, aWork); + sqlite3_free(aWork); +#ifdef SQLITE_DEBUG + { + int ii; + for(ii=1; iinPg; ii++){ + assert( p->aPg[ii]>p->aPg[ii-1] ); + } + } +#endif + } + } +} + +static int hctSavePhysical(void *pCtx, i64 iPhys){ + HctFreelistCtx *p = (HctFreelistCtx*)pCtx; + if( p->nPg==p->nAlloc ){ + int nNew = (p->nPg>0) ? p->nPg * 4 : 64; + i64 *aNew = (i64*)sqlite3_realloc(p->aPg, nNew*sizeof(i64));; + if( aNew==0 ) return SQLITE_NOMEM; + p->aPg = aNew; + p->nAlloc = nNew; + } + p->aPg[p->nPg++] = iPhys; + return SQLITE_OK; +} + +static int hctScanOne(void *pCtx, const char *zFile){ + HctFreelistCtx *p = (HctFreelistCtx*)pCtx; + int rc = SQLITE_OK; + HctLogReader rdr; + + sqlite3HctDbSetSavePhysical(p->p->pHctDb, hctSavePhysical, pCtx); + + rc = hctLogReaderOpen(zFile, &rdr); + if( rc==SQLITE_OK && rdr.bEof==0 ){ + u32 iPrevRoot =0; + RecoverCsr csr; + memset(&csr, 0, sizeof(csr)); + sqlite3HctDbRecoverTid(p->p->pHctDb, rdr.iTid); + for(/* no-op */; rc==SQLITE_OK && rdr.bEof==0; hctLogReaderNext(&rdr)){ + + if( rdr.iRoot!=iPrevRoot ){ + hctRecoverCursorClose(p->p, &csr); + rc = hctRecoverCursorOpen(p->p, rdr.iRoot, &csr); + } + + if( rc==SQLITE_OK ){ + int dummy = 0; + if( rdr.nKey ){ + sqlite3VdbeRecordUnpack(csr.pKeyInfo, rdr.nKey, rdr.aKey, csr.pRec); + } + rc = sqlite3HctDbCsrRollbackSeek(csr.pCsr, csr.pRec, rdr.iKey, &dummy); + } + } + + hctRecoverCursorClose(p->p, &csr); + } + + sqlite3HctDbSetSavePhysical(p->p->pHctDb, 0, 0); + hctLogReaderClose(&rdr); + return rc; +} + +static void hctRootpageAdd(int *pRc, HctFreelistCtx *pCtx, i64 iRoot){ + if( *pRc==SQLITE_OK ){ + if( pCtx->nRoot==pCtx->nRootAlloc ){ + int nNew = (pCtx->nRoot>0) ? pCtx->nRoot * 4 : 64; + i64 *aNew = (i64*)sqlite3_realloc(pCtx->aRoot, nNew*sizeof(i64));; + if( aNew==0 ){ + *pRc = SQLITE_NOMEM; + return; + } + pCtx->aRoot = aNew; + pCtx->nRootAlloc = nNew; + } + + pCtx->aRoot[pCtx->nRoot++] = iRoot; + } +} + +/* +** Assemble a list of the root pages in the current schema in the +** pCtx->aRoot[] array. +*/ +static void hctRootpageList(int *pRc, HctFreelistCtx *pCtx){ + Schema *pSchema = (Schema*)pCtx->p->pSchema; + HashElem *pE = 0; + for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ + Table *pTab = (Table*)sqliteHashData(pE); + Index *pIdx = 0; + hctRootpageAdd(pRc, pCtx, pTab->tnum); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + hctRootpageAdd(pRc, pCtx, pIdx->tnum); + } + } +} + +/* +** This is called as part of recovery, before any log files are rolled back, +** to rebuild the free-page list (or, if you like, to initialize the +** page-manager). This involves the following: +** +** 1) Scanning the sqlite_hct_journal table, if any, from the first hole +** to the last entry to determine the list of physical database pages +** that will be required if sqlite3_hct_journal_rollback() is called. +** +** 2) Scanning each log file that will be rolled back, accumulating a +** list of the physical database pages that will be required to find +** the "old" values required to roll them back. +** +** 3) Scanning the page map, checking for pages with the PHYSICAL_IN_USE +** flag clear. Each such page is added to the free-page list. If the +** page was one of those found in the scans in steps (1) or (2), then +** it is not available for reuse until after tid $TID, and all previous +** tids, have been committed. Otherwise, it is available for reuse +** immediately. +** +** $TID is set to the TID of the next transaction that will be written +** to this database (page-map entry TRANSID_EOF+1). +** +** This is a complicated procedure. +*/ +static int hctRecoverFreeList(HBtree *p){ + HctFreelistCtx ctx; + HctFile *pFile = sqlite3HctDbFile(p->pHctDb); + int rc = SQLITE_OK; + + memset(&ctx, 0, sizeof(ctx)); + ctx.p = p; + + /* If this is a replication database, scan all journal entries that may + ** be rolled back using a call to sqlite3_hct_journal_rollback(). Record + ** the set of physical pages that may be required by this call in the + ** ctx.aPg[] array. */ + if( p->pHctJrnl ){ + void *pCtx = (void*)&ctx; + rc = sqlite3HctJrnlSavePhysical( + p->config.db, p->pHctJrnl, hctSavePhysical, pCtx + ); + } + + /* Also scan any log files, adding the list of physical pages that must + ** be preserved to the ctx.aPg[] array. */ + if( rc==SQLITE_OK ){ + sqlite3HctDbRollbackMode(p->pHctDb, 2); + rc = sqlite3HctFileFindLogs(pFile, (void*)&ctx, hctScanOne); + sqlite3HctDbRollbackMode(p->pHctDb, 0); + } + + /* Sort the list of physical page numbers accumulated above. */ + hctFreelistSort(&rc, &ctx); + + /* Assemble a list of root pages. */ + hctRootpageList(&rc, &ctx); + + /* Scan the page-map, taking into account the physical pages that must + ** be preserved, and the set of root pages in the current db schema. */ + if( rc==SQLITE_OK ){ + rc = sqlite3HctFileRecoverFreelists( + pFile, ctx.nRoot, ctx.aRoot, ctx.nPg, ctx.aPg + ); + } + + sqlite3_free(ctx.aPg); + sqlite3_free(ctx.aRoot); + return rc; +} + +static int hctAttemptRecovery(HBtree *p){ + int rc = SQLITE_OK; + if( p->bRecoveryDone==0 ){ + HctFile *pFile = sqlite3HctDbFile(p->pHctDb); + if( p->pHctDb && sqlite3HctFileStartRecovery(pFile, 0) ){ + p->bRecoveryDone = 1; + rc = hctRecoverFreeList(p); + + if( rc==SQLITE_OK ){ + rc = hctRecoverLogs(p); + } + + if( rc==SQLITE_OK && p->pHctJrnl ){ + sqlite3HctDbRollbackMode(p->pHctDb, 0); + rc = sqlite3HctJrnlRecovery(p->pHctJrnl, p->pHctDb); + } + rc = sqlite3HctDbFinishRecovery(p->pHctDb, 0, rc); + } + + p->bRecoveryDone = (rc==SQLITE_OK); + } + + return rc; +} + +/* +** Attempt to start a new transaction. A write-transaction +** is started if the second argument is nonzero, otherwise a read- +** transaction. If the second argument is 2 or more and exclusive +** transaction is started, meaning that no other process is allowed +** to access the database. A preexisting transaction may not be +** upgraded to exclusive by calling this routine a second time - the +** exclusivity flag only works for a new transaction. +** +** A write-transaction must be started before attempting any +** changes to the database. None of the following routines +** will work unless a transaction is started first: +** +** sqlite3HctBtreeCreateTable() +** sqlite3HctBtreeCreateIndex() +** sqlite3HctBtreeClearTable() +** sqlite3HctBtreeDropTable() +** sqlite3HctBtreeInsert() +** sqlite3HctBtreeDelete() +** sqlite3HctBtreeUpdateMeta() +*/ +SQLITE_PRIVATE int sqlite3HctBtreeBeginTrans(Btree *pBt, int wrflag, int *pSchemaVersion){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + int req = wrflag ? SQLITE_TXN_WRITE : SQLITE_TXN_READ; + + assert( wrflag==0 || p->pHctDb==0 || pSchemaVersion ); + + if( p->eTrans==SQLITE_TXN_ERROR ) return SQLITE_BUSY_SNAPSHOT; + + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbStartRead(p->pHctDb, p->pHctJrnl); + } + + if( rc==SQLITE_OK && pSchemaVersion ){ + sqlite3HctBtreeGetMeta((Btree*)p, 1, (u32*)pSchemaVersion); + sqlite3HctDbTransIsConcurrent(p->pHctDb, p->config.db->eConcurrent); + } + + if( rc==SQLITE_OK && wrflag ){ + rc = sqlite3HctTreeBegin(p->pHctTree, 1 + p->config.db->nSavepoint); + } + if( rc==SQLITE_OK && p->eTranseTrans = req; + } + return rc; +} + +/* +** This is called just after the schema is loaded for b-tree pBt. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSchemaLoaded(Btree *pBt){ + int rc = SQLITE_OK; + HBtree *const p = (HBtree*)pBt; + if( p->bRecoveryDone==0 ){ + rc = hctDetectJournals(p); + if( rc==SQLITE_OK ){ + rc = hctAttemptRecovery(p); + } + if( rc==SQLITE_OK ){ + sqlite3HctDbEndRead(p->pHctDb); + } + } + if( rc==SQLITE_OK && p->pHctJrnl ){ + sqlite3HctJournalFixSchema(p->pHctJrnl, p->config.db, p->pSchema); + } + return rc; +} + +/* +** A write-transaction must be opened before calling this function. +** It performs a single unit of work towards an incremental vacuum. +** +** If the incremental vacuum is finished after this function has run, +** SQLITE_DONE is returned. If it is not finished, but no error occurred, +** SQLITE_OK is returned. Otherwise an SQLite error code. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeIncrVacuum(Btree *p){ + return SQLITE_DONE; +} + +/* +** This routine does the first phase of a two-phase commit. This routine +** causes a rollback journal to be created (if it does not already exist) +** and populated with enough information so that if a power loss occurs +** the database can be restored to its original state by playing back +** the journal. Then the contents of the journal are flushed out to +** the disk. After the journal is safely on oxide, the changes to the +** database are written into the database file and flushed to oxide. +** At the end of this call, the rollback journal still exists on the +** disk and we are still holding all locks, so the transaction has not +** committed. See sqlite3HctBtreeCommitPhaseTwo() for the second phase of the +** commit process. +** +** This call is a no-op if no write-transaction is currently active on pBt. +** +** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to +** the name of a super-journal file that should be written into the +** individual journal file, or is NULL, indicating no super-journal file +** (single database transaction). +** +** When this is called, the super-journal should already have been +** created, populated with this journal pointer and synced to disk. +** +** Once this is routine has returned, the only thing required to commit +** the write-transaction for this database file is to delete the journal. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ + /* Everything happens in sqlite3HctBtreeCommitPhaseTwo() */ + return SQLITE_OK; +} + +typedef struct FlushOneCtx FlushOneCtx; +struct FlushOneCtx { + HBtree *p; + int bRollback; +}; + +static int btreeFlushOneToDisk(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ + FlushOneCtx *pFC = (FlushOneCtx*)pCtx; + HBtree *p = pFC->p; + int iRollbackDir = pFC->bRollback ? -1 : 1; + + HctDatabase *pDb = p->pHctDb; + HctTreeCsr *pCsr = 0; + int rc; + UnpackedRecord *pRec = 0; + + if( pKeyInfo ){ + pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRec==0 ) return SQLITE_NOMEM_BKPT; + } + + rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr); + if( rc==SQLITE_OK ){ + for(rc=sqlite3HctTreeCsrFirst(pCsr); rc==SQLITE_OK ; /* no-op */){ + int nRetry = 0; + int ii; + i64 iKey = 0; + int nData = 0; + int bDel = 0; + const u8 *aData = 0; + sqlite3HctTreeCsrKey(pCsr, &iKey); + sqlite3HctTreeCsrData(pCsr, &nData, &aData); + bDel = sqlite3HctTreeCsrIsDelete(pCsr); + if( pRec ) sqlite3VdbeRecordUnpack(pKeyInfo, nData, aData, pRec); + rc = sqlite3HctDbInsert(pDb, iRoot, pRec, iKey, bDel,nData,aData,&nRetry); + p->nRollbackOp += (iRollbackDir * (1 - nRetry)); + if( rc ) break; + p->stats.nKeyOp++; + + if( pFC->bRollback && p->nRollbackOp==0 ){ + assert( nRetry==0 ); + rc = sqlite3HctDbInsertFlush(pDb, &nRetry); + if( rc ) break; + if( nRetry==0 ){ + rc = SQLITE_DONE; + break; + } + p->nRollbackOp = nRetry; + if( sqlite3HctTreeCsrEof(pCsr) ){ + sqlite3HctTreeCsrLast(pCsr); + } + } + + if( nRetry==0 ){ + sqlite3HctTreeCsrNext(pCsr); + if( sqlite3HctTreeCsrEof(pCsr) ){ + rc = sqlite3HctDbInsertFlush(pDb, &nRetry); + if( nRetry ){ + sqlite3HctTreeCsrLast(pCsr); + assert( sqlite3HctTreeCsrEof(pCsr)==0 ); + p->nRollbackOp -= (iRollbackDir * nRetry); + }else{ + /* Done - the table has been successfully flushed to disk */ + break; + } + } + }else{ + p->stats.nRetry++; + p->stats.nRetryKey += nRetry; + } + for(ii=1; iidb, pRec); + } + return rc; +} + +static int btreeLogIntkey(HctLogFile *pLog, u32 iRoot, i64 iRowid){ + u8 aBuf[16]; + memcpy(&aBuf[0], &iRoot, sizeof(u32)); + memset(&aBuf[4], 0, sizeof(u32)); + memcpy(&aBuf[8], &iRowid, sizeof(i64)); + return hctLogFileWrite(pLog, aBuf, sizeof(aBuf)); +} + +static int btreeLogIndex( + HctLogFile *pLog, + u32 iRoot, + const u8 *aData, int nData +){ + if( hctLogFileWrite(pLog, &iRoot, sizeof(iRoot)) + || hctLogFileWrite(pLog, &nData, sizeof(nData)) + || hctLogFileWrite(pLog, aData, nData) + ){ + return sqlite3HctIoerr(SQLITE_IOERR_WRITE); + } + return SQLITE_OK; +} + +static int btreeLogOneToDisk(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ + HBtree *p = (HBtree*)pCtx; + HctTreeCsr *pCsr = 0; + int rc; + + rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr); + if( rc==SQLITE_OK ){ + for(rc=sqlite3HctTreeCsrFirst(pCsr); + rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; + rc=sqlite3HctTreeCsrNext(pCsr) + ){ + if( pKeyInfo ){ + int nData = 0; + const u8 *aData = 0; + sqlite3HctTreeCsrData(pCsr, &nData, &aData); + rc = btreeLogIndex(p->pLog, iRoot, aData, nData); + }else{ + i64 iRowid = 0; + sqlite3HctTreeCsrKey(pCsr, &iRowid); + rc = btreeLogIntkey(p->pLog, iRoot, iRowid); + } + + if( rc!=SQLITE_OK ) break; + } + sqlite3HctTreeCsrClose(pCsr); + } + + return rc; +} + +static int btreeFlushData(HBtree *p, int bRollback){ + int rc = SQLITE_OK; + + if( bRollback ) sqlite3HctDbRollbackMode(p->pHctDb, 1); + if( bRollback && p->nRollbackOp==0 ){ + rc = SQLITE_DONE; + } + + if( rc==SQLITE_OK ){ + FlushOneCtx ctx; + ctx.p = p; + ctx.bRollback = bRollback; + rc = sqlite3HctTreeForeach(p->pHctTree, 0, (void*)&ctx,btreeFlushOneToDisk); + } + if( bRollback ) sqlite3HctDbRollbackMode(p->pHctDb, 0); + return rc; +} + +static int btreeWriteLog(HBtree *p){ + int rc = SQLITE_OK; + + if( p->pLog==0 ){ + char *zLog = sqlite3HctDbLogFile(p->pHctDb); + if( zLog==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = hctLogFileOpen(zLog, p->config.szLogChunk, &p->pLog); + } + } + + if( rc==SQLITE_OK ){ + hctLogFileRestart(p->pLog); + rc = sqlite3HctTreeForeach(p->pHctTree, 0, (void*)p, btreeLogOneToDisk); + } + + return rc; +} + +/* +** Flush the contents of Btree.pHctTree to Btree.pHctDb. +*/ +static int btreeFlushToDisk(HBtree *p){ + int i; + int rc = SQLITE_OK; + int rcok = SQLITE_OK; + u64 iTid = 0; + u64 iCid = 0; + int bTmapScan = 0; + int bCustomValid = 0; /* True if xValidate() was invoked */ + + /* Write a log file for this transaction. The TID field is still set + ** to zero at this point. */ + if( p->config.db->bHctMigrate==0 ){ + rc = btreeWriteLog(p); + } + + if( rc==SQLITE_OK ){ + /* Obtain the TID for this transaction. */ + iTid = sqlite3HctJrnlWriteTid(p->pHctJrnl, &iCid); + if( iTid==0 ){ + sqlite3HctDbStartWrite(p->pHctDb, &iTid); + } + + /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ + if( p->config.db->xMtCommit ){ + p->config.db->xMtCommit(p->config.db->pMtCommitCtx, 0); + } + + assert( iTid>0 ); + if( p->pLog ) rc = hctLogFileFinish(p->pLog, iTid); + } + + /* Initialize the root pages of any new tables or indexes created by this + ** transaction. At this point the logical root page numbers have been + ** assigned by the page-manager, but there is no mapped physical page, + ** and the LOGICAL_IN_USE and LOGICAL_IS_ROOT flags are not yet set + ** for the page. This allocates and populates the physical root page, + ** and sets the two flags on the logical page slot. + ** + ** If the current transaction does not commit (i.e. failed validiation), + ** then the new tree is returned to the page-manage to be recycled + ** immediately. Or, if a crash occurs, then recovery will see the + ** LOGICAL_IS_ROOT flag on a root page that is not in the sqlite_schema + ** table and free the pages then. */ + for(i=0; rc==SQLITE_OK && inSchemaOp; i++){ + BtSchemaOp *pOp = &p->aSchemaOp[i]; + assert( + pOp->eSchemaOp==HCT_SCHEMAOP_DROP + || pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INTKEY + || pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INDEX + ); + if( pOp->eSchemaOp!=HCT_SCHEMAOP_DROP ){ + int bIndex = (pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INDEX); + rc = sqlite3HctDbRootInit(p->pHctDb, bIndex, pOp->pgnoRoot); + } + } + + /* Write all the new database entries to the database. Any write/write + ** conflicts are detected here - SQLITE_BUSY is returned in that case. */ + p->nRollbackOp = 0; + if( rc==SQLITE_OK ){ + rc = btreeFlushData(p, 0); + } + + /* Assuming the data has been flushed to disk without error or a + ** write/write conflict, allocate a CID and validate the transaction. */ + if( rc==SQLITE_OK ){ + /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ + if( p->config.db->xMtCommit ){ + p->config.db->xMtCommit(p->config.db->pMtCommitCtx, 1); + } + + /* Validate the transaction */ + rc = sqlite3HctDbValidate(p->config.db, p->pHctDb, &iCid, &bTmapScan); + + /* If validation passed and this database is configured for replication, + ** write the journal entry and invoke the custom validation hook */ + if( rc==SQLITE_OK && p->pHctJrnl ){ + rc = sqlite3HctJrnlLog( + p->pHctJrnl, + p->config.db, + (Schema*)p->pSchema, + iCid, iTid, &bCustomValid + ); + } + } + + /* If conflicts have been detected, roll back the transaction */ + assert( rc!=SQLITE_BUSY ); + if( rc==SQLITE_BUSY_SNAPSHOT ){ + rcok = SQLITE_BUSY_SNAPSHOT; + rc = btreeFlushData(p, 1); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + if( iCid>0 && p->pHctJrnl ){ + rc = sqlite3HctJrnlWriteEmpty(p->pHctJrnl, iCid, iTid, + (bCustomValid ? 0 : p->config.db) + ); + } + } + + for(i=0; rc==SQLITE_OK && inSchemaOp; i++){ + BtSchemaOp *pOp = &p->aSchemaOp[i]; + if( (rcok==SQLITE_OK && pOp->eSchemaOp==HCT_SCHEMAOP_DROP) + || (rcok!=SQLITE_OK && pOp->eSchemaOp!=HCT_SCHEMAOP_DROP) + ){ + HctFile *pFile = sqlite3HctDbFile(p->pHctDb); + rc = sqlite3HctFileTreeFree(pFile, pOp->pgnoRoot, rcok!=SQLITE_OK); + } + } + + /* Zero the log file and set the entry in the transaction-map to + ** finish the transaction. */ + if( rc==SQLITE_OK && p->pLog ){ + rc = btreeLogFileZero(p->pLog); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbEndWrite(p->pHctDb, iCid, rcok!=SQLITE_OK); + } + assert( rc==SQLITE_OK ); + if( bTmapScan ){ + sqlite3HctDbTMapScan(p->pHctDb); + } + + sqlite3HctJrnlInvokeHook(p->pHctJrnl, p->config.db); + return (rc==SQLITE_OK ? rcok : rc); +} + +static void hctEndTransaction(HBtree *p){ + if( p->eTrans>SQLITE_TXN_NONE + && p->pCsrList==0 + && p->config.db->nVdbeRead<=1 + ){ + if( p->pHctDb ){ + sqlite3HctDbEndRead(p->pHctDb); + } + p->eTrans = SQLITE_TXN_NONE; + p->eMetaState = HCT_METASTATE_NONE; + } +} + + +static int hctBtreeMigrateInsert( + HBtCursor *pCur, + UnpackedRecord *pRec, + i64 iKey, + int nData, + const u8 *aData +){ + int rc = SQLITE_OK; + HBtree *p = pCur->pBtree; + int nRetry = 0; + + if( 0==sqlite3HctDbTid(p->pHctDb) ){ + i64 iDummy = 0; + rc = sqlite3HctDbStartWrite(p->pHctDb, &iDummy); + if( rc!=SQLITE_OK ) return rc; + } + + rc = sqlite3HctDbInsert( + p->pHctDb, + sqlite3HctTreeCsrRoot(pCur->pHctTreeCsr), + pRec, iKey, 0, nData, aData, &nRetry + ); + if( nRetry>0 ){ + rc = SQLITE_ABORT; + } + + return rc; +} + +static int hctBtreeMigrateCommit(HBtree *p){ + int rc = SQLITE_OK; + i64 iCid = 0; + int bTmapScan = 0; + int nRetry = 0; + + rc = sqlite3HctDbInsertFlush(p->pHctDb, &nRetry); + if( nRetry>0 ){ + rc = SQLITE_ABORT; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbValidate(p->config.db, p->pHctDb, &iCid, &bTmapScan); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbEndWrite(p->pHctDb, iCid, 0); + } + + if( bTmapScan ){ + sqlite3HctDbTMapScan(p->pHctDb); + } + + return rc; +} + +#define BT_IS_MIGRATE(pBt) (pBt->config.db->bHctMigrate) +#define CSR_IS_MIGRATE(pCsr) (pCsr->pBtree->config.db->bHctMigrate) + +/* +** Commit the transaction currently in progress. +** +** This routine implements the second phase of a 2-phase commit. The +** sqlite3HctBtreeCommitPhaseOne() routine does the first phase and should +** be invoked prior to calling this routine. The sqlite3HctBtreeCommitPhaseOne() +** routine did all the work of writing information out to disk and flushing the +** contents so that they are written onto the disk platter. All this +** routine has to do is delete or truncate or zero the header in the +** the rollback journal (which causes the transaction to commit) and +** drop locks. +** +** Normally, if an error occurs while the pager layer is attempting to +** finalize the underlying journal file, this function returns an error and +** the upper layer will attempt a rollback. However, if the second argument +** is non-zero then this b-tree transaction is part of a multi-file +** transaction. In this case, the transaction has already been committed +** (by deleting a super-journal file) and the caller will ignore this +** functions return code. So, even if an error occurs in the pager layer, +** reset the b-tree objects internal state to indicate that the write +** transaction has been closed. This is quite safe, as the pager will have +** transitioned to the error state. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseTwo(Btree *pBt, int bCleanup){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + + if( p->eTrans==SQLITE_TXN_ERROR ) return SQLITE_BUSY_SNAPSHOT; + + if( BT_IS_MIGRATE(p) ){ + rc = hctBtreeMigrateCommit(p); + }else{ + if( p->eTrans==SQLITE_TXN_WRITE ){ + if( p->pCsrList ){ + /* Cannot commit with open cursors in hctree */ + return SQLITE_LOCKED; + } + + sqlite3HctTreeRelease(p->pHctTree, 0); + if( p->pHctDb ){ + rc = btreeFlushToDisk(p); + sqlite3HctTreeClear(p->pHctTree); + p->nSchemaOp = 0; + } + p->eTrans = SQLITE_TXN_READ; + } + } + + if( rc==SQLITE_OK ){ + hctEndTransaction(p); + }else{ + p->eTrans = SQLITE_TXN_ERROR; + } + return rc; +} + +/* +** Do both phases of a commit. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCommit(Btree *pBt){ + int rc; + HBtree *const p = (HBtree*)pBt; + rc = sqlite3HctBtreeCommitPhaseOne((Btree*)p, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3HctBtreeCommitPhaseTwo((Btree*)p, 0); + } + return rc; +} + +/* +** This routine sets the state to CURSOR_FAULT and the error +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. +** +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. +** +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeTripAllCursors(Btree *pBt, int errCode, int writeOnly){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + if( p ){ + HBtCursor *pCur; + for(pCur=p->pCsrList; pCur; pCur=pCur->pCsrNext){ + if( writeOnly==0 || pCur->wrFlag ){ + sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); + pCur->pHctTreeCsr = 0; + pCur->errCode = errCode; + } + } + } + return rc; +} + +/* +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeRollback(Btree *pBt, int tripCode, int writeOnly){ + HBtree *const p = (HBtree*)pBt; + + assert( SQLITE_TXN_ERROR==4 && SQLITE_TXN_WRITE==2 ); + assert( SQLITE_TXN_READ==1 && SQLITE_TXN_NONE==0 ); + assert( p->eTrans!=SQLITE_TXN_ERROR || p->pCsrList==0 ); + + if( p->eTrans>=SQLITE_TXN_WRITE ){ + sqlite3HctTreeRollbackTo(p->pHctTree, 0); + if( p->pHctDb ){ + sqlite3HctTreeClear(p->pHctTree); + } + p->eTrans = SQLITE_TXN_READ; + p->nSchemaOp = 0; + } + hctEndTransaction(p); + return SQLITE_OK; +} + +/* +** Start a statement subtransaction. The subtransaction can be rolled +** back independently of the main transaction. You must start a transaction +** before starting a subtransaction. The subtransaction is ended automatically +** if the main transaction commits or rolls back. +** +** Statement subtransactions are used around individual SQL statements +** that are contained within a BEGIN...COMMIT block. If a constraint +** error occurs within the statement, the effect of that one statement +** can be rolled back without having to rollback the entire transaction. +** +** A statement sub-transaction is implemented as an anonymous savepoint. The +** value passed as the second parameter is the total number of savepoints, +** including the new anonymous savepoint, open on the B-Tree. i.e. if there +** are no active savepoints and no other statement-transactions open, +** iStatement is 1. This anonymous savepoint can be released or rolled back +** using the sqlite3HctBtreeSavepoint() function. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeBeginStmt(Btree *pBt, int iStatement){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + assert( p->eTrans!=SQLITE_TXN_ERROR ); + rc = sqlite3HctTreeBegin(p->pHctTree, iStatement+1); + return rc; +} + +static int btreeRollbackRoot(HBtree *p, int iSavepoint){ + int i; + int rc = SQLITE_OK; + for(i=p->nSchemaOp-1; rc==SQLITE_OK && i>=0; i--){ + if( p->aSchemaOp[i].iSavepoint<=iSavepoint ) break; + rc = sqlite3HctDbRootFree(p->pHctDb, p->aSchemaOp[i].pgnoRoot); + } + p->nSchemaOp = i+1; + return rc; +} + +/* +** The second argument to this function, op, is always SAVEPOINT_ROLLBACK +** or SAVEPOINT_RELEASE. This function either releases or rolls back the +** savepoint identified by parameter iSavepoint, depending on the value +** of op. +** +** Normally, iSavepoint is greater than or equal to zero. However, if op is +** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the +** contents of the entire transaction are rolled back. This is different +** from a normal transaction rollback, as no locks are released and the +** transaction remains open. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSavepoint(Btree *pBt, int op, int iSavepoint){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + if( p && p->eTrans==SQLITE_TXN_WRITE ){ + int i; + assert( op==SAVEPOINT_ROLLBACK || op==SAVEPOINT_RELEASE ); + if( op==SAVEPOINT_RELEASE ){ + for(i=0; inSchemaOp; i++){ + if( p->aSchemaOp[i].iSavepoint>iSavepoint ){ + p->aSchemaOp[i].iSavepoint = iSavepoint; + } + } + sqlite3HctTreeRelease(p->pHctTree, iSavepoint+1); + }else{ + sqlite3HctTreeRollbackTo(p->pHctTree, iSavepoint+2); + btreeRollbackRoot(p, iSavepoint); + p->eMetaState = HCT_METASTATE_NONE; + } + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctBtreeIsNewTable(Btree *pBt, u64 iRoot){ + HBtree *const p = (HBtree*)pBt; + int ii; + for(ii=0; iinSchemaOp && p->aSchemaOp[ii].pgnoRoot!=iRoot; ii++); + return iinSchemaOp; +} + +SQLITE_PRIVATE u64 sqlite3HctBtreeSnapshotId(Btree *pBt){ + HBtree *const p = (HBtree*)pBt; + return sqlite3HctDbSnapshotId(p->pHctDb); +} + +/* +** Open a new cursor +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursor( + Btree *pBt, /* The btree */ + Pgno iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ + BtCursor *pCursor /* Write new cursor here */ +){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + int bNosnap = 0; + int bReadonly = sqlite3HctJournalIsReadonly(p->pHctJrnl, iTable, &bNosnap); + + assert( p->eTrans!=SQLITE_TXN_NONE ); + assert( p->eTrans!=SQLITE_TXN_ERROR ); + assert( pCur->pHctTreeCsr==0 ); + assert( BT_IS_MIGRATE(p)==0 || wrFlag ); + + /* If this is an attempt to open a read/write cursor on either the + ** sqlite_hct_journal or sqlite_hct_baseline tables, return an error + ** immediately. */ + if( wrFlag && bReadonly ){ + return SQLITE_READONLY; + } + + pCur->pKeyInfo = pKeyInfo; + rc = sqlite3HctTreeCsrOpen(p->pHctTree, iTable, &pCur->pHctTreeCsr); + if( rc==SQLITE_OK && p->pHctDb ){ + int ii; + for(ii=0; iinSchemaOp && p->aSchemaOp[ii].pgnoRoot!=iTable; ii++); + if( ii==p->nSchemaOp ){ + rc = sqlite3HctDbCsrOpen(p->pHctDb, pKeyInfo, iTable, &pCur->pHctDbCsr); + sqlite3HctDbCsrNosnap(pCur->pHctDbCsr, bNosnap); + } + } + if( rc==SQLITE_OK ){ + pCur->pCsrNext = p->pCsrList; + pCur->pBtree = p; + pCur->wrFlag = wrFlag; + p->pCsrList = pCur; + }else{ + sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); + pCur->pHctTreeCsr = 0; + pCur->pKeyInfo = 0; + } + + return rc; +} + +/* +** Return the size of a BtCursor object in bytes. +** +** This interfaces is needed so that users of cursors can preallocate +** sufficient storage to hold a cursor. The BtCursor object is opaque +** to users so they cannot do the sizeof() themselves - they must call +** this routine. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursorSize(void){ + return ROUND8(sizeof(HBtCursor)); +} + +/* +** Initialize memory that will be converted into a BtCursor object. +** +** The simple approach here would be to memset() the entire object +** to zero. But it turns out that the apPage[] and aiIdx[] arrays +** do not need to be zeroed and they are large, so we can save a lot +** of run-time by skipping the initialization of those elements. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeCursorZero(BtCursor *p){ + /* hct takes the simple approach mentioned above */ + memset(p, 0, sizeof(HBtCursor)); +} + +/* +** Close a cursor. The read lock on the database file is released +** when the last cursor is closed. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCloseCursor(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + HBtree *const pBtree = pCur->pBtree; + if( pBtree ){ + HBtCursor **pp; + sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); + sqlite3HctDbCsrClose(pCur->pHctDbCsr); + for(pp=&pBtree->pCsrList; *pp!=pCur; pp=&(*pp)->pCsrNext); + *pp = pCur->pCsrNext; + pCur->pHctTreeCsr = 0; + pCur->pBtree = 0; + pCur->pCsrNext = 0; + if( (pBtree->openFlags & BTREE_SINGLE) && pBtree->pCsrList==0 ){ + sqlite3HctBtreeClose((Btree*)pBtree); + } + } + return SQLITE_OK; +} + +/* +** Return true if the given BtCursor is valid. A valid cursor is one +** that is currently pointing to a row in a (non-empty) table. +** This is a verification routine is used only within assert() statements. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValid(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + return pCur && ( + !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) + || !sqlite3HctDbCsrEof(pCur->pHctDbCsr) + ); +} +SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValidNN(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + return ( + !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) + || !sqlite3HctDbCsrEof(pCur->pHctDbCsr) + ); +} + +/* +** Return the value of the integer key or "rowid" for a table btree. +** This routine is only valid for a cursor that is pointing into a +** ordinary table btree. If the cursor points to an index btree or +** is invalid, the result of this routine is undefined. +*/ +SQLITE_PRIVATE i64 sqlite3HctBtreeIntegerKey(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + i64 iKey; + if( pCur->bUseTree ){ + sqlite3HctTreeCsrKey(pCur->pHctTreeCsr, &iKey); + }else{ + sqlite3HctDbCsrKey(pCur->pHctDbCsr, &iKey); + } + return iKey; +} + +/* +** Pin or unpin a cursor. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeCursorPin(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + sqlite3HctTreeCsrPin(pCur->pHctTreeCsr); +} +SQLITE_PRIVATE void sqlite3HctBtreeCursorUnpin(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + sqlite3HctTreeCsrUnpin(pCur->pHctTreeCsr); +} + +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC +/* +** Return the offset into the database file for the start of the +** payload to which the cursor is pointing. +*/ +SQLITE_PRIVATE i64 sqlite3HctBtreeOffset(BtCursor *pCur){ + assert( 0 ); + return 0; +} +#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ + +/* +** Return the number of bytes of payload for the entry that pCur is +** currently pointing to. For table btrees, this will be the amount +** of data. For index btrees, this will be the size of the key. +** +** The caller must guarantee that the cursor is pointing to a non-NULL +** valid entry. In other words, the calling procedure must guarantee +** that the cursor has Cursor.eState==CURSOR_VALID. +*/ +SQLITE_PRIVATE u32 sqlite3HctBtreePayloadSize(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int nData; + if( pCur->bUseTree ){ + sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nData, 0); + }else{ + sqlite3HctDbCsrData(pCur->pHctDbCsr, &nData, 0); + } + return nData; +} + +/* +** Return an upper bound on the size of any record for the table +** that the cursor is pointing into. +** +** This is an optimization. Everything will still work if this +** routine always returns 2147483647 (which is the largest record +** that SQLite can handle) or more. But returning a smaller value might +** prevent large memory allocations when trying to interpret a +** corrupt datrabase. +** +** The current implementation merely returns the size of the underlying +** database file. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3HctBtreeMaxRecordSize(BtCursor *pCur){ + assert( 0 ); + return 0x7FFFFFFF; +} + +/* +** Read part of the payload for the row at which that cursor pCur is currently +** pointing. "amt" bytes will be transferred into pBuf[]. The transfer +** begins at "offset". +** +** pCur can be pointing to either a table or an index b-tree. +** If pointing to a table btree, then the content section is read. If +** pCur is pointing to an index b-tree then the key section is read. +** +** For sqlite3HctBtreePayload(), the caller must ensure that pCur is pointing +** to a valid row in the table. For sqlite3HctBtreePayloadChecked(), the +** cursor might be invalid or might need to be restored before being read. +** +** Return SQLITE_OK on success or an error code if anything goes +** wrong. An error is returned if "offset+amt" is larger than +** the available payload. +*/ +SQLITE_PRIVATE int sqlite3HctBtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ + u32 n = 0; + const u8 *p = 0; + + p = (const u8*)sqlite3HctBtreePayloadFetch(pCur, &n); + assert( offset+amt<=n ); + memcpy(pBuf, &p[offset], amt); + + return SQLITE_OK; +} + + +static int btreeSetUseTree(HBtCursor *pCur){ + int rc = SQLITE_OK; + int bTreeEof = sqlite3HctTreeCsrEof(pCur->pHctTreeCsr); + int bDbEof = sqlite3HctDbCsrEof(pCur->pHctDbCsr); + + assert( pCur->eDir==BTREE_DIR_FORWARD || pCur->eDir==BTREE_DIR_REVERSE ); + assert( pCur->pHctTreeCsr ); + + if( bTreeEof ){ + pCur->bUseTree = 0; + }else if( bDbEof ){ + pCur->bUseTree = 1; + }else if( pCur->pKeyInfo==0 ){ + i64 iKeyTree; + i64 iKeyDb; + + sqlite3HctTreeCsrKey(pCur->pHctTreeCsr, &iKeyTree); + sqlite3HctDbCsrKey(pCur->pHctDbCsr, &iKeyDb); + + if( iKeyTree==iKeyDb ){ + pCur->bUseTree = 2; + }else{ + pCur->bUseTree = (iKeyTree < iKeyDb); + if( pCur->eDir==BTREE_DIR_REVERSE ) pCur->bUseTree = !pCur->bUseTree; + } + }else{ + UnpackedRecord *pKeyDb = 0; + const u8 *aKeyTree = 0; + int nKeyTree = 0; + + rc = sqlite3HctDbCsrLoadAndDecode(pCur->pHctDbCsr, &pKeyDb); + if( rc==SQLITE_OK ){ + int res; + int nSave = pKeyDb->nField; + sqlite3HctDbRecordTrim(pKeyDb); + sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nKeyTree, &aKeyTree); + res = sqlite3VdbeRecordCompare(nKeyTree, aKeyTree, pKeyDb); + pKeyDb->nField = nSave; + if( res==0 ){ + pCur->bUseTree = 2; + }else{ + pCur->bUseTree = (res<0); + if( pCur->eDir==BTREE_DIR_REVERSE ) pCur->bUseTree = !pCur->bUseTree; + } + } + } + + return rc; +} + +static int hctReseekBlobCsr(HBtCursor *pCsr){ + int rc = SQLITE_OK; + assert( pCsr->pKeyInfo==0 ); + if( sqlite3HctTreeCsrHasMoved(pCsr->pHctTreeCsr) ){ + int res = 0; + rc = sqlite3HctTreeCsrReseek(pCsr->pHctTreeCsr, &res); + if( rc==SQLITE_OK && res==0 ){ + pCsr->bUseTree = 1; + } + } + return rc; +} + +/* +** This variant of sqlite3HctBtreePayload() works even if the cursor has not +** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() +** interface. +*/ +#ifndef SQLITE_OMIT_INCRBLOB +SQLITE_PRIVATE int sqlite3HctBtreePayloadChecked( + BtCursor *pCur, + u32 offset, + u32 amt, + void *pBuf +){ + HBtCursor *pCsr = (HBtCursor*)pCur; + int rc = SQLITE_OK; + rc = hctReseekBlobCsr(pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3HctBtreePayload(pCur, offset, amt, pBuf); + } + return rc; +} +#endif /* SQLITE_OMIT_INCRBLOB */ + +/* +** For the entry that cursor pCur is point to, return as +** many bytes of the key or data as are available on the local +** b-tree page. Write the number of available bytes into *pAmt. +** +** The pointer returned is ephemeral. The key/data may move +** or be destroyed on the next call to any Btree routine, +** including calls from other threads against the same cache. +** Hence, a mutex on the BtShared should be held prior to calling +** this routine. +** +** These routines is used to get quick access to key and data +** in the common case where no overflow pages are used. +*/ +SQLITE_PRIVATE const void *sqlite3HctBtreePayloadFetch(BtCursor *pCursor, u32 *pAmt){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + const u8 *aData; + int nData; + if( pCur->bUseTree ){ + sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nData, &aData); + }else{ + sqlite3HctDbCsrData(pCur->pHctDbCsr, &nData, &aData); + } + *pAmt = (u32)nData; + return aData; +} + +/* Move the cursor to the first entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeFirst(BtCursor *pCursor, int *pRes){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int rc = SQLITE_OK; + + sqlite3HctTreeCsrFirst(pCur->pHctTreeCsr); + if( pCur->pHctDbCsr ){ + rc = sqlite3HctDbCsrFirst(pCur->pHctDbCsr); + } + if( rc==SQLITE_OK ){ + pCur->eDir = BTREE_DIR_FORWARD; + btreeSetUseTree(pCur); + if( pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ + rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + *pRes = sqlite3HctBtreeEof((BtCursor*)pCur); + } + + return rc; +} + +/* Move the cursor to the last entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeLast(BtCursor *pCursor, int *pRes){ + int rc = SQLITE_OK; + HBtCursor *const pCur = (HBtCursor*)pCursor; + + if( pCur->isLast==0 ){ + sqlite3HctTreeCsrLast(pCur->pHctTreeCsr); + if( pCur->pHctDbCsr ){ + rc = sqlite3HctDbCsrLast(pCur->pHctDbCsr); + } + if( rc==SQLITE_OK ){ + int bTreeEof = sqlite3HctTreeCsrEof(pCur->pHctTreeCsr); + int bDbEof = sqlite3HctDbCsrEof(pCur->pHctDbCsr); + *pRes = (bTreeEof && bDbEof); + pCur->eDir = BTREE_DIR_REVERSE; + btreeSetUseTree(pCur); + if( pCur->bUseTree ){ + if( sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ + rc = sqlite3HctBtreePrevious((BtCursor*)pCur, 0); + if( rc==SQLITE_DONE ){ + *pRes = sqlite3HctBtreeEof((BtCursor*)pCur); + rc = SQLITE_OK; + } + }else{ + pCur->isLast = 1; + } + } + } + } + + return rc; +} + +/* Move the cursor so that it points to an entry near the key +** specified by pIdxKey or intKey. Return a success code. +** +** For INTKEY tables, the intKey parameter is used. pIdxKey +** must be NULL. For index tables, pIdxKey is used and intKey +** is ignored. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than intKey/pIdxKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches intKey/pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than intKey/pIdxKey. +** +** For index tables, the pIdxKey->eqSeen field is set to 1 if there +** exists an entry in the table that exactly matches pIdxKey. +*/ +static int hctBtreeMovetoUnpacked( + HBtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + i64 intKey, /* The table key */ + int biasRight, /* If true, bias the search to the high end */ + int *pRes /* Write search results here */ +){ + int rc = SQLITE_OK; + int res1 = 0; + int res2 = -1; + + pCur->isLast = 0; + rc = sqlite3HctTreeCsrSeek(pCur->pHctTreeCsr, pIdxKey, intKey, &res1); + if( rc==SQLITE_OK && pCur->pHctDbCsr ){ + rc = sqlite3HctDbCsrSeek(pCur->pHctDbCsr, pIdxKey, intKey, &res2); + } + + if( pCur->eDir==BTREE_DIR_NONE ){ + if( res1==0 || pCur->pHctDbCsr==0 ){ + *pRes = res1; + pCur->bUseTree = 1; + if( sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ + *pRes = -1; + } + }else{ + pCur->bUseTree = 0; + *pRes = res2; + } + }else{ + if( pCur->eDir==BTREE_DIR_FORWARD ){ + if( rc==SQLITE_OK && res2<0 && !sqlite3HctDbCsrEof(pCur->pHctDbCsr) ){ + rc = sqlite3HctDbCsrNext(pCur->pHctDbCsr); + } + if( rc==SQLITE_OK && res1<0 && !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) ){ + rc = sqlite3HctTreeCsrNext(pCur->pHctTreeCsr); + } + + if( res1==0 || (res2==0 && pCur->pHctDbCsr) ){ + *pRes = 0; + }else if( sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) + && sqlite3HctDbCsrEof(pCur->pHctDbCsr) + ){ + *pRes = -1; + }else{ + *pRes = +1; + } + }else{ + assert( pCur->eDir==BTREE_DIR_REVERSE ); + assert( res2<=0 ); + if( rc==SQLITE_OK && res1>0 && !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) ){ + rc = sqlite3HctTreeCsrPrev(pCur->pHctTreeCsr); + } + if( res1==0 || res2==0 ){ + *pRes = 0; + }else{ + *pRes = -1; + } + } + + btreeSetUseTree(pCur); + if( pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ + if( pCur->eDir==BTREE_DIR_FORWARD ){ + rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0); + if( rc==SQLITE_DONE ){ + /* Cursor points at EOF. *pRes must be -ve in this case. */ + rc = SQLITE_OK; + *pRes = -1; + }else if( pIdxKey==0 ){ + *pRes = 1; + }else{ + u32 nKey; + const void *a = sqlite3HctBtreePayloadFetch((BtCursor*)pCur, &nKey); + *pRes = sqlite3VdbeRecordCompareWithSkip(nKey, a, pIdxKey, 0); + } + }else{ + rc = sqlite3HctBtreePrevious((BtCursor*)pCur, 0); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + *pRes = -1; + } + } + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctBtreeTableMoveto( + BtCursor *pCursor, /* The cursor to be moved */ + i64 intKey, /* The table key */ + int biasRight, /* If true, bias the search to the high end */ + int *pRes /* Write search results here */ +){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + assert( CSR_IS_MIGRATE(pCur)==0 ); + if( pCur->isLast && sqlite3HctBtreeIntegerKey(pCursor)eDir = eDir; + if( pCur->pHctDbCsr ){ + sqlite3HctDbCsrDir(pCur->pHctDbCsr, eDir); + } +} + +/* +** Return TRUE if the cursor is not pointing at an entry of the table. +** +** TRUE will be returned after a call to sqlite3HctBtreeNext() moves +** past the last entry in the table or sqlite3HctBtreePrev() moves past +** the first entry. TRUE is also returned if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeEof(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries + ** have been deleted? This API will need to change to return an error code + ** as well as the boolean result value. + */ + return ( + sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) + && sqlite3HctDbCsrEof(pCur->pHctDbCsr) + ); +} + +/* +** Return an estimate for the number of rows in the table that pCur is +** pointing to. Return a negative number if no estimate is currently +** available. +*/ +SQLITE_PRIVATE i64 sqlite3HctBtreeRowCountEst(BtCursor *pCur){ + /* TODO: Fix this so that it returns a meaningful value. */ + return -1; +} + +/* +** Advance the cursor to the next entry in the database. +** Return value: +** +** SQLITE_OK success +** SQLITE_DONE cursor is already pointing at the last element +** otherwise some kind of error occurred +** +** The main entry point is sqlite3HctBtreeNext(). That routine is optimized +** for the common case of merely incrementing the cell counter BtCursor.aiIdx +** to the next cell on the current page. The (slower) btreeNext() helper +** routine is called when it is necessary to move to a different page or +** to restore the cursor. +** +** If bit 0x01 of the F argument in sqlite3HctBtreeNext(C,F) is 1, then the +** cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument +** is a hint to the implement. SQLite btree implementation does not use +** this hint, but COMDB2 does. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeNext(BtCursor *pCursor, int flags){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int rc = SQLITE_OK; + int bDummy; + + assert( pCur->isLast==0 ); + rc = sqlite3HctBtreeCursorRestore((BtCursor*)pCur, &bDummy); + if( rc!=SQLITE_OK ) return rc; + + if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ + rc = SQLITE_DONE; + }else{ + assert( pCur->eDir==BTREE_DIR_FORWARD ); + do{ + if( pCur->bUseTree ){ + rc = sqlite3HctTreeCsrNext(pCur->pHctTreeCsr); + } + if( rc==SQLITE_OK && (pCur->bUseTree==0 || pCur->bUseTree==2) ){ + rc = sqlite3HctDbCsrNext(pCur->pHctDbCsr); + } + if( rc==SQLITE_OK ){ + if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ + rc = SQLITE_DONE; + }else{ + btreeSetUseTree(pCur); + } + } + }while( rc==SQLITE_OK + && pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) + ); + } + return rc; +} + +/* +** Step the cursor to the back to the previous entry in the database. +** Return values: +** +** SQLITE_OK success +** SQLITE_DONE the cursor is already on the first element of the table +** otherwise some kind of error occurred +** +** The main entry point is sqlite3HctBtreePrevious(). That routine is optimized +** for the common case of merely decrementing the cell counter BtCursor.aiIdx +** to the previous cell on the current page. The (slower) btreePrevious() +** helper routine is called when it is necessary to move to a different page +** or to restore the cursor. +** +** If bit 0x01 of the F argument to sqlite3HctBtreePrevious(C,F) is 1, then +** the cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument is a +** hint to the implement. The native SQLite btree implementation does not +** use this hint, but COMDB2 does. +*/ +SQLITE_PRIVATE int sqlite3HctBtreePrevious(BtCursor *pCursor, int flags){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int rc = SQLITE_OK; + int bDummy; + assert( pCur->eDir==BTREE_DIR_REVERSE ); + + pCur->isLast = 0; + rc = sqlite3HctBtreeCursorRestore((BtCursor*)pCur, &bDummy); + if( rc!=SQLITE_OK ) return rc; + + do{ + if( pCur->bUseTree ){ + rc = sqlite3HctTreeCsrPrev(pCur->pHctTreeCsr); + } + if( rc==SQLITE_OK && (pCur->bUseTree==0 || pCur->bUseTree==2) ){ + rc = sqlite3HctDbCsrPrev(pCur->pHctDbCsr); + } + if( rc==SQLITE_OK ){ + if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ + rc = SQLITE_DONE; + }else{ + btreeSetUseTree(pCur); + } + } + }while( rc==SQLITE_OK + && pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) + ); + return rc; +} + +static void hctBtreeClearIsLast(HBtree *pBt, HBtCursor *pExcept){ + HBtCursor *p; + for(p=pBt->pCsrList; p; p=p->pCsrNext){ + if( p!=pExcept ) p->isLast = 0; + } +} + +/* +** Insert a new record into the BTree. The content of the new record +** is described by the pX object. The pCur cursor is used only to +** define what table the record should be inserted into, and is left +** pointing at a random location. +** +** For a table btree (used for rowid tables), only the pX.nKey value of +** the key is used. The pX.pKey value must be NULL. The pX.nKey is the +** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields +** hold the content of the row. +** +** For an index btree (used for indexes and WITHOUT ROWID tables), the +** key is an arbitrary byte sequence stored in pX.pKey,nKey. The +** pX.pData,nData,nZero fields must be zero. +** +** If the seekResult parameter is non-zero, then a successful call to +** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already +** been performed. In other words, if seekResult!=0 then the cursor +** is currently pointing to a cell that will be adjacent to the cell +** to be inserted. If seekResult<0 then pCur points to a cell that is +** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell +** that is larger than (pKey,nKey). +** +** If seekResult==0, that means pCur is pointing at some unknown location. +** In that case, this routine must seek the cursor to the correct insertion +** point for (pKey,nKey) before doing the insertion. For index btrees, +** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked +** key values and pX->aMem can be used instead of pX->pKey to avoid having +** to decode the key. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeInsert( + BtCursor *pCursor, /* Insert data into the table of this cursor */ + const BtreePayload *pX, /* Content of the row to be inserted */ + int flags, /* True if this is likely an append */ + int seekResult /* Result of prior MovetoUnpacked() call */ +){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + HctTreeCsr *pTreeCsr = pCur->pHctTreeCsr; + int rc = SQLITE_OK; + UnpackedRecord r; + UnpackedRecord *pRec = 0; + const u8 *aData; + int nData; + int nZero; + i64 iKey = 0; + int bMigrate = pCur->pBtree->config.db->bHctMigrate; + + hctBtreeClearIsLast(pCur->pBtree, pCur); + if( pX->pKey ){ + aData = pX->pKey; + nData = pX->nKey; + nZero = 0; + if( pX->nMem ){ + memset(&r, 0, sizeof(r)); + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + pRec = &r; + }else{ + pRec = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + if( pRec==0 ) return SQLITE_NOMEM_BKPT; + sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nData, aData, pRec); + } + iKey = 0; + }else{ + aData = pX->pData; + nData = pX->nData; + nZero = pX->nZero; + iKey = pX->nKey; + } + + if( CSR_IS_MIGRATE(pCur) ){ + assert( nZero==0 ); + rc = hctBtreeMigrateInsert(pCur, pRec, iKey, nData, aData); + }else{ + if( pCur->isLast && seekResult<0 ){ + rc = sqlite3HctTreeAppend( + pTreeCsr, pCur->pKeyInfo, iKey, nData, aData, nZero + ); + }else{ + rc = sqlite3HctTreeInsert(pTreeCsr, pRec, iKey, nData, aData, nZero); + pCur->isLast = 0; + } + } + + if( pRec && pRec!=&r ){ + sqlite3DbFree(pCur->pKeyInfo->db, pRec); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctSchemaOp(Btree *pBt, const char *zSql){ + int rc = SQLITE_OK; + HBtree *const p = (HBtree*)pBt; + if( p->pHctJrnl ){ + HctTreeCsr *pCsr = 0; + + rc = sqlite3HctTreeCsrOpen(p->pHctTree, HCT_TREE_SCHEMAOP_ROOT, &pCsr); + if( rc==SQLITE_OK ){ + int nSql = sqlite3Strlen30(zSql); + i64 iRowid = 1; + sqlite3HctTreeCsrLast(pCsr); + if( sqlite3HctTreeCsrEof(pCsr)==0 ){ + sqlite3HctTreeCsrKey(pCsr, &iRowid); + iRowid++; + } + + rc = sqlite3HctTreeInsert(pCsr, 0, iRowid, nSql, (const u8*)zSql, 0); + sqlite3HctTreeCsrClose(pCsr); + } + } + return rc; +} + +/* +** Delete the entry that the cursor is pointing to. +** +** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then +** the cursor is left pointing at an arbitrary location after the delete. +** But if that bit is set, then the cursor is left in a state such that +** the next call to BtreeNext() or BtreePrev() moves it to the same row +** as it would have been on if the call to BtreeDelete() had been omitted. +** +** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes +** associated with a single table entry and its indexes. Only one of those +** deletes is considered the "primary" delete. The primary delete occurs +** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete +** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. +** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, +** but which might be used by alternative storage engines. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeDelete(BtCursor *pCursor, u8 flags){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int rc = SQLITE_OK; + + hctBtreeClearIsLast(pCur->pBtree, 0); + if( pCur->pHctDbCsr==0 ){ + rc = sqlite3HctTreeDelete(pCur->pHctTreeCsr); + }else if( pCur->pKeyInfo==0 ){ + i64 iKey = sqlite3HctBtreeIntegerKey((BtCursor*)pCur); + rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, 0, iKey, 0, 0); + }else{ + u32 nKey; + const u8 *aKey = (u8*)sqlite3HctBtreePayloadFetch((BtCursor*)pCur, &nKey); + UnpackedRecord *pRec = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + + if( pRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, aKey, pRec); + rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, pRec, 0, nKey, aKey); + sqlite3DbFree(pCur->pBtree->config.db, pRec); + } + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctBtreeIdxDelete(BtCursor *pCursor, UnpackedRecord *pKey){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + int rc = SQLITE_OK; + + hctBtreeClearIsLast(pCur->pBtree, 0); + if( pCur->pHctDbCsr ){ + u8 *aRec = 0; + int nRec = 0; + rc = sqlite3HctSerializeRecord(pKey, &aRec, &nRec); + if( rc==SQLITE_OK ){ + rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, pKey, 0, nRec, aRec); + sqlite3_free(aRec); + } + }else{ + int res = 0; + rc = sqlite3HctTreeCsrSeek(pCur->pHctTreeCsr, pKey, 0, &res); + if( res==0 ){ + rc = sqlite3HctTreeDelete(pCur->pHctTreeCsr); + } + } + return rc; +} + +static int hctreeAddNewSchemaOp(HBtree *p, u32 iRoot, int eOp){ + BtSchemaOp *aSchemaOp; + + /* Grow the Btree.aSchemaOp array */ + assert( p->pHctDb ); + aSchemaOp = (BtSchemaOp*)sqlite3_realloc( + p->aSchemaOp, sizeof(BtSchemaOp)*(p->nSchemaOp+1) + ); + if( aSchemaOp==0 ) return SQLITE_NOMEM_BKPT; + + p->aSchemaOp = aSchemaOp; + p->aSchemaOp[p->nSchemaOp].pgnoRoot = iRoot; + p->aSchemaOp[p->nSchemaOp].iSavepoint = p->config.db->nSavepoint; + p->aSchemaOp[p->nSchemaOp].eSchemaOp = eOp; + p->nSchemaOp++; + + return SQLITE_OK; +} + +static int hctreeAddNewRoot(HBtree *p, u32 iRoot, int bIndex){ + int eOp = bIndex ? HCT_SCHEMAOP_CREATE_INDEX : HCT_SCHEMAOP_CREATE_INTKEY; + return hctreeAddNewSchemaOp(p, iRoot, eOp); +} + +/* +** Create a new BTree table. Write into *piTable the page +** number for the root page of the new table. +** +** The type of type is determined by the flags parameter. Only the +** following values of flags are currently in use. Other values for +** flags might not work: +** +** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys +** BTREE_ZERODATA Used for SQL indices +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCreateTable(Btree *pBt, Pgno *piTable, int flags){ + HBtree *const p = (HBtree*)pBt; + Pgno iNew = 0; + int rc = SQLITE_OK; + if( p->pHctDb ){ + rc = sqlite3HctDbRootNew(p->pHctDb, &iNew); + if( rc==SQLITE_OK ){ + rc = hctreeAddNewRoot(p, iNew, (flags & BTREE_INTKEY)==0); + } + }else{ + iNew = p->iNextRoot++; + } + *piTable = iNew; + return rc; +} + +/* +** Delete all information from a single table in the database. iTable is +** the page number of the root of the table. After this routine returns, +** the root page is empty, but still exists. +** +** This routine will fail with SQLITE_LOCKED if there are any open +** read cursors on the table. Open write cursors are moved to the +** root of the table. +** +** If pnChange is not NULL, then table iTable must be an intkey table. The +** integer value pointed to by pnChange is incremented by the number of +** entries in the table. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeClearTable(Btree *pBt, int iTable, i64 *pnChange){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + KeyInfo *pKeyInfo = 0; + + rc = hctFindKeyInfo(p, iTable, &pKeyInfo); + if( rc==SQLITE_OK ){ + i64 nChange = 0; + BtCursor *pCsr = 0; + HctTreeCsr *pTreeCsr = 0; + UnpackedRecord *pRec = 0; + + if( pKeyInfo ){ + pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRec==0 ) rc = SQLITE_NOMEM_BKPT; + } + pCsr = (BtCursor*)sqlite3HctMalloc(&rc, sizeof(HBtCursor)); + if( rc==SQLITE_OK ){ + rc = sqlite3HctBtreeCursor(pBt, iTable, 0, pKeyInfo, pCsr); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctTreeCsrOpen(p->pHctTree, iTable, &pTreeCsr); + } + + if( rc==SQLITE_OK ){ + int res = 0; + rc = sqlite3HctBtreeFirst(pCsr, &res); + if( res==0 ){ + while( rc==SQLITE_OK ){ + nChange++; + if( pKeyInfo ){ + const u8 *aData = 0; + u32 nData = 0; + aData = (const u8*)sqlite3HctBtreePayloadFetch(pCsr, &nData); + sqlite3VdbeRecordUnpack(pKeyInfo, nData, aData, pRec); + rc = sqlite3HctTreeDeleteKey(pTreeCsr, pRec, 0, nData, aData); + }else{ + i64 iKey = sqlite3HctBtreeIntegerKey((BtCursor*)pCsr); + rc = sqlite3HctTreeDeleteKey(pTreeCsr, 0, iKey, 0, 0); + } + rc = sqlite3HctBtreeNext(pCsr, 0); + } + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + } + if( pnChange ) *pnChange = nChange; + + sqlite3KeyInfoUnref(pKeyInfo); + sqlite3HctBtreeCloseCursor(pCsr); + sqlite3HctTreeCsrClose(pTreeCsr); + sqlite3DbFree(p->config.db, pRec); + sqlite3_free(pCsr); + } + return rc; +} + +/* +** Delete all information from the single table that pCur is open on. +** +** This routine only work for pCur on an ephemeral table. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeClearTableOfCursor(BtCursor *pCursor){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + return sqlite3HctTreeClearOne( + pCur->pBtree->pHctTree, sqlite3HctTreeCsrRoot(pCur->pHctTreeCsr), 0 + ); +} + +/* +** Drop the table with root page iTable. Set (*piMoved) to 0 before +** returning. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeDropTable(Btree *pBt, int iTable, int *piMoved){ + HBtree *const p = (HBtree*)pBt; + *piMoved = 0; + return hctreeAddNewSchemaOp(p, iTable, HCT_SCHEMAOP_DROP); +} + + +/* +** This function may only be called if the b-tree connection already +** has a read or write transaction open on the database. +** +** Read the meta-information out of a database file. Meta[0] +** is the number of free pages currently in the database. Meta[1] +** through meta[15] are available for use by higher layers. Meta[0] +** is read-only, the others are read/write. +** +** The schema layer numbers meta values differently. At the schema +** layer (and the SetCookie and ReadCookie opcodes) the number of +** free pages is not visible. So Cookie[0] is the same as Meta[1]. +** +** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead +** of reading the value out of the header, it instead loads the "DataVersion" +** from the pager. The BTREE_DATA_VERSION value is not actually stored in the +** database file. It is a number computed by the pager. But its access +** pattern is the same as header meta values, and so it is convenient to +** read it from this routine. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){ + HBtree *const p = (HBtree*)pBt; + + assert( idx>=0 && idxpHctDb ); + if( idx==BTREE_DATA_VERSION ){ + /* TODO: Fix this so that the data_version does not change when the + ** database is written by the current connection. */ + i64 iSnapshot = sqlite3HctDbSnapshotId(p->pHctDb); + *pMeta = (u32)iSnapshot; + }else{ + if( p->eMetaState==HCT_METASTATE_NONE ){ + int rc = SQLITE_OK; + if( p->eTrans==SQLITE_TXN_NONE ){ + rc = sqlite3HctDbGetMeta( + p->pHctDb, (u8*)p->aMeta, SQLITE_N_BTREE_META*4 + ); + }else{ + int res = 0; + HBtCursor csr; + BtCursor *pCsr = (BtCursor*)&csr; + memset(&csr, 0, sizeof(csr)); + + sqlite3HctBtreeCursor(pBt, 2, 0, 0, pCsr); + rc = sqlite3HctBtreeTableMoveto(pCsr, 0, 0, &res); + assert( rc==SQLITE_OK ); + if( rc==SQLITE_OK && res==0 ){ + const void *aMeta = 0; + u32 nMeta = 0; + aMeta = sqlite3HctBtreePayloadFetch(pCsr, &nMeta); + memcpy(p->aMeta, aMeta, MAX(nMeta, SQLITE_N_BTREE_META*4)); + } + sqlite3HctBtreeCloseCursor(pCsr); + } + sqlite3HctJournalSchemaVersion( + p->pHctJrnl, &p->aMeta[BTREE_SCHEMA_VERSION] + ); + } + *pMeta = p->aMeta[idx]; + } +} + +/* +** Write meta-information back into the database. Meta[0] is +** read-only and may not be written. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){ + HBtree *const p = (HBtree*)pBt; + u32 dummy; + sqlite3HctBtreeGetMeta((Btree*)p, 0, &dummy); + p->aMeta[idx] = iMeta; + return sqlite3HctTreeUpdateMeta( + p->pHctTree, (u8*)p->aMeta, SQLITE_N_BTREE_META*4 + ); +} + +static char *hctDbMPrintf(int *pRc, const char *zFormat, ...){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFormat); + zRet = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( !zRet ) *pRc = SQLITE_NOMEM_BKPT; + } + return zRet; +} + +SQLITE_PRIVATE int sqlite3HctBtreePragma(Btree *pBt, char **aFnctl){ + HBtree *const p = (HBtree*)pBt; + int rc = SQLITE_OK; + const char *zLeft = aFnctl[1]; + const char *zRight = aFnctl[2]; + char *zRet = 0; + + if( 0==sqlite3_stricmp("hct_ndbfile", zLeft) ){ + HctFile *pFile = sqlite3HctDbFile(p->pHctDb); + int iCurrent = 0; + int bFixed = 0; + if( zRight ){ + int iVal = sqlite3Atoi(zRight); + if( iVal<1 || iVal>HCT_MAX_NDBFILE ){ + rc = SQLITE_RANGE; + }else{ + p->config.nDbFile = iVal; + } + } + if( rc==SQLITE_OK ){ + iCurrent = sqlite3HctFileNFile(pFile, &bFixed); + if( bFixed==0 ) iCurrent = p->config.nDbFile; + zRet = hctDbMPrintf(&rc, "%d", iCurrent); + } + } + + else if( 0==sqlite3_stricmp("hct_try_before_unevict", zLeft) ){ + int iVal = 0; + if( zRight ){ + iVal = sqlite3Atoi(zRight); + } + if( iVal>0 ){ + p->config.nTryBeforeUnevict = iVal; + } + zRet = hctDbMPrintf(&rc, "%d", p->config.nTryBeforeUnevict); + } + else if( 0==sqlite3_stricmp("hct_npageset", zLeft) ){ + int iVal = 0; + if( zRight ){ + iVal = sqlite3Atoi(zRight); + } + if( iVal>0 ){ + p->config.nPageSet = iVal; + } + zRet = hctDbMPrintf(&rc, "%d", p->config.nPageSet); + } + else if( 0==sqlite3_stricmp("hct_ncasfail", zLeft) ){ + zRet = hctDbMPrintf(&rc, "%lld", sqlite3HctDbNCasFail(p->pHctDb)); + } + else if( p->pHctDb && 0==sqlite3_stricmp("hct_npagescan", zLeft) ){ + int iVal = 0; + if( zRight ){ + iVal = sqlite3Atoi(zRight); + } + if( iVal>0 ){ + p->config.nPageScan = iVal; + } + zRet = hctDbMPrintf(&rc, "%d", p->config.nPageScan); + } + else if( 0==sqlite3_stricmp("hct_quiescent_integrity_check", zLeft) ){ + int iVal = 0; + if( zRight ){ + iVal = sqlite3Atoi(zRight); + } + if( iVal>0 ){ + p->config.bQuiescentIntegrityCheck = (iVal==0 ? 0 : 1); + } + zRet = hctDbMPrintf(&rc, "%d", p->config.bQuiescentIntegrityCheck); + }else{ + rc = SQLITE_NOTFOUND; + } + + aFnctl[0] = zRet; + return rc; +} + +/* +** The first argument, pCur, is a cursor opened on some b-tree. Count the +** number of entries in the b-tree and write the result to *pnEntry. +** +** SQLITE_OK is returned if the operation is successfully executed. +** Otherwise, if an error is encountered (i.e. an IO error or database +** corruption) an SQLite error code is returned. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCount(sqlite3 *db, BtCursor *pCursor, i64 *pnEntry){ + HBtCursor *const pCur = (HBtCursor*)pCursor; + i64 nEntry = 0; + int dummy = 0; + int rc; + for(rc = sqlite3HctBtreeFirst((BtCursor*)pCur, &dummy); + rc==SQLITE_OK && 0==sqlite3HctBtreeEof((BtCursor*)pCur); + rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0) + ){ + nEntry++; + } + *pnEntry = nEntry; + return SQLITE_OK; +} + +/* +** Return the pager associated with a BTree. This routine is used for +** testing and debugging only. +*/ +SQLITE_PRIVATE Pager *sqlite3HctBtreePager(Btree *pBt){ + HBtree *const p = (HBtree*)pBt; + return p->pFakePager; +} + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK +/* +** This routine does a complete check of the given BTree file. aRoot[] is +** an array of pages numbers were each page number is the root page of +** a table. nRoot is the number of entries in aRoot. +** +** A read-only or read-write transaction must be opened before calling +** this function. +** +** Write the number of error seen in *pnErr. Except for some memory +** allocation errors, an error message held in memory obtained from +** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is +** returned. If a memory allocation error occurs, NULL is returned. +** +** If the first entry in aRoot[] is 0, that indicates that the list of +** root pages is incomplete. This is a "partial integrity-check". This +** happens when performing an integrity check on a single table. The +** zero is skipped, of course. But in addition, the freelist checks +** and the checks to make sure every page is referenced are also skipped, +** since obviously it is not possible to know which pages are covered by +** the unverified btrees. Except, if aRoot[1] is 1, then the freelist +** checks are still performed. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeIntegrityCheck( + sqlite3 *db, /* Database connection that is running the check */ + Btree *pBt, /* The btree to be checked */ + Pgno *aRoot, /* An array of root pages numbers for individual trees */ + Mem *aCnt, + int nRoot, /* Number of entries in aRoot[] */ + int mxErr, /* Stop reporting errors after this many */ + int *pnErr, /* Write number of errors seen to this variable */ + char **pzErr +){ + HBtree *const p = (HBtree*)pBt; + char *zRet = 0; /* Return value */ + *pnErr = 0; + int ii; + for(ii=0; iiconfig.bQuiescentIntegrityCheck && nRoot>0 && aRoot[0]!=0 ){ + zRet = sqlite3HctDbIntegrityCheck(p->pHctDb, aRoot, aCnt, nRoot, pnErr); + assert( zRet==0 || (*pnErr)>0 ); + } + *pzErr = zRet; + return 0; +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +/* +** Return the full pathname of the underlying database file. Return +** an empty string if the database is in-memory or a TEMP database. +** +** The pager filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. +*/ +SQLITE_PRIVATE const char *sqlite3HctBtreeGetFilename(Btree *p){ + return 0; +} + +/* +** Return the pathname of the journal file for this database. The return +** value of this routine is the same regardless of whether the journal file +** has been created or not. +** +** The pager journal filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. +*/ +SQLITE_PRIVATE const char *sqlite3HctBtreeGetJournalname(Btree *p){ + return 0; +} + +/* +** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE +** to describe the current transaction state of Btree p. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeTxnState(Btree *pBt){ + HBtree *const p = (HBtree*)pBt; + return p ? p->eTrans : SQLITE_TXN_NONE; +} + +#ifndef SQLITE_OMIT_WAL +/* +** Run a checkpoint on the Btree passed as the first argument. +** +** Return SQLITE_LOCKED if this or any other connection has an open +** transaction on the shared-cache the argument Btree is connected to. +** +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ + return SQLITE_OK; +} +#endif + +/* +** Return true if there is currently a backup running on Btree p. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeIsInBackup(Btree *p){ + return 0; +} + +/* +** This function returns a pointer to a blob of memory associated with +** a single shared-btree. The memory is used by client code for its own +** purposes (for example, to store a high-level schema associated with +** the shared-btree). The btree layer manages reference counting issues. +** +** The first time this is called on a shared-btree, nBytes bytes of memory +** are allocated, zeroed, and returned to the caller. For each subsequent +** call the nBytes parameter is ignored and a pointer to the same blob +** of memory returned. +** +** If the nBytes parameter is 0 and the blob of memory has not yet been +** allocated, a null pointer is returned. If the blob has already been +** allocated, it is returned as normal. +** +** Just before the shared-btree is closed, the function passed as the +** xFree argument when the memory allocation was made is invoked on the +** blob of allocated memory. The xFree function should not call sqlite3_free() +** on the memory, the btree layer does that. +*/ +SQLITE_PRIVATE void *sqlite3HctBtreeSchema(Btree *pBt, int nBytes, void(*xFree)(void *)){ + HBtree *const p = (HBtree*)pBt; + void *pRet = 0; + if( p->pSchema ){ + pRet = p->pSchema; + }else if( nBytes>0 ){ + pRet = p->pSchema = sqlite3_malloc(nBytes); + if( pRet ){ + memset(pRet, 0, nBytes); + p->xSchemaFree = xFree; + } + } + return pRet; +} + +/* +** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared +** btree as the argument handle holds an exclusive lock on the +** sqlite_schema table. Otherwise SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSchemaLocked(Btree *p){ + return SQLITE_OK; +} + +SQLITE_PRIVATE HctDatabase *sqlite3HctDbFind(sqlite3 *db, int iDb){ + Btree *pBt = db->aDb[iDb].pBt; + return sqlite3IsHct(pBt) ? ((HBtree*)pBt)->pHctDb : 0; +} +SQLITE_PRIVATE HctJournal *sqlite3HctJrnlFind(sqlite3 *db){ + Btree *pBt = db->aDb[0].pBt; + return sqlite3IsHct(pBt) ? ((HBtree*)pBt)->pHctJrnl : 0; +} + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Obtain a lock on the table whose root page is iTab. The +** lock is a write lock if isWritelock is true or a read lock +** if it is false. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ + int rc = SQLITE_OK; + assert( 0 ); + return rc; +} +#endif + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Argument pCur must be a cursor opened for writing on an +** INTKEY table currently pointing at a valid table entry. +** This function modifies the data stored as part of that entry. +** +** Only the data content may only be modified, it is not possible to +** change the length of the data stored. If this function is called with +** parameters that attempt to write past the end of the existing data, +** no modifications are made and SQLITE_CORRUPT is returned. +*/ +SQLITE_PRIVATE int sqlite3HctBtreePutData(BtCursor *pCur, u32 offset, u32 amt, void *z){ + HBtCursor *pCsr = (HBtCursor*)pCur; + int rc = SQLITE_OK; + + if( pCsr->wrFlag==0 ){ + rc = SQLITE_READONLY; + }else{ + rc = hctReseekBlobCsr(pCsr); + } + if( rc==SQLITE_OK ){ + u32 nData = 0; + const void *aData = sqlite3HctBtreePayloadFetch(pCur, &nData); + if( offset+amt>nData ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + u8 *aBuf = (u8*)sqlite3_malloc(nData+1); + if( aBuf ){ + BtreePayload payload; + memcpy(aBuf, aData, nData); + memcpy(&aBuf[offset], z, amt); + + memset(&payload, 0, sizeof(payload)); + payload.nKey = sqlite3HctBtreeIntegerKey(pCur); + payload.pData = (const void*)aBuf; + payload.nData = nData; + rc = sqlite3HctBtreeInsert(pCur, &payload, 0, 0); + if( rc==SQLITE_OK ){ + int dummy = 0; + rc = sqlite3HctBtreeTableMoveto(pCur, payload.nKey, 0, &dummy); + assert( dummy==0 ); + } + sqlite3_free(aBuf); + }else{ + rc = SQLITE_NOMEM; + } + } + } + + return rc; +} + +/* +** Mark this cursor as an incremental blob cursor. +*/ +SQLITE_PRIVATE void sqlite3HctBtreeIncrblobCursor(BtCursor *pCur){ + HBtCursor *pCsr = (HBtCursor*)pCur; + sqlite3HctTreeCsrIncrblob(pCsr->pHctTreeCsr); +} +#endif + +/* +** Set both the "read version" (single byte at byte offset 18) and +** "write version" (single byte at byte offset 19) fields in the database +** header to iVersion. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSetVersion(Btree *pBtree, int iVersion){ + assert( 0 ); + return SQLITE_OK; +} + +/* +** Return true if the cursor has a hint specified. This routine is +** only used from within assert() statements +*/ +SQLITE_PRIVATE int sqlite3HctBtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ + return 0; +} + +/* +** Return true if the given Btree is read-only. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeIsReadonly(Btree *p){ + return 0; +} + +#if !defined(SQLITE_OMIT_SHARED_CACHE) +/* +** Return true if the Btree passed as the only argument is sharable. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeSharable(Btree *p){ + assert( 0 ); + return 0; +} + +/* +** Return the number of connections to the BtShared object accessed by +** the Btree handle passed as the only argument. For private caches +** this is always 1. For shared caches it may be 1 or greater. +*/ +SQLITE_PRIVATE int sqlite3HctBtreeConnectionCount(Btree *p){ + assert( 0 ); + return 1; +} +#endif + +SQLITE_PRIVATE int sqlite3HctBtreeExclusiveLock(Btree *p){ + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctBtreeTransferRow(BtCursor *p1, BtCursor *p2, i64 iKey){ + assert( 0 ); + return SQLITE_LOCKED; +} + +SQLITE_PRIVATE int sqlite3HctLockedErr(u32 pgno, const char *zReason){ + return SQLITE_LOCKED; +} + +SQLITE_PRIVATE i64 sqlite3HctMainStats(sqlite3 *db, int iStat, const char **pzStat){ + Btree *pBt = db->aDb[0].pBt; + + i64 iRet = 0; + + if( sqlite3IsHct(pBt) ){ + HBtree *pHct = (HBtree*)pBt; + switch( iStat ){ + case 0: + *pzStat = "nretry"; + iRet = pHct->stats.nRetry; + break; + case 1: + *pzStat = "nretrykey"; + iRet = pHct->stats.nRetryKey; + break; + case 2: + *pzStat = "nkeyop"; + iRet = pHct->stats.nKeyOp; + break; + } + } + + return iRet; +} + + +#endif /* SQLITE_ENABLE_HCT */ + +/************** End of hctree.c **********************************************/ +/************** Begin file hct_tree.c ****************************************/ +/* +** 2020 September 24 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + + +/* #include "hctInt.h" */ +/* #include */ +/* #include */ + +#define HCT_TREE_MAX_DEPTH 60 + +typedef struct HctTreeNode HctTreeNode; +typedef struct HctTreeRoot HctTreeRoot; + +struct HctTree { + int nRootHash; + int nRootEntry; + HctTreeRoot **apRootHash; + HctTreeNode *pRollback; /* List of rollback list items */ + HctTreeNode **apStmt; /* Array of open statement transactions */ + int nStmt; /* Allocated size of apStmt[] */ + int iStmt; /* Current entry in apStmt (-1 == none) */ +}; + +/* +** pReseek: +** Set to non-NULL if the cursor was disrupted by a write. The cursor +** should be seeked to the key in node pReseek. +*/ +struct HctTreeCsr { + HctTree *pTree; + HctTreeRoot *pRoot; + u8 bPin; /* True if cursor is pinned */ + u8 eIncrblob; /* Incrblob cursor state */ + i64 iSeekRowid; /* Last rowid value seeked to */ + int iSkip; /* -ve -> skip Prev(), +ve -> skip Next() */ + int iNode; /* Current depth */ + HctTreeNode *apNode[HCT_TREE_MAX_DEPTH]; + HctTreeNode *pReseek; + HctTreeCsr *pCsrNext; /* Next item in HctTreeRoot.pCsrList list */ +}; + +#define TREE_INCRBLOB_NONE 0 +#define TREE_INCRBLOB_READY 1 +#define TREE_INCRBLOB_ABORT 2 + +struct HctTreeNode { + i64 iKey; /* 64-bit key for this node */ + u8 bBlack; /* 1 for black node, 0 for red node */ + u8 nRef; /* Number of pointers to this node */ + u8 bDelete; /* True if this is a delete key */ + int nData; /* Size of aData[] in bytes */ + u8 *aData; /* Pointer to associated data (or NULL) */ + u32 iRoot; /* Root id of table this node belongs to */ + HctTreeNode *pLeft; /* Left child in tree */ + HctTreeNode *pRight; /* Right child in tree */ + + /* Rollback list related variables */ + HctTreeNode *pPrev; /* Previous entry in rollback list */ + HctTreeNode *pClobber; /* If non-NULL, entry this one clobbered */ +}; + +static HctTreeNode hctTreeGlobalEofNode; +#define TREE_RESEEK_EOF (&hctTreeGlobalEofNode) + +/* +** pCsrCache: +** List of unused cursor objects for this table/index. +*/ +struct HctTreeRoot { + u32 iRoot; /* Name of this tree structure */ + KeyInfo *pKeyInfo; + HctTreeNode *pNode; /* Root node of tree (or NULL) */ + HctTreeRoot *pHashNext; /* Next entry in hash-chain */ + HctTreeCsr *pCsrList; /* Cursors open on this tree */ + HctTreeCsr *pCsrCache; /* Cache of unused cursor objects */ +}; + +/* +** Allocate and return nByte bytes of zeroed memory. +*/ +static void *hctMallocZero(int nByte){ + void *pNew = sqlite3_malloc(nByte); + if( pNew ){ + memset(pNew, 0, nByte); + } + return pNew; +} + +SQLITE_PRIVATE int sqlite3HctTreeNew(HctTree **ppTree){ + HctTree *pNew; + int rc = SQLITE_OK; + + pNew = (HctTree*)hctMallocZero(sizeof(HctTree)); + if( pNew ){ + pNew->apRootHash = (HctTreeRoot**)hctMallocZero(sizeof(HctTreeRoot*)*16); + pNew->nRootHash = 16; + } + if( pNew==0 || pNew->apRootHash==0 ){ + sqlite3_free(pNew); + rc = SQLITE_NOMEM_BKPT; + } + + *ppTree = pNew; + return rc; +} + +static void treeNodeUnref(HctTreeNode *pNode){ + if( pNode!=TREE_RESEEK_EOF ){ + assert( pNode->nRef>0 ); + pNode->nRef--; + if( pNode->nRef==0 ){ + sqlite3_free(pNode); + } + } +} + +static void hctTreeFreeNode(HctTreeNode *pNode){ + if( pNode ){ + hctTreeFreeNode(pNode->pLeft); + hctTreeFreeNode(pNode->pRight); + assert( pNode->nRef==1 ); + treeNodeUnref(pNode); + } +} + +SQLITE_PRIVATE void sqlite3HctTreeFree(HctTree *pTree){ + if( pTree ){ + int i; + sqlite3HctTreeRelease(pTree, 0); + assert( pTree->pRollback==0 ); + for(i=0; inRootHash; i++){ + while( pTree->apRootHash[i] ){ + HctTreeRoot *p = pTree->apRootHash[i]; + HctTreeCsr *pCsr = p->pCsrCache; + sqlite3KeyInfoUnref(p->pKeyInfo); + pTree->apRootHash[i] = p->pHashNext; + while( pCsr ){ + HctTreeCsr *pNext = pCsr->pCsrNext; + sqlite3_free(pCsr); + pCsr = pNext; + } + hctTreeFreeNode(p->pNode); + sqlite3_free(p); + } + } + sqlite3_free(pTree->apRootHash); + sqlite3_free(pTree->apStmt); + sqlite3_free(pTree); + } +} + +#ifdef SQLITE_DEBUG +/* #include */ +static void hct_print_subtree2(HctTreeNode *pNode, char *aPrefix){ + if( pNode ){ + int n = strlen(aPrefix); + fprintf(stdout, "%-8s %s k=%lld\n", + aPrefix, pNode->bBlack ? "BLACK" : "RED ", pNode->iKey + ); + aPrefix[n] = 'L'; + hct_print_subtree2(pNode->pLeft, aPrefix); + aPrefix[n] = 'R'; + hct_print_subtree2(pNode->pRight, aPrefix); + aPrefix[n] = '\0'; + } +} +static void hct_print_subtree(HctTreeNode *pNode){ + if( pNode ){ + char aPrefix[64]; + memset(aPrefix, 0, sizeof(aPrefix)); + hct_print_subtree2(pNode, aPrefix); + fflush(stdout); + } +} + +/* +** To be used as: +** +** assert( hct_tree_check(pTree) ) +** +** An assert() fails if any of the following tree properties are violated: +** +** 1. Root node must be black. +** 2. A red node may not have a red parent. +** 3. Every path from root to NULL passes through the same number +** of black nodes. +*/ +static void hct_tree_check_subtree(HctTreeNode *pNode, int nDepth, int nExpect){ + if( pNode ){ + int nThisDepth = nDepth; + if( pNode->bBlack ){ + nThisDepth++; + }else{ + /* Property 2 - red parents have black children */ + assert( pNode->pLeft==0 || pNode->pLeft->bBlack ); + assert( pNode->pRight==0 || pNode->pRight->bBlack ); + } + + /* Property 3 - Every path from root to NULL has same black-depth */ + assert( (pNode->pLeft && pNode->pRight) || nThisDepth==nExpect ); + + hct_tree_check_subtree(pNode->pLeft, nThisDepth, nExpect); + hct_tree_check_subtree(pNode->pRight, nThisDepth, nExpect); + } + hct_print_subtree(0); /* no-op - just to avoid a warning */ +} +static int hct_tree_check(HctTreeRoot *pRoot){ + if( 0 && pRoot->pNode ){ + int nBlack = 0; + HctTreeNode *pNode = 0; + assert( pRoot->pNode->bBlack ); /* 1. Root is black */ + + /* Calculate the expected number of black nodes between root and NULL. */ + for(pNode=pRoot->pNode; pNode; pNode=pNode->pLeft){ + if( pNode->bBlack ) nBlack++; + } + + hct_tree_check_subtree(pRoot->pNode, 0, nBlack); + } + return 1; +} +#endif + +static HctTreeRoot *hctTreeFindRoot(HctTree *pTree, u32 iRoot){ + HctTreeRoot *pNew = 0; + + /* Search the hash table for an existing root. Return immediately if + ** one is found. */ + HctTreeRoot *pRoot; + for(pRoot = pTree->apRootHash[iRoot % pTree->nRootHash]; + pRoot; + pRoot=pRoot->pHashNext + ){ + if( pRoot->iRoot==iRoot ) return pRoot; + } + + /* If the hash table needs to grow, do that now */ + if( (pTree->nRootEntry+1)*2 > pTree->nRootHash ){ + int ii; + int nOld = pTree->nRootHash; + int nNew = nOld ? nOld*2 : 16; + HctTreeRoot **apNew = (HctTreeRoot**)sqlite3_realloc( + pTree->apRootHash, nNew*sizeof(HctTreeRoot*) + ); + if( apNew==0 ) return 0; + memset(&apNew[nOld], 0, (nNew-nOld)*sizeof(HctTreeRoot*)); + + for(ii=0; iipHashNext; + int iHash = p->iRoot % nNew; + p->pHashNext = apNew[iHash]; + apNew[iHash] = p; + p = pNext; + } + } + + pTree->apRootHash = apNew; + pTree->nRootHash = nNew; + } + + /* Allocate a new root and add it to the hash table */ + pNew = hctMallocZero(sizeof(HctTreeRoot)); + if( pNew ){ + int iHash = iRoot % pTree->nRootHash; + pNew->iRoot = iRoot; + pNew->pHashNext = pTree->apRootHash[iHash]; + pTree->apRootHash[iHash] = pNew; + pTree->nRootEntry++; + } + + return pNew; +} + +static void leftRotate(HctTreeNode **pp){ + HctTreeNode *pG = *pp; + HctTreeNode *pRight = pG->pRight; + + pG->pRight = pRight->pLeft; + pRight->pLeft = pG; + *pp = pRight; +} + +static void rightRotate(HctTreeNode **pp){ + HctTreeNode *pG = *pp; + HctTreeNode *pLeft = pG->pLeft; + + pG->pLeft = pLeft->pRight; + pLeft->pRight = pG; + *pp = pLeft; +} + +static HctTreeNode **hctTreeFindPointer(HctTreeCsr *pCsr, int iNode){ + HctTreeNode **pp; + if( iNode==0 ){ + assert( pCsr->apNode[0]==pCsr->pRoot->pNode ); + pp = &pCsr->pRoot->pNode; + }else{ + HctTreeNode *pParent = pCsr->apNode[iNode-1]; + if( pParent->pLeft==pCsr->apNode[iNode] ){ + pp = &pParent->pLeft; + }else{ + assert( pParent->pRight==pCsr->apNode[iNode] ); + pp = &pParent->pRight; + } + } + return pp; +} + +static void hctTreeFixInsert( + HctTree *pTree, + HctTreeCsr *pCsr, + HctTreeNode *pX +){ + HctTreeNode *pP = pCsr->apNode[pCsr->iNode]; + HctTreeNode *pG = pCsr->apNode[pCsr->iNode-1]; + HctTreeNode *pU; + + assert( pCsr->iNode>=1 ); + + if( pG->pLeft==pP ){ + pU = pG->pRight; + }else{ + pU = pG->pLeft; + } + + if( pU && pU->bBlack==0 ){ + /* Uncle of X is red */ + pP->bBlack = 1; + pU->bBlack = 1; + if( pCsr->iNode>1 ){ + pG->bBlack = 0; + if( pCsr->apNode[pCsr->iNode-2]->bBlack==0 ){ + pCsr->iNode -= 2; + hctTreeFixInsert(pTree, pCsr, pG); + } + } + }else{ + /* Uncle of X is black */ + int iCase = ((pG->pRight==pP) ? 2 : 0) + (pP->pRight==pX ? 1 : 0); + HctTreeNode **ppG = hctTreeFindPointer(pCsr, pCsr->iNode-1); + + switch( iCase ){ + case 1: /* left/right */ + leftRotate(&pG->pLeft); + pP = pX; + /* fall-through */ + case 0: /* left/left */ + rightRotate(ppG); + pP->bBlack = 1; + pG->bBlack = 0; + break; + case 2: /* right/left */ + rightRotate(&pG->pRight); + pP = pX; + /* fall-through */ + case 3: /* right/right */ + leftRotate(ppG); + pP->bBlack = 1; + pG->bBlack = 0; + break; + default: + assert( 0 ); + } + } +} + +static int hctSaveCursors( + HctTreeRoot *pRoot, + HctTreeCsr *pExcept, + int bAbortBlob, + i64 iRowid +){ + int rc = SQLITE_OK; + HctTreeCsr *pCsr; + for(pCsr=pRoot->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ + if( pCsr!=pExcept && pCsr->pReseek==0 ){ + if( pCsr->iNode>=0 ){ + if( pCsr->bPin ){ + return SQLITE_CONSTRAINT_PINNED; + } + pCsr->pReseek = pCsr->apNode[pCsr->iNode]; + pCsr->pReseek->nRef++; + }else{ + pCsr->pReseek = TREE_RESEEK_EOF; + } + } + if( bAbortBlob + && pCsr->eIncrblob==TREE_INCRBLOB_READY + && pCsr->iSeekRowid==iRowid + ){ + pCsr->eIncrblob = TREE_INCRBLOB_ABORT; + } + } + return rc; +} + + +static int hctTreeCsrSeekInt( + HctTreeCsr *pCsr, + i64 iKey, + int *pRes +){ + int rc = SQLITE_OK; /* Return code */ + int res = -1; /* Value to return via *pRes */ + HctTreeNode *pNode = pCsr->pRoot->pNode; + pCsr->iNode = -1; + while( pNode ){ + i64 iNodeKey = pNode->iKey; + pCsr->apNode[++pCsr->iNode] = pNode; + if( iNodeKey==iKey ){ + res = 0; + break; + } + if( iKeypLeft; + }else{ + res = -1; + pNode = pNode->pRight; + } + assert( pCsr->iNodepRoot->pNode; + pCsr->iNode = -1; + while( pNode ){ + pCsr->apNode[++pCsr->iNode] = pNode; + res = sqlite3VdbeRecordCompare(pNode->nData, pNode->aData, pRec); + if( res==0 ) break; + if( res>0 ){ + /* pRec is smaller than this node's key. Go left. */ + pNode = pNode->pLeft; + }else{ + /* pRec is larger than this node's key. Go left. */ + pNode = pNode->pRight; + } + assert( pCsr->iNodepRoot->pKeyInfo==0 ){ + pCsr->pRoot->pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); + } + + if( pRes ) *pRes = res; + return rc; +} + +static int hctTreeCsrSeekPacked( + HctTreeCsr *pCsr, + int nKey, + const u8 *aKey, + int *pRes +){ + int rc; + KeyInfo *pKeyInfo = pCsr->pRoot->pKeyInfo; + UnpackedRecord *pRec; + + assert( pKeyInfo ); + pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRec ){ + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, aKey, pRec); + rc = hctTreeCsrSeekUnpacked(pCsr, pRec, pRes); + sqlite3DbFree(pKeyInfo->db, pRec); + }else{ + rc = SQLITE_NOMEM; + } + return rc; +} + + +static int hctRestoreCursor(HctTreeCsr *pCsr, int *pRes){ + int rc = SQLITE_OK; + HctTreeNode *pReseek = pCsr->pReseek; + if( pReseek ){ + if( pReseek!=TREE_RESEEK_EOF ){ + if( pCsr->pRoot->pKeyInfo ){ + rc = hctTreeCsrSeekPacked(pCsr, pReseek->nData, pReseek->aData, pRes); + }else{ + rc = hctTreeCsrSeekInt(pCsr, pReseek->iKey, pRes); + } + treeNodeUnref(pReseek); + } + pCsr->pReseek = 0; + }else{ + *pRes = 0; + } + return rc; +} + +static void hctRestoreDiscard(HctTreeCsr *pCsr){ + if( pCsr->pReseek ){ + treeNodeUnref(pCsr->pReseek); + pCsr->pReseek = 0; + pCsr->iNode = -1; + } + pCsr->iSkip = 0; +} + +static int treeInsertNode( + HctTree *pTree, + int bRollback, + UnpackedRecord *pKey, + i64 iKey, + HctTreeNode *pNew +){ + HctTreeRoot *pRoot = hctTreeFindRoot(pTree, pNew->iRoot); + UnpackedRecord *pFree = 0; + int res = 0; + HctTreeCsr csr; + memset(&csr, 0, sizeof(csr)); + csr.pRoot = pRoot; + csr.pTree = pTree; + + /* Special case. If this insert is to effect a rollback on an index + ** tree, pKey will still be NULL. In this case construct a pKey value + ** with which to do the seek. */ + if( pRoot->pKeyInfo && pKey==0 ){ + assert( bRollback ); + pFree = sqlite3VdbeAllocUnpackedRecord(pRoot->pKeyInfo); + if( pFree==0 ){ + return SQLITE_NOMEM; + } + sqlite3VdbeRecordUnpack(pRoot->pKeyInfo, pNew->nData, pNew->aData, pFree); + pKey = pFree; + } + + sqlite3HctTreeCsrSeek(&csr, pKey, iKey, &res); + if( csr.iNode<0 ){ + assert( pRoot->pNode==0 ); + pRoot->pNode = pNew; + }else{ + HctTreeNode *pNode = csr.apNode[csr.iNode]; + if( res==0 ){ + pNew->pLeft = pNode->pLeft; + pNew->pRight = pNode->pRight; + pNew->bBlack = pNode->bBlack; + *(hctTreeFindPointer(&csr, csr.iNode)) = pNew; + if( bRollback==0 && pTree->iStmt>=0 ){ + pNew->pClobber = pNode; + assert( pNew->iKey==pNode->iKey ); + }else{ + treeNodeUnref(pNode); + } + }else{ + if( res<0 ){ + assert( pNode->pRight==0 ); + pNode->pRight = pNew; + }else{ + assert( pNode->pLeft==0 ); + pNode->pLeft = pNew; + } + if( pNode->bBlack==0 ){ + hctTreeFixInsert(pTree, &csr, pNew); + } + } + } + pNew->nRef++; + + /* Root node is always black */ + pRoot->pNode->bBlack = 1; + assert( hct_tree_check(pRoot) ); + if( pFree ){ + sqlite3DbFree(pFree->pKeyInfo->db, pFree); + } + return SQLITE_OK; +} + +static HctTreeNode *treeNewNode2( + HctTree *pTree, + HctTreeRoot *pRoot, + i64 iKey, + int bDelete, + int nData, + const u8 *aData, + int nZero +){ + HctTreeNode *pNew; + + pNew = (HctTreeNode*)hctMallocZero(sizeof(HctTreeNode) + nData + nZero); + if( pNew ){ + pNew->iKey = iKey; + pNew->nData = nData + nZero; + pNew->iRoot = pRoot->iRoot; + pNew->bDelete = bDelete; + if( (nData+nZero)>0 ){ + pNew->aData = (u8*)&pNew[1]; + memcpy(pNew->aData, aData, nData); + } + + if( pTree->iStmt>0 ){ + pNew->pPrev = pTree->pRollback; + pTree->pRollback = pNew; + pNew->nRef = 1; + } + } + + return pNew; +} + +/* +** Allocate a new tree node. Link it into the rollback list. +*/ +static HctTreeNode *treeNewNode( + HctTreeCsr *pCsr, + i64 iKey, + int bDelete, + int nData, + const u8 *aData, + int nZero +){ + return treeNewNode2( + pCsr->pTree, pCsr->pRoot, iKey, bDelete, nData, aData, nZero + ); +} + +static int treeInsert( + HctTreeCsr *pCsr, + UnpackedRecord *pKey, + i64 iKey, + int bDelete, + int nData, + const u8 *aData, + int nZero +){ + HctTree *pTree = pCsr->pTree; + HctTreeNode *pNew; + int rc = SQLITE_OK; + + assert( bDelete==0 || pKey || (aData==0 && nData==0 && nZero==0) ); + + pNew = treeNewNode(pCsr, iKey, bDelete, nData, aData, nZero); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int nSave = 0; + int bPinSave = pCsr->bPin; + if( pKey ){ + nSave = pKey->nField; + sqlite3HctDbRecordTrim(pKey); + } + pCsr->bPin = 0; + rc = hctSaveCursors(pCsr->pRoot, 0, (pCsr->eIncrblob==0), iKey); + if( rc==SQLITE_OK && bPinSave ){ + int dummy; + rc = hctRestoreCursor(pCsr, &dummy); + } + pCsr->bPin = bPinSave; + if( rc==SQLITE_OK ){ + rc = treeInsertNode(pTree, pTree->iStmt<=0, pKey, iKey, pNew); + } + if( pKey ) pKey->nField = nSave; + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTreeUpdateMeta( + HctTree *pTree, + const u8 *aMeta, /* Meta data */ + int nMeta /* Size of meta data in bytes */ +){ + HctTreeRoot *pRoot = hctTreeFindRoot(pTree, 2); + HctTreeNode *pNew = treeNewNode2(pTree, pRoot, 0, 0, nMeta, aMeta, 0); + treeInsertNode(pTree, pTree->iStmt<=0, 0, 0, pNew); + return SQLITE_OK; +} + +/* +** This function is like sqlite3HctTreeInsert(), except that: +** +** 1) the new key is always larger than any existing key in the +** tree, and +** +** 2) unless the tree is empty, cursor pCsr is guaranteed to point to the +** largest record in it, and +** +** 3) before returning, this function leaves cursor pCsr pointing to the +** new entry. +*/ +SQLITE_PRIVATE int sqlite3HctTreeAppend( + HctTreeCsr *pCsr, + KeyInfo *pKeyInfo, + i64 iKey, + int nData, + const u8 *aData, + int nZero +){ + HctTreeRoot *pRoot = pCsr->pRoot; + int rc = SQLITE_OK; + + assert( pCsr->pTree->iStmt>0 ); + + if( pKeyInfo && pRoot->pKeyInfo==0 ){ + pRoot->pKeyInfo = sqlite3KeyInfoRef(pKeyInfo); + } + + rc = hctSaveCursors(pRoot, pCsr, pCsr->eIncrblob==0, iKey); + if( rc==SQLITE_OK ){ + HctTreeNode *pNew = treeNewNode(pCsr, iKey, 0, nData, aData, nZero); + if( pNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + pNew->nRef++; + if( pRoot->pNode==0 ){ + pRoot->pNode = pNew; + pCsr->apNode[0] = pNew; + pCsr->iNode = 0; + }else{ + HctTreeNode *pParent = pCsr->apNode[pCsr->iNode]; + + assert( pCsr->iNode>=0 ); + assert( pParent->pRight==0 ); + pParent->pRight = pNew; + + if( pParent->bBlack==0 ){ + hctTreeFixInsert(pCsr->pTree, pCsr, pNew); + sqlite3HctTreeCsrLast(pCsr); + }else{ + pCsr->apNode[++pCsr->iNode] = pNew; + } + } + + /* Root node is always black */ + pRoot->pNode->bBlack = 1; + assert( hct_tree_check(pRoot) ); + } + } + + return rc; +} + +#if 0 +static void debug_write_op( + HctTreeCsr *pCsr, + const char *zOp, + UnpackedRecord *pKey, + i64 iKey, + int nData, + const u8 *aData +){ + printf("%s(%d) ", zOp, (int)pCsr->pRoot->iRoot); + if( pKey ){ + char *z = sqlite3HctDbRecordToText(0, aData, nData); + printf("[%s]\n", z); + }else{ + printf("%lld\n", iKey); + } + fflush(stdout); +} +#else +# define debug_write_op(r,s,w,x,y,z) +#endif + +SQLITE_PRIVATE int sqlite3HctTreeInsert( + HctTreeCsr *pCsr, + UnpackedRecord *pKey, + i64 iKey, + int nData, + const u8 *aData, + int nZero +){ + assert( pKey==0 || iKey==0 ); + debug_write_op(pCsr, "INSERT", pKey, iKey, nData, aData); + return treeInsert(pCsr, pKey, iKey, 0, nData, aData, nZero); +} + +SQLITE_PRIVATE int sqlite3HctTreeDeleteKey( + HctTreeCsr *pCsr, + UnpackedRecord *pKey, + i64 iKey, + int nData, + const u8 *aData +){ + debug_write_op(pCsr, "DELETE", pKey, iKey, nData, aData); + return treeInsert(pCsr, pKey, iKey, 1, nData, aData, 0); +} + +/* +** Cursor pCsr currently points at a double-black node. Fix it. +*/ +static void hctTreeFixDelete(HctTreeCsr *pCsr){ + assert( pCsr->iNode>0 || pCsr->pRoot->pNode->bBlack ); + if( pCsr->iNode>0 ){ + HctTreeNode *pDB; /* The double-black */ + HctTreeNode *pP; /* Parent of pDB */ + HctTreeNode *pS; /* Sibling of pDB */ + + pDB = pCsr->apNode[pCsr->iNode]; + pP = pCsr->apNode[pCsr->iNode-1]; + pS = pP->pLeft==pDB ? pP->pRight : pP->pLeft; + + if( pS->bBlack ){ + HctTreeNode *pR = 0; + if( pS->pLeft && pS->pLeft->bBlack==0 ){ + pR = pS->pLeft; + }else if( pS->pRight && pS->pRight->bBlack==0 ){ + pR = pS->pRight; + } + + if( pR ){ + /* Sibling is black, pR is a red child */ + HctTreeNode **ppP = hctTreeFindPointer(pCsr, pCsr->iNode-1); + int iCase = ((pP->pRight==pS) ? 2 : 0) + (pS->pRight==pR ? 1 : 0); + switch( iCase ){ + case 0: /* Left/Left */ + pR->bBlack = 1; + pS->bBlack = pP->bBlack; + rightRotate(ppP); + pP->bBlack = 1; + break; + case 1: /* Left/Right */ + leftRotate(&pP->pLeft); + rightRotate(ppP); + pR->bBlack = pP->bBlack; + pP->bBlack = 1; + break; + case 2: /* Right/Left */ + rightRotate(&pP->pRight); + leftRotate(ppP); + pR->bBlack = pP->bBlack; + pP->bBlack = 1; + break; + case 3: /* Right/Right */ + pR->bBlack = 1; + pS->bBlack = pP->bBlack; + leftRotate(ppP); + pP->bBlack = 1; + break; + } + }else{ + /* Sibling is black, with no red children. */ + pS->bBlack = 0; + if( pP->bBlack ){ + pCsr->iNode--; + hctTreeFixDelete(pCsr); + }else{ + pP->bBlack = 1; + } + } + }else{ + HctTreeNode **ppP = hctTreeFindPointer(pCsr, pCsr->iNode-1); + + /* Sibling is red. Because it is the red sibling of a double-black, it + ** must have children on both sides. And because it is red, both those + ** children must be black. */ + assert( pS->pLeft->bBlack && pS->pRight->bBlack ); + + if( pS==pP->pLeft ){ + rightRotate(ppP); + }else{ + leftRotate(ppP); + } + pS->bBlack = 1; + pP->bBlack = 0; + pCsr->apNode[pCsr->iNode-1] = pS; + pCsr->apNode[pCsr->iNode] = pP; + pCsr->apNode[pCsr->iNode+1] = pDB; + pCsr->iNode++; + hctTreeFixDelete(pCsr); + } + } +} + +static int treeDelete(HctTreeCsr *pCsr, int bRollback){ + HctTreeNode *pDel = pCsr->apNode[pCsr->iNode]; + HctTreeNode *pU = 0; + HctTreeNode *pReseek = 0; + int rc; + + /* Save the positions of all cursors on this table */ + rc = hctSaveCursors(pCsr->pRoot, pCsr, 0, 0); + if( rc ) return rc; + + assert( pCsr->pReseek==0 ); + assert( pCsr->iNode>=0 ); +#if 0 + fprintf(stdout, "deleting %lld\n", iKey); + hct_print_subtree(pCsr->pRoot->pNode); +#endif + + if( bRollback==0 ){ + HctTreeNode *pEntry = hctMallocZero(sizeof(*pEntry)); + if( pEntry==0 ) return SQLITE_NOMEM; + pEntry->iKey = pDel->iKey; + pEntry->pClobber = pDel; + pEntry->pPrev = pCsr->pTree->pRollback; + pEntry->nRef = 1; + pEntry->iRoot = pCsr->pRoot->iRoot; + pDel->nRef++; + pCsr->pTree->pRollback = pEntry; + pReseek = pDel; + pReseek->nRef++; + } + + /* If node pDel has two children, swap it with its immediate successor + ** in the tree. This node is guaranteed to have pNode->pLeft==0. */ + if( pDel->pLeft && pDel->pRight ){ + int iDel = pCsr->iNode; + HctTreeNode *pSwap; + sqlite3HctTreeCsrNext(pCsr); + pSwap = pCsr->apNode[pCsr->iNode]; + SWAP(HctTreeNode*, pSwap->pLeft, pDel->pLeft); + SWAP(HctTreeNode*, pSwap->pRight, pDel->pRight); + SWAP(int, pSwap->bBlack, pDel->bBlack); + *hctTreeFindPointer(pCsr, iDel) = pSwap; + pCsr->apNode[iDel] = pSwap; + *hctTreeFindPointer(pCsr, pCsr->iNode) = pDel; + pCsr->apNode[pCsr->iNode] = pDel; + + assert( pDel->pLeft==0 ); + assert( hct_tree_check(pCsr->pRoot) ); + } + + assert( pCsr->apNode[pCsr->iNode]==pDel ); + assert( pDel->pLeft==0 || pDel->pRight==0 ); + + pU = pDel->pLeft ? pDel->pLeft : pDel->pRight; + *hctTreeFindPointer(pCsr, pCsr->iNode) = pU; + if( pDel->bBlack==0 || (pU && pU->bBlack==0) || pCsr->pRoot->pNode==0 ){ + /* Simple case. If either pDel or its child pU are red, then + ** replacing the pDel with the child and ensuring the child is + ** colored black is enough. No change in black-height for the + ** children of pU. */ + if( pU ) pU->bBlack = 1; + }else{ + pCsr->apNode[pCsr->iNode] = pU; + hctTreeFixDelete(pCsr); + } + + treeNodeUnref(pDel); + assert( pCsr->pReseek==0 ); + pCsr->pReseek = pReseek; + +#if 0 + fprintf(stdout, "finished deleting %lld\n", iKey); + hct_print_subtree(pCsr->pRoot->pNode); +#endif + assert( hct_tree_check(pCsr->pRoot) ); + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeDelete(HctTreeCsr *pCsr){ + int rc; + assert( pCsr->pReseek==0 ); + rc = treeDelete(pCsr, 0); + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTreeBegin(HctTree *pTree, int iStmt){ + if( iStmt>pTree->iStmt ){ + int ii; + if( pTree->nStmt<=iStmt ){ + int nNew = iStmt+16; + HctTreeNode **apNew = (HctTreeNode**)hctMallocZero(nNew*sizeof(*apNew)); + if( apNew==0 ) return SQLITE_NOMEM; + if( pTree->apStmt ){ + memcpy(apNew, pTree->apStmt, pTree->nStmt*sizeof(*apNew)); + sqlite3_free(pTree->apStmt); + } + pTree->apStmt = apNew; + pTree->nStmt = nNew; + } + for(ii=pTree->iStmt+1; ii<=iStmt; ii++){ + pTree->apStmt[ii] = pTree->pRollback; + } + pTree->iStmt = iStmt; + } + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeRelease(HctTree *pTree, int iStmt){ + if( iStmtiStmt ){ + if( iStmt==0 ){ + HctTreeNode *pStop = pTree->apStmt[iStmt+1]; + HctTreeNode *pNode; + HctTreeNode *pPrev; + for(pNode=pTree->pRollback; pNode!=pStop; pNode=pPrev){ + pPrev = pNode->pPrev; + if( pNode->pClobber ) treeNodeUnref(pNode->pClobber); + treeNodeUnref(pNode); + } + pTree->pRollback = pStop; + } + pTree->iStmt = iStmt; + } + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeRollbackTo(HctTree *pTree, int iStmt){ + int rc = SQLITE_OK; + if( iStmt<=pTree->iStmt ){ + HctTreeNode *pStop = pTree->apStmt[iStmt]; + HctTreeNode *pNode; + HctTreeNode *pPrev; + for(pNode=pTree->pRollback; pNode!=pStop; pNode=pPrev){ + KeyInfo *pKeyInfo = 0; + UnpackedRecord *pRec = 0; + HctTreeRoot *pRoot = hctTreeFindRoot(pTree, pNode->iRoot); + + pPrev = pNode->pPrev; + + if( (pKeyInfo = pRoot->pKeyInfo) ){ + pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRec==0 ){ + rc = SQLITE_NOMEM; + pStop = pNode; + break; + } + sqlite3VdbeRecordUnpack(pKeyInfo, pNode->nData, pNode->aData, pRec); + } + + if( pNode->pClobber ){ + HctTreeNode *pClobber = pNode->pClobber; + assert( pNode->iKey==pNode->pClobber->iKey ); + pClobber->pLeft = pClobber->pRight = 0; + pClobber->bBlack = 0; + if( (rc = hctSaveCursors(pRoot, 0, 0, 0)) + || (rc = treeInsertNode(pTree, 1, pRec, pNode->iKey, pClobber)) ){ + pStop = pNode; + break; + } + treeNodeUnref(pClobber); + }else{ + HctTreeCsr csr; + int res; + memset(&csr, 0, sizeof(csr)); + csr.pRoot = pRoot; + csr.pTree = pTree; + sqlite3HctTreeCsrSeek(&csr, pRec, pNode->iKey, &res); + if( res==0 ) treeDelete(&csr, 1); + } + if( pRec ) sqlite3DbFree(pKeyInfo->db, pRec); + treeNodeUnref(pNode); + } + pTree->pRollback = pStop; + pTree->iStmt = iStmt; + } + return rc; +} + +/* +** Clear the contents of the entire tree. +*/ +SQLITE_PRIVATE void sqlite3HctTreeClear(HctTree *pTree){ + HctTreeRoot **pp; + HctTreeRoot **pEnd = &pTree->apRootHash[pTree->nRootHash]; + for(pp=pTree->apRootHash; pppHashNext){ + hctSaveCursors(p, 0, 0, 0); + hctTreeFreeNode(p->pNode); + p->pNode = 0; + sqlite3KeyInfoUnref(p->pKeyInfo); + p->pKeyInfo = 0; + } + } +} + +SQLITE_PRIVATE int sqlite3HctTreeClearOne(HctTree *pTree, u32 iRoot, i64 *pnRow){ + HctTreeCsr csr; + int rc = SQLITE_OK; + int nRow = 0; + + memset(&csr, 0, sizeof(csr)); + csr.pTree = pTree; + csr.pRoot = hctTreeFindRoot(pTree, iRoot); + csr.iNode = -1; + rc = hctSaveCursors(csr.pRoot, 0, 0, 0); + if( rc ) return rc; + while( rc==SQLITE_OK && csr.pRoot->pNode ){ + sqlite3HctTreeCsrFirst(&csr); + rc = sqlite3HctTreeDelete(&csr); + nRow++; + hctRestoreDiscard(&csr); + } + if( pnRow ) *pnRow = nRow; + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrOpen(HctTree *pTree, u32 iRoot, HctTreeCsr **ppCsr){ + int rc = SQLITE_OK; + HctTreeCsr *pNew = 0; + HctTreeRoot *pRoot = hctTreeFindRoot(pTree, iRoot); + if( pRoot==0 ){ + rc = SQLITE_NOMEM; + }else{ + if( pRoot->pCsrCache ){ + pNew = pRoot->pCsrCache; + pRoot->pCsrCache = pNew->pCsrNext; + pNew->pCsrNext = 0; + assert( pNew->pTree==pTree ); + assert( pNew->pRoot==pRoot ); + assert( pNew->iNode==-1 ); + assert( pNew->eIncrblob==TREE_INCRBLOB_NONE ); + }else{ + pNew = (HctTreeCsr*)hctMallocZero(sizeof(HctTreeCsr)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pNew->pTree = pTree; + pNew->pRoot = pRoot; + pNew->iNode = -1; + } + } + pNew->pCsrNext = pRoot->pCsrList; + pRoot->pCsrList = pNew; + } + *ppCsr = pNew; + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrClose(HctTreeCsr *pCsr){ + if( pCsr ){ + HctTreeCsr **pp; + for(pp=&pCsr->pRoot->pCsrList; *pp!=pCsr; pp=&(*pp)->pCsrNext); + *pp = pCsr->pCsrNext; + if( pCsr->pReseek ){ + treeNodeUnref(pCsr->pReseek); + pCsr->pReseek = 0; + } + pCsr->pCsrNext = pCsr->pRoot->pCsrCache; + pCsr->pRoot->pCsrCache = pCsr; + pCsr->iSkip = 0; + pCsr->bPin = 0; + pCsr->iNode = -1; + pCsr->eIncrblob = TREE_INCRBLOB_NONE; + } + return SQLITE_OK; +} + +/* +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than intKey/pIdxKey. Or, the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches intKey/pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than intKey/pIdxKey. +*/ +SQLITE_PRIVATE int sqlite3HctTreeCsrSeek( + HctTreeCsr *pCsr, + UnpackedRecord *pRec, + i64 iKey, + int *pRes +){ + hctRestoreDiscard(pCsr); + pCsr->iSeekRowid = iKey; + if( pRec ){ + return hctTreeCsrSeekUnpacked(pCsr, pRec, pRes); + } + return hctTreeCsrSeekInt(pCsr, iKey, pRes); +} + +/* +** Move the cursor to EOF. +*/ +SQLITE_PRIVATE void sqlite3HctTreeCsrClear(HctTreeCsr *pCsr){ + hctRestoreDiscard(pCsr); + pCsr->iNode = -1; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrNext(HctTreeCsr *pCsr){ + int iNode; + int res = 0; + + assert( pCsr->pReseek==0 || pCsr->iSkip==0 ); + if( pCsr->iSkip>0 ){ + pCsr->iSkip = 0; + return SQLITE_OK; + } + if( hctRestoreCursor(pCsr, &res) ) return SQLITE_NOMEM; + if( res>0 ) return SQLITE_OK; + + iNode = pCsr->iNode; + if( iNode>=0 ){ + HctTreeNode *pNode = pCsr->apNode[iNode]; + assert( iNode>=0 ); + if( pNode->pRight ){ + pNode = pNode->pRight; + while( pNode ){ + iNode++; + pCsr->apNode[iNode] = pNode; + pNode = pNode->pLeft; + } + }else{ + while( (--iNode)>=0 ){ + HctTreeNode *pParent = pCsr->apNode[iNode]; + assert( pNode==pParent->pLeft || pNode==pParent->pRight ); + if( pNode==pParent->pLeft ) break; + pNode = pParent; + } + } + pCsr->iNode = iNode; + } + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrPrev(HctTreeCsr *pCsr){ + int iNode; + int res = 0; + + assert( pCsr->pReseek==0 || pCsr->iSkip==0 ); + if( pCsr->iSkip<0 ){ + pCsr->iSkip = 0; + return SQLITE_OK; + } + if( hctRestoreCursor(pCsr, &res) ) return SQLITE_NOMEM; + if( res<0 ) return SQLITE_OK; + + iNode = pCsr->iNode; + if( iNode>=0 ){ + HctTreeNode *pNode = pCsr->apNode[iNode]; + assert( iNode>=0 ); + if( pNode->pLeft ){ + pNode = pNode->pLeft; + while( pNode ){ + iNode++; + pCsr->apNode[iNode] = pNode; + pNode = pNode->pRight; + } + }else{ + while( (--iNode)>=0 ){ + HctTreeNode *pParent = pCsr->apNode[iNode]; + assert( pNode==pParent->pLeft || pNode==pParent->pRight ); + if( pNode==pParent->pRight ) break; + pNode = pParent; + } + } + pCsr->iNode = iNode; + } + return SQLITE_OK; +} + +/* +** Return false if cursor points to a valid entry, or true otherwise. +*/ +SQLITE_PRIVATE int sqlite3HctTreeCsrEof(HctTreeCsr *pCsr){ + return (pCsr->iNode<0); +} + +static void hctTreeCursorEnd(HctTreeCsr *pCsr, int bLast){ + int iNode = -1; + HctTreeNode *pNode = pCsr->pRoot->pNode; + + hctRestoreDiscard(pCsr); + while( pNode ){ + iNode++; + assert( iNodeapNode[iNode] = pNode; + pNode = (bLast ? pNode->pRight : pNode->pLeft); + } + pCsr->iNode = iNode; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrFirst(HctTreeCsr *pCsr){ + hctTreeCursorEnd(pCsr, 0); + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrLast(HctTreeCsr *pCsr){ + hctTreeCursorEnd(pCsr, 1); + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrKey(HctTreeCsr *pCsr, i64 *piKey){ + assert( pCsr->iNode>=0 ); + assert( pCsr->pReseek==0 ); + *piKey = pCsr->apNode[pCsr->iNode]->iKey; + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrData(HctTreeCsr *pCsr, int *pnData, const u8 **paData){ + HctTreeNode *pNode = pCsr->apNode[pCsr->iNode]; + assert( pCsr->pReseek==0 ); + assert( pCsr->iNode>=0 ); + *pnData = pNode->nData; + if( paData ) *paData = pNode->aData; + return SQLITE_OK; +} + +/* +** Return non-zero if the cursor is pointing to a delete key. Return zero +** if it is pointing to an insert or to EOF. +*/ +SQLITE_PRIVATE int sqlite3HctTreeCsrIsDelete(HctTreeCsr *pCsr){ + assert( pCsr->pReseek==0 ); + return (pCsr->iNode>=0 && pCsr->apNode[pCsr->iNode]->bDelete); +} + +SQLITE_PRIVATE void sqlite3HctTreeCsrPin(HctTreeCsr *pCsr){ + pCsr->bPin = 1; +} +SQLITE_PRIVATE void sqlite3HctTreeCsrUnpin(HctTreeCsr *pCsr){ + pCsr->bPin = 0; +} + +SQLITE_PRIVATE void sqlite3HctTreeCsrIncrblob(HctTreeCsr *pCsr){ + if( pCsr->eIncrblob==TREE_INCRBLOB_NONE ){ + pCsr->eIncrblob = TREE_INCRBLOB_READY; + } +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrHasMoved(HctTreeCsr *pCsr){ + return pCsr && pCsr->pReseek!=0; +} + +SQLITE_PRIVATE int sqlite3HctTreeCsrReseek(HctTreeCsr *pCsr, int *pRes){ + assert( + pCsr->eIncrblob==TREE_INCRBLOB_READY + || pCsr->eIncrblob==TREE_INCRBLOB_ABORT + ); + assert( pCsr->pReseek ); + if( pCsr->eIncrblob==TREE_INCRBLOB_ABORT ) return SQLITE_ABORT; + return sqlite3HctTreeCsrSeek(pCsr, 0, pCsr->iSeekRowid, pRes); +} + + +SQLITE_PRIVATE int sqlite3HctTreeCsrRestore(HctTreeCsr *pCsr, int *pIsDifferent){ + int rc = SQLITE_OK; + if( pCsr->pReseek ){ + assert( pCsr->iSkip==0 ); + rc = hctRestoreCursor(pCsr, &pCsr->iSkip); + } + *pIsDifferent = pCsr->iSkip; + return rc; +} + +SQLITE_PRIVATE u32 sqlite3HctTreeCsrRoot(HctTreeCsr *pCsr){ + return pCsr->pRoot->iRoot; +} + +SQLITE_PRIVATE int sqlite3HctTreeForeach( + HctTree *pTree, + int bSchemaOp, + void *pCtx, + int (*x)(void *, u32, KeyInfo*) +){ + int i; + int rc = SQLITE_OK; + for(i=0; rc==SQLITE_OK && inRootHash; i++){ + HctTreeRoot *p; + for(p=pTree->apRootHash[i]; rc==SQLITE_OK && p; p=p->pHashNext){ + if( p->pNode && (bSchemaOp || p->iRoot!=HCT_TREE_SCHEMAOP_ROOT) ){ + rc = x(pCtx, p->iRoot, p->pKeyInfo); + } + } + } + return rc; +} + + + +/************** End of hct_tree.c ********************************************/ +/************** Begin file hct_file.c ****************************************/ +/* +** 2020 October 13 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + + +/* #include "hctInt.h" */ +/* #include */ +/* #include */ +/* #include */ + +/* #include */ +/* #include */ +#include +/* #include */ +/* #include */ + +/* #include */ + +#define HCT_DEFAULT_PAGESIZE 4096 + +/* +** The database file is extended and managed in chunks of +** HCT_DEFAULT_PAGEPERCHUNK pages. Since pages are normally 4096 bytes, this +** is 2MiB by default. But, if the file is mmap()ed 2MiB at a time, we +** quickly read the system limit for number of mappings (on Linux, this is +** kernel parameter vm.max_map_count - 65530 by default). So, each mapping +** is made for HCT_MMAP_QUANTA times this amount. Since we need mappings for +** both the database file and page-map, this means we can mmap() a database of: +** +** 32765 * 1024*512*4096 bytes +** +** or around 64TiB. +*/ +#define HCT_DEFAULT_PAGEPERCHUNK 512 +#define HCT_MMAP_QUANTA 1024 + +#define HCT_HEADER_PAGESIZE 4096 + +#define HCT_LOCK_OFFSET (1024*1024) +#define HCT_LOCK_SIZE 1 + + +/* +** Pagemap slots used for special purposes. +*/ +#define HCT_ROOTPAGE_SCHEMA 1 +#define HCT_ROOTPAGE_META 2 + +#define HCT_PAGEMAP_LOGICAL_EOF 3 +#define HCT_PAGEMAP_PHYSICAL_EOF 4 + +#define HCT_PAGEMAP_TRANSID_EOF 16 + +#define HCT_PMF_LOGICAL_EVICTED (((u64)0x00000001)<<56) +#define HCT_PMF_LOGICAL_IRREVICTED (((u64)0x00000002)<<56) +#define HCT_PMF_PHYSICAL_IN_USE (((u64)0x00000004)<<56) +#define HCT_PMF_LOGICAL_IN_USE (((u64)0x00000008)<<56) +#define HCT_PMF_LOGICAL_IS_ROOT (((u64)0x00000010)<<56) + +#define HCT_FIRST_LOGICAL 33 + +/* +** Masks for use with pagemap values. +*/ +#define HCT_PAGEMAP_FMASK (((u64)0xFF) << 56) /* Flags MASK */ +#define HCT_PAGEMAP_VMASK (~HCT_PAGEMAP_FMASK) /* Value MASK */ + +#define assert_pgno_ok(iPg) assert( ((u64)iPg)<((u64)1<<48) && iPg>0 ) + +typedef struct HctFileServer HctFileServer; +typedef struct HctMapping HctMapping; +typedef struct HctMappingChunk HctMappingChunk; + +/* +** Global variables for this module. +** +** pServerList: +** Linked list of distinct files opened by this process. Access to this +** variable is protected by SQLITE_MUTEX_STATIC_VFS1. +** +** nCASFailCnt/nCASFailReset: +** These are used to inject CAS instruction failures for testing purposes. +** Set by the sqlite3_hct_cas_failure() API. They are not threadsafe. +** +** nProcFailCnt +** These are used to inject process failures (i.e. abort() calls) for +** testing purposes. Set by the sqlite3_hct_proc_failure() API. Not +** threadsafe. +*/ +static struct HctFileGlobalVars { + HctFileServer *pServerList; + + int nCASFailCnt; + int nCASFailReset; + + int nProcFailCnt; +} g; + +SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset){ + g.nCASFailCnt = nCASFailCnt; + g.nCASFailReset = nCASFailReset; +} +SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt){ + g.nProcFailCnt = nProcFailCnt; +} + +/* +** This is called to check if a CAS fault should be injected. It returns +** true if a fault should be injected, or false otherwise. +*/ +static int inject_cas_failure(void){ + if( g.nCASFailCnt>0 ){ + if( (--g.nCASFailCnt)==0 ){ + g.nCASFailCnt = g.nCASFailReset; + return 1; + } + } + if( g.nProcFailCnt>0 ){ + if( (--g.nProcFailCnt)==0 ){ + abort(); + } + } + return 0; +} + +/* +** nRef: +** Number of references to this object held by the system. The +** HctFileServer object may hold one reference, each HctFile may +** also hold one. +** +** iLogPPC: +** Log2 of number of pages-per-chunk. e.g. if there are 512 pages +** on each mapping chunk, this value is set to 9. +** +** aPagemap/nPagemap: +** Mapping of the current page-map file. +*/ +struct HctMappingChunk { + void *pData; /* Mapping of chunk in data file */ + u64 *aMap; /* Mapping of chunk in map file */ +}; +struct HctMapping { + int nRef; /* Number of pointers to this array */ + int szPage; /* Size of pages in bytes */ + int nChunk; /* Size of aChunk[] array */ + u32 mapShift; + u32 mapMask; + HctMappingChunk *aChunk; /* Array of database chunk mappings */ +}; + +/* +** eInitState: +** Set to one of the HCT_INIT_XXX constants defined below. See comments +** above those constants for details. +** +** iNextFileId: +** Used to allocate unique ids to each HctFile associated with this +** HctFileServer object. These ids are used for debugging, and also +** to generate log file names. +*/ +struct HctFileServer { + sqlite3_mutex *pMutex; /* Mutex to protect this object */ + HctFile *pFileList; + + u64 iCommitId; /* CID value */ + u64 nWriteCount; /* Write count */ + + int iNextFileId; + char *zPath; /* Path to database (aFdDb[0]) */ + char *zDir; /* Directory component of zPath */ + int fdMap; /* Read/write file descriptor for page-map */ + int nFdDb; /* Number of valid entries in aFdDb[] */ + int aFdDb[HCT_MAX_NDBFILE]; + + int szPage; /* Page size for database */ + int nPagePerChunk; + HctMapping *pMapping; /* Mapping of pagemap and db pages */ + + int bReadOnlyMap; /* True for a read-only mapping of db file */ + + HctTMapServer *pTMapServer; /* Transaction map server */ + HctPManServer *pPManServer; /* Page manager server */ + int eInitState; + + void *pJrnlPtr; + void(*xJrnlDel)(void*); + + i64 st_dev; /* File identification 1 */ + i64 st_ino; /* File identification 2 */ + HctFileServer *pServerNext; /* Next object in g.pServerList list */ +}; + +/* +** System initialization state: +** +** HCT_INIT_NONE: +** No initialization has been done. +** +** HCT_INIT_RECOVER1: +** The sqlite_schema table (root page 1) has been recovered. And the +** page-map scanned to initialize the page-manager. +** +** HCT_INIT_RECOVER2: +** Other tables (apart from sqlite_schema) have been recovered. +** Initialization has finished. +*/ +#define HCT_INIT_NONE 0 +#define HCT_INIT_RECOVER1 1 +#define HCT_INIT_RECOVER2 2 + +/* +** Event counters used by the hctstats virtual table. +*/ +typedef struct HctFileStats HctFileStats; +struct HctFileStats { + i64 nCasAttempt; + i64 nCasFail; + i64 nIncrAttempt; + i64 nIncrFail; + i64 nMutex; + i64 nMutexBlock; +}; + +/* +** iCurrentTid: +** Most recent value returned by sqlite3HctFileAllocateTransid(). This +** is the current TID while the upper layer is writing the database, and +** meaningless at other times. Used by this object as the "current TID" +** when freeing a page. +** +** nPageAlloc: +** The total number of physical page allocations requested by the upper +** layer in the lifetime of this object. +*/ +struct HctFile { + HctConfig *pConfig; /* Connection configuration object */ + HctFileServer *pServer; /* Connection to global db object */ + HctFile *pFileNext; /* Next handle opened on same file */ + int iFileId; /* Id used for debugging output */ + int eInitState; + + HctTMapClient *pTMapClient; /* Transaction map client object */ + HctPManClient *pPManClient; /* Transaction map client object */ + + u64 iCurrentTid; + u64 nPageAlloc; + + /* Copies of HctFileServer variables */ + int szPage; + HctMapping *pMapping; + + /* Event counters used by the hctstats virtual table */ + HctFileStats stats; +}; + +static int hctLog2(int n){ + int i; + assert( (n & (n-1))==0 ); + for(i=0; (1<0 ){ + if( (--g.nCASFailCnt)==0 ){ + g.nCASFailCnt = g.nCASFailReset; + return 0; + } + } +#endif + return HctCASBool(pPtr, iOld, iNew); +} + +/* +** Allocate and return a new HctMapping object with enough space for +** nChunk chunks. +*/ +static HctMapping *hctMappingNew(int *pRc, HctMapping *pOld, int nChunk){ + HctMapping *pNew = 0; + if( *pRc==SQLITE_OK ){ + int nByte = sizeof(HctMapping) + nChunk*sizeof(HctMappingChunk); + pNew = (HctMapping*)sqlite3MallocZero(nByte); + if( pNew ){ + pNew->aChunk = (HctMappingChunk*)&pNew[1]; + pNew->nRef = 1; + pNew->nChunk = nChunk; + if( pOld ){ + assert( nChunk>pOld->nChunk ); + pNew->mapShift = pOld->mapShift; + pNew->mapMask = pOld->mapMask; + pNew->szPage = pOld->szPage; + memcpy(pNew->aChunk,pOld->aChunk,pOld->nChunk*sizeof(HctMappingChunk)); + } + }else{ + *pRc = SQLITE_NOMEM_BKPT; + } + } + return pNew; +} + +static void hctMappingUnref(HctMapping *p){ + if( p ){ + p->nRef--; + if( p->nRef==0 ){ + sqlite3_free(p); + } + } +} + + +static u64 *hctPagemapPtr(HctMapping *p, u32 iSlot){ + return &(p->aChunk[(iSlot-1) >> p->mapShift].aMap[(iSlot-1) & p->mapMask]); +} + +static void *hctPagePtr(HctMapping *p, u32 iPhys){ + return &((u8*)(p->aChunk[(iPhys-1) >> p->mapShift].pData))[ + ((iPhys-1) & p->mapMask) * p->szPage + ]; +} + +/* +** Buffer aBuf[] is p->szPage bytes in size. This function writes the +** contents of said buffer to physical database page iPhys. +*/ +static int hctPageWriteToDisk(HctFileServer *p, u64 iPhys, u8 *aBuf){ + i64 iChunk = ((iPhys-1) / p->nPagePerChunk); + int iFd = iChunk % p->nFdDb; + i64 iOff = p->szPage * ( + ((iChunk / p->nFdDb) * p->nPagePerChunk) + + (iPhys-1) % p->nPagePerChunk + ); + ssize_t res; + assert_pgno_ok( iPhys ); + res = pwrite(p->aFdDb[iFd], aBuf, p->szPage, iOff); + return (res==p->szPage ? SQLITE_OK : SQLITE_ERROR); +} + +static void hctFilePagemapSetDirect(HctMapping *p, u32 iSlot, u64 iNew){ + u64 *pPtr = hctPagemapPtr(p, iSlot); + *pPtr = iNew; +} + +static void hctFilePagemapSetFlag(HctMapping *p, u32 iSlot, u64 mask){ + u64 *pPtr = hctPagemapPtr(p, iSlot); + *pPtr = *pPtr | mask; +} + +/* +** Use a CAS instruction to the value of page-map slot iSlot. Return true +** if the slot is successfully set to value iNew, or false otherwise. +*/ +static int hctFilePagemapSet(HctFile *pFile, u32 iSlot, u64 iOld, u64 iNew){ + u64 *pPtr = hctPagemapPtr(pFile->pMapping, iSlot); + pFile->stats.nCasAttempt++; + if( hctBoolCompareAndSwap64(pPtr, iOld, iNew) ) return 1; + pFile->stats.nCasFail++; + return 0; +} + + +static u64 hctFilePagemapGet(HctMapping *p, u32 iSlot){ + return HctAtomicLoad( hctPagemapPtr(p, iSlot) ); +} + +static u64 hctFilePagemapGetSafe(HctMapping *p, u32 iSlot){ + if( ((iSlot-1)>>p->mapShift)>=p->nChunk ){ + return 0; + } + return hctFilePagemapGet(p, iSlot); +} + +static u64 hctFileAtomicIncr(HctFile *pFile, u64 *pPtr, int nIncr){ + u64 iOld; + while( 1 ){ + iOld = HctAtomicLoad(pPtr); + pFile->stats.nIncrAttempt++; + if( hctBoolCompareAndSwap64(pPtr, iOld, iOld+nIncr) ) return iOld+nIncr; + pFile->stats.nIncrFail++; + } +} + +/* +** Increment the value in slot iSlot by nIncr. Return the new value. +*/ +static u64 hctFilePagemapIncr(HctFile *pFile, u32 iSlot, int nIncr){ + u64 *pPtr = hctPagemapPtr(pFile->pMapping, iSlot); + u64 iOld; + while( 1 ){ + iOld = HctAtomicLoad(pPtr); + pFile->stats.nIncrAttempt++; + if( hctBoolCompareAndSwap64(pPtr, iOld, iOld+nIncr) ) return iOld+nIncr; + pFile->stats.nIncrFail++; + } +} + +/* +** Set the physical page id mapped from logical page iLogical to physical +** page id iNew. Return 1 if successful, or 0 if the operation fails. The +** operation fails if either: +** +** * the LOGICAL_EVICTED flag is already set for the logical page, or +** * the current physical page id to which the logical page is mapped +** is not equal to parameter iOld. +*/ +static int hctFilePagemapSetLogical( + HctFile *pFile, /* Use mapping object of this file */ + u32 iLogical, /* Logical page to set the physical id for */ + u64 iOld, /* Old physical page id */ + u64 iNew /* New physical page id */ +){ + HctMapping *p = pFile->pMapping; + while( 1 ){ + u64 i1 = hctFilePagemapGet(p, iLogical); + u64 iOld1 = (iOld & HCT_PAGEMAP_VMASK) | (i1 & HCT_PAGEMAP_FMASK); + u64 iNew1 = (iNew & HCT_PAGEMAP_VMASK) | (i1 & HCT_PAGEMAP_FMASK); + + iNew1 |= HCT_PMF_LOGICAL_IN_USE; + + /* If a CAS instruction failure injection is scheduled, return 0 + ** to the caller. */ + if( inject_cas_failure() ) return 0; + + /* This operation fails if LOGICAL_EVICTED has been set. */ + iOld1 &= ~HCT_PMF_LOGICAL_EVICTED; + iNew1 &= ~HCT_PMF_LOGICAL_EVICTED; + + if( hctFilePagemapSet(pFile, iLogical, iOld1, iNew1) ){ + return 1; + } + if( i1!=iOld1 ) return 0; + } + + assert( !"unreachable" ); + return 0; +} + +/* +** Set the EVICTED or IRREVICTED flag on page iLogical. +*/ +static int hctFileSetEvicted( + HctFile *pFile, + u32 iLogical, + u32 iOldPg, + int bIrrevocable +){ + u64 *pPtr = hctPagemapPtr(pFile->pMapping, iLogical); + while( 1 ){ + u64 iOld = HctAtomicLoad(pPtr); + u64 iNew = iOld | ( + bIrrevocable ? HCT_PMF_LOGICAL_IRREVICTED : HCT_PMF_LOGICAL_EVICTED + ); + + /* Fail if either the current physical page mapped to logical page iLogical + ** is not iOldPg, or if the LOGICAL_EVICTED flag has already been set. */ + if( (iOld & HCT_PAGEMAP_VMASK)!=iOldPg + || ((iOld & HCT_PMF_LOGICAL_EVICTED) && !bIrrevocable) + || ((iOld & HCT_PMF_LOGICAL_EVICTED)==0 && bIrrevocable) + || ((iOld & HCT_PMF_LOGICAL_IN_USE)==0) + ){ + return 0; + } + if( inject_cas_failure() ) return 0; + + pFile->stats.nCasAttempt++; + if( hctBoolCAS64(pPtr, iOld, iNew) ) return 1; + pFile->stats.nCasFail++; + } + + assert( !"unreachable" ); + return 0; +} + +/* +** Clear the LOGICAL_EVICTED flag from page-map entry iLogical. This will +** fail if the LOGICAL_IRREVICTED flag is already set. Return 1 if the +** flag is successfully cleared, or 0 otherwise. +*/ +static int hctFileClearEvicted(HctFile *pFile, u32 iLogical){ + u64 *pPtr = hctPagemapPtr(pFile->pMapping, iLogical); + while( 1 ){ + u64 iOld = HctAtomicLoad(pPtr); + u64 iNew = iOld & ~HCT_PMF_LOGICAL_EVICTED; + + if( (iOld & HCT_PMF_LOGICAL_IRREVICTED) ) return 0; + if( inject_cas_failure() ) return 0; + + pFile->stats.nCasAttempt++; + if( hctBoolCAS64(pPtr, iOld, iNew) ) return 1; + pFile->stats.nCasFail++; + } + + assert( !"unreachable" ); + return 0; +} + +static void hctFilePagemapZeroValue(HctFile *pFile, u32 iSlot){ + while( 1 ){ + u64 i1 = hctFilePagemapGet(pFile->pMapping, iSlot); + u64 i2 = (i1 & HCT_PMF_PHYSICAL_IN_USE); + if( hctFilePagemapSet(pFile, iSlot, i1, i2) ) return; + } +} + +static int hctFileOpen(int *pRc, const char *zFile, const char *zPost){ + int fd = 0; + if( *pRc==SQLITE_OK ){ + char *zPath = sqlite3_mprintf("%s%s", zFile, zPost); + if( zPath==0 ){ + *pRc = SQLITE_NOMEM_BKPT; + }else{ + fd = open(zPath, O_CREAT|O_RDWR, 0644); + if( fd<0 ){ + *pRc = SQLITE_CANTOPEN_BKPT; + } + sqlite3_free(zPath); + } + } + return fd; +} + +/* +** Take an exclusive POSIX lock on the file-descriptor passed as the +** second argument. +*/ +static void hctFileLock(int *pRc, int fd, const char *zFile){ + if( *pRc==SQLITE_OK ){ + int res; + struct flock l; + memset(&l, 0, sizeof(l)); + l.l_type = F_WRLCK; + l.l_whence = SEEK_SET; + l.l_start = HCT_LOCK_OFFSET; + l.l_len = HCT_LOCK_SIZE; + res = fcntl(fd, F_SETLK, &l); + if( res!=0 ){ + fcntl(fd, F_GETLK, &l); + sqlite3_log(SQLITE_BUSY, "hct file \"%s\" locked by process %lld", + zFile, (i64)l.l_pid + ); + *pRc = SQLITE_BUSY; + } + } +} + +/* +** Argument fd is an open file-handle. Return the size of the file in bytes. +** +** This function is a no-op (returns 0) if *pRc is other than SQLITE_OK +** when it is called. If an error occurs, *pRc is set to an SQLite error +** code before returning. +*/ +static i64 hctFileSize(int *pRc, int fd){ + i64 szRet = 0; + if( *pRc==SQLITE_OK ){ + struct stat sStat; + if( fstat(fd, &sStat) ){ + *pRc = sqlite3HctIoerr(SQLITE_IOERR_FSTAT); + }else{ + szRet = (i64)(sStat.st_size); + } + } + return szRet; +} + +static int hctFileTruncate(int *pRc, int fd, i64 sz){ + if( *pRc==SQLITE_OK ){ + int res = ftruncate(fd, (off_t)sz); + if( res ){ + *pRc = sqlite3HctIoerr(SQLITE_IOERR_TRUNCATE); + } + } + return *pRc; +} + +static void hctFileUnlink(int *pRc, const char *zFile){ + if( *pRc==SQLITE_OK ) unlink(zFile); +} + + +/* +** This function is a no-op if (*pRc) is set to other than SQLITE_OK +** when it is called. +** +** Otherwise, argument fd is assumed to be an open file-descriptor. This +** function attempts to map and return a pointer to a region nByte bytes in +** size at offset iOff of the open file. The mapping is read-only if parameter +** bRO is non-zero, or read/write if it is zero. +** +** If an error occurs, NULL is returned and (*pRc) set to an SQLite error +** code. +*/ +static void *hctFileMmap(int *pRc, int fd, i64 nByte, i64 iOff, int bRO){ + void *pRet = 0; + if( *pRc==SQLITE_OK ){ + const int flags = PROT_READ | (bRO ? 0 : PROT_WRITE); + pRet = mmap(0, nByte, flags, MAP_SHARED, fd, iOff); + if( pRet==MAP_FAILED ){ + pRet = 0; + *pRc = sqlite3HctIoerr(SQLITE_IOERR_MMAP); + } + } + return pRet; +} + +static void hctFileMunmap(void *pMap, i64 nByte){ + if( pMap ) munmap(pMap, nByte); +} + +static char *hctStrdup(int *pRc, const char *zIn){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + zRet = sqlite3_mprintf("%s", zIn); + if( zRet==0 ) *pRc = SQLITE_NOMEM_BKPT; + } + return zRet; +} + + +/* +** Given local path zFile, return the associated canonical path in a buffer +** obtained from sqlite3_malloc(). It is the responsibility of the caller +** to eventually free this buffer using sqlite3_free(). +*/ +static char *fileGetFullPath(int *pRc, const char *zFile){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + char *zFree = realpath(zFile, 0); + if( zFree==0 ){ + *pRc = SQLITE_CANTOPEN_BKPT; + }else{ + zRet = hctStrdup(pRc, zFree); + free(zFree); + } + } + return zRet; +} + +static int hctFileFindLogs( + HctFileServer *pServer, + void *pCtx, + int (*xLog)(void*, const char*) +){ + DIR *d; + const char *zName = &pServer->zPath[strlen(pServer->zDir)]; + int nName = strlen(zName); + int rc = SQLITE_OK; + + d = opendir(pServer->zDir); + if (d) { + struct dirent *dir; + while( rc==SQLITE_OK && (dir = readdir(d))!=NULL ){ + const char *zFile = (const char*)dir->d_name; + int nFile = strlen(zFile); + if( nFile>(nName+5) + && memcmp(zFile, zName, nName)==0 + && memcmp(&zFile[nName], "-log-", 5)==0 + ){ + char *zFull = sqlite3_mprintf("%s/%s", pServer->zDir, zFile); + rc = xLog(pCtx, zFull); + sqlite3_free(zFull); + } + } + closedir(d); + } + + return rc; +} + +static int hctFileServerInitUnlinkLog(void *pDummy, const char *zFile){ + int rc = SQLITE_OK; + hctFileUnlink(&rc, zFile); + return rc; +} + +static void hctFileReadHdr( + int *pRc, + void *pHdr, + int *pszPage, + int *pnDbFile +){ + *pszPage = 0; + if( *pRc==SQLITE_OK ){ + /* 12345678901234567890123456789012 */ + int szPage = 0; + int nDbFile = 0; + char *zHdr = "Hctree database version 00000001"; + u8 aEmpty[32] = {0}; + + assert( strlen(zHdr)==32 ); + if( memcmp(zHdr, pHdr, 32)==0 ){ + memcpy(&szPage, &((u8*)pHdr)[32], sizeof(int)); + if( szPage<512 || szPage>32768 || (szPage & (szPage-1))!=0 ){ + *pRc = SQLITE_CANTOPEN_BKPT; + return; + } + + memcpy(&nDbFile, &((u8*)pHdr)[36], sizeof(int)); + if( nDbFile<1 || nDbFile>HCT_MAX_NDBFILE ){ + *pRc = SQLITE_CANTOPEN_BKPT; + return; + } + }else if( memcmp(aEmpty, pHdr, 32)==0 ){ + /* no-op */ + }else{ + *pRc = SQLITE_CANTOPEN_BKPT; + } + + *pszPage = szPage; + *pnDbFile = nDbFile; + } +} + +static void *hctFileMmapDbChunk( + int *pRc, + HctFileServer *p, + HctMapping *pMap, + int iChunk +){ + void *pRet = 0; + i64 szChunk = p->nPagePerChunk * p->szPage; + int iFd = iChunk % p->nFdDb; + int iChunkOfFile = (iChunk / p->nFdDb); + + if( (iChunkOfFile % HCT_MMAP_QUANTA)==0 ){ + i64 iOff = szChunk * iChunkOfFile; + pRet = hctFileMmap( + pRc, p->aFdDb[iFd], szChunk*HCT_MMAP_QUANTA, iOff, p->bReadOnlyMap + ); + }else{ + pRet = (void*)(((u8*)pMap->aChunk[iChunk - p->nFdDb].pData) + szChunk); + } + + return pRet; +} + +static void *hctFileMmapPagemapChunk( + int *pRc, + HctFileServer *p, + HctMapping *pMap, + int iChunk +){ + void *pRet = 0; + i64 szChunk = p->nPagePerChunk * sizeof(u64); + + if( (iChunk % HCT_MMAP_QUANTA)==0 ){ + pRet = hctFileMmap( + pRc, p->fdMap, szChunk*HCT_MMAP_QUANTA, (szChunk*iChunk), 0 + ); + }else{ + pRet = (void*)(((u8*)(pMap->aChunk[iChunk-1].aMap)) + szChunk); + } + + return pRet; +} + +static void hctFileOpenDataFiles( + int *pRc, + HctFileServer *p, + int nDbFile +){ + int ii; + int rc = *pRc; + assert( p->nFdDb==1 ); + for(ii=1; iiaFdDb[ii] = hctFileOpen(&rc, p->zPath, z); + sqlite3_free(z); + if( rc==SQLITE_OK ) p->nFdDb = ii+1; + } + + if( rc!=SQLITE_OK ){ + for(ii=1; iinFdDb; ii++){ + close(p->aFdDb[ii]); + } + p->nFdDb = 1; + } + *pRc = rc; +} + +static i64 round_up(i64 iVal, i64 nQuanta){ + return ((iVal + nQuanta - 1) / nQuanta) * nQuanta; +} + +static void hctFileAllocateMapping( + int *pRc, + HctFileServer *p, + int nChunk +){ + i64 szChunkPagemap = p->nPagePerChunk * sizeof(u64); + i64 szChunkData = p->nPagePerChunk * p->szPage; + int rc = *pRc; + HctMapping *pMapping = 0; + int iFd = 0; + int i = 0; + + p->pMapping = pMapping = hctMappingNew(&rc, 0, nChunk); + if( rc==SQLITE_OK ){ + pMapping->mapShift = hctLog2(p->nPagePerChunk); + pMapping->mapMask = (1<mapShift)-1; + pMapping->szPage = p->szPage; + } + + /* Map all chunks of the pagemap file using a single call to mmap() */ + { + int nAll = round_up(nChunk, HCT_MMAP_QUANTA); + u8 *pMap = (u8*)hctFileMmap(&rc, p->fdMap, nAll*szChunkPagemap,0,0); + for(i=0; rc==SQLITE_OK && iaChunk[i].aMap = (u64*)&pMap[i * szChunkPagemap]; + } + } + + /* Map all chunks of the data files. One call to mmap() for each file. */ + for(iFd=0; iFdnFdDb && rc==SQLITE_OK; iFd++){ + int nFileChunk = (nChunk / p->nFdDb) + (iFd < (nChunk % p->nFdDb)); + i64 n = round_up(nFileChunk, HCT_MMAP_QUANTA) * szChunkData; + u8 *pMap = (u8*)hctFileMmap(&rc, p->aFdDb[iFd], n, 0, p->bReadOnlyMap); + for(i=0; inFdDb; + pMapping->aChunk[iChunk].pData = &pMap[i*szChunkData]; + } + } + + *pRc = rc; +} + +typedef struct Uncommitted Uncommitted; +struct Uncommitted { + int nAlloc; + int nTid; + i64 *aTid; +}; + +static int hctFileServerInitUncommitted(void *pCtx, const char *zFile){ + int fd; + Uncommitted *p = (Uncommitted*)pCtx; + + fd = open(zFile, O_RDONLY); + if( fd>=0 ){ + i64 iTid = 0; + read(fd, &iTid, sizeof(iTid)); + close(fd); + if( iTid>0 ){ + if( p->nTid==p->nAlloc ){ + int nNew = p->nTid ? p->nTid*4 : 64; + i64 *aNew = sqlite3_realloc(p->aTid, nNew*sizeof(i64)); + if( aNew==0 ){ + return SQLITE_NOMEM; + }else{ + p->aTid = aNew; + p->nAlloc = nNew; + } + } + p->aTid[p->nTid++] = iTid; + } + } + return SQLITE_OK; +} + +static int hctFileServerInit( + HctFileServer *p, + HctConfig *pConfig, + const char *zFile +){ + int rc = SQLITE_OK; + assert( sqlite3_mutex_held(p->pMutex) ); + if( p->zPath==0 ){ + i64 szHdr; /* Size of header file */ + i64 szMap; /* Size of pagemap file */ + int nChunk = 0; /* Number of chunks in database */ + int szPage = 0; + int nDbFile = 0; + + Uncommitted unc; + memset(&unc, 0, sizeof(unc)); + + /* Open the data and page-map files */ + p->fdMap = hctFileOpen(&rc, zFile, "-pagemap"); + p->zPath = fileGetFullPath(&rc, zFile); + + if( rc==SQLITE_OK ){ + int n = strlen(p->zPath); + while( p->zPath[n-1]!='/' && n>1 ) n--; + p->zDir = sqlite3_mprintf("%.*s", n, p->zPath); + if( p->zDir==0 ) rc = SQLITE_NOMEM_BKPT; + } + + /* Initialize the page-manager */ + p->pPManServer = sqlite3HctPManServerNew(&rc, p); + + /* If the header file is zero bytes in size, or is not yet populated, + ** then the database is empty, regardless of the contents of the + ** *-data or *-pagemap file. Truncate the pagemap and data files to + ** zero bytes in size to make sure of this. + ** + ** Alternatively, if the header file is the right size, try to read it. + */ + szHdr = hctFileSize(&rc, p->aFdDb[0]); + if( rc==SQLITE_OK ){ + void *pHdr = 0; + if( szHdr==0 ){ + szHdr = HCT_HEADER_PAGESIZE*2; + hctFileTruncate(&rc, p->aFdDb[0], szHdr); + }else if( szHdr<(HCT_HEADER_PAGESIZE*2) ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + pHdr = hctFileMmap(&rc, p->aFdDb[0], HCT_HEADER_PAGESIZE*2, 0, 1); + hctFileReadHdr(&rc, pHdr, &szPage, &nDbFile); + if( rc==SQLITE_OK && szPage==0 ){ + hctFileTruncate(&rc, p->fdMap, 0); + hctFileTruncate(&rc, p->fdMap, HCT_DEFAULT_PAGEPERCHUNK*sizeof(i64)); + szHdr = HCT_HEADER_PAGESIZE*2; + hctFileTruncate(&rc, p->aFdDb[0], szHdr); + if( rc==SQLITE_OK ){ + rc = hctFileFindLogs(p, 0, hctFileServerInitUnlinkLog); + } + }else{ + if( rc==SQLITE_OK ){ + rc = hctFileFindLogs(p, (void*)&unc, hctFileServerInitUncommitted); + } + hctFileOpenDataFiles(&rc, p, nDbFile); + } + hctFileMunmap(pHdr, HCT_HEADER_PAGESIZE*2); + } + p->nPagePerChunk = HCT_DEFAULT_PAGEPERCHUNK; + + assert( szPage==0 || rc==SQLITE_OK ); + if( szPage>0 ){ + i64 szChunkPagemap = p->nPagePerChunk * sizeof(u64); + + p->szPage = szPage; + szMap = hctFileSize(&rc, p->fdMap); + if( rc==SQLITE_OK ){ + if( szMapnFdDb==1 && szHdr!=p->szPage*(szMap/sizeof(u64))) + ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + nChunk = szMap / szChunkPagemap; + } + } + + hctFileAllocateMapping(&rc, p, nChunk); + } + + /* Initialize CID value */ + p->iCommitId = 5; + + /* Allocate a transaction map server */ + if( rc==SQLITE_OK && p->pTMapServer==0 ){ + u64 iFirst = 0; /* First tid that will be written in tmap */ + u64 iLast = 0; /* Last such tid */ + int ii; /* To iterate through unc.aTid[] */ + + if( p->pMapping ){ + iFirst = hctFilePagemapGet(p->pMapping, HCT_PAGEMAP_TRANSID_EOF); + iFirst = (iFirst & HCT_TID_MASK) + 1; + }else{ + iFirst = 1; + } + + iLast = iFirst; + for(ii=0; ii=iLast ) iLast = iThis+1; + } + + /* Allocate the tmap-server object. Set all entries between iFirst and + ** iLast to (HCT_TMAP_COMMITTED, cid=1). Ensuring that the contents of + ** these transactions are visible to all readers. + ** + ** Then go back and set the entry for all tid values in unc.aTid[] to + ** (HCT_TMAP_ROLLBACK, 0) - not visible to any readers. */ + rc = sqlite3HctTMapServerNew(iFirst, iLast, &p->pTMapServer); + for(ii=0; iipTMapServer, iThis, HCT_TMAP_ROLLBACK); + } + } + sqlite3_free(unc.aTid); + } + return rc; +} + +/* +** This is called as part of initializing a new database on disk. Mutex +** HctFileServer.mutex must be held to call this function. It writes a +** new, empty, root page to physical page iPhys, to be used for either +** HCT_ROOTPAGE_SCHEMA or HCT_ROOTPAGE_META. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int hctFileInitSystemRoot(HctFileServer *p, u64 iPhys){ + int rc = SQLITE_OK; + u8 *aBuf = sqlite3_malloc(p->szPage); + + assert( sqlite3_mutex_held(p->pMutex) ); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3HctDbRootPageInit(0, aBuf, p->szPage); + + if( p->bReadOnlyMap ){ + rc = hctPageWriteToDisk(p, iPhys, aBuf); + }else{ + u8 *a = (u8*)hctPagePtr(p->pMapping, iPhys); + memcpy(a, aBuf, p->szPage); + } + sqlite3_free(aBuf); + } + return rc; +} + +static int hctFileInitHdr(HctFileServer *p){ + int rc = SQLITE_OK; + u8 *aBuf = sqlite3_malloc(HCT_HEADER_PAGESIZE); + assert( sqlite3_mutex_held(p->pMutex) ); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + char *zHdr = "Hctree database version 00000001"; + assert( strlen(zHdr)==32 ); + memset(aBuf, 0, HCT_HEADER_PAGESIZE); + memcpy(aBuf, zHdr, 32); + memcpy(&aBuf[32], &p->szPage, sizeof(int)); + memcpy(&aBuf[36], &p->nFdDb, sizeof(int)); + if( p->bReadOnlyMap ){ + ssize_t res = pwrite(p->aFdDb[0], aBuf, HCT_HEADER_PAGESIZE, 0); + rc = (res==HCT_HEADER_PAGESIZE ? SQLITE_OK : SQLITE_ERROR); + }else{ + memcpy(p->pMapping->aChunk[0].pData, aBuf, HCT_HEADER_PAGESIZE); + } + } + sqlite3_free(aBuf); + return rc; +} + + +/* +** This is called each time a new snapshot is opened. If HctFile.szPage is +** still set to 0, then: +** +** a) this is the first snapshot opened by connection pFile, and +** b) the database had not been created when pFile was opened. +** +** In this case the server-mutex is taken, and if the db has still not been +** created (HctFileServer.szPage==0), then it is created on disk under the +** cover of the mutex. +*/ +SQLITE_PRIVATE int sqlite3HctFileNewDb(HctFile *pFile){ + int rc = SQLITE_OK; + if( pFile->szPage==0 ){ + HctFileServer *p = pFile->pServer; + sqlite3_mutex_enter(p->pMutex); + if( p->szPage==0 ){ + HctConfig *pConfig = pFile->pConfig; + HctMapping *pMapping = 0; + int szPage = pConfig->pgsz; + int nDbFile = pConfig->nDbFile; + + p->szPage = szPage; + hctFileTruncate(&rc, p->fdMap, p->nPagePerChunk * sizeof(u64)); + hctFileTruncate(&rc, p->aFdDb[0], p->nPagePerChunk * szPage); + + hctFileAllocateMapping(&rc, p, 1); + pMapping = p->pMapping; + + assert( nDbFile>=1 && nDbFile<=HCT_MAX_NDBFILE ); + hctFileOpenDataFiles(&rc, p, nDbFile); + + /* 1. Make logical page 1 an empty intkey root page (SQLite uses this + ** as the root of sqlite_schema). + ** + ** 2. Set the initial values of the largest logical and physical page + ** ids allocated fields. + */ + + /* Set the initial values of the largest logical and physical page + ** ids allocated fields. These will be used when the set of free pages + ** is recovered in sqlite3HctFileRecoverFreelists(). */ + if( rc==SQLITE_OK ){ + const int nPageSet = pConfig->nPageSet; + hctFilePagemapSetDirect(pMapping, HCT_PAGEMAP_LOGICAL_EOF, nPageSet); + hctFilePagemapSetDirect(pMapping, HCT_PAGEMAP_PHYSICAL_EOF, nPageSet); + } + + if( rc==SQLITE_OK ){ + const u64 f = HCT_PMF_LOGICAL_IN_USE | HCT_PMF_LOGICAL_IS_ROOT; + u64 aRoot[] = { + HCT_ROOTPAGE_SCHEMA, + HCT_ROOTPAGE_META, + }; + int ii = 0; + u64 iPhys1 = 1 + (((HCT_HEADER_PAGESIZE*2)+szPage-1) / szPage); + + for(ii=0; iipMapping); + p->pMapping = 0; + } + } + + if( rc==SQLITE_OK ){ + pFile->szPage = p->szPage; + pFile->pMapping = p->pMapping; + pFile->pMapping->nRef++; + pFile->eInitState = p->eInitState; + } + sqlite3_mutex_leave(p->pMutex); + } + return rc; +} + + +/* +** Return true if the db has not yet been created on disk. Or false +** if it already has. +*/ +SQLITE_PRIVATE int sqlite3HctFileIsNewDb(HctFile *pFile){ + int bRet = 0; + if( pFile->szPage==0 ){ + HctFileServer *p = pFile->pServer; + sqlite3_mutex_enter(p->pMutex); + if( p->szPage==0 ){ + bRet = 1; + } + sqlite3_mutex_leave(p->pMutex); + } + return bRet; +} + +static sqlite3_int64 current_time(){ + struct timeval sNow; + gettimeofday(&sNow, 0); + return (sqlite3_int64)sNow.tv_sec*1000 + sNow.tv_usec/1000; +} + +static void hctFileEnterServerMutex(HctFile *pFile){ + sqlite3_mutex *pMutex = pFile->pServer->pMutex; + pFile->stats.nMutex++; + if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ + pFile->stats.nMutexBlock++; + sqlite3_mutex_enter(pMutex); + } +} + +/* +** This is called to ensure that the mapping currently held by client +** pFile contains at least nChunk chunks. +*/ +static int hctFileGrowMapping(HctFile *pFile, int nChunk){ + int rc = SQLITE_OK; + if( pFile->pMapping->nChunkpServer; + HctMapping *pOld; + hctFileEnterServerMutex(pFile); + hctMappingUnref(pFile->pMapping); + pFile->pMapping = 0; + pOld = p->pMapping; + nOld = pOld->nChunk; + if( nOldnPagePerChunk*p->szPage; + i64 szChunkMap = p->nPagePerChunk*sizeof(u64); + int i; + + /* Grow the mapping file */ + hctFileTruncate(&rc, p->fdMap, nChunk*szChunkMap); + + for(i=nOld; iaChunk[i]; + + /* Grow the data file */ + int iFd = (i % p->nFdDb); + i64 sz = ((i / p->nFdDb) + 1) * szChunkData; + hctFileTruncate(&rc, p->aFdDb[iFd], sz); + + /* Map the new chunks of both the data and mapping files. */ + pChunk->aMap = hctFileMmapPagemapChunk(&rc, p, pNew, i); + pChunk->pData = hctFileMmapDbChunk(&rc, p, pNew, i); + } + + if( rc==SQLITE_OK ){ + p->pMapping = pNew; + hctMappingUnref(pOld); + }else{ + hctMappingUnref(pNew); + } + } + } + pFile->pMapping = p->pMapping; + pFile->pMapping->nRef++; + sqlite3_mutex_leave(p->pMutex); + } + return rc; +} + +/* +** Grow the mapping so that it is at least large enough to have an entry +** for slot iSlot. Return SQLITE_OK if successful (or if the mapping does +** not need to grow), or an SQLite error code otherwise. +*/ +static int hctFileGrowMappingForSlot(HctFile *pFile, u32 iSlot){ + assert( iSlot>0 ); + return hctFileGrowMapping(pFile, 1 + ((iSlot-1) / HCT_DEFAULT_PAGEPERCHUNK)); +} + + +static int hctFileServerFind(HctFile *pFile, const char *zFile){ + int rc = SQLITE_OK; + struct stat sStat; + HctFileServer *pServer = 0; + sqlite3_mutex *pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1); + + memset(&sStat, 0, sizeof(sStat)); + + /* Take the VFS1 mutex that protects the globals in this file */ + sqlite3_mutex_enter(pMutex); + + /* Search for an existing HctFileServer already open on this database */ + if( 0==stat(zFile, &sStat) ){ + for(pServer=g.pServerList; pServer; pServer=pServer->pServerNext){ + if( pServer->st_ino==(i64)sStat.st_ino + && pServer->st_dev==(i64)sStat.st_dev + ){ + break; + } + } + } + + if( pServer==0 ){ + int fd = hctFileOpen(&rc, zFile, ""); + if( rc==SQLITE_OK ){ + hctFileLock(&rc, fd, zFile); + pServer = (HctFileServer*)sqlite3HctMalloc(&rc, sizeof(*pServer)); + if( pServer==0 ){ + if( fd ) close(fd); + }else{ + fstat(fd, &sStat); + pServer->st_dev = (i64)sStat.st_dev; + pServer->st_ino = (i64)sStat.st_ino; + pServer->pServerNext = g.pServerList; + pServer->aFdDb[0] = fd; + pServer->nFdDb = 1; + pServer->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); + /* pServer->bReadOnlyMap = 1; */ + g.pServerList = pServer; + } + } + } + + if( rc==SQLITE_OK ){ + pFile->pServer = pServer; + pFile->pFileNext = pServer->pFileList; + pServer->pFileList = pFile; + } + + /* Release the global mutex */ + sqlite3_mutex_leave(pMutex); + + return rc; +} + + +/* +** Open a connection to the database zFile. +*/ +SQLITE_PRIVATE HctFile *sqlite3HctFileOpen(int *pRc, const char *zFile, HctConfig *pConfig){ + int rc = *pRc; + HctFile *pNew; + + pNew = (HctFile*)sqlite3HctMalloc(&rc, sizeof(*pNew)); + if( pNew ){ + pNew->pConfig = pConfig; + rc = hctFileServerFind(pNew, zFile); + if( rc==SQLITE_OK ){ + HctFileServer *pServer = pNew->pServer; + + sqlite3_mutex_enter(pServer->pMutex); + rc = hctFileServerInit(pServer, pConfig, zFile); + assert( rc==SQLITE_OK ); + if( rc==SQLITE_OK && pServer->szPage>0 ){ + pNew->szPage = pServer->szPage; + pNew->pMapping = pServer->pMapping; + pNew->pMapping->nRef++; + } + pNew->eInitState = pServer->eInitState; + pNew->iFileId = pServer->iNextFileId++; + sqlite3_mutex_leave(pServer->pMutex); + + if( rc==SQLITE_OK ){ + sqlite3HctTMapClientNew( + pServer->pTMapServer, pConfig, &pNew->pTMapClient + ); + } + if( rc==SQLITE_OK ){ + pNew->pPManClient = sqlite3HctPManClientNew( + &rc, pConfig, pServer->pPManServer, pNew + ); + } + }else{ + sqlite3_free(pNew); + pNew = 0; + } + + if( rc!=SQLITE_OK ){ + sqlite3HctFileClose(pNew); + pNew = 0; + } + } + assert( (rc==SQLITE_OK)==(pNew!=0) ); + *pRc = rc; + return pNew; +} + +SQLITE_PRIVATE HctTMapClient *sqlite3HctFileTMapClient(HctFile *pFile){ + return pFile->pTMapClient; +} +SQLITE_PRIVATE HctPManClient *sqlite3HctFilePManClient(HctFile *pFile){ + return pFile->pPManClient; +} + +SQLITE_PRIVATE void sqlite3HctFileClose(HctFile *pFile){ + if( pFile ){ + HctFileServer *pDel = 0; + HctFile **pp; + HctFileServer *pServer = pFile->pServer; + + /* Release the page-manager client */ + sqlite3HctPManClientFree(pFile->pPManClient); + pFile->pPManClient = 0; + + /* Release the transaction map client */ + sqlite3HctTMapClientFree(pFile->pTMapClient); + pFile->pTMapClient = 0; + + /* Release the reference to the HctMapping object, if any */ + hctMappingUnref(pFile->pMapping); + pFile->pMapping = 0; + + /* Remove this object from the HctFileServer.pFileList list. If this + ** means there are no longer any connections to this server object, + ** remove the HctFileServer object itself from the global list. In + ** this case leave stack variable pDel set to point to the + ** HctFileServer. */ + sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1) ); + for(pp=&pServer->pFileList; *pp!=pFile; pp=&(*pp)->pFileNext); + *pp = pFile->pFileNext; + if( pServer->pFileList==0 ){ + HctFileServer **ppS; + pDel = pServer; + for(ppS=&g.pServerList; *ppS!=pServer; ppS=&(*ppS)->pServerNext); + *ppS = pServer->pServerNext; + } + sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1) ); + + /* It if was removed from the global list, clean up the HctFileServer + ** object. */ + if( pDel ){ + int szChunkData = pDel->nPagePerChunk*pDel->szPage; + int szChunkMap = pDel->nPagePerChunk*sizeof(u64); + int i; + HctMapping *pMapping = pDel->pMapping; + + sqlite3HctTMapServerFree(pDel->pTMapServer); + pDel->pTMapServer = 0; + + sqlite3HctPManServerFree(pDel->pPManServer); + pDel->pPManServer = 0; + + if( pMapping ){ + pDel->pMapping = 0; + for(i=0; inChunk; i++){ + HctMappingChunk *pChunk = &pMapping->aChunk[i]; + if( pChunk->aMap ) hctFileMunmap(pChunk->aMap, szChunkMap); + if( pChunk->pData ) hctFileMunmap(pChunk->pData, szChunkData); + } + hctMappingUnref(pMapping); + } + + /* Close the data files and the mapping file. */ + for(i=0; inFdDb; i++){ close(pDel->aFdDb[i]); } + if( pDel->fdMap ) close(pDel->fdMap); + + if( pDel->xJrnlDel ){ + pDel->xJrnlDel(pDel->pJrnlPtr); + } + sqlite3_free(pDel->zDir); + sqlite3_free(pDel->zPath); + sqlite3_mutex_free(pDel->pMutex); + sqlite3_free(pDel); + } + + /* Finally, free the HctFile object */ + sqlite3_free(pFile); + } +} + +SQLITE_PRIVATE u32 sqlite3HctFileMaxpage(HctFile *pFile){ + u64 iVal = hctFilePagemapGet(pFile->pMapping, HCT_PAGEMAP_PHYSICAL_EOF); + return (iVal & 0xFFFFFFFF); +} + +/* +** Set the flags in mask within page-map slot iSlot. +*/ +static int hctFileSetFlag(HctFile *pFile, u32 iSlot, u64 mask){ + int rc = hctFileGrowMappingForSlot(pFile, iSlot); + if( rc==SQLITE_OK ){ + HctMapping *pMapping = pFile->pMapping; + while( 1 ){ + u64 iVal = hctFilePagemapGet(pMapping, iSlot); + if( hctFilePagemapSet(pFile, iSlot, iVal, iVal | mask) ) break; + } + } + return rc; +} + +/* +** Clear the flags in mask within page-map slot iSlot. +*/ +static int hctFileClearFlag(HctFile *pFile, u32 iSlot, u64 mask){ + int rc = hctFileGrowMappingForSlot(pFile, iSlot); + if( rc==SQLITE_OK ){ + HctMapping *pMapping = pFile->pMapping; + while( 1 ){ + u64 iVal = hctFilePagemapGet(pMapping, iSlot); + if( hctFilePagemapSet(pFile, iSlot, iVal, iVal & ~mask) ) break; + } + } + return rc; +} + + +SQLITE_PRIVATE int sqlite3HctFileRootFree(HctFile *pFile, u32 iRoot){ + /* TODO - do something with freed root-page */ + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctFilePageClearIsRoot(HctFile *pFile, u32 iRoot){ + return hctFileClearFlag(pFile, iRoot, HCT_PMF_LOGICAL_IS_ROOT); +} +SQLITE_PRIVATE int sqlite3HctFilePageClearInUse(HctFile *pFile, u32 iPg, int bLogic){ + u64 flag = bLogic ? HCT_PMF_LOGICAL_IN_USE : HCT_PMF_PHYSICAL_IN_USE; + return hctFileClearFlag(pFile, iPg, flag); +} + +SQLITE_PRIVATE int sqlite3HctFileTreeFree(HctFile *pFile, u32 iRoot, int bImmediate){ + u64 iTid = bImmediate ? 0 : pFile->iCurrentTid; + return sqlite3HctPManFreeTree(pFile->pPManClient, pFile, iRoot, iTid); +} + +static int hctFilePagemapGetGrow(HctFile *pFile, u32 iPg, u64 *piVal){ + int rc = hctFileGrowMapping(pFile, 1+(iPg>>pFile->pMapping->mapShift)); + if( rc==SQLITE_OK ){ + *piVal = hctFilePagemapGet(pFile->pMapping, iPg); + } + return rc; +} + +/* +** Obtain the lower 32-bits of the value currently stored in slot iSlot. +*/ +static int hctFilePagemapGetGrow32(HctFile *pFile, u32 iSlot, u32 *piVal){ + int rc; + u64 val = 0; + rc = hctFilePagemapGetGrow(pFile, iSlot, &val); + *piVal = (u32)(val & 0xFFFFFFFF); + return rc; +} + + +static int hctFilePagemapPtr(HctFile *pFile, u32 iPg, u8 **paData){ + int rc = hctFileGrowMapping(pFile, 1+(iPg>>pFile->pMapping->mapShift)); + if( rc==SQLITE_OK ){ + *paData = hctPagePtr(pFile->pMapping, iPg); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctFilePageGet(HctFile *pFile, u32 iPg, HctFilePage *pPg){ + int rc; + assert( iPg!=0 ); + memset(pPg, 0, sizeof(*pPg)); + pPg->pFile = pFile; + pPg->iPg = iPg; + rc = hctFilePagemapGetGrow32(pFile, iPg, &pPg->iOldPg); + if( rc==SQLITE_OK ){ + u32 iPhys = pPg->iOldPg; + assert( iPhys!=0 ); + rc = hctFilePagemapPtr(pFile, iPhys, &pPg->aOld); + } + return rc; +} + +SQLITE_PRIVATE u32 sqlite3HctFilePageMapping(HctFile *pFile, u32 iLogical, int *pbEvicted){ + u64 val = hctFilePagemapGet(pFile->pMapping, iLogical); + *pbEvicted = (val & HCT_PMF_LOGICAL_EVICTED) ? 1 : 0; + return (u32)(val & 0xFFFFFFFF); +} + +/* +** Obtain a reference to physical page iPg. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageGetPhysical(HctFile *pFile, u32 iPg, HctFilePage *pPg){ + u32 iVal; + int rc; + assert( iPg!=0 ); + memset(pPg, 0, sizeof(*pPg)); + rc = hctFilePagemapGetGrow32(pFile, iPg, &iVal); + if( rc==SQLITE_OK ){ + pPg->iOldPg = iPg; + pPg->aOld = (u8*)hctPagePtr(pFile->pMapping, iPg); + } + return rc; +} + +static u32 hctFileAllocPg(int *pRc, HctFile *pFile, int bLogical){ + int rc = *pRc; + u32 iRet = 0; + + if( bLogical==0 ) pFile->nPageAlloc++; + iRet = sqlite3HctPManAllocPg(&rc, pFile->pPManClient, pFile, bLogical); + if( rc==SQLITE_OK ){ + rc = hctFileGrowMappingForSlot(pFile, iRet); + if( rc!=SQLITE_OK ){ + /* TODO: Something about this resource leak */ + iRet = 0; + } + } + + *pRc = rc; + return iRet; +} + +/* +** This function makes the page object pPg writable if it is not already +** so. Specifically, it allocates a new physical page and sets the +** following variables accordingly: +** +** HctFilePage.iNewPg +** HctFilePage.aNew +** +** The PHYSICAL_IN_USE flag is set on the new physical page allocated +** here. +*/ +static void hctFilePageMakeWritable(int *pRc, HctFilePage *pPg){ + if( pPg->aNew==0 ){ + HctFile *pFile = pPg->pFile; + u32 iNewPg = hctFileAllocPg(pRc, pFile, 0); + if( iNewPg ){ + hctFileSetFlag(pPg->pFile, iNewPg, HCT_PMF_PHYSICAL_IN_USE); + pPg->iNewPg = iNewPg; + + if( pFile->pServer->bReadOnlyMap ){ + pPg->aNew = (u8*)sqlite3_malloc(pFile->szPage); + /* todo: handle oom here */ + }else{ + pPg->aNew = (u8*)hctPagePtr(pPg->pFile->pMapping, iNewPg); + } + } + } +} + + +#if 0 +static void debug_printf(const char *zFmt, ...){ + va_list ap; + va_start(ap, zFmt); + vprintf(zFmt, ap); + va_end(ap); +} + +static void debug_slot_value(HctFile *pFile, u32 iSlot){ + u64 iVal = hctFilePagemapGet(pFile->pMapping, iSlot); + printf("[flags=%02x val=%lld]", (u32)(iVal>>56), iVal & HCT_PAGEMAP_VMASK); +} + +#define DEBUG_PAGE_MUTEX_ENTER(pPg) \ + sqlite3_mutex_enter(pPg->pFile->pServer->pMutex) + +#define DEBUG_PAGE_MUTEX_LEAVE(pPg) \ + fflush(stdout); sqlite3_mutex_leave(pPg->pFile->pServer->pMutex) + +#define DEBUG_PRINTF(...) debug_printf(__VA_ARGS__) +#define DEBUG_SLOT_VALUE(pFile, iSlot) debug_slot_value(pFile, iSlot) + +SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...){ + va_list ap; + sqlite3_mutex_enter(pFile->pServer->pMutex); + printf("f=%d: ", pFile->iFileId); + va_start(ap, zFmt); + vprintf(zFmt, ap); + va_end(ap); + sqlite3_mutex_leave(pFile->pServer->pMutex); +} + +#else +# define DEBUG_PAGE_MUTEX_ENTER(x) +# define DEBUG_PAGE_MUTEX_LEAVE(x) +# define DEBUG_PRINTF(...) +# define DEBUG_SLOT_VALUE(x,y) +SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...){ } +#endif + +void hctFileFreePg( + int *pRc, + HctFile *pFile, + i64 iTid, /* Associated TID value */ + u32 iPg, /* Page number */ + int bLogical /* True for logical, false for physical */ +){ + if( pFile->eInitState>=HCT_INIT_RECOVER1 ){ + sqlite3HctPManFreePg(pRc, pFile->pPManClient, iTid, iPg, bLogical); + } +} + + +static int hctFilePageFlush(HctFilePage *pPg){ + int rc = SQLITE_OK; + if( pPg->aNew ){ + u32 iOld = pPg->iOldPg; + + DEBUG_PAGE_MUTEX_ENTER(pPg); + DEBUG_PRINTF("f=%d: Flushing page %d orig=", pPg->pFile->iFileId, pPg->iPg); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + DEBUG_PRINTF(" (ioldpg=%d) (inewpg=%d)", pPg->iOldPg, pPg->iNewPg); + + DEBUG_PRINTF("\n"); + DEBUG_PAGE_MUTEX_LEAVE(pPg); + + if( pPg->pFile->pServer->bReadOnlyMap ){ + rc = hctPageWriteToDisk(pPg->pFile->pServer, pPg->iNewPg, pPg->aNew); + } + + if( rc==SQLITE_OK ){ + if( !hctFilePagemapSetLogical(pPg->pFile, pPg->iPg, iOld, pPg->iNewPg) ){ + rc = SQLITE_LOCKED_ERR(pPg->iPg, "flush"); + }else{ + if( iOld ){ + u64 iTid = pPg->pFile->iCurrentTid; + hctFileFreePg(&rc, pPg->pFile, iTid, iOld, 0); + hctFileClearFlag(pPg->pFile, iOld, HCT_PMF_PHYSICAL_IN_USE); + } + pPg->iOldPg = pPg->iNewPg; + if( pPg->pFile->pServer->bReadOnlyMap ){ + sqlite3_free(pPg->aNew); + pPg->aOld = hctPagePtr(pPg->pFile->pMapping, pPg->iOldPg); + }else{ + pPg->aOld = pPg->aNew; + } + pPg->aNew = 0; + pPg->iNewPg = 0; + } + } + + DEBUG_PAGE_MUTEX_ENTER(pPg); + DEBUG_PRINTF("f=%d:", pPg->pFile->iFileId); + + DEBUG_PRINTF(" rc=%d final=", rc); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + DEBUG_PRINTF("%s\n", rc==SQLITE_LOCKED ? " SQLITE_LOCKED" : ""); + DEBUG_PAGE_MUTEX_LEAVE(pPg); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctFilePageCommit(HctFilePage *pPg){ + assert( pPg->iPg ); + return hctFilePageFlush(pPg); +} + +SQLITE_PRIVATE int sqlite3HctFilePageEvict(HctFilePage *pPg, int bIrrevocable){ + int ret; + + DEBUG_PAGE_MUTEX_ENTER(pPg); + DEBUG_PRINTF("f=%d: Evicting page %d (irrecocable=%d) orig=", + pPg->pFile->iFileId, pPg->iPg, bIrrevocable + ); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + + ret = hctFileSetEvicted(pPg->pFile, pPg->iPg, pPg->iOldPg, bIrrevocable); + ret = (ret ? SQLITE_OK : SQLITE_LOCKED_ERR(pPg->iPg, "evict")); + + DEBUG_PRINTF(" rc=%d final=", ret); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + DEBUG_PRINTF("%s\n", ret==SQLITE_LOCKED ? " SQLITE_LOCKED" : ""); + DEBUG_PAGE_MUTEX_LEAVE(pPg); + return ret; +} + +SQLITE_PRIVATE void sqlite3HctFilePageUnevict(HctFilePage *pPg){ + DEBUG_PAGE_MUTEX_ENTER(pPg); + DEBUG_PRINTF("f=%d: Unevicting page %d orig=", pPg->pFile->iFileId, pPg->iPg); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + + hctFileClearEvicted(pPg->pFile, pPg->iPg); + + DEBUG_PRINTF(" final="); + DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); + DEBUG_PRINTF("\n"); + DEBUG_PAGE_MUTEX_LEAVE(pPg); +} + +SQLITE_PRIVATE int sqlite3HctFilePageIsEvicted(HctFile *pFile, u32 iPgno){ + u64 val; + int rc = hctFilePagemapGetGrow(pFile, iPgno, &val); + return (rc || (val & HCT_PMF_LOGICAL_EVICTED)!=0); +} + +SQLITE_PRIVATE int sqlite3HctFilePageIsFree(HctFile *pFile, u32 iPgno, int bLogical){ + u64 iVal = hctFilePagemapGet(pFile->pMapping, iPgno); + u64 mask = (bLogical ? HCT_PMF_LOGICAL_IN_USE : HCT_PMF_PHYSICAL_IN_USE); + return (iVal & mask) ? 0 : 1; +} + +SQLITE_PRIVATE int sqlite3HctFilePageRelease(HctFilePage *pPg){ + int rc = SQLITE_OK; + if( pPg->iPg ){ + rc = hctFilePageFlush(pPg); + }else if( pPg->aNew && pPg->pFile->pServer->bReadOnlyMap ){ + rc = hctPageWriteToDisk(pPg->pFile->pServer, pPg->iNewPg, pPg->aNew); + sqlite3_free(pPg->aNew); + } + memset(pPg, 0, sizeof(*pPg)); + return rc; +} + + + +/* +** Allocate a new physical page and set (*pPg) to refer to it. The new +** physical page number is available in HctFilePage.iNewPg. +*/ +SQLITE_PRIVATE int sqlite3HctFilePageNewPhysical(HctFile *pFile, HctFilePage *pPg){ + int rc = SQLITE_OK; + memset(pPg, 0, sizeof(*pPg)); + pPg->pFile = pFile; + hctFilePageMakeWritable(&rc, pPg); + return rc; +} + +/* +** Allocate a new logical page. If parameter iPg is zero, then a new +** logical page number is allocated. Otherwise, it must be a logical page +** number obtained by an earlier call to sqlite3HctFileRootPgno(). +*/ +SQLITE_PRIVATE int sqlite3HctFilePageNew(HctFile *pFile, HctFilePage *pPg){ + int rc = SQLITE_OK; /* Return code */ + u32 iLPg = hctFileAllocPg(&rc, pFile, 1); + if( rc==SQLITE_OK ){ + memset(pPg, 0, sizeof(*pPg)); + pPg->pFile = pFile; + pPg->iPg = iLPg; + hctFilePagemapZeroValue(pFile, iLPg); + hctFilePageMakeWritable(&rc, pPg); + } + + return rc; +} + +/* +** Allocate a new logical root page number. +*/ +SQLITE_PRIVATE int sqlite3HctFileRootPgno(HctFile *pFile, u32 *piRoot){ + int rc = SQLITE_OK; + u32 iRoot = hctFileAllocPg(&rc, pFile, 1); + if( rc==SQLITE_OK ){ + hctFilePagemapZeroValue(pFile, iRoot); + *piRoot = iRoot; + } + return rc; +} + +/* +** Parameter iRoot is a root page number previously obtained from +** sqlite3HctFileRootPgno(). This function allocates a physical +** page to go with the logical one. +*/ +SQLITE_PRIVATE int sqlite3HctFileRootNew(HctFile *pFile, u32 iRoot, HctFilePage *pPg){ + int rc = SQLITE_OK; /* Return code */ + + memset(pPg, 0, sizeof(*pPg)); + pPg->pFile = pFile; + pPg->iPg = iRoot; + hctFilePageMakeWritable(&rc, pPg); + + /* Set the LOGICAL_IN_USE and LOGICAL_IS_ROOT flags on page iRoot. At + ** the same time, set the mapping to 0. Take care not to clear the + ** PHYSICAL_IN_USE flag while doing so, in case there is a physical + ** page with page number iRoot currently in use somewhere. */ + while( rc==SQLITE_OK ){ + u64 i1 = hctFilePagemapGet(pFile->pMapping, iRoot); + u64 i2 = (i1 & HCT_PMF_PHYSICAL_IN_USE); + i2 |= (HCT_PMF_LOGICAL_IS_ROOT|HCT_PMF_LOGICAL_IN_USE); + if( hctFilePagemapSet(pFile, iRoot, i1, i2) ) break; + } + + return rc; +} + +SQLITE_PRIVATE void sqlite3HctFilePageUnwrite(HctFilePage *pPg){ + int rc = SQLITE_OK; + if( pPg->aNew ){ + hctFileClearFlag(pPg->pFile, pPg->iNewPg, HCT_PMF_PHYSICAL_IN_USE); + hctFileFreePg(&rc, pPg->pFile, 0, pPg->iNewPg, 0); + if( pPg->pFile->pServer->bReadOnlyMap ){ + sqlite3_free(pPg->aNew); + } + pPg->iNewPg = 0; + pPg->aNew = 0; + if( pPg->iOldPg==0 ){ + assert( pPg->aOld==0 ); + hctFileFreePg(&rc, pPg->pFile, 0, pPg->iPg, 1); + pPg->iPg = 0; + } + } +} + +SQLITE_PRIVATE int sqlite3HctFilePageWrite(HctFilePage *pPg){ + int rc = SQLITE_OK; /* Return code */ + hctFilePageMakeWritable(&rc, pPg); + return rc; +} + +SQLITE_PRIVATE u64 sqlite3HctFileAllocateTransid(HctFile *pFile){ + u64 iVal = hctFilePagemapIncr(pFile, HCT_PAGEMAP_TRANSID_EOF, 1); + pFile->iCurrentTid = (iVal & HCT_TID_MASK); + return pFile->iCurrentTid; +} +SQLITE_PRIVATE u64 sqlite3HctFileAllocateCID(HctFile *pFile, int nWrite){ + assert( nWrite>0 ); + return hctFileAtomicIncr(pFile, &pFile->pServer->iCommitId, nWrite); +} + +SQLITE_PRIVATE void sqlite3HctFileSetCID(HctFile *pFile, u64 iVal){ + HctAtomicStore(&pFile->pServer->iCommitId, iVal); +} + +SQLITE_PRIVATE u64 sqlite3HctFileIncrWriteCount(HctFile *pFile, int nIncr){ + return hctFileAtomicIncr(pFile, &pFile->pServer->nWriteCount, nIncr); +} + +SQLITE_PRIVATE u64 sqlite3HctFileGetSnapshotid(HctFile *pFile){ + return HctAtomicLoad( &pFile->pServer->iCommitId ); +} + +SQLITE_PRIVATE int sqlite3HctFilePgsz(HctFile *pFile){ + return pFile->szPage; +} + +SQLITE_PRIVATE void sqlite3HctFileSetJrnlPtr( + HctFile *pFile, + void *pPtr, + void(*xDel)(void*) +){ + assert( pFile->pServer->pJrnlPtr==0 ); + assert( pFile->pServer->xJrnlDel==0 ); + pFile->pServer->pJrnlPtr = pPtr; + pFile->pServer->xJrnlDel = xDel; +} + +SQLITE_PRIVATE void *sqlite3HctFileGetJrnlPtr(HctFile *pFile){ + return pFile->pServer->pJrnlPtr; +} + +/* +** Return the current "safe" TID value. +*/ +SQLITE_PRIVATE u64 sqlite3HctFileSafeTID(HctFile *pFile){ + return sqlite3HctTMapSafeTID(pFile->pTMapClient); +} + +/* +** Allocate a block of nPg physical or logical page ids from the +** end of the current range. +*/ +SQLITE_PRIVATE u32 sqlite3HctFilePageRangeAlloc(HctFile *pFile, int bLogical, int nPg){ + u32 iSlot = HCT_PAGEMAP_PHYSICAL_EOF - bLogical; + u64 iNew = 0; + + assert( bLogical==0 || iSlot==HCT_PAGEMAP_LOGICAL_EOF ); + assert( bLogical!=0 || iSlot==HCT_PAGEMAP_PHYSICAL_EOF ); + + /* Increment the selected slot by nPg. The returned value, iNew, is the + ** new value of the slot - the last page in the range allocated. */ + iNew = hctFilePagemapIncr(pFile, iSlot, nPg); + + /* Return the first page number in the range of nPg allocated */ + return (iNew+1 - nPg); +} + +/* +** This function is called by the upper layer to clear the: +** +** * LOGICAL_IN_USE flag on the specified page id, and the +** * PHYSICAL_IN_USE flag on currently mapped physical page id. +** +** If parameter bReuseNow is true, then the page was never properly linked +** into a list, and so the logical and physical page ids can be reused +** immediately. Otherwise, they are handled as if freed by the current +** transaction. +*/ +SQLITE_PRIVATE int sqlite3HctFileClearInUse(HctFilePage *pPg, int bReuseNow){ + int rc = SQLITE_OK; + if( pPg->pFile ){ + u64 iTid = pPg->pFile->iCurrentTid; + u32 iPhysPg = pPg->iOldPg; + + assert( pPg->iPg>0 ); + assert( pPg->iOldPg>0 ); + +#ifdef SQLITE_DEBUG + if( bReuseNow==0 ){ + u64 iVal = hctFilePagemapGet(pPg->pFile->pMapping, pPg->iPg); + assert( iVal & HCT_PMF_LOGICAL_EVICTED ); + } +#endif + + hctFileClearFlag(pPg->pFile, pPg->iPg, HCT_PMF_LOGICAL_IN_USE); + hctFileClearFlag(pPg->pFile, iPhysPg, HCT_PMF_PHYSICAL_IN_USE); + hctFileFreePg(&rc, pPg->pFile, iTid, pPg->iPg, 1); + hctFileFreePg(&rc, pPg->pFile, iTid, iPhysPg, 0); + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctFileClearPhysInUse(HctFile *pFile, u32 pgno, int bReuseNow){ + u64 iTid = pFile->iCurrentTid; + int rc = SQLITE_OK; + + hctFileClearFlag(pFile, pgno, HCT_PMF_PHYSICAL_IN_USE); + hctFileFreePg(&rc, pFile, iTid, pgno, 0); + return rc; +} + +SQLITE_PRIVATE char *sqlite3HctFileLogFile(HctFile *pFile){ + char *zRet = 0; + HctFileServer *pServer = pFile->pServer; + sqlite3_mutex_enter(pServer->pMutex); + zRet = sqlite3_mprintf("%s-log-%d", pServer->zPath, pFile->iFileId); + sqlite3_mutex_leave(pServer->pMutex); + return zRet; +} + +SQLITE_PRIVATE int sqlite3HctFileStartRecovery(HctFile *pFile, int iStage){ + int bRet = 0; + if( pFile->eInitState==iStage ){ + HctFileServer *pServer = pFile->pServer; + sqlite3_mutex_enter(pServer->pMutex); + if( pServer->eInitState==iStage ){ + bRet = 1; + }else{ + pFile->eInitState = pServer->eInitState; + sqlite3_mutex_leave(pServer->pMutex); + } + } + return bRet; +} + +SQLITE_PRIVATE int sqlite3HctFileFinishRecovery(HctFile *pFile, int iStage, int rc){ + HctFileServer *pServer = pFile->pServer; + if( rc==SQLITE_OK ){ + pFile->eInitState = iStage+1; + pServer->eInitState = iStage+1; + } + sqlite3HctPManClientHandoff(pFile->pPManClient); + sqlite3_mutex_leave(pFile->pServer->pMutex); + return rc; +} + +SQLITE_PRIVATE int sqlite3HctFileRecoverFreelists( + HctFile *pFile, /* File to recover freelists for */ + int nRoot, i64 *aRoot, /* Array of root page numbers */ + int nPhys, i64 *aPhys /* Sorted array of phys. pages to preserve */ +){ + int rc = SQLITE_OK; + HctFileServer *pServer = pFile->pServer; + HctPManServer *pPManServer = pServer->pPManServer; + HctMapping *pMapping = pServer->pMapping; + u64 iSafeTid = hctFilePagemapGet(pMapping, HCT_PAGEMAP_TRANSID_EOF); + u64 nPg1 = hctFilePagemapGet(pMapping, HCT_PAGEMAP_PHYSICAL_EOF); + u64 nPg2 = hctFilePagemapGet(pMapping, HCT_PAGEMAP_LOGICAL_EOF); + u32 iPg; + u32 nPg; + u32 iPhysOff = ((HCT_HEADER_PAGESIZE*2)+pServer->szPage-1)/pServer->szPage; + + int iPhys = 0; + + nPg1 = nPg1 & HCT_PAGEMAP_VMASK; + nPg2 = nPg2 & HCT_PAGEMAP_VMASK; + + /* TODO: Really - page-manager must be empty at this point. Should assert() + ** that instead of making this call. */ + sqlite3HctPManServerReset(pPManServer); + + nPg = MAX((nPg1 & 0xFFFFFFFF), (nPg2 & 0xFFFFFFFF)); + for(iPg=1; iPg<=nPg; iPg++){ + u64 iVal = hctFilePagemapGetSafe(pMapping, iPg); + + if( (iVal & HCT_PMF_LOGICAL_IS_ROOT) && iPg>=3 ){ + int ii; + for(ii=0; iiiPhysOff) + ){ + /* Check if page iPg is one that must be preserved. */ + u64 iTid = iSafeTid; + while( iPhys=HCT_FIRST_LOGICAL + ){ + sqlite3HctPManServerInit(&rc, pPManServer, iSafeTid, iPg, 1); + } + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctFileFindLogs( + HctFile *pFile, + void *pCtx, + int (*xLog)(void*, const char*) +){ + return hctFileFindLogs(pFile->pServer, pCtx, xLog); +} + +SQLITE_PRIVATE int sqlite3HctFileRootArray( + HctFile *pFile, + u32 **paiRoot, + int *pnRoot +){ + int nAlloc = 0; + int nRoot = 0; + u32 *aRoot = 0; + u32 nLogic = 0; + int ii; + int rc; + + rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_LOGICAL_EOF, &nLogic); + for(ii=1; rc==SQLITE_OK && ii<=nLogic; ii++){ + u64 val; + rc = hctFilePagemapGetGrow(pFile, ii, &val); + if( rc==SQLITE_OK && (val & HCT_PMF_LOGICAL_IS_ROOT) ){ + if( nRoot>=nAlloc ){ + int nNew = (nAlloc ? nAlloc*2 : 16); + u32 *aNew = (u32*)sqlite3_realloc(aRoot, nNew*sizeof(u32)); + if( aNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + nAlloc = nNew; + aRoot = aNew; + } + } + + if( rc==SQLITE_OK ){ + aRoot[nRoot++] = ii; + } + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(aRoot); + aRoot = 0; + nRoot = 0; + } + *paiRoot = aRoot; + *pnRoot = nRoot; + return rc; +} + +SQLITE_PRIVATE u64 sqlite3HctFileWriteCount(HctFile *pFile){ + return pFile->nPageAlloc; +} + +SQLITE_PRIVATE void sqlite3HctFileICArrays( + HctFile *pFile, + u8 **paLogic, u32 *pnLogic, + u8 **paPhys, u32 *pnPhys +){ + int rc = SQLITE_OK; + u32 nLogic = 0; + u32 nPhys = 0; + u8 *aLogic = 0; + u8 *aPhys = 0; + u32 ii; + + rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_LOGICAL_EOF, &nLogic); + if( rc==SQLITE_OK ){ + rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_PHYSICAL_EOF, &nPhys); + } + + if( rc==SQLITE_OK ){ + aLogic = (u8*)sqlite3HctMalloc(&rc, (nLogic + nPhys) * sizeof(u8)); + if( aLogic ){ + aPhys = &aLogic[nLogic]; + } + } + + for(ii=1; ii<=nLogic && rc==SQLITE_OK; ii++){ + u64 val; + rc = hctFilePagemapGetGrow(pFile, ii, &val); + if( rc==SQLITE_OK && (val & HCT_PMF_LOGICAL_IN_USE)==0 ){ + aLogic[ii-1] = 1; + } + } + for(ii=1; ii<=nPhys && rc==SQLITE_OK; ii++){ + u64 val; + rc = hctFilePagemapGetGrow(pFile, ii, &val); + if( rc==SQLITE_OK && (val & HCT_PMF_PHYSICAL_IN_USE)==0 ){ + aPhys[ii-1] = 1; + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(aLogic); + aLogic = aPhys = 0; + nLogic = nPhys = 0; + } + + *paLogic = aLogic; + *paPhys = aPhys; + *pnLogic = nLogic; + *pnPhys = nPhys; +} + +SQLITE_PRIVATE i64 sqlite3HctFileStats(sqlite3 *db, int iStat, const char **pzStat){ + i64 iVal = -1; + HctFile *pFile = sqlite3HctDbFile(sqlite3HctDbFind(db, 0)); + + switch( iStat ){ + case 0: + *pzStat = "cas_attempt"; + iVal = pFile->stats.nCasAttempt; + break; + case 1: + *pzStat = "cas_fail"; + iVal = pFile->stats.nCasFail; + break; + case 2: + *pzStat = "incr_attempt"; + iVal = pFile->stats.nIncrAttempt; + break; + case 3: + *pzStat = "incr_fail"; + iVal = pFile->stats.nIncrFail; + break; + case 4: + *pzStat = "mutex_attempt"; + iVal = pFile->stats.nMutex; + break; + case 5: + *pzStat = "mutex_block"; + iVal = pFile->stats.nMutexBlock; + break; + default: + break; + } + + return iVal; +} + +SQLITE_PRIVATE int sqlite3HctFileNFile(HctFile *pFile, int *pbFixed){ + int iRet = 0; + HctFileServer *p = pFile->pServer; + sqlite3_mutex_enter(p->pMutex); + iRet = p->nFdDb; + *pbFixed = (p->szPage>0); + sqlite3_mutex_leave(p->pMutex); + return iRet; +} + +/************************************************************************* +** Beginning of vtab implemetation. +*************************************************************************/ + +#define HCT_PGMAP_SCHEMA \ +" CREATE TABLE hct_pgmap(" \ +" slot INTEGER," \ +" value INTEGER," \ +" comment TEXT," \ +" physical_in_use BOOLEAN," \ +" logical_in_use BOOLEAN," \ +" logical_evicted BOOLEAN," \ +" logical_irrevicted BOOLEAN,"\ +" logical_is_root BOOLEAN" \ +" );" + +/* +** Virtual table type for "hctpgmap". +*/ +typedef struct pgmap_vtab pgmap_vtab; +struct pgmap_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; + +/* +** Virtual cursor type for "hctpgmap". +*/ +typedef struct pgmap_cursor pgmap_cursor; +struct pgmap_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + HctFile *pFile; /* Database to report on */ + u64 iMaxSlotno; /* Maximum page number for this scan */ + u64 slotno; /* The page-number/rowid value */ + u64 iVal; /* Value read from pagemap */ +}; + +/* +** The pgmapConnect() method is invoked to create a new +** template virtual table. +** +** Think of this routine as the constructor for pgmap_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the pgmap_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against the virtual table will look like. +*/ +static int pgmapConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + pgmap_vtab *pNew; + int rc; + + rc = sqlite3_declare_vtab(db, HCT_PGMAP_SCHEMA); + pNew = (pgmap_vtab*)sqlite3HctMalloc(&rc, sizeof(*pNew)); + if( pNew ){ + pNew->db = db; + } + + *ppVtab = (sqlite3_vtab*)pNew; + return rc; +} + +/* +** This method is the destructor for pgmap_vtab objects. +*/ +static int pgmapDisconnect(sqlite3_vtab *pVtab){ + pgmap_vtab *p = (pgmap_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new pgmap_cursor object. +*/ +static int pgmapOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + pgmap_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a pgmap_cursor. +*/ +static int pgmapClose(sqlite3_vtab_cursor *cur){ + pgmap_cursor *pCur = (pgmap_cursor*)cur; + sqlite3_free(pCur); + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int pgmapEof(sqlite3_vtab_cursor *cur){ + pgmap_cursor *pCur = (pgmap_cursor*)cur; + return pCur->slotno>pCur->iMaxSlotno; +} + +static int pgmapLoadSlot(pgmap_cursor *pCur){ + return hctFilePagemapGetGrow( + pCur->pFile, pCur->slotno, &pCur->iVal + ); +} + +/* +** Advance a hctdb_cursor to its next row of output. +*/ +static int pgmapNext(sqlite3_vtab_cursor *cur){ + pgmap_cursor *pCur = (pgmap_cursor*)cur; + pCur->slotno++; + return pgmapEof(cur) ? SQLITE_OK : pgmapLoadSlot(pCur); +} + +static void pgmapGetComment(sqlite3_context *ctx, i64 iSlot){ + const char *zText = 0; + + switch( iSlot ){ + case HCT_ROOTPAGE_SCHEMA: + zText = "ROOTPAGE_SCHEMA"; + break; + case HCT_ROOTPAGE_META: + zText = "ROOTPAGE_META"; + break; + case HCT_PAGEMAP_LOGICAL_EOF: + zText = "LOGICAL_EOF"; + break; + case HCT_PAGEMAP_PHYSICAL_EOF: + zText = "PHYSICAL_EOF"; + break; + case HCT_PAGEMAP_TRANSID_EOF: + zText = "TRANSID_EOF"; + break; + } + + if( zText ){ + sqlite3_result_text(ctx, zText, -1, SQLITE_TRANSIENT); + } +} + +/* +** Return values of columns for the row at which the pgmap_cursor +** is currently pointing. +*/ +static int pgmapColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + pgmap_cursor *pCur = (pgmap_cursor*)cur; + switch( i ){ + case 0: { /* slotno */ + sqlite3_result_int64(ctx, pCur->slotno); + break; + } + case 1: { /* pgno */ + sqlite3_result_int64(ctx, (pCur->iVal & 0xFFFFFFFF)); + break; + } + case 2: { /* pgno */ + pgmapGetComment(ctx, pCur->slotno); + break; + } + case 3: { /* physical_in_use */ + sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_PHYSICAL_IN_USE)?1:0); + break; + } + case 4: { /* logical_in_use */ + sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IN_USE)?1:0); + break; + } + case 5: { /* logical_evicted */ + sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_EVICTED)?1:0); + break; + } + case 6: { /* logical_irrevicted */ + sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IRREVICTED)?1:0); + break; + } + case 7: { /* logical_is_root */ + sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IS_ROOT)?1:0); + break; + } + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the slotno value. +*/ +static int pgmapRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + pgmap_cursor *pCur = (pgmap_cursor*)cur; + *pRowid = pCur->slotno; + return SQLITE_OK; +} + +/* +** This method is called to "rewind" the pgmap_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to pgmapColumn() or pgmapRowid() or +** pgmapEof(). +*/ +static int pgmapFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + pgmap_cursor *pCur = (pgmap_cursor*)pVtabCursor; + pgmap_vtab *pTab = (pgmap_vtab*)(pCur->base.pVtab); + int rc; + u64 max1; + u64 max2; + + pCur->pFile = sqlite3HctDbFile(sqlite3HctDbFind(pTab->db, 0)); + pCur->slotno = 1; + max1 = hctFilePagemapGet(pCur->pFile->pMapping, HCT_PAGEMAP_PHYSICAL_EOF); + max2 = hctFilePagemapGet(pCur->pFile->pMapping, HCT_PAGEMAP_LOGICAL_EOF); + max1 &= HCT_PGNO_MASK; + max2 &= HCT_PGNO_MASK; + pCur->iMaxSlotno = max1>max2 ? max1 : max2; + rc = pgmapLoadSlot(pCur); + return rc; +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int pgmapBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)10; + pIdxInfo->estimatedRows = 10; + return SQLITE_OK; +} + +/* +** This function is the implementation of the xUpdate callback used by +** hctpgmap virtual tables. It is invoked by SQLite each time a row is +** to be inserted, updated or deleted. +** +** A delete specifies a single argument - the rowid of the row to remove. +** +** Update and insert operations pass: +** +** 1. The "old" rowid (for an UPDATE), or NULL (for an INSERT). +** 2. The "new" rowid. +** 3. Values for each of the 6 columns. +** +** Specifically: +** +** apVal[2]: slot +** apVal[3]: value +** apVal[4]: comment +** apVal[5]: physical_in_use +** apVal[6]: logical_in_use +** apVal[7]: logical_evicted +** apVal[8]: logical_irrevicted +** apVal[9]: logical_is_root +*/ +static int pgmapUpdate( + sqlite3_vtab *pVtab, + int nVal, + sqlite3_value **apVal, + sqlite3_int64 *piRowid +){ + pgmap_vtab *p = (pgmap_vtab*)pVtab; + HctFile *pFile = sqlite3HctDbFile(sqlite3HctDbFind(p->db, 0)); + u32 iSlot = 0; + u64 val = 0; + u64 *pPtr = 0; + + i64 iValue = 0; + int bPhysicalInUse = 0; + int bLogicalInUse = 0; + int bLogicalEvicted = 0; + int bLogicalIrrevicted = 0; + int bLogicalIsRoot = 0; + + if( nVal==1 || sqlite3_value_type(apVal[0])!=SQLITE_INTEGER ){ + return SQLITE_CONSTRAINT; + } + iSlot = sqlite3_value_int64(apVal[0]); + + iValue = sqlite3_value_int64(apVal[3]); + bPhysicalInUse = sqlite3_value_int(apVal[5]); + bLogicalInUse = sqlite3_value_int(apVal[6]); + bLogicalEvicted = sqlite3_value_int(apVal[7]); + bLogicalIrrevicted = sqlite3_value_int(apVal[8]); + bLogicalIsRoot = sqlite3_value_int(apVal[9]); + + val = iValue & HCT_PAGEMAP_VMASK; + val |= (bPhysicalInUse ? HCT_PMF_PHYSICAL_IN_USE : 0); + val |= (bLogicalInUse ? HCT_PMF_LOGICAL_IN_USE : 0); + val |= (bLogicalEvicted ? HCT_PMF_LOGICAL_EVICTED : 0); + val |= (bLogicalIrrevicted ? HCT_PMF_LOGICAL_IRREVICTED : 0); + val |= (bLogicalIsRoot ? HCT_PMF_LOGICAL_IS_ROOT : 0); + + pPtr = hctPagemapPtr(pFile->pMapping, iSlot); + AtomicStore(pPtr, val); + + *piRowid = iSlot; + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3HctFileVtabInit(sqlite3 *db){ + static sqlite3_module pgmapModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ pgmapConnect, + /* xBestIndex */ pgmapBestIndex, + /* xDisconnect */ pgmapDisconnect, + /* xDestroy */ 0, + /* xOpen */ pgmapOpen, + /* xClose */ pgmapClose, + /* xFilter */ pgmapFilter, + /* xNext */ pgmapNext, + /* xEof */ pgmapEof, + /* xColumn */ pgmapColumn, + /* xRowid */ pgmapRowid, + /* xUpdate */ pgmapUpdate, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + return sqlite3_create_module(db, "hctpgmap", &pgmapModule, 0); +} + +SQLITE_PRIVATE int sqlite3HctIoerr(int rc){ + assert( 0 ); + abort(); + return rc; +} + + +/************** End of hct_file.c ********************************************/ +/************** Begin file hct_database.c ************************************/ +/* +** 2020 October 13 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +/* #include "hctInt.h" */ +/* #include "vdbeInt.h" */ +/* #include */ +/* #include */ + +typedef struct HctDatabase HctDatabase; +typedef struct HctDbIndexEntry HctDbIndexEntry; +typedef struct HctDbIndexLeaf HctDbIndexLeaf; +typedef struct HctDbIndexNode HctDbIndexNode; +typedef struct HctDbIndexNodeEntry HctDbIndexNodeEntry; +typedef struct HctDbIndexNodeHdr HctDbIndexNodeHdr; +typedef struct HctDbIntkeyEntry HctDbIntkeyEntry; +typedef struct HctDbIntkeyLeaf HctDbIntkeyLeaf; +typedef struct HctDbIntkeyNodeEntry HctDbIntkeyNodeEntry; +typedef struct HctDbIntkeyNode HctDbIntkeyNode; +typedef struct HctDbKey HctDbKey; +typedef struct HctDbLeaf HctDbLeaf; +typedef struct HctDbLeafHdr HctDbLeafHdr; +typedef struct HctDbWriter HctDbWriter; +typedef struct HctDbPageHdr HctDbPageHdr; +typedef struct HctDbHistoryFan HctDbHistoryFan; +typedef struct HctDbRangeCsr HctDbRangeCsr; + +typedef struct HctCsrIntkeyOp HctCsrIntkeyOp; +typedef struct HctCsrIndexOp HctCsrIndexOp; + +typedef struct HctDbPageArray HctDbPageArray; + +struct HctCsrIntkeyOp { + HctCsrIntkeyOp *pNextOp; + i64 iFirst; + i64 iLast; + + u32 iLogical; + u32 iPhysical; +}; + +struct HctCsrIndexOp { + HctCsrIndexOp *pNextOp; + u8 *pFirst; + int nFirst; + u8 *pLast; + int nLast; + + u32 iLogical; + u32 iPhysical; +}; + +struct CsrIntkey { + HctCsrIntkeyOp *pOpList; + HctCsrIntkeyOp *pCurrentOp; +}; +struct CsrIndex { + HctCsrIndexOp *pOpList; + HctCsrIndexOp *pCurrentOp; +}; + +struct HctDbKey { + i64 iKey; /* Integer key value */ + UnpackedRecord *pKey; /* Index key value */ + HctBuffer buf; /* Buffer for pKey data (if required) */ +}; + +/* +** eRange: +** Set to one of the HCT_RANGE_* constants defined below. +*/ +struct HctDbRangeCsr { + HctDbKey lowkey; + HctDbKey highkey; + u64 iRangeTid; /* The range TID that was followed here */ + + int eRange; /* HCT_RANGE_* constant */ + int iCell; + HctFilePage pg; +}; + +#define HCT_RANGE_FOLLOW 0 /* Follow range-pointers only */ +#define HCT_RANGE_MERGE 1 /* Merge in data + follow range-pointers */ +#define HCT_RANGE_FAN 2 /* HctDbRangeCsr.pg is a fan page */ + +#define IS_HCT_MIGRATE(pDb) (pDb->pConfig->db->bHctMigrate) + +/* +** iRoot: +** Logical root page of tree structure that this cursor is open on. +** +** pKeyInfo: +** NULL for cursors open on intkey trees, otherwise points to the +** KeyInfo used to compare keys in the open index tree. For cursors +** opened by the user, this is set when the cursor is opened within +** sqlite3HctDbCsrOpen() and never modified. +** +** pRec: +** UnpackedRecord structure suitable for use with pKeyInfo. This is +** allocated the first time it is required and then retained for +** the lifetime of the HctDbCsr structure. +** +** eDir: +** One of BTREE_DIR_NONE, BTREE_DIR_FORWARD or BTREE_DIR_REVERSE. +** +** pIntkeyOps: +*/ +struct HctDbCsr { + HctDatabase *pDb; /* Database that owns this cursor */ + u32 iRoot; /* Root page cursor is opened on */ + KeyInfo *pKeyInfo; + UnpackedRecord *pRec; + int eDir; /* Direction cursor will step after Seek() */ + int bNosnap; /* The "no-snapshot" flag */ + + u8 *aRecord; /* Record in allocated memory */ + int nRecord; /* Size of aRecord[] in bytes */ + HctBuffer rec; /* Buffer used to manage aRecord[] */ + + struct CsrIntkey intkey; + struct CsrIndex index; + HctDbCsr *pNextScanner; + + int iCell; /* Current cell within page */ + HctFilePage pg; /* Current leaf page */ + + int nRange; + int nRangeAlloc; + HctDbRangeCsr *aRange; +}; + +#define HCTDB_MAX_DIRTY (HCTDB_MAX_PAGEARRAY-2) +// #define HCTDB_MAX_DIRTY (HCTDB_STATIC_PAGEARRAY-2) +#define HCTDB_MAX_PAGEARRAY 2048 +#define HCTDB_STATIC_PAGEARRAY (8+2) + +#define HCTDB_APPEND_MODE_THRESHOLD 5 + + +#define LARGEST_TID ((((u64)1)<<56)-1) +#define HCT_TID_ROLLBACK_OVERRIDE (((u64)0x01) << 56) + + +struct HctDbPageArray { + int nPg; + HctFilePage *aPg; + HctFilePage aStatic[HCTDB_STATIC_PAGEARRAY]; + HctFilePage *aDyn; + int nDyn; +}; + +typedef struct HctDbOverflow HctDbOverflow; +typedef struct HctDbOverflowArray HctDbOverflowArray; + +struct HctDbOverflow { + u32 pgno; + int nOvfl; +}; + +struct HctDbOverflowArray { + int nEntry; + int nAlloc; + HctDbOverflow *aOvfl; +}; + +typedef struct HctDbFPKey HctDbFPKey; +struct HctDbFPKey { + i64 iKey; + u8 *aKey; + HctBuffer buf; +}; + +/* +** +** iHeight: +** The height of the list that this writer is writing to. 0 for leaves, +** 1 for the parents of leaves, etc. +** +** aWritePg/nWritePg: +** +** nWriteKey: +** Number of hctDbInsert() calls since last flush - i.e. how many have to +** be retried if we hit a CAS failure and have to redo this write operation. +** +** iWriteFpKey/aWriteFpKey: +** These two variables store the fence-post key for the peer page of +** the rightmost page in the aWritePg[] array - aWritePg[nWritePg-1]. +** For intkey tables, iWriteFpKey is the 64-bit integer key value. For +** index tables, aWriteFpKey points to a buffer containing the FP key, +** and iWriteFpKey its size in bytes. The buffer is allocated with +** sqlite3_malloc(). +** +** If there is no peer page and writing to an intkey list, iWriteFpKey +** is set to LARGEST_INT64. If writing to an index list, aWriteFpKey is +** set to NULL and iWriteFpKey to 0. +** +** discardpg: +** Pages to the right of writepg[0] that will be removed from the list +** if the CAS instruction for this write succeeds. +** +** bAppend: +** True if the writer is in append mode. +** +** bDoCleanup: +** True if hctDbInsert() has been called since the most recent +** hctDbWriterCleanup(). +*/ +struct HctDbWriter { + int iHeight; /* Height to write at (0==leaves) */ + HctDbPageArray writepg; + int nWriteKey; /* Number of new keys in writepg array */ + + int bAppend; /* Writer is in "append" mode */ + HctDbFPKey fp; /* Fence-Post key. */ + + HctDbCsr writecsr; /* Used to find target page while writing */ + HctDbPageArray discardpg; + HctFilePage fanpg; + + int bDoCleanup; + int nEvictLocked; + u32 iEvictLockedPgno; + + HctDbOverflowArray delOvfl; /* Overflow chains to free on write */ + HctDbOverflowArray insOvfl; /* Overflow chains to free on don't-write */ + + int nOverflow; + + int nMigrateKey; +}; + +/* +** This is used by the rebalance operation implemented by hctDbBalance(). +** The first step of that operation is to assemble an array of these +** structures - one for each cell that will be distributed between the +** output pages. +** +** nByte: +** Total bytes of space required by cell on new page. This includes +** the header entry and the data stored in the cell area. +** +** aEntry: +** Pointer to buffer containing cell entry. Or NULL to indicate that +** the HctDbCellSz structure corresponds to a new cell being written +** (that is not on any input page). +** +** aCell: +** Only valid if (aEntry!=0). Pointer to buffer containing leaf-page +** portion of cell. +*/ +typedef struct HctDbCellSz HctDbCellSz; +struct HctDbCellSz { + int nByte; /* Size of cell in bytes */ + u8 *aEntry; /* Buffer containing cell entry */ + u8 *aCell; /* Buffer containing cell body */ +}; + +typedef struct HctBalance HctBalance; +struct HctBalance { + u8 *aPg[3]; + int nSzAlloc; /* Allocated size of aSz[] array */ + HctDbCellSz *aSz; /* aSz[] array */ +}; + +/* +** Given the database page-size as an argument, the maximum number of cells +** that may fit on any page with variable sized entries (an index leaf or node, +** or intkey leaf page). +*/ +#define MAX_CELLS_PER_PAGE(pgsz) ((pgsz) / 8) + +/* +** This structure, an instance of which is part of each HctDatabase object, +** holds counters collected for the hctstats structure. +*/ +typedef struct HctDatabaseStats HctDatabaseStats; +struct HctDatabaseStats { + i64 nBalanceIntkey; + i64 nBalanceIndex; + i64 nBalanceSingle; + i64 nTMapLookup; + i64 nUpdateInPlace; + i64 nInternalRetry; +}; + +/* +** pScannerList: +** Linked list of cursors used by the current transaction. If this turns +** out to be a write transaction, this list is used to detect read/write +** conflicts. +** +** iJrnlWriteCid: +** This value is set within calls to sqlite3_hct_journal_write(). The CID +** of the journal entry being written to the db. +*/ +struct HctDatabase { + HctFile *pFile; + HctConfig *pConfig; + i64 nCasFail; /* Number cas-collisions so far */ + int pgsz; /* Page size in bytes */ + + u8 *aTmp; /* Temp buffer pgsz bytes in size */ + HctBalance *pBalance; /* Space for hctDbBalance() */ + + HctDbCsr *pScannerList; + + u64 iJrnlWriteCid; + + HctTMap *pTmap; /* Transaction map (non-NULL if trans open) */ + u64 iSnapshotId; /* Snapshot id for reading */ + u64 iLocalMinTid; + HctDbWriter pa; + HctDbCsr rbackcsr; /* Used to find old values during rollback */ + u64 iTid; /* Transaction id for writing */ + u64 nWriteCount; /* Write-count at start of commit */ + + int eMode; /* HCT_MODE_XXX constant */ + int bConcurrent; /* Collect validation information */ + + int (*xSavePhysical)(void*, i64); + void *pSavePhysical; + + HctDatabaseStats stats; +}; + +/* +** Values for HctDatabase.eMode. +*/ +#define HCT_MODE_NORMAL 0 +#define HCT_MODE_ROLLBACK 1 +#define HCT_MODE_VALIDATE 3 + + +/* +** 8-byte database page header. Described in fileformat.wiki. +*/ +struct HctDbPageHdr { + u8 hdrFlags; + u8 nHeight; /* 0 for leaves, 1 for parents etc. */ + u16 nEntry; + u32 iPeerPg; +}; + +/* +** Page types. These are the values that may appear in the page-type +** field of a page header. +*/ +#define HCT_PAGETYPE_INTKEY 0x01 +#define HCT_PAGETYPE_INDEX 0x03 +#define HCT_PAGETYPE_OVERFLOW 0x05 +#define HCT_PAGETYPE_HISTORY 0x06 + +#define HCT_PAGETYPE_MASK 0x07 + +/* +** Page types may be ORed with the following: +*/ +#define HCT_PAGETYPE_LEFTMOST 0x80 + +#define hctPagetype(p) (((HctDbPageHdr*)(p))->hdrFlags&HCT_PAGETYPE_MASK) +#define hctIsLeftmost(p) (((HctDbPageHdr*)(p))->hdrFlags&HCT_PAGETYPE_LEFTMOST) +#define hctPageheight(p) (((HctDbPageHdr*)(p))->nHeight) +#define hctPagenentry(p) (((HctDbPageHdr*)(p))->nEntry) +#define hctPagePeer(p) (((HctDbPageHdr*)(p))->iPeerPg) + +/* +** 16-byte leaf page header. Used by both index and intkey leaf pages. +** Described in fileformat.wiki. +*/ +struct HctDbLeafHdr { + u16 nFreeGap; /* Size of free-space region, in bytes */ + u16 nFreeBytes; /* Total free bytes on page */ + u32 unused; +}; + +struct HctDbLeaf { + HctDbPageHdr pg; + HctDbLeafHdr hdr; +}; + + +struct HctDbIntkeyEntry { + u32 nSize; /* 0: Total size of data (local+overflow) */ + u16 iOff; /* 4: Offset of record within this page */ + u8 flags; /* 6: Flags (see below) */ + u8 unused; /* 7: */ + i64 iKey; /* 8: Integer key value */ +}; + +struct HctDbIndexEntry { + u32 nSize; /* 0: Total size of data (local+overflow) */ + u16 iOff; /* 4: Offset of record within this page */ + u8 flags; /* 6: Flags (see below) */ + u8 unused; /* 7: */ +}; + +struct HctDbIndexNodeEntry { + u32 nSize; + u16 iOff; + u8 flags; + u8 unused; + u32 iChildPg; +}; + +struct HctDbIntkeyNodeEntry { + i64 iKey; /* Value of FP key on page iChild */ + u32 iChildPg; /* Child page */ + u32 unused; +}; + +struct HctDbIntkeyNode { + HctDbPageHdr pg; + HctDbIntkeyNodeEntry aEntry[0]; +}; + +struct HctDbIntkeyLeaf { + HctDbPageHdr pg; + HctDbLeafHdr hdr; + HctDbIntkeyEntry aEntry[0]; +}; + +struct HctDbIndexLeaf { + HctDbPageHdr pg; + HctDbLeafHdr hdr; + HctDbIndexEntry aEntry[0]; +}; + +struct HctDbIndexNodeHdr { + u16 nFreeGap; /* Size of free-space region, in bytes */ + u16 nFreeBytes; /* Total free bytes on page */ +}; + +struct HctDbIndexNode { + HctDbPageHdr pg; + HctDbIndexNodeHdr hdr; + HctDbIndexNodeEntry aEntry[0]; +}; + +/* +** History fanout page. +** +** iSplit0: +** The index of a key in page aPgOld1[0]. This key is the first that +** should be considered in aPgOld1[0]. Implying that no key equal to +** or greater than this from pgOld0 should be considered. +*/ +struct HctDbHistoryFan { + HctDbPageHdr pg; + + u64 iRangeTid0; + u64 iFollowTid0; + u32 pgOld0; + + int iSplit0; + + u64 iRangeTid1; + u32 aPgOld1[0]; +}; + +/* +** Structure for reading/writing cells from and to pages. +*/ +typedef struct HctDbCell HctDbCell; +struct HctDbCell { + u64 iTid; + u64 iRangeTid; + u32 iRangeOld; + u32 iOvfl; + const u8 *aPayload; +}; + +#if 1 +__attribute__ ((noinline)) +static void hctMemcpy(void *a, const void *b, size_t c){ + if( c ) memcpy(a, b, c); +} +#else +# define hctMemcpy memcpy +#endif + + + +/* +** Flags for HctDbIntkeyEntry.flags +*/ +#define HCTDB_HAS_TID 0x01 /* 8 bytes */ +#define HCTDB_HAS_OVFL 0x04 /* 4 bytes */ +#define HCTDB_HAS_RANGETID 0x08 /* 8 bytes */ +#define HCTDB_HAS_RANGEOLD 0x10 /* 4 bytes */ + +#define HCTDB_MAX_EXTRA_CELL_DATA (8+4+8+4) + +SQLITE_PRIVATE int sqlite3HctBufferGrow(HctBuffer *pBuf, int nSize){ + int rc = SQLITE_OK; + if( nSize>pBuf->nAlloc ){ + u8 *aNew = sqlite3_realloc(pBuf->aBuf, nSize); + if( aNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + pBuf->aBuf = aNew; + pBuf->nAlloc = nSize; + } + } + return rc; +} + +SQLITE_PRIVATE void sqlite3HctBufferFree(HctBuffer *pBuf){ + sqlite3_free(pBuf->aBuf); + memset(pBuf, 0, sizeof(HctBuffer)); +} + +static int hctBufferSet(HctBuffer *pBuf, const u8 *aData, int nData){ + int rc = sqlite3HctBufferGrow(pBuf, nData); + if( rc==SQLITE_OK ){ + hctMemcpy(pBuf->aBuf, aData, nData); + } + return rc; +} + + +#ifdef SQLITE_DEBUG +static int hctSqliteBusy(int iLine){ + return SQLITE_BUSY_SNAPSHOT; +} +# define HCT_SQLITE_BUSY hctSqliteBusy(__LINE__) +#else +# define HCT_SQLITE_BUSY SQLITE_BUSY_SNAPSHOT +#endif /* SQLITE_DEBUG */ + +static u64 hctDbTMapLookup(HctDatabase *pDb, u64 iTid, u64 *peState){ + u64 iVal = 0; + HctTMap *pTmap = pDb->pTmap; + if( iTid==LARGEST_TID ){ + *peState = HCT_TMAP_ROLLBACK; + }else if( iTidiFirstTid ){ + *peState = HCT_TMAP_COMMITTED; + }else{ + int iMap = (iTid - pTmap->iFirstTid) / HCT_TMAP_PAGESIZE; + + if( iMap>=pTmap->nMap ){ + HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); + sqlite3HctTMapUpdate(pTMapClient, &pDb->pTmap); + assert( iTid<(pDb->pTmap->nMap*HCT_TMAP_PAGESIZE)+pDb->pTmap->iFirstTid ); + return hctDbTMapLookup(pDb, iTid, peState); + } + + { + int iOff = (iTid - pTmap->iFirstTid) % HCT_TMAP_PAGESIZE; + iOff = HCT_TMAP_ENTRYSLOT(iOff); + iVal = AtomicLoad(&pTmap->aaMap[iMap][iOff]); + pDb->stats.nTMapLookup++; + } + + *peState = (iVal & HCT_TMAP_STATE_MASK); + } + return (iVal & HCT_TMAP_CID_MASK); +} + + +static void print_out_tmap(HctDatabase *pDb, int nLimit){ + int ii; + + for(ii=0; iipTmap->iFirstTid + ii; + u64 iCid = hctDbTMapLookup(pDb, iTid, &eState); + + printf("tid=%d -> (%s, %d)\n", (int)iTid, + eState==HCT_TMAP_WRITING ? "WRITING" : + eState==HCT_TMAP_VALIDATING ? "VALIDATING" : + eState==HCT_TMAP_ROLLBACK ? "ROLLBACK" : + eState==HCT_TMAP_COMMITTED ? "COMMITTED" : "???", + (int)iCid + ); + } + +} + +static void hctDbPageArrayReset(HctDbPageArray *pArray){ + sqlite3_free(pArray->aDyn); + pArray->nPg = 0; + pArray->aPg = pArray->aStatic; + pArray->aDyn = 0; + pArray->nDyn = 0; +} + +static int hctDbPageArrayGrow(HctDbPageArray *pArray){ + assert( pArray->aDyn==0 ); + pArray->aDyn = sqlite3MallocZero(sizeof(HctFilePage) * HCTDB_MAX_PAGEARRAY); + if( pArray->aDyn==0 ){ + return SQLITE_NOMEM_BKPT; + } + pArray->nDyn = HCTDB_MAX_PAGEARRAY; + pArray->aPg = pArray->aDyn; + hctMemcpy(pArray->aPg, pArray->aStatic, + sizeof(HctFilePage)*HCTDB_STATIC_PAGEARRAY + ); + return SQLITE_OK; +} + +/* +** Grow the dynamic arrays used by the writer, if necessary +*/ +static int hctDbWriterGrow(HctDbWriter *pWriter){ + int rc = SQLITE_OK; + if( pWriter->writepg.aDyn==0 ){ + if( pWriter->writepg.nPg>=(HCTDB_STATIC_PAGEARRAY-2) + || pWriter->discardpg.nPg>=(HCTDB_STATIC_PAGEARRAY-2) + ){ + rc = hctDbPageArrayGrow(&pWriter->writepg); + if( rc==SQLITE_OK ){ + rc = hctDbPageArrayGrow(&pWriter->discardpg); + } + } + } + return rc; +} + +SQLITE_PRIVATE HctDatabase *sqlite3HctDbOpen( + int *pRc, + const char *zFile, + HctConfig *pConfig +){ + int rc = *pRc; + HctDatabase *pNew = 0; + + pNew = (HctDatabase*)sqlite3HctMalloc(&rc, sizeof(*pNew)); + if( pNew ){ + pNew->pFile = sqlite3HctFileOpen(&rc, zFile, pConfig); + pNew->pConfig = pConfig; + if( pNew->pFile ) pNew->pgsz = sqlite3HctFilePgsz(pNew->pFile); + } + + if( rc!=SQLITE_OK ){ + sqlite3HctDbClose(pNew); + pNew = 0; + } + + *pRc = rc; + return pNew; +} + +SQLITE_PRIVATE int sqlite3HctDbPagesize(HctDatabase *pDb){ + return pDb->pgsz; +} + + +SQLITE_PRIVATE void sqlite3HctDbClose(HctDatabase *p){ + if( p ){ + sqlite3_free(p->aTmp); + sqlite3HctFileClose(p->pFile); + p->pFile = 0; + sqlite3_free(p->pBalance); + sqlite3_free(p); + } +} + +SQLITE_PRIVATE HctFile *sqlite3HctDbFile(HctDatabase *pDb){ + return pDb->pFile; +} + +SQLITE_PRIVATE int sqlite3HctDbRootNew(HctDatabase *p, u32 *piRoot){ + return sqlite3HctFileRootPgno(p->pFile, piRoot); +} + +SQLITE_PRIVATE int sqlite3HctDbRootFree(HctDatabase *p, u32 iRoot){ + return sqlite3HctFileRootFree(p->pFile, iRoot); +} + +SQLITE_PRIVATE void sqlite3HctDbRootPageInit( + int bIndex, /* True for an index, false for intkey */ + u8 *aPage, /* Buffer to initialize */ + int szPage /* Size of aPage[] in bytes */ +){ + HctDbLeaf *pLeaf = (HctDbLeaf*)aPage; + memset(aPage, 0, szPage); + if( bIndex ){ + pLeaf->pg.hdrFlags = HCT_PAGETYPE_INDEX | HCT_PAGETYPE_LEFTMOST; + }else{ + pLeaf->pg.hdrFlags = HCT_PAGETYPE_INTKEY | HCT_PAGETYPE_LEFTMOST; + } + pLeaf->hdr.nFreeBytes = szPage - sizeof(HctDbLeaf); + pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; +} + +static void hctDbRootPageInit( + int bIndex, /* True for an index, false for intkey */ + int nHeight, /* Initial height */ + u32 iChildPg, /* Child page number */ + u8 *aPage, /* Buffer to initialize */ + int szPage /* Size of aPage[] in bytes */ +){ + HctDbPageHdr *pPg = (HctDbPageHdr*)aPage; + memset(aPage, 0, szPage); + if( bIndex ){ + pPg->hdrFlags = HCT_PAGETYPE_INDEX | HCT_PAGETYPE_LEFTMOST; + }else{ + pPg->hdrFlags = HCT_PAGETYPE_INTKEY | HCT_PAGETYPE_LEFTMOST; + } + if( nHeight>0 ){ + pPg->nHeight = nHeight; + pPg->nEntry = 1; + if( bIndex ){ + HctDbIndexNode *pNode = (HctDbIndexNode*)pPg; + pNode->aEntry[0].iChildPg = iChildPg; + pNode->hdr.nFreeBytes = + szPage - sizeof(HctDbIndexNode) - sizeof(HctDbIndexNodeEntry); + pNode->hdr.nFreeGap = pNode->hdr.nFreeBytes; + }else{ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pPg; + pNode->aEntry[0].iKey = SMALLEST_INT64; + pNode->aEntry[0].iChildPg = iChildPg; + } + }else{ + HctDbLeaf *pLeaf = (HctDbLeaf*)pPg; + pLeaf->hdr.nFreeBytes = szPage - sizeof(HctDbLeaf); + pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; + } +} + +/* +** Open a read transaction, if one is not already open. +*/ +SQLITE_PRIVATE int sqlite3HctDbStartRead(HctDatabase *pDb, HctJournal *pJrnl){ + int rc = SQLITE_OK; + + assert( (pDb->iSnapshotId==0)==(pDb->pTmap==0) ); + assert( pDb->iSnapshotId!=0 || pDb->bConcurrent==0 ); + if( pDb->iSnapshotId==0 && SQLITE_OK==(rc=sqlite3HctFileNewDb(pDb->pFile)) ){ + if( pDb->aTmp==0 ){ + pDb->pgsz = sqlite3HctFilePgsz(pDb->pFile); + pDb->aTmp = (u8*)sqlite3HctMalloc(&rc, pDb->pgsz); + } + if( rc==SQLITE_OK ){ + u64 iSnapshot = 0; + HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); + + iSnapshot = sqlite3HctJournalSnapshot(pJrnl); + rc = sqlite3HctTMapBegin(pTMapClient, iSnapshot, &pDb->pTmap); + assert( rc==SQLITE_OK ); /* todo */ + + iSnapshot = sqlite3HctJournalSnapshot(pJrnl); + if( iSnapshot==0 ){ + iSnapshot = sqlite3HctFileGetSnapshotid(pDb->pFile); + } + pDb->iSnapshotId = iSnapshot; + pDb->iLocalMinTid = sqlite3HctTMapCommitedTID(pTMapClient); + assert( pDb->iSnapshotId>0 ); + } + } + + return rc; +} + +static u64 hctGetU64(const u8 *a){ + u64 ret; + hctMemcpy(&ret, a, sizeof(u64)); + return ret; +} +static u32 hctGetU32(const u8 *a){ + u32 ret; + hctMemcpy(&ret, a, sizeof(u32)); + return ret; +} + +static void hctPutU32(u8 *a, u32 val){ + hctMemcpy(a, &val, sizeof(u32)); +} + +/* +** Return true if TID iTid maps to a commit-id visible to the current +** client. Or false otherwise. +*/ +static int hctDbTidIsVisible(HctDatabase *pDb, u64 iTid, int bNosnap){ + + if( (iTid & HCT_TID_MASK)<=pDb->iLocalMinTid ) return 1; + while( 1 ){ + u64 eState = 0; + u64 iCid = hctDbTMapLookup(pDb, (iTid & HCT_TID_MASK), &eState); + if( iTid & HCT_TID_ROLLBACK_OVERRIDE ){ + eState = HCT_TMAP_COMMITTED; + } + if( eState==HCT_TMAP_WRITING || eState==HCT_TMAP_ROLLBACK ){ + return 0; + } + if( eState==HCT_TMAP_COMMITTED ){ + if( bNosnap==0 && iCid>pDb->iSnapshotId ){ + return 0; + } + return 1; + } + assert( eState==HCT_TMAP_VALIDATING ); + if( iCid>pDb->iSnapshotId || iTid==pDb->iTid ){ + return 0; + } + } + + assert( 0 ); + return 0; +} + +/* +** This is called when writing keys to the database as part of committing +** a transaction. One of the writes will clobber a key associated with +** transaction-id iTid. This function returns true if this represents +** a write/write conflict and the transaction should be rolled back, or +** false if the write should proceed. +*/ +static int hctDbTidIsConflict(HctDatabase *pDb, u64 iTid){ + if( iTid==pDb->iTid || iTid<=pDb->iLocalMinTid || iTid==LARGEST_TID ){ + return 0; + }else{ + u64 eState = 0; + u64 iCid = hctDbTMapLookup(pDb, iTid & HCT_TID_MASK, &eState); + + /* This should only be called while writing or validating. */ + assert( pDb->iTid ); + if( iTid & HCT_TID_ROLLBACK_OVERRIDE ){ + eState = HCT_TMAP_COMMITTED; + } + + if( eState==HCT_TMAP_COMMITTED && iCid<=pDb->iSnapshotId ) return 0; + if( iCid==pDb->iJrnlWriteCid ) return 0; + return 1; + + if( eState==HCT_TMAP_WRITING || eState==HCT_TMAP_VALIDATING ) return 1; + + /* It's tempting to return 0 here - how can a key that has been rolled + ** back be a conflict? The problem is that the previous version of the + ** key - the one before this rolled back version - may be a write/write + ** conflict. Ideally, this code would check that and return accordingly. */ + if( eState==HCT_TMAP_ROLLBACK ) return 1; + + assert( eState==HCT_TMAP_COMMITTED ); + return (iCid > pDb->iSnapshotId); + } +} + + +static int hctDbOffset(int iOff, int flags){ + static const int aVal[] = { + 0+0+0+0+0, 0+0+0+0+8, 0+0+0+0+0, 0+0+0+0+8, + 0+0+4+0+0, 0+0+4+0+8, 0+0+4+0+0, 0+0+4+0+8, + 0+8+0+0+0, 0+8+0+0+8, 0+8+0+0+0, 0+8+0+0+8, + 0+8+4+0+0, 0+8+4+0+8, 0+8+4+0+0, 0+8+4+0+8, + + 4+0+0+0+0, 4+0+0+0+8, 4+0+0+0+0, 4+0+0+0+8, + 4+0+4+0+0, 4+0+4+0+8, 4+0+4+0+0, 4+0+4+0+8, + 4+8+0+0+0, 4+8+0+0+8, 4+8+0+0+0, 4+8+0+0+8, + 4+8+4+0+0, 4+8+4+0+8, 4+8+4+0+0, 4+8+4+0+8, + }; + + assert( HCTDB_HAS_RANGEOLD==0x10 ); /* +4 */ + assert( HCTDB_HAS_RANGETID==0x08 ); /* +8 */ + assert( HCTDB_HAS_OVFL==0x04 ); /* +4 */ + assert( HCTDB_HAS_TID==0x01 ); /* +8 */ + + assert( aVal[ flags & 0x1F ]==( + ((flags & HCTDB_HAS_TID) ? 8 : 0) + + ((flags & HCTDB_HAS_RANGETID) ? 8 : 0) + + ((flags & HCTDB_HAS_RANGEOLD) ? 4 : 0) + + ((flags & HCTDB_HAS_OVFL) ? 4 : 0) + )); + + return iOff + aVal[ flags&0x1F ]; +} + + +/* +** Wrapper around sqlite3HctFilePageGetPhysical() that also invokes the +** xSavePhysical callback, if one is configured. +*/ +static int hctDbGetPhysical(HctDatabase *pDb, u32 iPg, HctFilePage *pPg){ + int rc = sqlite3HctFilePageGetPhysical(pDb->pFile, iPg, pPg); + if( rc==SQLITE_OK && pDb->xSavePhysical ){ + rc = pDb->xSavePhysical(pDb->pSavePhysical, (i64)iPg); + } + return rc; +} + +/* +** Load the meta-data record from the database and store it in buffer aBuf +** (size nBuf bytes). The meta-data record is stored with rowid=0 int the +** intkey table with root-page=2. +*/ +SQLITE_PRIVATE int sqlite3HctDbGetMeta(HctDatabase *pDb, u8 *aBuf, int nBuf){ + HctFilePage pg; + int rc; + + assert( pDb->iSnapshotId ); + memset(aBuf, 0, nBuf); + rc = sqlite3HctFilePageGet(pDb->pFile, 2, &pg); + while( rc==SQLITE_OK ){ + HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)pg.aOld; + int iOff; + u8 flags; + + if( pLeaf->pg.nEntry==0 ){ + break; + } + + assert( pLeaf->pg.nEntry==1 ); + assert( pLeaf->aEntry[0].iKey==0 ); + assert( pLeaf->aEntry[0].nSize==nBuf ); + iOff = pLeaf->aEntry[0].iOff; + flags = pLeaf->aEntry[0].flags; + + assert( flags==HCTDB_HAS_TID + || flags==(HCTDB_HAS_RANGEOLD|HCTDB_HAS_RANGETID|HCTDB_HAS_TID) + ); + if( (flags & HCTDB_HAS_RANGEOLD) + && 0==hctDbTidIsVisible(pDb, hctGetU64(&pg.aOld[iOff]), 0) + ){ + u32 iOld = hctGetU32(&pg.aOld[iOff+8+8]); + if( iOld==0 ) break; + sqlite3HctFilePageRelease(&pg); + rc = hctDbGetPhysical(pDb, iOld, &pg); + }else{ + iOff = hctDbOffset(iOff, pLeaf->aEntry[0].flags ); + hctMemcpy(aBuf, &pg.aOld[iOff], nBuf); + sqlite3HctFilePageRelease(&pg); + break; + } + } + + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbTransIsConcurrent(HctDatabase *pDb, int eConcurrent){ + pDb->bConcurrent = (eConcurrent!=0); +} + +static int hctDbValidateMeta(HctDatabase *pDb){ + int rc = SQLITE_OK; + HctFilePage pg; + + assert( pDb->iSnapshotId>0 ); + rc = sqlite3HctFilePageGet(pDb->pFile, 2, &pg); + if( rc==SQLITE_OK ){ + HctDbIntkeyEntry *p = &((HctDbIntkeyLeaf*)pg.aOld)->aEntry[0]; + if( p->flags & HCTDB_HAS_TID ){ + u64 iTid = hctGetU64(&pg.aOld[p->iOff]); + if( hctDbTidIsConflict(pDb, iTid) ) rc = HCT_SQLITE_BUSY; + } + sqlite3HctFilePageRelease(&pg); + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbRootInit(HctDatabase *p, int bIndex, u32 iRoot){ + HctFilePage pg; + int rc = SQLITE_OK; + + rc = sqlite3HctFileRootNew(p->pFile, iRoot, &pg); + if( rc==SQLITE_OK ){ + sqlite3HctDbRootPageInit(bIndex, pg.aNew, p->pgsz); + rc = sqlite3HctFilePageRelease(&pg); + } + return rc; +} + +static i64 hctDbIntkeyFPKey(const void *aPg){ + if( ((HctDbPageHdr*)aPg)->nHeight==0 ){ + return ((HctDbIntkeyLeaf*)aPg)->aEntry[0].iKey; + } + return ((HctDbIntkeyNode*)aPg)->aEntry[0].iKey; +} + + +static i64 hctDbGetIntkey(const u8 *aTarget, int iCell){ + assert( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ); + assert( hctPageheight(aTarget)==0 ); + assert( iCell>=0 && iCell<((HctDbIntkeyLeaf*)aTarget)->pg.nEntry ); + + return ((HctDbIntkeyLeaf*)aTarget)->aEntry[iCell].iKey; +} + +#if 0 +static i64 hctDbGetIntkeyFromPhys( + int *pRc, + HctDatabase *pDb, + u32 iPhys, + int iCell +){ + i64 iRet = 0; + int rc = *pRc; + if( rc==SQLITE_OK ){ + HctFilePage pg; + rc = sqlite3HctFilePageGetPhysical(pDb->pFile, iPhys, &pg); + if( rc==SQLITE_OK ){ + iRet = hctDbGetIntkey(pg.aOld, iCell); + sqlite3HctFilePageRelease(&pg); + } + } + *pRc = rc; + return iRet; +} +#endif + + +/* +** Buffer aPg contains an intkey leaf page. +** +** This function searches the leaf page for key iKey. If found, it returns +** the index of the matching key within the page and sets output variable +** (*pbExact) to 1. If there is no match for key iKey, this function returns +** the index of the smallest key on the page that is larger than iKey, or +** (nEntry) if all keys on the page are smaller than iKey. (*pbExact) is +** set to 0 before returning in this case. +*/ +static int hctDbIntkeyLeafSearch( + const u8 *aPg, + i64 iKey, + int *pbExact +){ + const HctDbIntkeyLeaf *pLeaf = (const HctDbIntkeyLeaf*)aPg; + int i1 = 0; + int i2 = pLeaf->pg.nEntry; + + assert( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ); + assert( pLeaf->pg.nHeight==0 ); + while( i2>i1 ){ + int iTest = (i1+i2)/2; + i64 iPgKey = pLeaf->aEntry[iTest].iKey; + if( iPgKey==iKey ){ + *pbExact = 1; + return iTest; + }else if( iPgKey=0 ); + assert( i2==pLeaf->pg.nEntry || iKeyaEntry[i2].iKey ); + assert( i2==0 || iKey>pLeaf->aEntry[i2-1].iKey ); + + *pbExact = 0; + return i2; +} + +static int hctDbIntkeyLocalsize(int pgsz, int nSize){ + const int nMax = ( + pgsz - + sizeof(HctDbIntkeyLeaf) - + sizeof(HctDbIntkeyEntry) - + (HCTDB_MAX_EXTRA_CELL_DATA - sizeof(u32)) + ); + + int nLocal; + if( nSize (nMax-sizeof(u32)) ){ + nLocal = nMin; + } + } + + return nLocal; +} + +static int hctDbIndexLocalsize(int pgsz, int nSize){ + int nLocal; + int nMax = pgsz/4; + if( nSizenMax ){ + nLocal = nMin; + } + } + return nLocal; +} + +static int hctDbLocalsize(const u8 *aPg, int pgsz, int nSize){ + if( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ){ + return hctDbIntkeyLocalsize(pgsz, nSize); + } + return hctDbIndexLocalsize(pgsz, nSize); +} + +static int hctDbIntkeyEntrySize(HctDbIntkeyEntry *pEntry, int pgsz){ + int sz = hctDbIntkeyLocalsize(pgsz, pEntry->nSize) + + hctDbOffset(0, pEntry->flags); + return sz; +} + +static int hctDbIndexEntrySize(HctDbIndexEntry *pEntry, int pgsz){ + int sz = hctDbIndexLocalsize(pgsz, pEntry->nSize) + + hctDbOffset(0, pEntry->flags); + return sz; +} + +static int hctDbIndexNodeEntrySize(HctDbIndexNodeEntry *pEntry, int pgsz){ + return hctDbIndexLocalsize(pgsz, pEntry->nSize) + + ((pEntry->flags & HCTDB_HAS_OVFL) ? 4 : 0); +} + +/* +** The pointer passed as the first argument is a pointer to a buffer +** containing a page that uses variable sized records. That is, an +** intkey leaf page, or an index leaf or node page. This function +** returns the number of bytes of record-area space consumed by +** entry iEntry on the page. +*/ +static int hctDbPageRecordSize(void *aPg, int pgsz, int iEntry){ + int eType = hctPagetype(aPg); + if( eType==HCT_PAGETYPE_INTKEY ){ + assert( hctPageheight(aPg)==0 ); + return hctDbIntkeyEntrySize(&((HctDbIntkeyLeaf*)aPg)->aEntry[iEntry], pgsz); + }else if( hctPageheight(aPg)==0 ){ + return hctDbIndexEntrySize(&((HctDbIndexLeaf*)aPg)->aEntry[iEntry], pgsz); + } + return hctDbIndexNodeEntrySize(&((HctDbIndexNode*)aPg)->aEntry[iEntry], pgsz); +} +static int hctDbPageEntrySize(void *aPg){ + int eType = hctPagetype(aPg); + if( eType==HCT_PAGETYPE_INTKEY ){ + assert( hctPageheight(aPg)==0 ); + return sizeof(HctDbIntkeyEntry); + }else if( hctPageheight(aPg)==0 ){ + return sizeof(HctDbIndexEntry); + } + return sizeof(HctDbIndexNodeEntry); +} + +/* +** The buffer passed as the first argument contains a page that is +** guaranteed to be either an intkey leaf, or an index leaf or node. +** This function returns a pointer to HctDbIndexEntry structure +** associated with page entry iEntry. +*/ +static HctDbIndexEntry *hctDbEntryEntry(const void *aPg, int iEntry){ + int iOff; + + assert( (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) + || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) + ); + + if( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ){ + iOff = sizeof(HctDbIntkeyLeaf) + iEntry*sizeof(HctDbIntkeyEntry); + }else if( hctPageheight(aPg)==0 ){ + iOff = sizeof(HctDbIndexLeaf) + iEntry*sizeof(HctDbIndexEntry); + }else{ + iOff = sizeof(HctDbIndexNode) + iEntry*sizeof(HctDbIndexNodeEntry); + } + + return (HctDbIndexEntry*)&((u8*)aPg)[iOff]; +} + +/* +** Argument aPg[] is a buffer containing either an index tree page, or an +** intkey leaf page. This function locates the record associated with +** cell iCell on the page, and populates output variables *pnData and +** *paData with the size and a pointer to a buffer containing the record, +** respectively. +** +** If the record in cell iCell does not overflow the page, (*paData) is +** set to point into the body of the page itself. If the record does +** overflow the page, then buffer pBuf is used to store the record and +** (*paData) is set to point to the buffer's allocation. In this case +** it is the responsibility of the caller to eventually release the buffer. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int hctDbLoadRecord( + HctDatabase *pDb, + HctBuffer *pBuf, + const u8 *aPg, + int iCell, + int *pnData, + const u8 **paData +){ + int rc = SQLITE_OK; + HctDbIndexEntry *p = hctDbEntryEntry(aPg, iCell); + + *pnData = p->nSize; + if( paData ){ + if( p->flags & HCTDB_HAS_OVFL ){ + rc = sqlite3HctBufferGrow(pBuf, p->nSize); + *paData = pBuf->aBuf; + if( rc==SQLITE_OK ){ + u32 pgOvfl; + int nLocal = hctDbLocalsize(aPg, pDb->pgsz, p->nSize); + + int iOff = hctDbOffset(p->iOff, p->flags); + hctMemcpy(pBuf->aBuf, &aPg[iOff], nLocal); + pgOvfl = hctGetU32(&aPg[iOff-sizeof(u32)]); + iOff = nLocal; + + while( rc==SQLITE_OK && iOffnSize ){ + HctFilePage ovfl; + rc = hctDbGetPhysical(pDb, pgOvfl, &ovfl); + if( rc==SQLITE_OK ){ + int nCopy = MIN(pDb->pgsz-8, p->nSize-iOff); + hctMemcpy(&pBuf->aBuf[iOff],&ovfl.aOld[sizeof(HctDbPageHdr)],nCopy); + iOff += nCopy; + pgOvfl = ((HctDbPageHdr*)ovfl.aOld)->iPeerPg; + sqlite3HctFilePageRelease(&ovfl); + } + } + } + }else{ + int iOff = hctDbOffset(p->iOff, p->flags); + *paData = &aPg[iOff]; + } + } + + return rc; +} + +/* +** Buffer aPg[] contains either an index page or an intkey leaf (i.e. a page +** that contains variable length records). This function loads the record +** associated with cell iCell on the page, and populates output object +** pFP with the results. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int hctDbLoadRecordFP( + HctDatabase *pDb, /* Database handle */ + const u8 *aPg, /* Page to load record from */ + int iCell, /* Cell to load */ + HctDbFPKey *pFP /* Populate this structure with record */ +){ + const u8 *aKey = 0; + int nKey = 0; + int rc = SQLITE_OK; + + rc = hctDbLoadRecord(pDb, &pFP->buf, aPg, iCell, &nKey, &aKey); + if( rc==SQLITE_OK ){ + if( aKey!=pFP->buf.aBuf ){ + rc = sqlite3HctBufferGrow(&pFP->buf, nKey); + if( rc==SQLITE_OK ){ + hctMemcpy(pFP->buf.aBuf, aKey, nKey); + } + } + pFP->iKey = nKey; + pFP->aKey = pFP->buf.aBuf; + } + + return rc; +} + +/* +** Buffer aPg[] contains a history fan page. +** +** This page searches the page, returning the index of the entry that +** points to the page with the largest key that is less than or equal +** to parameter pKey/iKey. +*/ +static int hctDbFanSearch( + int *pRc, + HctDatabase *pDb, + const u8 *aPg, + UnpackedRecord *pKey, + i64 iKey +){ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)aPg; + int rc = *pRc; + int i1 = 0; + int i2 = pFan->pg.nEntry-1; + HctBuffer buf = {0, 0, 0}; + + assert( hctPagetype(aPg)==HCT_PAGETYPE_HISTORY ); + + while( rc==SQLITE_OK && i2>i1 ){ + HctFilePage pg; + int iTest = (i1+i2)/2; + + rc = hctDbGetPhysical(pDb, pFan->aPgOld1[iTest], &pg); + while( rc==SQLITE_OK && hctPagetype(pg.aOld)==HCT_PAGETYPE_HISTORY ){ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aOld; + rc = hctDbGetPhysical(pDb, pFan->pgOld0, &pg); + } + if( rc==SQLITE_OK ){ + int iCell = (iTest==0 ? pFan->iSplit0 : 0); + + assert( pKey || hctPagetype(pg.aOld)==HCT_PAGETYPE_INTKEY ); + assert( pKey==0 || hctPagetype(pg.aOld)==HCT_PAGETYPE_INDEX ); + + if( pKey==0 ){ + i64 iPgKey = hctDbGetIntkey(pg.aOld, iCell); + if( iPgKey==iKey ){ + i1 = i2 = iTest+1; + }else if( iPgKeypKeyInfo->db, pRec); + } +} + +static UnpackedRecord *hctDbAllocateUnpacked(int *pRc, KeyInfo *pKeyInfo){ + UnpackedRecord *pRet = 0; + if( *pRc==SQLITE_OK ){ + pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRet==0 ) *pRc = SQLITE_NOMEM_BKPT; + } + return pRet; +} + +SQLITE_PRIVATE void sqlite3HctDbRecordTrim(UnpackedRecord *pRec){ + if( pRec && pRec->pKeyInfo->nUniqField ){ + int ii; + u16 nUniqField = pRec->pKeyInfo->nUniqField; + for(ii=0; iiaMem[ii].flags & MEM_Null ){ + return; + } + } + pRec->nField = nUniqField; + } +} + + +/* +** This function returns the current snapshot-id. It may only be called +** when a read transaction is active. +*/ +SQLITE_PRIVATE i64 sqlite3HctDbSnapshotId(HctDatabase *pDb){ + assert( pDb->iSnapshotId>0 ); + return pDb->iSnapshotId; +} + +/* +** Load the key belonging to cell iCell on page aPg[] into structure (*pKey). +*/ +static void hctDbGetKey( + int *pRc, + HctDatabase *pDb, + KeyInfo *pKeyInfo, + int bDup, + const u8 *aPg, + int iCell, + HctDbKey *pKey +){ + int rc = *pRc; + + if( rc==SQLITE_OK ){ + assert( hctPageheight(aPg)==0 ); + assert( iCell>=0 && iCelliKey = hctDbGetIntkey(aPg, iCell); + }else{ + const u8 *aRec = 0; + int nRec = 0; + rc = hctDbLoadRecord(pDb, &pKey->buf, aPg, iCell, &nRec, &aRec); + if( aRec!=pKey->buf.aBuf && bDup && rc==SQLITE_OK ){ + rc = hctBufferSet(&pKey->buf, aRec, nRec); + aRec = pKey->buf.aBuf; + } + pKey->pKey = hctDbAllocateUnpacked(&rc, pKeyInfo); + if( rc==SQLITE_OK ){ + sqlite3VdbeRecordUnpack(pKeyInfo, nRec, aRec, pKey->pKey); + } + if( rc==SQLITE_OK ){ + sqlite3HctDbRecordTrim(pKey->pKey); + } + } + } + *pRc = rc; +} + +/* +** Retrieve the key from iCell of physical page iPhys. iPhys may be an +** intkey or index leaf page. Populate structure (*pKey) with the key +** value before returning. +*/ +static void hctDbGetKeyFromPage( + int *pRc, + HctDatabase *pDb, + KeyInfo *pKeyInfo, + int bLogical, /* True for logical, false for physical */ + u32 iPg, + int iCell, + HctDbKey *pKey +){ + int rc = *pRc; + + if( rc==SQLITE_OK ){ + HctFilePage pg; + if( bLogical ){ + rc = sqlite3HctFilePageGet(pDb->pFile, iPg, &pg); + }else{ + rc = hctDbGetPhysical(pDb, iPg, &pg); + while( rc==SQLITE_OK && hctPagetype(pg.aOld)==HCT_PAGETYPE_HISTORY ){ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aOld; + rc = hctDbGetPhysical(pDb, pFan->pgOld0, &pg); + } + } + if( rc==SQLITE_OK ){ + hctDbGetKey(&rc, pDb, pKeyInfo, 1, pg.aOld, iCell, pKey); + sqlite3HctFilePageRelease(&pg); + } + } + *pRc = rc; +} + +/* static RecordCompare find_record_compare((UnpackedRecord*, RecordCompare); */ +#define find_record_compare(pRec, xCompare) ( \ + (xCompare) ? (xCompare) : sqlite3VdbeFindCompare(pRec) \ +) + + +static int hctDbIndexSearch( + HctDatabase *pDb, + const u8 *aPg, + RecordCompare xCompare, + UnpackedRecord *pRec, + int *piPos, + int *pbExact +){ + int rc = SQLITE_OK; + HctBuffer buf; + int i1 = 0; + int i2 = ((HctDbPageHdr*)aPg)->nEntry; + + if( pRec ) xCompare = find_record_compare(pRec, xCompare); + memset(&buf, 0, sizeof(buf)); + + while( i2>i1 ){ + int iTest = (i1+i2)/2; + int res; + int nRec = 0; + const u8 *aRec = 0; + + rc = hctDbLoadRecord(pDb, &buf, aPg, iTest, &nRec, &aRec); + if( rc!=SQLITE_OK ) break; + if( nRec==0 ){ + res = -1; + }else{ + res = xCompare(nRec, aRec, pRec); + } + + if( res==0 ){ + *pbExact = 1; + *piPos = iTest; + sqlite3HctBufferFree(&buf); + return SQLITE_OK; + }else if( res<0 ){ + i1 = iTest+1; + }else{ + i2 = iTest; + } + } + + assert( i1==i2 && i2>=0 ); + sqlite3HctBufferFree(&buf); + *pbExact = 0; + *piPos = i2; + return rc; +} + + +/* +** The first argument is a pointer to an intkey internal node page. +** +** This function searches the node page for key iKey. If found, it returns +** the index of the matching key within the page and sets output variable +** (*pbExact) to 1. If there is no match for key iKey, this function returns +** the index of the smallest key on the page that is larger than iKey, or +** (nEntry) if all keys on the page are smaller than iKey. (*pbExact) is +** set to 0 before returning in this case. +*/ +static int hctDbIntkeyNodeSearch( + void *aPg, + i64 iKey, + int *pbExact +){ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPg; + int i1 = 0; + int i2 = pNode->pg.nEntry; + + assert( hctPagetype(pNode)==HCT_PAGETYPE_INTKEY && pNode->pg.nHeight>0 ); + while( i2>i1 ){ + int iTest = (i1+i2)/2; + i64 iPgKey = pNode->aEntry[iTest].iKey; + if( iPgKey==iKey ){ + *pbExact = 1; + return iTest; + }else if( iPgKey=0 ); + assert( i2==pNode->pg.nEntry || iKeyaEntry[i2].iKey ); + assert( i2==0 || iKey>pNode->aEntry[i2-1].iKey ); + + *pbExact = 0; + return i2; +} + +/* +** Set (*bGe) to true if (pRec >= (FP-key for aPg)). +*/ +static int hctDbCompareFPKey( + HctDatabase *pDb, + UnpackedRecord *pRec, + const u8 *aPg, + int *pbGe +){ + const u8 *aFP = 0; + int nFP = 0; + int res; + int rc; + HctBuffer buf = {0,0,0}; + + rc = hctDbLoadRecord(pDb, &buf, aPg, 0, &nFP, &aFP); + if( rc==SQLITE_OK ){ + res = sqlite3VdbeRecordCompare(nFP, aFP, pRec); + sqlite3HctBufferFree(&buf); + *pbGe = (res<=0); + } + return rc; +} + +static int hctDbCsrGoLeft(HctDbCsr*); + +/* +** Seek the cursor within its tree. This only seeks within the tree, it does +** not follow any old-data pointers. +*/ +int hctDbCsrSeek( + HctDbCsr *pCsr, /* Cursor to seek */ + HctDbFPKey *pFP, + int iHeight, /* Height to seek at (0==leaf, 1==parent) */ + RecordCompare xCompare, + UnpackedRecord *pRec, /* Key for index/without rowid tables */ + i64 iKey, /* Key for intkey tables */ + int *pbExact +){ + HctFile *pFile = pCsr->pDb->pFile; + u32 iPg = pCsr->iRoot; + int rc = SQLITE_OK; + + HctFilePage par; + memset(&par, 0, sizeof(par)); + int iPar = 0; + + if( pRec ) xCompare = find_record_compare(pRec, xCompare); + while( rc==SQLITE_OK ){ + if( iPg ) rc = sqlite3HctFilePageGet(pFile, iPg, &pCsr->pg); + if( rc==SQLITE_OK ){ + HctDbPageHdr *pHdr = (HctDbPageHdr*)pCsr->pg.aOld; + int i2 = pHdr->nEntry-1; + int bExact; + if( pHdr->nHeight==0 ){ + if( pRec ){ + rc = hctDbIndexSearch( + pCsr->pDb, pCsr->pg.aOld, xCompare, pRec, &i2, &bExact + ); + }else{ + i2 = hctDbIntkeyLeafSearch(pCsr->pg.aOld, iKey, &bExact); + } + if( bExact==0 ) i2--; + }else{ + if( pRec ){ + HctDbIndexNode *pNode = (HctDbIndexNode*)pCsr->pg.aOld; + rc = hctDbIndexSearch( + pCsr->pDb, pCsr->pg.aOld, xCompare, pRec, &i2, &bExact + ); + i2 -= !bExact; + iPg = pNode->aEntry[i2].iChildPg; + assert( iPg ); + }else{ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pCsr->pg.aOld; + i2 = hctDbIntkeyNodeSearch(pNode, iKey, &bExact); + assert( i2==pHdr->nEntry || iKey<=pNode->aEntry[i2].iKey ); + assert( i2==pHdr->nEntry || bExact==(iKey==pNode->aEntry[i2].iKey) ); + assert( i2nEntry || bExact==0 ); + i2 -= !bExact; + iPg = pNode->aEntry[i2].iChildPg; + assert( iPg ); + } + + /* Avoid following a pointer to an EVICTED page */ + if( pHdr->nHeight!=iHeight ){ + while( sqlite3HctFilePageIsEvicted(pFile, iPg) ){ + i2--; + if( i2<0 ){ + rc = hctDbCsrGoLeft(pCsr); + if( rc!=SQLITE_OK ) break; + i2 = pCsr->iCell; + } + + bExact = 0; + if( pRec ){ + HctDbIndexNode *pNode = (HctDbIndexNode*)pCsr->pg.aOld; + iPg = pNode->aEntry[i2].iChildPg; + }else{ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pCsr->pg.aOld; + iPg = pNode->aEntry[i2].iChildPg; + } + } + } + } + + + /* Test if it is necessary to skip to the peer node. */ + if( i2>=0 && i2==pHdr->nEntry-1 && pHdr->iPeerPg!=0 ){ + HctFilePage peer; + rc = sqlite3HctFilePageGet(pFile, pHdr->iPeerPg, &peer); + if( rc==SQLITE_OK ){ + int bGotoPeer; + if( pRec ){ + rc = hctDbCompareFPKey(pCsr->pDb, pRec, peer.aOld, &bGotoPeer); + }else{ + i64 iFP = hctDbIntkeyFPKey(peer.aOld); + bGotoPeer = (iFP<=iKey); + } + if( bGotoPeer ){ + SWAP(HctFilePage, pCsr->pg, peer); + sqlite3HctFilePageRelease(&peer); + assert( pCsr->pg.aOld ); + iPg = 0; + continue; + } + sqlite3HctFilePageRelease(&peer); + } + } + + if( pHdr->nHeight==iHeight ){ + pCsr->iCell = i2; + if( pbExact ) *pbExact = bExact; + + /* If parameter pFP was not NULL and there is a parent page stored + ** in variable par, try to load the FP key from that page. This + ** is used when seeking a cursor for writing. */ + if( pFP && par.aOld ){ + i64 iPeer = ((HctDbPageHdr*)pCsr->pg.aOld)->iPeerPg; + if( pRec ){ + HctDbIndexNode *pPar = (HctDbIndexNode*)par.aOld; + if( (iPar+1)pg.nEntry + && pPar->aEntry[iPar+1].iChildPg==iPeer + ){ + rc = hctDbLoadRecordFP(pCsr->pDb, par.aOld, iPar+1, pFP); + } + }else{ + HctDbIntkeyNode *pPar = (HctDbIntkeyNode*)par.aOld; + if( (iPar+1)pg.nEntry + && pPar->aEntry[iPar+1].iChildPg==iPeer + ){ + pFP->iKey = pPar->aEntry[iPar+1].iKey; + } + } + } + + break; + } + + if( pFP && pHdr->nHeight==iHeight+1 ){ + par = pCsr->pg; + iPar = i2; + memset(&pCsr->pg, 0, sizeof(HctFilePage)); + }else{ + sqlite3HctFilePageRelease(&pCsr->pg); + } + assert( rc!=SQLITE_OK || iPg!=0 ); + } + } + + if( pFP ) sqlite3HctFilePageRelease(&par); + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbCsrDir(HctDbCsr *pCsr, int eDir){ + pCsr->eDir = eDir; +} + +static int hctDbCellOffset(const u8 *aPage, int iCell, u8 *pFlags){ + HctDbPageHdr *pHdr = (HctDbPageHdr*)aPage; + int iRet; + if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ + HctDbIntkeyEntry *pEntry = &((HctDbIntkeyLeaf*)pHdr)->aEntry[iCell]; + *pFlags = pEntry->flags; + iRet = pEntry->iOff; + }else if( hctPageheight(pHdr)>0 ){ + HctDbIndexNodeEntry *pEntry = &((HctDbIndexNode*)pHdr)->aEntry[iCell]; + *pFlags = pEntry->flags; + iRet = pEntry->iOff; + }else{ + HctDbIndexEntry *pEntry = &((HctDbIndexLeaf*)pHdr)->aEntry[iCell]; + *pFlags = pEntry->flags; + iRet = pEntry->iOff; + } + return iRet; +} + +/* +** If the cursor is open on an index tree, ensure that the UnpackedRecord +** structure is allocated. Return SQLITE_NOMEM if an OOM is encountered +** while attempting to allocate said structure, or SQLITE_OK otherwise. +*/ +static int hctDbCsrAllocateUnpacked(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + if( pCsr->pKeyInfo && pCsr->pRec==0 ){ + pCsr->pRec = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo); + if( pCsr->pRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + } + } + return rc; +} + +static const u8 *hctDbCsrPageAndCellIdx( + HctDbCsr *pCsr, + int iIdx, + int *piCell +){ + const u8 *aPg = 0; + int iCell = 0; + + if( iIdx<0 ){ + aPg = pCsr->pg.aOld; + iCell = pCsr->iCell; + }else{ + aPg = pCsr->aRange[iIdx].pg.aOld; + iCell = pCsr->aRange[iIdx].iCell; + } + *piCell = iCell; + return aPg; +} + +/* +** Return a pointer to the current page accessed by the cursor. Before +** returning, also set output variable (*piCell) to the index of the +** current cell within the page. +*/ +static const u8 *hctDbCsrPageAndCell(HctDbCsr *pCsr, int *piCell){ + const u8 *aPg = 0; + int iCell = 0; + if( pCsr->nRange ){ + aPg = pCsr->aRange[pCsr->nRange-1].pg.aOld; + iCell = pCsr->aRange[pCsr->nRange-1].iCell; + }else{ + aPg = pCsr->pg.aOld; + iCell = pCsr->iCell; + } + + *piCell = iCell; + return aPg; +} + +static void hctDbFreeKeyContents(HctDbKey *pKey){ + hctDbFreeUnpacked(pKey->pKey); + sqlite3HctBufferFree(&pKey->buf); +} + +static void hctDbCsrAscendRange(HctDbCsr *pCsr){ + HctDbRangeCsr *pLast = &pCsr->aRange[--pCsr->nRange]; + assert( pCsr->nRange>=0 ); + hctDbFreeKeyContents(&pLast->highkey); + hctDbFreeKeyContents(&pLast->lowkey); + sqlite3HctFilePageRelease(&pLast->pg); +} + +static void hctDbCsrReset(HctDbCsr *pCsr){ + sqlite3HctFilePageRelease(&pCsr->pg); + pCsr->iCell = -1; + while( pCsr->nRange>0 ){ + hctDbCsrAscendRange(pCsr); + } +} + +static void hctDbFreeCsr(HctDbCsr *pCsr){ + hctDbCsrReset(pCsr); + while( pCsr->intkey.pOpList ){ + HctCsrIntkeyOp *pOp = pCsr->intkey.pOpList; + pCsr->intkey.pOpList = pOp->pNextOp; + sqlite3_free(pOp); + } + while( pCsr->index.pOpList ){ + HctCsrIndexOp *pOp = pCsr->index.pOpList; + pCsr->index.pOpList = pOp->pNextOp; + if( pOp->pLast!=pOp->pFirst ){ + sqlite3_free(pOp->pLast); + } + sqlite3_free(pOp->pFirst); + sqlite3_free(pOp); + } + if( pCsr->pRec ) sqlite3DbFree(pCsr->pKeyInfo->db, pCsr->pRec); + sqlite3KeyInfoUnref(pCsr->pKeyInfo); + sqlite3HctBufferFree(&pCsr->rec); + sqlite3_free(pCsr->aRange); + pCsr->aRange = 0; + pCsr->nRangeAlloc = 0; + sqlite3_free(pCsr); +} + +static void hctDbCsrCleanup(HctDbCsr *pCsr){ + hctDbCsrReset(pCsr); + if( pCsr->pKeyInfo ){ + sqlite3DbFree(pCsr->pKeyInfo->db, pCsr->pRec); + sqlite3KeyInfoUnref(pCsr->pKeyInfo); + pCsr->pKeyInfo = 0; + pCsr->pRec = 0; + } + sqlite3_free(pCsr->aRange); + pCsr->aRange = 0; + pCsr->nRangeAlloc = 0; + sqlite3HctBufferFree(&pCsr->rec); + pCsr->iRoot = 0; +} + +static int hctDbCsrScanStart(HctDbCsr *pCsr, UnpackedRecord *pRec, i64 iKey){ + int rc = SQLITE_OK; + + if( pCsr->pDb->bConcurrent ){ + if( pCsr->pDb->iTid==0 ){ + if( pCsr->pKeyInfo==0 ){ + HctCsrIntkeyOp *pOp = 0; + pOp = sqlite3MallocZero(sizeof(HctCsrIntkeyOp)); + if( pOp==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + assert( pCsr->intkey.pCurrentOp==0 ); + pOp->iFirst = pOp->iLast = iKey; + pCsr->intkey.pCurrentOp = pOp; + pOp->iLogical = pCsr->pg.iPg; + pOp->iPhysical = pCsr->pg.iOldPg; + } + }else{ + HctCsrIndexOp *pOp = 0; + pOp = sqlite3MallocZero(sizeof(HctCsrIndexOp)); + if( pOp==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + if( pRec ){ + rc = sqlite3HctSerializeRecord(pRec, &pOp->pFirst, &pOp->nFirst); + pOp->pLast = pOp->pFirst; + pOp->nLast = pOp->nFirst; + pOp->iLogical = pCsr->pg.iPg; + pOp->iPhysical = pCsr->pg.iOldPg; + } + assert( pCsr->index.pCurrentOp==0 ); + pCsr->index.pCurrentOp = pOp; + } + } + } + } + + return rc; +} + +static int hctDbCsrScanFinish(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + if( pCsr->pDb->bConcurrent ){ + if( pCsr->pKeyInfo==0 ){ + HctCsrIntkeyOp *pOp = pCsr->intkey.pCurrentOp; + pCsr->intkey.pCurrentOp = 0; + if( pOp ){ + HctCsrIntkeyOp *pPrev = pCsr->intkey.pOpList; + + if( pCsr->eDir!=BTREE_DIR_NONE ){ + i64 iVal = 0; + if( sqlite3HctDbCsrEof(pCsr) ){ + if( pCsr->eDir==BTREE_DIR_FORWARD ){ + iVal = LARGEST_INT64; + }else{ + iVal = SMALLEST_INT64; + } + pOp->iLogical = pOp->iPhysical = 0; + }else{ + sqlite3HctDbCsrKey(pCsr, &iVal); + if( pCsr->pg.iPg!=pOp->iLogical ){ + pOp->iLogical = pOp->iPhysical = 0; + } + } + + if( iVal>=pOp->iFirst ){ + pOp->iLast = iVal; + }else{ + pOp->iLast = pOp->iFirst; + pOp->iFirst = iVal; + } + } + + if( pPrev && pOp->iLast<=pPrev->iLast && pOp->iFirst>=pPrev->iFirst ){ + pPrev->iLogical = pPrev->iPhysical = 0; + sqlite3_free(pOp); + }else{ + pOp->pNextOp = pPrev; + pCsr->intkey.pOpList = pOp; + } + } + }else{ + HctCsrIndexOp *pOp = pCsr->index.pCurrentOp; + pCsr->index.pCurrentOp = 0; + if( pOp ){ + if( pCsr->eDir!=BTREE_DIR_NONE ){ + int nKey = 0; + u8 *aCopy = 0; + if( !sqlite3HctDbCsrEof(pCsr) ){ + const u8 *aKey = 0; + rc = sqlite3HctDbCsrData(pCsr, &nKey, &aKey); + if( rc==SQLITE_OK ){ + aCopy = sqlite3_malloc(nKey); + if( aCopy==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + hctMemcpy(aCopy, aKey, nKey); + } + } + if( pCsr->pg.iPg!=pOp->iLogical ){ + pOp->iLogical = pOp->iPhysical = 0; + } + }else{ + pOp->iLogical = pOp->iPhysical = 0; + } + + if( pCsr->eDir==BTREE_DIR_FORWARD ){ + pOp->pLast = aCopy; + pOp->nLast = nKey; + }else{ + pOp->pFirst = aCopy; + pOp->nFirst = nKey; + } + } + + pOp->pNextOp = pCsr->index.pOpList; + pCsr->index.pOpList = pOp; + } + } + } + + return rc; +} + +static int hctDbCsrFirst(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + + /* Starting at the root of the tree structure, follow the left-most + ** pointers to find the left-most node in the list of leaves. */ + u32 iPg = pCsr->iRoot; + HctFile *pFile = pCsr->pDb->pFile; + HctFilePage pg; + while( 1 ){ + HctDbPageHdr *pPg; + rc = sqlite3HctFilePageGet(pFile, iPg, &pg); + if( rc!=SQLITE_OK ) break; + pPg = (HctDbPageHdr*)pg.aOld; + if( pPg->nHeight==0 ){ + break; + }else if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY ){ + iPg = ((HctDbIntkeyNode*)pPg)->aEntry[0].iChildPg; + }else{ + iPg = ((HctDbIndexNode*)pPg)->aEntry[0].iChildPg; + } + sqlite3HctFilePageRelease(&pg); + } + hctMemcpy(&pCsr->pg, &pg, sizeof(pg)); + if( ((HctDbPageHdr*)pCsr->pg.aOld)->nEntry>0 ){ + pCsr->iCell = 0; + }else{ + pCsr->iCell = -1; + } + return rc; +} + +static int hctDbCsrFirstValid(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + + rc = hctDbCsrFirst(pCsr); + + /* Skip forward to the first visible entry, if any. */ + if( rc==SQLITE_OK ){ + pCsr->iCell = -1; + rc = sqlite3HctDbCsrNext(pCsr); + } + + return rc; +} + +static int hctDbCellPut( + u8 *aBuf, + HctDbCell *pCell, + int nLocal +){ + int iOff = 0; + if( pCell->iTid ){ + hctMemcpy(&aBuf[iOff], &pCell->iTid, sizeof(u64)); + iOff += sizeof(u64); + } + if( pCell->iRangeTid ){ + hctMemcpy(&aBuf[iOff], &pCell->iRangeTid, sizeof(u64)); + iOff += sizeof(u64); + } + if( pCell->iRangeOld ){ + hctMemcpy(&aBuf[iOff], &pCell->iRangeOld, sizeof(u32)); + iOff += sizeof(u32); + } + if( pCell->iOvfl ){ + hctMemcpy(&aBuf[iOff], &pCell->iOvfl, sizeof(u32)); + iOff += sizeof(u32); + } + hctMemcpy(&aBuf[iOff], pCell->aPayload, nLocal); + return iOff+nLocal; +} + +static void hctDbCellGet( + HctDatabase *pDb, + const u8 *aBuf, + int flags, + HctDbCell *pCell +){ + int iOff = 0; + memset(pCell, 0, sizeof(HctDbCell)); + + if( flags & HCTDB_HAS_TID ){ + hctMemcpy(&pCell->iTid, &aBuf[iOff], sizeof(u64)); + iOff += sizeof(u64); + } + if( flags & HCTDB_HAS_RANGETID ){ + hctMemcpy(&pCell->iRangeTid, &aBuf[iOff], sizeof(u64)); + iOff += sizeof(u64); + } + if( flags & HCTDB_HAS_RANGEOLD ){ + hctMemcpy(&pCell->iRangeOld, &aBuf[iOff], sizeof(u32)); + iOff += sizeof(u32); + } + if( flags & HCTDB_HAS_OVFL ){ + hctMemcpy(&pCell->iOvfl, &aBuf[iOff], sizeof(u32)); + iOff += sizeof(u32); + } + + pCell->aPayload = &aBuf[iOff]; +} + +static void hctDbCellGetByIdx( + HctDatabase *pDb, + const u8 *aPg, + int iIdx, + HctDbCell *pCell +){ + HctDbIndexEntry *p = hctDbEntryEntry(aPg, iIdx); + hctDbCellGet(pDb, &aPg[p->iOff], p->flags, pCell); +} + +static u8 hctDbCellToFlags(HctDbCell *pCell){ + u8 flags = 0; + if( pCell->iTid ) flags |= HCTDB_HAS_TID; + if( pCell->iOvfl ) flags |= HCTDB_HAS_OVFL; + if( pCell->iRangeTid ) flags |= HCTDB_HAS_RANGETID; + if( pCell->iRangeOld ) flags |= HCTDB_HAS_RANGEOLD; + return flags; +} + +typedef struct HctRangePtr HctRangePtr; +struct HctRangePtr { + u64 iRangeTid; + u64 iFollowTid; + u32 iOld; +}; + +/* +** This function is called when a reader encounters an old-range pointer +** with associated TID value iRangeTid. It returns true if the pointer +** should be followed, or false otherwise. +** +** If the data items on the linked page should be merged in to the cursor +** results, output parameter (*pbMerge) is set to true before returning. +** This happens if the transaction with TID iRangeTid is not visible to +** the reader. Or, if the only reason to follow the pointer is in order +** to follow other pointers on the indicated page, (*pbMerge) is set to +** true. This happens when iRangeTid is included in the transaction, but +** there exists one or more transactions with TID values smaller than iRangeTid +** that are not. +*/ +static int hctDbFollowRangeOld( + HctDatabase *pDb, + HctRangePtr *pPtr, + int *pbMerge +){ + int bRet = 0; + int bMerge = 0; + u64 iRangeTidValue = (pPtr->iRangeTid & HCT_TID_MASK); + + /* HctDatabase.iTid is set when writing, validating or rolling back a + ** transaction. When writing or validating, old-ranges created by this + ** transaction should not be merge in, even if they are followed. But, when + ** doing rollback, they must be merged in (to find the old data). */ + + i64 iDoNotMergeTid = (pDb->eMode==HCT_MODE_VALIDATE) ? 0 : pDb->iTid; + assert( pDb->eMode!=HCT_MODE_ROLLBACK ); + + if( iRangeTidValue>pDb->iLocalMinTid ){ + bRet = 1; + if( iDoNotMergeTid!=iRangeTidValue ){ + bMerge = (0==hctDbTidIsVisible(pDb, pPtr->iRangeTid, 0)); + } + }else if( (pPtr->iFollowTid & HCT_TID_MASK)>pDb->iLocalMinTid ){ + bRet = 1; + assert( bMerge==0 ); + } + + *pbMerge = bMerge; + assert( bRet==0 || iRangeTidValue>0 ); + return bRet; +} + +static int hctDbCsrExtendRange(HctDbCsr *pCsr){ + if( pCsr->nRange==pCsr->nRangeAlloc ){ + int nNew = pCsr->nRangeAlloc ? pCsr->nRangeAlloc*2 : 16; + HctDbRangeCsr *aNew = 0; + + aNew = (HctDbRangeCsr*)sqlite3_realloc( + pCsr->aRange, nNew*sizeof(HctDbRangeCsr) + ); + if( aNew==0 ) return SQLITE_NOMEM_BKPT; + pCsr->nRangeAlloc = nNew; + pCsr->aRange = aNew; + } + + memset(&pCsr->aRange[pCsr->nRange], 0, sizeof(HctDbRangeCsr)); + pCsr->nRange++; + return SQLITE_OK; +} + +static int hctDbCompareKey2( + KeyInfo *pKeyInfo, + UnpackedRecord *pKey1, + i64 iKey1, + HctDbKey *p2 +){ + int ret = 0; + if( pKeyInfo ){ + int ii = 0; + int n1, n2; + + if( pKey1==0 ) return 1; + if( p2->pKey==0 ) return -1; + + n1 = pKey1->nField; + n2 = p2->pKey->nField; + + for(ii=0; ret==0 && iiaColl[ii]; + ret = sqlite3MemCompare(&pKey1->aMem[ii], &p2->pKey->aMem[ii], pColl); + if( pKeyInfo->aSortFlags[ii] & KEYINFO_ORDER_DESC ) ret = -ret; + } + if( ret==0 ){ + /* default_rc==1 if the key has been passed to hctDbDecrementKey() */ + assert( pKey1->default_rc==0 || pKey1->default_rc==1 ); + assert( p2->pKey->default_rc==0 || p2->pKey->default_rc==1 ); + ret = p2->pKey->default_rc - pKey1->default_rc; + } + if( ret==0 ){ + if( n1n2 ){ + ret = +1; + } + } + }else{ + if( iKey1iKey ){ + ret = -1; + }else if( iKey1>p2->iKey ){ + ret = +1; + } + } + return ret; +} + +/* +** Compare the key values in p1 and p2, returning a value less than, equal +** to, or greater than zero if p1 is respectively less than, equal to or +** greater than p2. i.e. +** +** res = (*p1) - (*p2) +*/ +static int hctDbCompareKey(KeyInfo *pKeyInfo, HctDbKey *p1, HctDbKey *p2){ + return hctDbCompareKey2(pKeyInfo, p1->pKey, p1->iKey, p2); +} + +static int hctDbCopyKey(HctDbKey *p1, HctDbKey *p2){ + if( p2->pKey ){ + int ii; + int bNew = 0; + if( p1->pKey==0 || p1->pKey->nFieldpKey->nField ){ + int rc = SQLITE_OK; + hctDbFreeUnpacked(p1->pKey); + p1->pKey = hctDbAllocateUnpacked(&rc, p2->pKey->pKeyInfo); + if( rc!=SQLITE_OK ) return rc; + bNew = 1; + p1->pKey->default_rc = 0; + } + for(ii=0; iipKey->nField; ii++){ + Mem *pFrom = &p2->pKey->aMem[ii]; + Mem *pTo = &p1->pKey->aMem[ii]; + if( bNew ) sqlite3VdbeMemInit(pTo, pFrom->db, 0); + sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Static); + } + p1->pKey->nField = p2->pKey->nField; + p1->pKey->default_rc = p2->pKey->default_rc; + }else{ + p1->iKey = p2->iKey; + } + return SQLITE_OK; +} + +static void hctDbDecrementKey(HctDbKey *pKey){ + if( pKey->pKey ){ + /* TODO: Is this correct? Or should it be +1? Or...? */ + pKey->pKey->default_rc = +1; + }else if( pKey->iKey!=SMALLEST_INT64 ){ + pKey->iKey--; + } +} + +static void hctDbCsrDescendRange( + int *pRc, + HctDbCsr *pCsr, + u64 iRangeTid, + u32 iRangeOld, + int bMerge +){ + int rc = *pRc; + + if( rc==SQLITE_OK ){ + rc = hctDbCsrExtendRange(pCsr); + } + + if( rc==SQLITE_OK ){ + HctDbRangeCsr *pNew = &pCsr->aRange[pCsr->nRange-1]; + assert( bMerge==HCT_RANGE_FOLLOW || bMerge==HCT_RANGE_MERGE ); + + pNew->eRange = bMerge; + pNew->iRangeTid = iRangeTid; + rc = hctDbGetPhysical(pCsr->pDb, iRangeOld, &pNew->pg); + + if( rc==SQLITE_OK ){ + int iPar = pCsr->nRange-2; + int iPCell = 0; + const u8 *aParent = hctDbCsrPageAndCellIdx(pCsr, iPar, &iPCell); + const HctDbPageHdr *pPar = (HctDbPageHdr*)aParent; + int bSeen = 0; + + /* Figure out the upper limit key for the scan of this page */ + if( hctPagetype(aParent)==HCT_PAGETYPE_HISTORY ){ + if( iPCell==0 && pPar->nEntry>1 ){ + const HctDbHistoryFan *pFan = (const HctDbHistoryFan*)aParent; + hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, + 0, pFan->aPgOld1[0], pFan->iSplit0, &pNew->highkey + ); + bSeen = 1; + } + }else{ + if( iPCell==(pPar->nEntry-1) ){ + if( pPar->iPeerPg ){ + hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, + 1, pPar->iPeerPg, 0, &pNew->highkey + ); + bSeen = 1; + } + }else{ + hctDbGetKey(&rc, + pCsr->pDb, pCsr->pKeyInfo, 0, aParent, iPCell+1, &pNew->highkey + ); + bSeen = 1; + } + } + + if( bSeen==0 ){ + if( iPar>=0 ){ + hctDbCopyKey(&pNew->highkey, &pNew[-1].highkey); + }else{ + pNew->highkey.iKey = LARGEST_INT64; + assert( pNew->highkey.pKey==0 ); + } + }else if( iPar>=0 ){ + /* The 'highkey' should be the minimum of pNew->highkey and the + ** parent highkey. highkey = MIN(highkey, parent.highkey); */ + HctDbKey *pPKey = &pNew[-1].highkey; + if( hctDbCompareKey(pCsr->pKeyInfo, &pNew->highkey, pPKey)>0 ){ + hctDbCopyKey(&pNew->highkey, pPKey); + } + } + + /* Figure the lower limit key for the scan of this page */ + pNew->lowkey.iKey = SMALLEST_INT64; + if( hctPagetype(aParent)==HCT_PAGETYPE_HISTORY ){ + if( iPCell>0 ){ + const HctDbHistoryFan *pFan = (const HctDbHistoryFan*)aParent; + hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, + 0, pFan->aPgOld1[0], pFan->iSplit0, &pNew->lowkey + ); + hctDbDecrementKey(&pNew->lowkey); + }else{ + hctDbCopyKey(&pNew->lowkey, &pNew[-1].lowkey); + } + }else{ + HctDbCell pcell; + hctDbGetKey(&rc, + pCsr->pDb, pCsr->pKeyInfo, 0, aParent, iPCell, &pNew->lowkey + ); + hctDbCellGetByIdx(pCsr->pDb, aParent, iPCell, &pcell); + if( hctDbTidIsVisible(pCsr->pDb, pcell.iTid, 0)==0 ){ + hctDbDecrementKey(&pNew->lowkey); + } + } + if( iPar>=0 ){ + /* The 'lowkey' should be the maximum of pNew->lowkey and the + ** parent lowkey. lowkey = MAX(lowkey, parent.lowkey); */ + HctDbKey *pPKey = &pNew[-1].lowkey; + if( hctDbCompareKey(pCsr->pKeyInfo, &pNew->lowkey, pPKey)<0 ){ + hctDbCopyKey(&pNew->lowkey, pPKey); + } + } + + if( rc==SQLITE_OK && hctPagetype(pNew->pg.aOld)==HCT_PAGETYPE_HISTORY){ + pNew->eRange = HCT_RANGE_FAN; + } + } + } + + *pRc = rc; +} + +static void hctDbGetRange( + const u8 *aPg, + int iCell, + HctRangePtr *pPtr +){ + if( iCell<0 ){ + memset(pPtr, 0, sizeof(*pPtr)); + }else if( hctPagetype(aPg)==HCT_PAGETYPE_HISTORY ){ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)aPg; + if( iCell==0 ){ + pPtr->iRangeTid = pFan->iRangeTid0; + pPtr->iFollowTid = pFan->iFollowTid0; + pPtr->iOld = pFan->pgOld0; + }else{ + pPtr->iFollowTid = pPtr->iRangeTid = pFan->iRangeTid1; + pPtr->iOld = pFan->aPgOld1[iCell-1]; + } + }else{ + HctDbCell cell; + hctDbCellGetByIdx(0, aPg, iCell, &cell); + pPtr->iFollowTid = pPtr->iRangeTid = cell.iRangeTid; + pPtr->iOld = cell.iRangeOld; + } + + assert( (pPtr->iFollowTid & HCT_TID_MASK)>=(pPtr->iRangeTid & HCT_TID_MASK) ); +} + +static void hctDbCsrGetRange( + HctDbCsr *pCsr, + HctRangePtr *pPtr +){ + const u8 *aPg = 0; + int iCell = 0; + aPg = hctDbCsrPageAndCell(pCsr, &iCell); + assert( ((HctDbPageHdr*)aPg)->nEntry>iCell ); + assert( ((HctDbPageHdr*)aPg)->nHeight==0 ); + hctDbGetRange(aPg, iCell, pPtr); +} + +/* +** Return true if the entry that the cursor currently points to is visible +** to the current transaction, or false otherwise. +*/ +static int hctDbCurrentIsVisible(HctDbCsr *pCsr){ + int iCell = 0; + HctDbIndexEntry *p; + const u8 *aPg = hctDbCsrPageAndCell(pCsr, &iCell); + u64 iTid = 0; + + if( pCsr->pKeyInfo ){ + p = &((HctDbIndexLeaf*)aPg)->aEntry[iCell]; + }else{ + p = (HctDbIndexEntry*)&((HctDbIntkeyLeaf*)aPg)->aEntry[iCell]; + } + if( (p->flags & HCTDB_HAS_TID)==0 ) return 1; + hctMemcpy(&iTid, &aPg[p->iOff], sizeof(u64)); + if( pCsr->pDb->iTid==iTid && pCsr->pDb->eMode==HCT_MODE_VALIDATE ) return 1; + + return hctDbTidIsVisible(pCsr->pDb, iTid, pCsr->bNosnap); +} + +/* +** Search leaf page aPg[] for a specified key. +** +** If the key is present in the page, set output variable (*piPos) to +** the index of the key in the page, and (*pbExact) to true. +** +** Or, if the key is not present in the page, set output variable (*piPos) +** to the index of the SMALLEST KEY THAT IS LARGER THAN IKEY/PKEY, and +** set (*pbExact) to false. +*/ +static int hctDbLeafSearch( + HctDatabase *pDb, + const u8 *aPg, + i64 iKey, + UnpackedRecord *pKey, + int *piPos, + int *pbExact +){ + if( hctPagetype(aPg)==HCT_PAGETYPE_INDEX ){ + if( pKey==0 ){ + *piPos = hctPagenentry(aPg); + *pbExact = 0; + }else{ + int rc = hctDbIndexSearch(pDb, aPg, 0, pKey, piPos, pbExact); + if( rc ) return rc; + } + }else{ + *piPos = hctDbIntkeyLeafSearch(aPg, iKey, pbExact); + } + return SQLITE_OK; +} + +static int hctDbCsrRollbackDescend( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index/without rowid tables */ + i64 iKey, /* Key for intkey tables */ + int *pbExact +){ + HctDatabase *pDb = pCsr->pDb; + int bExact = 0; + int rc = SQLITE_OK; + + assert( pDb->eMode==HCT_MODE_ROLLBACK ); + while( 1 ){ + HctRangePtr ptr; + HctDbRangeCsr *p = 0; + + hctDbCsrGetRange(pCsr, &ptr); + + if( (ptr.iFollowTid & HCT_TID_MASK)pDb->iTid ) break; + + rc = hctDbCsrExtendRange(pCsr); + if( rc==SQLITE_OK ){ + p = &pCsr->aRange[pCsr->nRange-1]; + rc = hctDbGetPhysical(pDb, ptr.iOld, &p->pg); + } + if( rc==SQLITE_OK ){ + p->iRangeTid = ptr.iRangeTid & HCT_TID_MASK; + if( hctPagetype(p->pg.aOld)==HCT_PAGETYPE_HISTORY ){ + p->eRange = HCT_RANGE_FAN; + p->iCell = hctDbFanSearch(&rc, pCsr->pDb, p->pg.aOld, pRec, iKey); + bExact = 0; + }else{ + p->eRange = HCT_RANGE_MERGE; + rc = hctDbLeafSearch( + pCsr->pDb, p->pg.aOld, iKey, pRec, &p->iCell, &bExact + ); + if( rc!=SQLITE_OK || bExact ) break; + p->iCell--; + if( p->iCell<0 ) break; + } + } + } + + *pbExact = bExact; + return rc; +} + +static int hctDbCsrSeekAndDescend( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index/without rowid tables */ + i64 iKey, /* Key for intkey tables */ + int bStopOnExact, /* Stop on exact match, even if not visible */ + int *pbExact +){ + int rc = SQLITE_OK; + int bExact = 0; + + /* This function is never called when writing to the database. Or while + ** doing rollback. But it is called during transaction preparation (iTid==0), + ** and validation (eMode==HCT_MODE_VALIDATE). */ + assert( pCsr->pDb->eMode==HCT_MODE_VALIDATE || pCsr->pDb->iTid==0 ); + + rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, iKey, &bExact); + if( bExact && bStopOnExact ){ + *pbExact = 1; + return rc; + } + + while( rc==SQLITE_OK && (0==bExact || 0==hctDbCurrentIsVisible(pCsr)) ){ + HctRangePtr ptr; + int bMerge = 0; + + /* Check if there is a range pointer that we should follow */ + hctDbCsrGetRange(pCsr, &ptr); + if( hctDbFollowRangeOld(pCsr->pDb, &ptr, &bMerge) ){ + hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); + if( rc==SQLITE_OK ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + + assert( hctDbCompareKey2(pCsr->pKeyInfo, pRec, iKey, &p->lowkey)>=0 ); + if( hctDbCompareKey2(pCsr->pKeyInfo, pRec, iKey, &p->lowkey)<=0 ){ + p->iCell = -1; + break; + } + + if( p->eRange==HCT_RANGE_FAN ){ + p->iCell = hctDbFanSearch(&rc, pCsr->pDb, p->pg.aOld, pRec, iKey); + bExact = 0; + }else{ + rc = hctDbLeafSearch( + pCsr->pDb, p->pg.aOld, iKey, pRec, &p->iCell, &bExact + ); + if( rc!=SQLITE_OK ) break; + if( bExact==0 ){ + p->iCell--; + }else if( bStopOnExact ){ + *pbExact = 1; + return SQLITE_OK; + } + if( p->iCell<0 ) break; + if( p->eRange==HCT_RANGE_FOLLOW ) bExact = 0; + } + } + }else{ + break; + } + } + + while( rc==SQLITE_OK && pCsr->nRange>0 ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + if( p->eRange==HCT_RANGE_MERGE && p->iCell>=0 ) break; + hctDbCsrAscendRange(pCsr); + } + + *pbExact = bExact; + return rc; +} + +/* +** Find the CID of the last transaction to write to a specified key. +** +** This must be called from within a transaction. +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrFindLastWrite( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index/without rowid tables */ + i64 iKey, /* Key for intkey tables */ + u64 *piCid /* Last CID to write to this key */ +){ + int rc = SQLITE_OK; + u64 iCid = 0; + int bExact = 0; + + rc = hctDbCsrSeekAndDescend(pCsr, pRec, iKey, 1, &bExact); + if( rc==SQLITE_OK && bExact ){ + u64 iTid = 0; + if( pCsr->nRange>1 ){ + /* In this case the key has been deleted. Find the TID of the + ** transaction that deleted it. */ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-2]; + HctRangePtr ptr; + hctDbGetRange(p->pg.aOld, p->iCell, &ptr); + iTid = ptr.iRangeTid; + }else{ + HctDbCell cell; + hctDbCellGetByIdx(pCsr->pDb, pCsr->pg.aOld, pCsr->iCell, &cell); + if( pCsr->nRange ){ + assert( pCsr->nRange==1 ); + iTid = cell.iRangeTid; + }else{ + iTid = cell.iTid; + } + } + + if( iTid ){ + u64 dummy = 0; + iTid = (iTid & HCT_TID_MASK); + iCid = hctDbTMapLookup(pCsr->pDb, iTid, &dummy); + }else{ + iCid = 1; + } + } + + *piCid = iCid; + return rc; +} + +/* +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than iKey/pRec or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches iKey/pRec. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than iKey/pRec. +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrSeek( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index tables */ + i64 iKey, /* Key for intkey tables */ + int *pRes /* Result of seek (see above) */ +){ + int rc = SQLITE_OK; + int bExact; + + /* Should not be called while committing, validating or during rollback. */ + assert( pCsr->pDb->eMode==HCT_MODE_NORMAL ); + assert( pCsr->pDb->iTid==0 ); + + rc = hctDbCsrScanFinish(pCsr); + hctDbCsrReset(pCsr); + + if( rc==SQLITE_OK ){ + rc = hctDbCsrSeekAndDescend(pCsr, pRec, iKey, 0, &bExact); + } + if( rc==SQLITE_OK ){ + rc = hctDbCsrScanStart(pCsr, pRec, iKey); + } + + /* The main cursor now points to the largest entry less than or equal + ** to the supplied key (pRec or iKey). If the supplied key is smaller + ** than all entries in the table, then pCsr->iCell is set to -1. */ + if( rc==SQLITE_OK ){ + if( pCsr->iCell<0 ){ + /* The supplied key is smaller than all keys in the table. If the cursor + ** is BTREE_DIR_REVERSE or NONE, then leave it as it is at EOF. + ** Otherwise, if the cursor is BTREE_DIR_FORWARD, attempt to move + ** it to the first valid entry. */ + if( pCsr->eDir==BTREE_DIR_FORWARD ){ + rc = hctDbCsrFirstValid(pCsr); + *pRes = sqlite3HctDbCsrEof(pCsr) ? -1 : +1; + }else{ + *pRes = -1; + } + }else{ + + if( rc==SQLITE_OK && 0==hctDbCurrentIsVisible(pCsr) ){ + switch( pCsr->eDir ){ + case BTREE_DIR_FORWARD: + *pRes = 1; + rc = sqlite3HctDbCsrNext(pCsr); + *pRes = sqlite3HctDbCsrEof(pCsr) ? -1 : +1; + break; + case BTREE_DIR_REVERSE: + rc = sqlite3HctDbCsrPrev(pCsr); + /* Either the cursor is is now at EOF or it points to a key + ** smaller than iKey/pRec. Either way, set (*pRes) to -ve. */ + *pRes = -1; + break; + default: assert( pCsr->eDir==BTREE_DIR_NONE ); + hctDbCsrReset(pCsr); + *pRes = -1; + break; + } + }else{ + *pRes = (bExact ? 0 : -1); + } + } + } + + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbSetSavePhysical( + HctDatabase *pDb, + int (*xSave)(void*, i64 iPhys), + void *pSave +){ + pDb->xSavePhysical = xSave; + pDb->pSavePhysical = pSave; +} + +SQLITE_PRIVATE int sqlite3HctDbCsrRollbackSeek( + HctDbCsr *pCsr, /* Cursor to seek */ + UnpackedRecord *pRec, /* Key for index tables */ + i64 iKey, /* Key for intkey tables */ + int *pOp /* Required rollback op */ +){ + HctDatabase *pDb = pCsr->pDb; + int rc = SQLITE_OK; + int bExact = 0; + int op = 0; + + hctDbCsrReset(pCsr); + + /* At this point pDb->bRollback is set and pDb->iTid is set to the TID + ** of the transaction being rolled back. There are four possibilities: + ** + ** 1) The key was written by transaction pDb->iTid and there was no + ** previous entry. + ** + ** 2) The key was written by transaction pDb->iTid and there is a + ** previous entry to restore. + ** + ** 3) The key was deleted by transaction pDb->iTid. + ** + ** 4) None of the above. No rollback required. + */ + + rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, iKey, &bExact); + if( rc==SQLITE_OK && bExact==0 ){ + rc = hctDbCsrRollbackDescend(pCsr, pRec, iKey, &bExact); + } + + if( rc==SQLITE_OK && bExact ){ + HctDbCell cell; + int iCell = 0; + const u8 *aPg = hctDbCsrPageAndCell(pCsr, &iCell); + + memset(&cell, 0, sizeof(cell)); + hctDbCellGetByIdx(pDb, aPg, iCell, &cell); + if( cell.iTid==pDb->iTid ){ + op = -1; + rc = hctDbCsrRollbackDescend(pCsr, pRec, iKey, &bExact); + } + + if( rc==SQLITE_OK + && bExact + && pCsr->nRange && pDb->iTid==pCsr->aRange[pCsr->nRange-1].iRangeTid + ){ + op = +1; + } + } + + *pOp = op; + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbIsIndex(HctDatabase *pDb, u32 iRoot, int *pbIndex){ + HctFilePage pg; + int rc = sqlite3HctFilePageGet(pDb->pFile, iRoot, &pg); + if( rc==SQLITE_OK ){ + *pbIndex = (hctPagetype(pg.aOld)==HCT_PAGETYPE_INDEX); + sqlite3HctFilePageRelease(&pg); + } + return rc; +} + +SQLITE_PRIVATE char *sqlite3HctDbLogFile(HctDatabase *pDb){ + return sqlite3HctFileLogFile(pDb->pFile); +} + +static void hctDbCsrInit( + HctDatabase *pDb, + u32 iRoot, + KeyInfo *pKeyInfo, + HctDbCsr *pCsr +){ + memset(pCsr, 0, sizeof(HctDbCsr)); + pCsr->pDb = pDb; + pCsr->iRoot = iRoot; + if( pKeyInfo ){ + pCsr->pKeyInfo = sqlite3KeyInfoRef(pKeyInfo); + } +} + + + +/* +** Return the size of the local part of a nData byte record stored on +** an intkey leaf page. +*/ +#if 0 +static int hctDbLocalSize(HctDatabase *pDb, int nData){ + int nOther = sizeof(HctDbIntkeyLeaf) + sizeof(HctDbIntkeyEntry) + 12; + if( nData<=(pDb->pgsz-nOther) ){ + return nData; + } + assert( !"todo" ); + return 0; +} +#endif + +#if 0 +static i64 hctDbIntkeyGetKey(u8 *aPg, int ii){ + HctDbIntkeyLeaf *p = (HctDbIntkeyLeaf*)aPg; + return p->aEntry[ii].iKey; +} +#endif + + + +/* +** Return the maximum number of entries that fit on an intkey internal +** node if the database page size is as specified by the only parameter. +*/ +static int hctDbMaxCellsPerIntkeyNode(int pgsz){ + return (pgsz - sizeof(HctDbIntkeyNode)) / sizeof(HctDbIntkeyNodeEntry); +} +static int hctDbMinCellsPerIntkeyNode(int pgsz){ + return (pgsz - sizeof(HctDbIntkeyNode)) / (3*sizeof(HctDbIntkeyNodeEntry)); +} + +static void hctDbIrrevocablyEvictPage(HctDatabase *pDb, HctDbWriter *p); + +static int hctDbOverflowArrayFree(HctDatabase *pDb, HctDbOverflowArray *p){ + int ii = 0; + int rc = SQLITE_OK; + + for(ii=0; rc==SQLITE_OK && iinEntry; ii++){ + u32 pgno = p->aOvfl[ii].pgno; + int nRem = p->aOvfl[ii].nOvfl; + while( 1 ){ + HctFilePage pg; + sqlite3HctFileClearPhysInUse(pDb->pFile, pgno, 0); + nRem--; + if( nRem==0 ) break; + rc = hctDbGetPhysical(pDb, pgno, &pg); + assert( rc==SQLITE_OK ); + pgno = ((HctDbPageHdr*)pg.aOld)->iPeerPg; + sqlite3HctFilePageRelease(&pg); + } + } + + return rc; +} + +#ifdef SQLITE_DEBUG +/* +** Do some assert() statements to check that: +** +** * the pages in discardpg[] are sorted according to key. +*/ +static void assert_writer_is_ok(HctDatabase *pDb, HctDbWriter *p){ + int ii; + HctBuffer buf = {0,0,0}; + UnpackedRecord *pRec = 0; + + for(ii=1; iidiscardpg.nPg; ii++){ + u8 *a1 = p->discardpg.aPg[ii-1].aOld; + u8 *a2 = p->discardpg.aPg[ii].aOld; + + if( hctPagetype(a1)==HCT_PAGETYPE_INTKEY ){ + i64 i1 = hctDbIntkeyFPKey(a1); + i64 i2 = hctDbIntkeyFPKey(a2); + assert( i2>i1 ); + }else{ + int nData = 0; + const u8 *aData = 0; + int rc = hctDbLoadRecord(pDb, &buf, a1, 0, &nData, &aData); + if( rc==SQLITE_OK && pRec==0 ){ + pRec = sqlite3VdbeAllocUnpackedRecord(p->writecsr.pKeyInfo); + if( pRec==0 ){ + rc = SQLITE_NOMEM; + } + } + if( rc==SQLITE_OK ){ + int bGe = 555; + sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nData, aData, pRec); + rc = hctDbCompareFPKey(pDb, pRec, a2, &bGe); + assert( rc!=SQLITE_OK || bGe==0 ); + } + } + } + + sqlite3HctBufferFree(&buf); + hctDbFreeUnpacked(pRec); +} +#else /* if !SQLITE_DEBUG */ +# define assert_writer_is_ok(pDb, p) +#endif + +/* +** Cleanup the writer object passed as the first argument. +*/ +static void hctDbWriterCleanup(HctDatabase *pDb, HctDbWriter *p, int bRevert){ + + if( p->bDoCleanup ){ + int ii; + + sqlite3HctFileDebugPrint(pDb->pFile, + "writer cleanup height=%d bRevert=%d\n", p->iHeight, bRevert + ); + + assert_writer_is_ok(pDb, p); + + sqlite3HctBufferFree(&p->fp.buf); + memset(&p->fp, 0, sizeof(p->fp)); + + /* sqlite3HctFilePageUnwrite(&p->fanpg); */ + sqlite3HctFilePageRelease(&p->fanpg); + + /* If not reverting, mark the overflow chains in p->delOvfl as free */ + if( bRevert==0 ){ + hctDbOverflowArrayFree(pDb, &p->delOvfl); + }else{ + hctDbOverflowArrayFree(pDb, &p->insOvfl); + } + sqlite3_free(p->delOvfl.aOvfl); + sqlite3_free(p->insOvfl.aOvfl); + memset(&p->delOvfl, 0, sizeof(p->delOvfl)); + memset(&p->insOvfl, 0, sizeof(p->insOvfl)); + + for(ii=0; iiwritepg.nPg; ii++){ + HctFilePage *pPg = &p->writepg.aPg[ii]; + if( bRevert ){ + if( pPg->aNew ){ + sqlite3HctFilePageUnwrite(pPg); + }else if( ii>0 ){ + sqlite3HctFileClearInUse(pPg, 1); + } + } + sqlite3HctFilePageRelease(pPg); + } + hctDbPageArrayReset(&p->writepg); + + for(ii=0; iidiscardpg.nPg; ii++){ + if( bRevert && pDb->pConfig->nTryBeforeUnevict>1 ){ + sqlite3HctFilePageUnevict(&p->discardpg.aPg[ii]); + } + sqlite3HctFilePageRelease(&p->discardpg.aPg[ii]); + } + + hctDbPageArrayReset(&p->discardpg); + p->fp.iKey = 0; + p->fp.aKey = 0; + + if( p->iEvictLockedPgno ){ + assert( p->writecsr.iRoot ); + p->nEvictLocked++; + if( p->nEvictLocked>=pDb->pConfig->nTryBeforeUnevict ){ + p->nEvictLocked = -1; + hctDbIrrevocablyEvictPage(pDb, p); + p->nEvictLocked = 0; + } + }else{ + p->nEvictLocked = 0; + } + p->iEvictLockedPgno = 0; + p->bAppend = 0; + + /* Free/zero various buffers and caches */ + hctDbCsrCleanup(&p->writecsr); + hctDbCsrCleanup(&pDb->rbackcsr); + p->bDoCleanup = 0; + } +} + +static int hctDbInsert( + HctDatabase *pDb, + HctDbWriter *p, + u32 iRoot, + UnpackedRecord *pRec, /* The key value for index tables */ + i64 iKey, /* For intkey tables, the key value */ + u32 iChildPg, /* For internal node ops, the child pgno */ + int bDel, /* True for a delete operation */ + int nData, const u8 *aData /* Record/key to insert */ +); + +typedef struct HctDbWriterOrigin HctDbWriterOrigin; +struct HctDbWriterOrigin { + u8 bDiscard; /* 1 for aDiscard[], 0 for aWritePg[] */ + i16 iPg; /* Index of page in array*/ +}; + +static int hctdbWriterSortFPKeys( + HctDatabase *pDb, + int eType, + HctDbWriter *p, + HctDbWriterOrigin *aOrigin /* Populate this array */ +){ + int iDiscard = 0; + int iWP = 1; + int iOut = 0; + int rc = SQLITE_OK; + + assert( eType==HCT_PAGETYPE_INDEX || eType==HCT_PAGETYPE_INTKEY ); + + while( iDiscarddiscardpg.nPg || iWPwritepg.nPg ){ + if( iDiscard>=p->discardpg.nPg ){ + aOrigin[iOut].bDiscard = 0; + aOrigin[iOut].iPg = iWP++; + iOut++; + } + else if( iWP>=p->writepg.nPg ){ + aOrigin[iOut].bDiscard = 1; + aOrigin[iOut].iPg = iDiscard++; + iOut++; + }else{ + int bDiscard = 0; + const u8 *aD = p->discardpg.aPg[iDiscard].aOld; + const u8 *aW = p->writepg.aPg[iWP].aOld; + + if( eType==HCT_PAGETYPE_INTKEY ){ + i64 i1 = hctDbIntkeyFPKey(aD); + i64 i2 = hctDbIntkeyFPKey(aW); + bDiscard = (i1<=i2); + }else{ + int nFP = 0; + const u8 *aFP = 0; + UnpackedRecord *pRec = p->writecsr.pRec; + rc = hctDbLoadRecord(pDb, &p->writecsr.rec, aW, 0, &nFP, &aFP); + if( rc!=SQLITE_OK ) break; + sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nFP, aFP, pRec); + rc = hctDbCompareFPKey(pDb, pRec, aD, &bDiscard); + if( rc!=SQLITE_OK ) break; + } + + aOrigin[iOut].bDiscard = bDiscard; + if( bDiscard ){ + aOrigin[iOut].iPg = iDiscard++; + }else{ + aOrigin[iOut].iPg = iWP++; + } + iOut++; + } + } + + return rc; +} + +#if 0 +/* +** +*/ +static int hctDbTruncateRecord( + HctBuffer *pBuf, /* Buffer to use for storage space */ + KeyInfo *pKeyInfo, /* Description of index */ + int *pnFP, /* IN/OUT: Size of record */ + const u8 **aFP /* IN/OUT: Pointer to record */ +){ +} +#endif + +/* +** This is a wrapper around: +** +** sqlite3HctFilePageEvict(pPg, 0); +** +** If the call fails with SQLITE_LOCKED because page pPg has been evicted, +** HctDbWriter.iEvictLockedPgno is set to the logical page number of pPg. +*/ +static int hctDbFilePageEvict(HctDbWriter *p, HctFilePage *pPg){ + int rc = sqlite3HctFilePageEvict(pPg, 0); + if( rc==SQLITE_LOCKED && sqlite3HctFilePageIsEvicted(pPg->pFile, pPg->iPg) ){ + p->iEvictLockedPgno = pPg->iPg; + } + return rc; +} + +static int hctDbFilePageCommit(HctDbWriter *p, HctFilePage *pPg){ + int rc = sqlite3HctFilePageCommit(pPg); + if( rc==SQLITE_LOCKED && sqlite3HctFilePageIsEvicted(pPg->pFile, pPg->iPg) ){ + p->iEvictLockedPgno = pPg->iPg; + } + return rc; +} + +static int hctDbMigrateReinsertKeys(HctDatabase *pDb, HctDbWriter *p); + +static int hctDbInsertFlushWrite(HctDatabase *pDb, HctDbWriter *p){ + int rc = SQLITE_OK; + int ii; + int eType = hctPagetype(p->writepg.aPg[0].aNew); + HctFilePage root; + int bUnevict = 0; + + memset(&root, 0, sizeof(root)); + + rc = hctDbMigrateReinsertKeys(pDb, p); + +#ifdef SQLITE_DEBUG + for(ii=1; rc==SQLITE_OK && iiwritepg.nPg; ii++){ + u32 iPeer = ((HctDbPageHdr*)p->writepg.aPg[ii-1].aNew)->iPeerPg; + assert( p->writepg.aPg[ii].iPg==iPeer ); + } +#endif + + /* Test if this is a split of a root page of the tree. */ + if( rc==SQLITE_OK + && p->writepg.nPg>1 + && p->writepg.aPg[0].iPg==p->writecsr.iRoot + ){ + HctFilePage *pPg0 = &p->writepg.aPg[0]; + hctMemcpy(&root, pPg0, sizeof(HctFilePage)); + memset(pPg0, 0, sizeof(HctFilePage)); + rc = sqlite3HctFilePageNew(pDb->pFile, pPg0); + if( rc==SQLITE_OK ){ + hctMemcpy(pPg0->aNew, root.aNew, pDb->pgsz); + hctDbRootPageInit(eType==HCT_PAGETYPE_INDEX, + hctPageheight(root.aNew)+1, pPg0->iPg, root.aNew, pDb->pgsz + ); + } + } + + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageRelease(&p->fanpg); + } + + /* Loop through the set of pages to write out. They must be + ** written in reverse order - so that page aWritePg[0] is written + ** last. */ + assert( p->writepg.nPg>0 ); + for(ii=p->writepg.nPg-1; rc==SQLITE_OK && ii>=0; ii--){ + rc = hctDbFilePageCommit(p, &p->writepg.aPg[ii]); + } + + /* If there is one, write the new root page to disk */ + if( rc==SQLITE_OK && root.iPg ){ + rc = hctDbFilePageCommit(p, &root); + sqlite3HctFilePageRelease(&root); + } + + if( rc!=SQLITE_OK ){ + bUnevict = 1; + } + + /* If there is more than one page in the writepg array, or more than + ** zero in the discardpg array, then the parent list must be updated. + ** This block does that. */ + if( (p->writepg.nPg>1 || p->discardpg.nPg>0) && rc==SQLITE_OK ){ + const u32 iRoot = p->writecsr.iRoot; + const int nOrig = p->discardpg.nPg + p->writepg.nPg - 1; + HctDbWriterOrigin aStatic[6]; + HctDbWriterOrigin *aDyn = 0; + HctDbWriterOrigin *aOrig = aStatic; + HctBuffer buf; + HctDbWriter wr; + int iOrig = 0; + + memset(&buf, 0, sizeof(buf)); + memset(&wr, 0, sizeof(wr)); + hctDbPageArrayReset(&wr.writepg); + hctDbPageArrayReset(&wr.discardpg); + + if( nOrig>ArraySize(aStatic) ){ + int nByte = sizeof(HctDbWriterOrigin) * nOrig; + aOrig = aDyn = (HctDbWriterOrigin*)sqlite3HctMalloc(&rc, nByte); + } + + if( rc==SQLITE_OK ){ + wr.iHeight = p->iHeight + 1; + rc = hctDbCsrAllocateUnpacked(&p->writecsr); + } + + if( rc==SQLITE_OK ){ + rc = hctdbWriterSortFPKeys(pDb, eType, p, aOrig); + } + + if( rc==SQLITE_OK ){ + do { + assert( rc==SQLITE_OK || rc==SQLITE_LOCKED ); + rc = SQLITE_OK; + + while( iOrigbDiscard; + + pPg = &(bDel ? p->discardpg.aPg : p->writepg.aPg)[pOrig->iPg]; + if( eType==HCT_PAGETYPE_INTKEY ){ + iKey = hctDbIntkeyFPKey(pPg->aOld); + }else{ + rc = hctDbLoadRecord(pDb, &buf, pPg->aOld, 0, &nFP, &aFP); + if( rc!=SQLITE_OK ) break; + pRec = p->writecsr.pRec; + sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nFP, aFP, pRec); + sqlite3HctDbRecordTrim(pRec); + } + + rc = hctDbInsert( + pDb, &wr, iRoot, pRec, iKey, pPg->iPg, bDel, nFP, aFP + ); + } + + if( rc==SQLITE_OK ){ + rc = hctDbInsertFlushWrite(pDb, &wr); + } + if( rc==SQLITE_LOCKED ){ + assert( iOrig>=wr.nWriteKey ); + iOrig -= wr.nWriteKey; + pDb->nCasFail++; + pDb->stats.nInternalRetry++; + } + hctDbWriterCleanup(pDb, &wr, (rc!=SQLITE_OK)); + wr.nWriteKey = 0; + + }while( rc==SQLITE_LOCKED ); + } + + sqlite3HctBufferFree(&buf); + sqlite3_free(aDyn); + } + + if( rc==SQLITE_OK ){ + for(ii=0; iidiscardpg.nPg; ii++){ + sqlite3HctFileClearInUse(&p->discardpg.aPg[ii], 0); + } + } + + /* Clean up the Writer object */ + hctDbWriterCleanup(pDb, p, bUnevict); + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbRollbackMode(HctDatabase *pDb, int eRollback){ + assert( eRollback==0 || pDb->eMode==HCT_MODE_NORMAL ); + pDb->pa.nWriteKey = 0; + pDb->eMode = eRollback ? HCT_MODE_ROLLBACK : HCT_MODE_NORMAL; + if( eRollback>1 ){ + memset(&pDb->pa, 0, sizeof(pDb->pa)); + hctDbPageArrayReset(&pDb->pa.writepg); + hctDbPageArrayReset(&pDb->pa.discardpg); + + /* During recovery rollback the connection should read the latest + ** version of the db - no exceptions. Set these two to the largest + ** possible values to ensure that this happens. */ + pDb->iSnapshotId = LARGEST_TID-1; + pDb->iLocalMinTid = LARGEST_TID-1; + } +} + +SQLITE_PRIVATE i64 sqlite3HctDbNCasFail(HctDatabase *pDb){ + return pDb->nCasFail; +} + +#if 0 +static HctDbIntkeyEntry *hctDbIntkeyEntry(u8 *aPg, int iCell){ + return iCell<0 ? 0 : (&((HctDbIntkeyLeaf*)aPg)->aEntry[iCell]); +} +#endif + +SQLITE_PRIVATE int sqlite3HctDbInsertFlush(HctDatabase *pDb, int *pnRetry){ + int rc = SQLITE_OK; + if( pDb->pa.writepg.nPg ){ + rc = hctDbInsertFlushWrite(pDb, &pDb->pa); + if( rc==SQLITE_LOCKED ){ + *pnRetry = pDb->pa.nWriteKey; + rc = SQLITE_OK; + pDb->nCasFail++; + }else{ + *pnRetry = 0; + } +#if 0 + { + sqlite3HctFileDebugPrint(pDb->pFile, + "%p: %s sqlite3HctDbInsertFlush() -> %d (nRetry=%d)\n", + pDb, (pDb->eMode==HCT_MODE_ROLLBACK ? "RB" : " "), rc, *pnRetry + ); + fflush(stdout); + } +#endif + pDb->pa.nWriteKey = 0; + } + return rc; +} + +/* +** If pRec is not NULL, it contains an unpacked index key. Compare this key +** with the write-fp-key in pDb->pa.aWriteFpKey. Return true if pRec is greater +** than or equal to the write-fp-key. +** +** Or, if pRec is NULL, iKey is the key and it is compared to +** pDb->iWriteFpKey. +*/ +static int hctDbTestWriteFpKey( + HctDbWriter *p, + RecordCompare xCompare, + UnpackedRecord *pRec, + i64 iKey +){ + if( pRec ){ + int r; + if( p->fp.aKey==0 ){ + r = 1; + }else{ + r = xCompare(p->fp.iKey, p->fp.aKey, pRec); + } + return (r <= 0); + } + return iKey>=p->fp.iKey; +} + +static int hctDbSetWriteFpKey(HctDatabase *pDb, HctDbWriter *p){ + int rc = SQLITE_OK; + HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[p->writepg.nPg-1].aNew; + + p->fp.aKey = 0; + p->fp.iKey = 0; + + if( pHdr->iPeerPg==0 ){ + if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ + p->fp.iKey = LARGEST_INT64; + } + }else{ + HctFilePage pg; + rc = sqlite3HctFilePageGet(pDb->pFile, pHdr->iPeerPg, &pg); + if( rc==SQLITE_OK ){ + if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ + p->fp.iKey = hctDbIntkeyFPKey(pg.aOld); + }else{ + rc = hctDbLoadRecordFP(pDb, pg.aOld, 0, &p->fp); + } + sqlite3HctFilePageRelease(&pg); + } + } + + return rc; +} + +/* +** Buffer aTarget[] contains a page that contains variable length keys +** (i.e. an intkey leaf or an index leaf or node). This function returns +** the offset of the aEntry[] array in aTarget. Before doing so, it sets +** output variable (*pszEntry) to the sizeof(aEntry[0]). +*/ +static int hctDbEntryArrayDim(const u8 *aTarget, int *pszEntry){ + int eType = hctPagetype(aTarget); + int nHeight = hctPageheight(aTarget); + int nRet; + + assert( eType==HCT_PAGETYPE_INTKEY || eType==HCT_PAGETYPE_INDEX ); + assert( eType==HCT_PAGETYPE_INDEX || nHeight==0 ); + if( eType==HCT_PAGETYPE_INTKEY ){ + *pszEntry = sizeof(HctDbIntkeyEntry); + nRet = sizeof(HctDbIntkeyLeaf); + }else if( nHeight==0 ){ + *pszEntry = sizeof(HctDbIndexEntry); + nRet = sizeof(HctDbIndexLeaf); + }else{ + *pszEntry = sizeof(HctDbIndexNodeEntry); + nRet = sizeof(HctDbIndexNode); + } + + return nRet; +} + +static int hctIsVarRecords(const u8 *aTarget){ + int eType = hctPagetype(aTarget); + int nHeight = hctPageheight(aTarget); + return (nHeight==0 || eType==HCT_PAGETYPE_INDEX); +} + +#ifdef SQLITE_DEBUG + +static void print_out_page(const char *zCaption, const u8 *aData, int nData){ + HctDbPageHdr *pPg = (HctDbPageHdr*)aData; + + if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY && pPg->nHeight==0 ){ + HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)pPg; + char *zPrint = 0; + const char *zSep = ""; + int ii; + + for(ii=0; iipg.nEntry; ii++){ + HctDbIntkeyEntry *pEntry = &pLeaf->aEntry[ii]; + zPrint = sqlite3_mprintf("%z%s(k=%lld f=%.2x %d..%d)", zPrint, zSep, + pEntry->iKey, pEntry->flags, + pEntry->iOff, pEntry->iOff+ hctDbIntkeyEntrySize(pEntry, nData) + ); + zSep = ","; + } + + printf("%s: nFreeGap=%d nFreeBytes=%d (intkey leaf)\n", zCaption, + pLeaf->hdr.nFreeGap, + pLeaf->hdr.nFreeBytes + ); + printf("%s: %s\n", zCaption, zPrint); + sqlite3_free(zPrint); + } + + if( hctPagetype(pPg)==HCT_PAGETYPE_INDEX && pPg->nHeight==0 ){ + HctDbIndexLeaf *pLeaf = (HctDbIndexLeaf*)pPg; + char *zPrint = 0; + const char *zSep = ""; + int ii; + + for(ii=0; iipg.nEntry; ii++){ + HctDbIndexEntry *pEntry = &pLeaf->aEntry[ii]; + zPrint = sqlite3_mprintf("%z%s(%d..%d)", zPrint, zSep, + pEntry->iOff, pEntry->iOff + hctDbIndexEntrySize(pEntry, nData) + ); + zSep = ","; + } + + printf("%s: nFreeGap=%d nFreeBytes=%d (index leaf)\n", zCaption, + pLeaf->hdr.nFreeGap, + pLeaf->hdr.nFreeBytes + ); + printf("%s: %s\n", zCaption, zPrint); + fflush(stdout); + sqlite3_free(zPrint); + } + + +} + +#define assert_or_print(E) \ + if( !(E) ){ \ + print_out_page("page", aData, nData); \ + assert( E ); \ + } + +typedef struct VarCellReader VarCellReader; +struct VarCellReader { + const u8 *aData; + int nData; + int szEntry; + int iEntry0; +}; + +static void hctVCRInit(VarCellReader *p, const u8 *aData, int nData){ + p->aData = aData; + p->nData = nData; + p->iEntry0 = hctDbEntryArrayDim(aData, &p->szEntry); +} + +static int hctVCRFindCell(VarCellReader *p, int iCell, int *pnByte){ + HctDbIndexNodeEntry *pEntry; + + pEntry = (HctDbIndexNodeEntry*)&p->aData[p->iEntry0 + iCell*p->szEntry]; + *pnByte = hctDbLocalsize(p->aData, p->nData, pEntry->nSize) + + hctDbOffset(0, pEntry->flags); + + return pEntry->iOff; +} + +static void assert_page_is_ok(const u8 *aData, int nData){ + + if( aData && hctIsVarRecords(aData) ){ + HctDbIndexNode *p = (HctDbIndexNode*)aData; + VarCellReader vcr; + int iEnd = nData; + int iStart = 0; + int nRecTotal = 0; + int ii = 0; + int nFreeExpect; + + hctVCRInit(&vcr, aData, nData); + for(ii=0; iipg.nEntry; ii++){ + int sz = 0; + int iOff = hctVCRFindCell(&vcr, ii, &sz); + if( iOff ){ + assert_or_print( (iOff+sz)<=nData ); + iEnd = MIN(iEnd, iOff); + nRecTotal += sz; + }else{ + assert( sz==0 && ii==0 ); + } + } + + iStart = vcr.iEntry0 + vcr.szEntry * p->pg.nEntry; + nFreeExpect = nData - (iStart + nRecTotal); + + assert_or_print( p->hdr.nFreeGap==(iEnd - iStart) ); + assert_or_print( p->hdr.nFreeBytes==nFreeExpect); + } + +} +#else +# define assert_page_is_ok(x,y) +#endif + +#ifdef SQLITE_DEBUG +static void assert_all_pages_ok(HctDatabase *pDb, HctDbWriter *p){ + int ii; + return; + for(ii=0; iiwritepg.nPg; ii++){ + u8 *aPg = p->writepg.aPg[ii].aNew; + assert( aPg[0]!=0x00 ); + assert( hctIsVarRecords(aPg) ); + assert_page_is_ok(aPg, pDb->pgsz); + assert( ii==p->writepg.nPg-1 + || ((HctDbPageHdr*)aPg)->iPeerPg==p->writepg.aPg[ii+1].iPg + ); + } +} +static void assert_all_pages_nonempty(HctDatabase *pDb, HctDbWriter *p){ + return; + if( p->writepg.nPg>1 ){ + int ii; + for(ii=0; iiwritepg.nPg; ii++){ + HctDbPageHdr *pPg = (HctDbPageHdr*)p->writepg.aPg[ii].aNew; + assert( pPg->nEntry>0 ); + } + } +} +#else +# define assert_all_pages_ok(x,y) +# define assert_all_pages_nonempty(x,y) +#endif + + +/* +** HOW INSERT/DELETE OPERATIONS WORK: +** +** 1. If the page array is not empty, flush it to disk if required. It +** should be flushed to disk if either: +** +** a) the key being written (specified by iKey/pRec) is greater or +** equal to the FP key to the right of the page array (stored +** in HctDbWriter.iWriteFpKey/aWriteFpKey). +** +** b) there are more than HCTDB_MAX_DIRTY pages in the array. +** +** 2. If the page array is empty, either because it was flushed to disk +** in (1) or because it was empty when this function was called, seek +** the write-cursor (HctDbWriter.writecsr) to the key being written. +** The page the cursor seeks to becomes the first page of the page +** array. +** +** 3. Locate within the page array the page into which the new key +** or delete-key should be inserted. There are three possible outcomes: +** +** i) the new key may just be written to the page. +** +** ii) the new key fits on the page, but leaves it underfull. In this +** context, "underfull" means that the total amount of free space +** on the page is less than or equal to (pgsz*2/3). +** +** iii) the new key does not fit on the page. +** +** In cases (ii) or (iii), first ensure that that the page has two peers in +** the page array (unless there are fewer than three pages in the list, in +** which case the entire list should be loaded). Then redistribute the keys +** between the minimum number of pages, discarding or adding nodes as +** required. +*/ + +/* +** Insert nPg new pages at index iPg into the write-array of the HctDbWriter +** passed as the second argument and link them into the list. +*/ +static int hctDbExtendWriteArray( + HctDatabase *pDb, + HctDbWriter *p, + int iPg, + int nPg +){ + int rc = SQLITE_OK; + int ii; + + assert( iPg>0 ); + assert( (p->writepg.nPg+nPg)>0 ); + assert( p->writepg.nPg>0 ); + + /* Add any new pages required */ + for(ii=iPg; rc==SQLITE_OK && iiwritepg.nPgwritepg.aPg) ); + assert( ii>0 ); + if( iiwritepg.nPg ){ + int nByte = sizeof(HctFilePage) * (p->writepg.nPg-ii); + memmove(&p->writepg.aPg[ii+1], &p->writepg.aPg[ii], nByte); + } + p->writepg.nPg++; + memset(&p->writepg.aPg[ii], 0, sizeof(HctFilePage)); + rc = sqlite3HctFilePageNew(pDb->pFile, &p->writepg.aPg[ii]); + if( rc==SQLITE_OK ){ + HctDbPageHdr *pNew = (HctDbPageHdr*)p->writepg.aPg[ii].aNew; + HctDbPageHdr *pPrev = (HctDbPageHdr*)p->writepg.aPg[ii-1].aNew; + memset(pNew, 0, sizeof(HctDbPageHdr)); + pNew->hdrFlags = hctPagetype(pPrev); + pNew->nHeight = pPrev->nHeight; + pNew->iPeerPg = pPrev->iPeerPg; + pPrev->iPeerPg = p->writepg.aPg[ii].iPg; + } + } + + /* Remove pages that are not required */ + for(ii=nPg; ii<0; ii++){ + HctDbPageHdr *pPrev = (HctDbPageHdr*)(p->writepg.aPg[iPg-1].aNew); + HctDbPageHdr *pRem = (HctDbPageHdr*)(p->writepg.aPg[iPg].aNew); + pPrev->iPeerPg = pRem->iPeerPg; + assert( p->writepg.nPg>1 ); + p->writepg.nPg--; + + assert( iPg!=0 ); + assert( p->writepg.aPg[iPg].aOld==0 ); + sqlite3HctFilePageUnwrite(&p->writepg.aPg[iPg]); + + if( iPg!=p->writepg.nPg ){ + int nByte = sizeof(HctFilePage) * (p->writepg.nPg-iPg); + assert( nByte>0 ); + memmove(&p->writepg.aPg[iPg], &p->writepg.aPg[iPg+1], nByte); + } + } + + return rc; +} + +static int hctDbCsrLoadAndDecode( + HctDbCsr *pCsr, + int iCell, + UnpackedRecord **ppRec +){ + const u8 *aPg = pCsr->pg.aNew ? pCsr->pg.aNew : pCsr->pg.aOld; + int nData = 0; + const u8 *aData = 0; + int rc; + + rc = hctDbLoadRecord(pCsr->pDb, &pCsr->rec, aPg, iCell, &nData, &aData); + if( rc==SQLITE_OK ){ + rc = hctDbCsrAllocateUnpacked(pCsr); + } + if( rc==SQLITE_OK ){ + *ppRec = pCsr->pRec; + sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, nData, aData, pCsr->pRec); + assert( pCsr->pRec->nField>0 ); + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbCsrLoadAndDecode(HctDbCsr *pCsr, UnpackedRecord **ppRec){ + return hctDbCsrLoadAndDecode(pCsr, pCsr->iCell, ppRec); +} + +/* +** +*/ +static int hctDbFindLhsPeer( + HctDatabase *pDb, + HctDbWriter *p, + HctFilePage *pPg, + HctFilePage *pOut +){ + HctDbCsr csr; + u8 *aLeft = pPg->aNew ? pPg->aNew : pPg->aOld; + int rc = SQLITE_OK; + + hctDbCsrInit(pDb, p->writecsr.iRoot, 0, &csr); + csr.pKeyInfo = p->writecsr.pKeyInfo; + if( hctPagetype(aLeft)==HCT_PAGETYPE_INTKEY ){ + i64 iKey = hctDbIntkeyFPKey(aLeft); + assert( iKey!=SMALLEST_INT64 ); + rc = hctDbCsrSeek(&csr, 0, p->iHeight, 0, 0, iKey-1, 0); + }else{ + UnpackedRecord *pRec = 0; + HctBuffer buf; + int nData = 0; + const u8 *aData = 0; + memset(&buf, 0, sizeof(buf)); + rc = hctDbLoadRecord(pDb, &buf, aLeft, 0, &nData, &aData); + if( rc==SQLITE_OK ){ + rc = hctDbCsrAllocateUnpacked(&p->writecsr); + } + if( rc==SQLITE_OK ){ + pRec = p->writecsr.pRec; + sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nData, aData, pRec); + sqlite3HctDbRecordTrim(pRec); + pRec->default_rc = 1; + rc = hctDbCsrSeek(&csr, 0, p->iHeight, 0, pRec, 0, 0); + pRec->default_rc = 0; + + assert( csr.pg.iPg!=pPg->iPg ); + } + sqlite3HctBufferFree(&buf); + } + + if( rc==SQLITE_OK + && ((HctDbPageHdr*)csr.pg.aOld)->iPeerPg==pPg->iPg + ){ + *pOut = csr.pg; + }else{ + memset(pOut, 0, sizeof(HctFilePage)); + rc = SQLITE_LOCKED_ERR(pPg->iPg, "peer"); + } + + return rc; +} + +static void hctDbIrrevocablyEvictPage(HctDatabase *pDb, HctDbWriter *p){ + int rc = SQLITE_OK; + u32 iLocked = p->iEvictLockedPgno; + int bDone = 0; + + KeyInfo *pKeyInfo = sqlite3KeyInfoRef(p->writecsr.pKeyInfo); + u32 iRoot = p->writecsr.iRoot; + + sqlite3HctFileDebugPrint(pDb->pFile,"BEGIN forced eviction of %d\n", iLocked); + + do { + HctFilePage pg1; + HctFilePage pg0; + memset(&pg1, 0, sizeof(pg1)); + if( p->writecsr.iRoot==0 ){ + hctDbCsrInit(pDb, iRoot, pKeyInfo, &p->writecsr); + } + rc = sqlite3HctFilePageGet(pDb->pFile, iLocked, &pg1); + while( rc==SQLITE_OK ){ + memset(&pg0, 0, sizeof(pg0)); + rc = hctDbFindLhsPeer(pDb, p, &pg1, &pg0); + if( rc ) break; + if( 0==sqlite3HctFilePageIsEvicted(pg0.pFile, pg0.iPg) ) break; + sqlite3HctFilePageRelease(&pg1); + pg1 = pg0; + memset(&pg0, 0, sizeof(pg0)); + } + + if( rc==SQLITE_OK ){ + bDone = (pg1.iPg==iLocked); + sqlite3HctFileDebugPrint( + pDb->pFile, "forcing write of %d->%d\n", pg0.iPg, pg1.iPg + ); + + rc = sqlite3HctFilePageEvict(&pg1, 1); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageWrite(&pg0); + } + if( rc==SQLITE_OK ){ + hctMemcpy(pg0.aNew, pg0.aOld, pDb->pgsz); + } + if( rc==SQLITE_OK ){ + p->writepg.aPg[0] = pg0; + p->writepg.nPg = 1; + rc = hctDbExtendWriteArray(pDb, p, 1, 1); + } + if( rc==SQLITE_OK ){ + hctMemcpy(p->writepg.aPg[1].aNew, pg1.aOld, pDb->pgsz); + p->discardpg.aPg[0] = pg1; + p->discardpg.nPg = 1; + } + + p->bDoCleanup = 1; + if( rc==SQLITE_OK ){ + rc = hctDbInsertFlushWrite(pDb, p); + }else{ + hctDbWriterCleanup(pDb, p, 1); + } + + }else{ + sqlite3HctFilePageRelease(&pg0); + sqlite3HctFilePageRelease(&pg1); + } + }while( rc==SQLITE_OK && bDone==0 ); + + sqlite3KeyInfoUnref(pKeyInfo); + sqlite3HctFileDebugPrint(pDb->pFile,"END forced eviction of %d\n", iLocked); +} + +/* +** +*/ +static int hctDbLoadPeers(HctDatabase *pDb, HctDbWriter *p, int *piPg){ + int rc = SQLITE_OK; + int iPg = *piPg; + + if( p->writepg.nPg<3 ){ + HctFilePage *pLeft = &p->writepg.aPg[0]; + + if( p->writepg.nPg==1 && 0==hctIsLeftmost(pLeft->aNew) ){ + HctFilePage *pCopy = 0; + assert( iPg==0 ); + + /* First, evict the page currently in p->writepg.aPg[0]. If we + ** successfully evict the page here, then of course no other thread + ** can - which guarantees that the seek operation below really does + ** find the left-hand peer (assuming the db is not corrupt). */ + rc = hctDbFilePageEvict(p, pLeft); + + /* Assuming the LOGICAL_EVICTED flag was successfully set, seek + ** cursor csr to the leaf page immediately to the left of pLeft. */ + if( rc==SQLITE_OK ){ + if( p->discardpg.nPg>0 ){ + int nMove = p->discardpg.nPg * sizeof(HctFilePage); + memmove(&p->discardpg.aPg[1], &p->discardpg.aPg[0], nMove); + } + pCopy = &p->discardpg.aPg[0]; + p->discardpg.nPg++; + *pCopy = *pLeft; + rc = hctDbFindLhsPeer(pDb, p, pCopy, pLeft); + } + if( rc==SQLITE_OK ){ + assert( ((HctDbPageHdr*)pLeft->aOld)->iPeerPg==pCopy->iPg ); + rc = sqlite3HctFilePageWrite(pLeft); + } + + if( rc==SQLITE_OK ){ + hctMemcpy(pLeft->aNew, pLeft->aOld, pDb->pgsz); + rc = hctDbExtendWriteArray(pDb, p, 1, 1); + } + if( rc==SQLITE_OK ){ + hctMemcpy(p->writepg.aPg[1].aNew, pCopy->aNew, pDb->pgsz); + sqlite3HctFilePageUnwrite(pCopy); + *piPg = 1; + } + } + + if( rc==SQLITE_OK ){ + HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[p->writepg.nPg-1].aNew; + if( pHdr->iPeerPg ){ + HctFilePage *pCopy = &p->discardpg.aPg[p->discardpg.nPg]; + + rc = sqlite3HctFilePageGet(pDb->pFile, pHdr->iPeerPg, pCopy); + if( rc==SQLITE_OK ){ + /* Evict the page immediately */ + rc = hctDbFilePageEvict(p, pCopy); + if( rc!=SQLITE_OK ){ + sqlite3HctFilePageRelease(pCopy); + }else{ + p->discardpg.nPg++; + } + } + + if( rc==SQLITE_OK ){ + rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); + } + if( rc==SQLITE_OK ){ + HctFilePage *pPg = &p->writepg.aPg[p->writepg.nPg-1]; + hctMemcpy(pPg->aNew, pCopy->aOld, pDb->pgsz); + rc = hctDbSetWriteFpKey(pDb, p); + } + } + } + } + + return rc; +} + +static int hctDbOverflowArrayAppend(HctDbOverflowArray *p, u32 ovfl, int nOvfl){ + assert( p->nAlloc>=p->nEntry ); + assert( ovfl>0 && nOvfl>0 ); + + if( p->nAlloc==p->nEntry ){ + int nNew = p->nAlloc ? p->nAlloc*2 : 16; + int nByte = nNew*sizeof(HctDbOverflow); + HctDbOverflow *aNew = (HctDbOverflow*)sqlite3_realloc(p->aOvfl, nByte); + + if( aNew==0 ){ + return SQLITE_NOMEM_BKPT; + } + p->aOvfl = aNew; + p->nAlloc = nNew; + } + + p->aOvfl[p->nEntry].pgno = ovfl; + p->aOvfl[p->nEntry].nOvfl = nOvfl; + p->nEntry++; + + return SQLITE_OK; +} + + +/* +** Buffer aTarget[] must contain a page with variable sized records - an +** index leaf or node, or an intkey leaf. This function returns the offset +** of the record for entry iEntry, and populates output variable *pFlags +** with the entry flags. +*/ +static int hctDbFindEntry(u8 *aTarget, int iEntry, u8 *pFlags, int *pnSize){ + int iRet; + if( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ){ + iRet = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].iOff; + *pFlags = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].flags; + *pnSize = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].nSize; + }else if( hctPageheight(aTarget)==0 ){ + iRet = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].iOff; + *pFlags = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].flags; + *pnSize = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].nSize; + }else{ + iRet = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].iOff; + *pFlags = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].flags; + *pnSize = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].nSize; + } + return iRet; +} + +static int hctDbRemoveOverflow( + HctDatabase *pDb, + HctDbWriter *p, + u8 *aPage, + int iCell +){ + int rc = SQLITE_OK; + + int nSize = 0; + u8 flags = 0; + int iOff = hctDbFindEntry(aPage, iCell, &flags, &nSize); + if( flags & HCTDB_HAS_OVFL ){ + u32 ovfl = 0; + int nOvfl = 0; + const int nBytePerOvfl = pDb->pgsz - sizeof(HctDbPageHdr); + int nLocal = hctDbLocalsize(aPage, pDb->pgsz, nSize); + + if( flags & HCTDB_HAS_TID ) iOff += 8; + if( flags & HCTDB_HAS_RANGETID ) iOff += 8; + if( flags & HCTDB_HAS_RANGEOLD ) iOff += 4; + + ovfl = hctGetU32(&aPage[iOff]); + nOvfl = ((nSize - nLocal) + nBytePerOvfl - 1) / nBytePerOvfl; + + rc = hctDbOverflowArrayAppend(&p->delOvfl, ovfl, nOvfl); + } + + return rc; +} + +static void hctDbRemoveTids( + HctDbIndexNodeEntry *p, + u8 *aPg, + u64 iSafeTid +){ + if( (p->flags & HCTDB_HAS_TID)==HCTDB_HAS_TID ){ + u64 iTid; + memcpy(&iTid, &aPg[p->iOff], sizeof(u64)); + if( (iTid & HCT_TID_MASK)<=iSafeTid ){ + p->flags &= ~HCTDB_HAS_TID; + p->iOff += sizeof(u64); + } + } + if( (p->flags & (HCTDB_HAS_TID|HCTDB_HAS_RANGETID))==HCTDB_HAS_RANGETID ){ + u64 iTid; + assert( p->flags & HCTDB_HAS_RANGEOLD ); + memcpy(&iTid, &aPg[p->iOff], sizeof(u64)); + if( (iTid & HCT_TID_MASK)<=iSafeTid ){ + p->flags &= ~(HCTDB_HAS_RANGETID|HCTDB_HAS_RANGEOLD); + p->iOff += (sizeof(u64) + sizeof(u32)); + } + } +} + +/* +** Populate the aSz[] array with the sizes and locations of each cell +** +** (bClobber && nNewCell==0) -> full-delete +** (bClobber) -> clobber +** (bClobber==0) -> insert of new key +*/ +static void hctDbBalanceGetCellSz( + HctDatabase *pDb, + HctDbWriter *pWriter, + int iInsert, + int bClobber, + int nNewCell, /* Bytes stored on page for new cell */ + u8 *aPg, + HctDbCellSz *aSz, + int *pnSz /* OUT: number of entries in aSz[] */ +){ + HctDbPageHdr *pPg = (HctDbPageHdr*)aPg; + u64 iSafeTid = sqlite3HctFileSafeTID(pDb->pFile); + int szEntry; + int i0 = hctDbEntryArrayDim(aPg, &szEntry); + int iCell = 0; /* Current cell of aPgCopy[ii] */ + int iSz = 0; /* Current populated size of aSz[] */ + int iIns = iInsert; + + for(iSz=0; iCellnEntry || iCell==iIns; iSz++){ + HctDbCellSz *pSz = &aSz[iSz]; + + assert( pPg->nEntrypgsz ); + if( iCell==iIns ){ + assert( nNewCell>0 || bClobber ); + if( nNewCell ){ + pSz->nByte = szEntry + nNewCell; + pSz->aEntry = 0; + pSz->aCell = 0; + }else{ + iSz--; + } + if( bClobber ){ + iCell++; + } + iIns = -1; + }else{ + HctDbIndexNodeEntry *pE = (HctDbIndexNodeEntry*)&aPg[i0+iCell*szEntry]; + hctDbRemoveTids(pE, aPg, iSafeTid); + + pSz->nByte = szEntry + hctDbPageRecordSize(pPg, pDb->pgsz, iCell); + pSz->aEntry = (u8*)pE; + pSz->aCell = &aPg[pE->iOff]; + assert( pSz->nByte>0 ); + iCell++; + } + } + if( pnSz ) *pnSz = iSz; +} + +typedef struct HctDbInsertOp HctDbInsertOp; +struct HctDbInsertOp { + u8 entryFlags; /* Flags for page entry added by this call */ + u8 *aEntry; /* Buffer containing formatted entry */ + int nEntry; /* Size of aEntry[] */ + int nEntrySize; /* Value for page header nSize field */ + + int iPg; /* Index in HctDbWriter.writepg.aPg */ + int iInsert; /* Index in page to write to */ + + i64 iIntkey; /* Key to insert (if intkey page) */ + + int eBalance; /* True if balance routine must be called */ + int bFullDel; /* True to skip insert */ + + u32 iOldPg; + const u8 *aOldPg; +}; + +/* +** Values for HctDbInsertOp.eBalance +*/ +#define BALANCE_NONE 0 +#define BALANCE_OPTIONAL 1 +#define BALANCE_REQUIRED 2 + + +static int hctDbBalanceAppend( + HctDatabase *pDb, + HctDbWriter *p, + HctDbInsertOp *pOp +){ + int rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); + if( rc==SQLITE_OK ){ + HctDbLeaf *pLeaf = (HctDbLeaf*)p->writepg.aPg[p->writepg.nPg-1].aNew; + pLeaf->hdr.nFreeBytes = pDb->pgsz - sizeof(HctDbLeaf); + pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; + assert( p->iHeight==0 ); + assert_all_pages_ok(pDb, p); + pOp->iPg = p->writepg.nPg-1; + pOp->iInsert = 0; + } + return rc; +} + +static HctBalance *hctDbBalanceSpace(int *pRc, HctDatabase *pDb){ + if( pDb->pBalance==0 ){ + HctBalance *p = 0; + int nPg = ArraySize(p->aPg); + int nSzAlloc = (nPg * 2 * MAX_CELLS_PER_PAGE(pDb->pgsz)) + 1; + + pDb->pBalance = p = (HctBalance*)sqlite3HctMalloc(pRc, + sizeof(HctBalance) + + nPg * pDb->pgsz + + sizeof(HctDbCellSz) * nSzAlloc + ); + if( p ){ + u8 *aCsr = (u8*)&p[1]; + int ii; + for(ii=0; iiaPg[ii] = aCsr; + aCsr += pDb->pgsz; + } + p->aSz = (HctDbCellSz*)aCsr; + p->nSzAlloc = nSzAlloc; + } + } + return pDb->pBalance; +} + +/* +** Rebalance routine for pages with variably-sized records - intkey leaves, +** index leaves and index nodes. +*/ +static int hctDbBalance( + HctDatabase *pDb, + HctDbWriter *p, + HctDbInsertOp *pOp, + int bClobber +){ + int rc = SQLITE_OK; /* Return code */ + int iPg = pOp->iPg; + int iIns = pOp->iInsert; + + int iLeftPg; /* Index of leftmost page used in balance */ + int nIn = 1; /* Number of input peers for balance */ + int ii; /* Iterator used for various things */ + int nOut = 0; /* Number of output peers */ + int szEntry = 0; + int iEntry0 = 0; + HctDbCellSz *aSz = 0; + int nSz = 0; + u8 **aPgCopy = 0; + + int nRem; + + int aPgRem[5]; + int aPgFirst[6]; + + /* Grab the temporary space used by balance operations. */ + HctBalance *pBal = 0; + pBal = hctDbBalanceSpace(&rc, pDb); + if( pBal==0 ) return rc; + + /* Populate the aSz[] and aPgCopy[] arrays as if this were a single-page + ** rebalance only. */ + aSz = &pBal->aSz[MAX_CELLS_PER_PAGE(pDb->pgsz) * 2]; + aPgCopy = pBal->aPg; + hctMemcpy(aPgCopy[0], p->writepg.aPg[iPg].aNew, pDb->pgsz); + hctDbBalanceGetCellSz(pDb, p, iIns, bClobber,pOp->nEntry,aPgCopy[0],aSz,&nSz); + + if( pOp->eBalance==BALANCE_OPTIONAL ){ + int nTotal = 0; + for(ii=0; iipgsz - sizeof(HctDbIntkeyLeaf)) ){ + /* This is a single page balance */ + nIn = 1; + nOut = 1; + iLeftPg = iPg; + } + } + + if( nOut==0 ){ + HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[iPg].aNew; + if( p->iHeight==0 + && bClobber==0 && pOp->nEntry>0 + && pHdr->iPeerPg==0 && pHdr->nEntry==iIns + ){ + p->bAppend = 1; + rc = hctDbBalanceAppend(pDb, p, pOp); + return rc; + } + + /* If the HctDbWriter.writepg.aPg[] array still contains a single page, + ** load some peer pages into it. */ + assert( p->discardpg.nPg>=0 ); + if( IS_HCT_MIGRATE(pDb)==0 ){ + rc = hctDbLoadPeers(pDb, p, &iPg); + if( rc!=SQLITE_OK ){ + return rc; + } + } + assert_all_pages_ok(pDb, p); + + /* Determine the subset of HctDbWriter.writepg.aPg[] pages that will be + ** rebalanced. Variable nIn is set to the number of input pages, and + ** iLeftPg to the index of the leftmost of them. */ + iLeftPg = iPg; + if( iPg==0 ){ + nIn = MIN(p->writepg.nPg, 3); + }else{ + if( iPg==p->writepg.nPg-1 ){ + nIn = MIN(p->writepg.nPg, 3); + iLeftPg -= (nIn-1); + }else{ + nIn = 3; + iLeftPg--; + } + SWAP(u8*, aPgCopy[0], aPgCopy[iPg-iLeftPg]); + } + + /* aPgCopy[iPg-iLeftPg] already contains a copy of page iPg at this + ** point. This loop takes copies of the other pages involved in the + ** balance operation. */ + for(ii=0; iiwritepg.aPg[iLeftPg+ii].aNew, pDb->pgsz); + } + + for(ii=(iPg-iLeftPg)-1; ii>=0; ii--){ + int nCell = hctPagenentry(aPgCopy[ii]); + aSz -= nCell; + nSz += nCell; + hctDbBalanceGetCellSz(pDb, p, -1, 0, 0, aPgCopy[ii], aSz, 0); + } + for(ii=(iPg-iLeftPg)+1; iiwritecsr.pKeyInfo==0 ){ + pDb->stats.nBalanceIntkey++; + }else{ + pDb->stats.nBalanceIndex++; + } + if( nIn==1 ){ + pDb->stats.nBalanceSingle++; + } + + /* Figure out how many output pages will be required. This loop calculates + ** a mapping heavily biased to the left. */ + aPgFirst[0] = 0; + if( nOut==0 ){ + assert( sizeof(HctDbIntkeyLeaf)==sizeof(HctDbIndexLeaf) ); + nRem = pDb->pgsz - sizeof(HctDbIntkeyLeaf); + nOut = 1; + for(ii=0; iinRem ){ + aPgRem[nOut-1] = nRem; + aPgFirst[nOut] = ii; + nOut++; + nRem = pDb->pgsz - sizeof(HctDbIntkeyLeaf); + assert( nOut<=ArraySize(aPgRem) ); + } + nRem -= aSz[ii].nByte; + } + aPgRem[nOut-1] = nRem; + } + aPgFirst[nOut] = nSz; + + /* Adjust the packing calculated by the previous loop. */ + for(ii=nOut-1; ii>0; ii--){ + /* Try to shift cells from output page (ii-1) to output page (ii). Shift + ** cells for as long as (a) there is more free space on page (ii) than on + ** page (ii-1), and (b) there is enough free space on page (ii) to fit + ** the last cell from page (ii-1). */ + while( aPgRem[ii]>aPgRem[ii-1] ){ /* condition (a) */ + HctDbCellSz *pLast = &aSz[aPgFirst[ii]-1]; + if( pLast->nByte>aPgRem[ii] ) break; /* condition (b) */ + aPgRem[ii] -= pLast->nByte; + aPgRem[ii-1] += pLast->nByte; + aPgFirst[ii] = (pLast - aSz); + } + } + + /* Allocate any required new pages and link them into the list. */ + rc = hctDbExtendWriteArray(pDb, p, iLeftPg+1, nOut-nIn); + + /* Populate the output pages */ + iEntry0 = hctDbEntryArrayDim(aPgCopy[0], &szEntry); + for(ii=0; iiwritepg.aPg[iIdx].aNew; + HctDbIndexLeaf *pLeaf = (HctDbIndexLeaf*)aTarget; + int iOff = pDb->pgsz; /* Start of data area in aTarget[] */ + int iLast = (ii==(nOut-1) ? nSz : aPgFirst[ii+1]); + int nNewEntry = 0; /* Number of entries on this output page */ + int i2; + + for(i2=0; i2<(iLast - aPgFirst[ii]); i2++){ + HctDbCellSz *pSz = &aSz[aPgFirst[ii] + i2]; + if( pSz->aEntry ){ + u8 *aETo = &aTarget[iEntry0 + nNewEntry*szEntry]; + int nCopy = pSz->nByte - szEntry; + hctMemcpy(aETo, pSz->aEntry, szEntry); + iOff -= nCopy; + ((HctDbIndexEntry*)aETo)->iOff = iOff; + hctMemcpy(&aTarget[iOff], pSz->aCell, nCopy); + nNewEntry++; + }else{ + pOp->iPg = iIdx; + pOp->iInsert = i2; + } + } + + pLeaf->pg.nEntry = nNewEntry; + pLeaf->hdr.nFreeBytes = iOff - (iEntry0 + nNewEntry*szEntry); + pLeaf->hdr.nFreeGap = iOff - (iEntry0 + nNewEntry*szEntry); + } + + return rc; +} + + +static int hctDbBalanceIntkeyNode( + HctDatabase *pDb, + HctDbWriter *p, + int iPg, + int iInsert, /* Index in iPg for new key, if any */ + i64 iKey, /* Integer key value */ + u32 iChildPg /* The child pgno */ +){ + int nMax = hctDbMaxCellsPerIntkeyNode(pDb->pgsz); + int rc = SQLITE_OK; + int nIn; /* Number of input pages */ + int nOut; /* Number of output pages */ + int iLeftPg; /* Index of left-most page in balance */ + int ii; /* Iterator variable */ + int nTotal = 0; /* Total number of keys for balance */ + u8 *aPgCopy[3]; + u8 *pFree = 0; + + assert( p->writepg.aPg[p->writepg.nPg-1].aNew ); + if( IS_HCT_MIGRATE(pDb)==0 ){ + rc = hctDbLoadPeers(pDb, p, &iPg); + if( rc!=SQLITE_OK ){ + return rc; + } + } + + iLeftPg = iPg; + if( iPg==0 ){ + nIn = MIN(p->writepg.nPg, 3); + }else if( iPg==p->writepg.nPg-1 ){ + nIn = MIN(p->writepg.nPg, 3); + iLeftPg -= (nIn-1); + }else{ + nIn = MIN(p->writepg.nPg, 3); + iLeftPg--; + assert( iLeftPg+nIn<=p->writepg.nPg ); + } + + /* Take a copy of each input page. Make the buffer used to store each + ** copy larger than required by the size of one entry. Then, there is + ** a new entry to add in stack variables (iKey/iChildPg), add it to the + ** copy of its page. This is to make the loop that populates the output + ** pages below easier to write. A real candidate for optimization, this. */ + pFree = (u8*)sqlite3Malloc(nIn*(pDb->pgsz+sizeof(HctDbIntkeyNodeEntry))); + if( pFree==0 ) return SQLITE_NOMEM; + for(ii=0; iipgsz + sizeof(HctDbIntkeyNodeEntry)) * ii]; + hctMemcpy(aPgCopy[ii], p->writepg.aPg[iLeftPg+ii].aNew, pDb->pgsz); + } + if( iInsert>=0 ){ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPgCopy[iPg-iLeftPg]; + if( iInsertpg.nEntry ){ + int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-iInsert); + memmove(&pNode->aEntry[iInsert+1], &pNode->aEntry[iInsert], nByte); + } + pNode->pg.nEntry++; + pNode->aEntry[iInsert].iKey = iKey; + pNode->aEntry[iInsert].iChildPg = iChildPg; + } + + /* Figure out how many entries there are, in total */ + for(ii=0; iipg.nEntry; + } + + /* Figure out how many output pages are required */ + nOut = (nTotal + (nMax-1)) / nMax; + rc = hctDbExtendWriteArray(pDb, p, iLeftPg+1, nOut-nIn); + assert( rc==SQLITE_OK ); /* todo */ + + /* Populate the output pages */ + if( rc==SQLITE_OK ){ + int nRem = nTotal; + int iIn = 0; + int iInEntry = 0; + + for(ii=0; iiwritepg.aPg[ii+iLeftPg].aNew; + for(pEntry=pNode->aEntry; pEntry<&pNode->aEntry[nCell]; pEntry++){ + HctDbIntkeyNode *pIn = (HctDbIntkeyNode*)aPgCopy[iIn]; + *pEntry = pIn->aEntry[iInEntry++]; + if( iInEntry>=pIn->pg.nEntry ){ + iInEntry = 0; + iIn++; + } + } + pNode->pg.nEntry = nCell; + nRem -= nCell; + } + } + + sqlite3_free(pFree); + return rc; +} + +/* +** This function handles the second part of an insert or delete operation +** on an internal intkey node key. The implementation is separate from the +** usual insert/delete routine because internal intkey nodes use fixed size +** records. The other three types of pages found in lists - intkey leaves, +** index leaves and index nodes - all use variable sized entries. +*/ +static int hctDbInsertIntkeyNode( + HctDatabase *pDb, + HctDbWriter *p, + int iPg, + int iInsert, + i64 iKey, /* Integer key value */ + u32 iChildPg, /* The child pgno */ + int bClobber, /* True to clobber entry iInsert */ + int bDel /* True for a delete operation */ +){ + int nMax = hctDbMaxCellsPerIntkeyNode(pDb->pgsz); + int nMin = hctDbMinCellsPerIntkeyNode(pDb->pgsz); + HctDbIntkeyNode *pNode; + int rc = SQLITE_OK; + + /* If bDel is set, then bClobber must also be set. */ + assert( bDel==0 || bClobber ); + + pNode = (HctDbIntkeyNode*)p->writepg.aPg[iPg].aNew; + if( (pNode->pg.nEntry>=nMax && bClobber==0 && bDel==0 ) ){ + /* Need to do a balance operation to make room for the new entry */ + rc = hctDbBalanceIntkeyNode(pDb, p, iPg, iInsert, iKey, iChildPg); + }else if( bDel ){ + assert( iInsertpg.nEntry ); + if( iInsert==0 ){ + rc = hctDbLoadPeers(pDb, p, &iPg); + pNode = (HctDbIntkeyNode*)p->writepg.aPg[iPg].aNew; + } + if( rc==SQLITE_OK ){ + if( iInsert<(pNode->pg.nEntry-1) ){ + int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-1-iInsert); + memmove(&pNode->aEntry[iInsert], &pNode->aEntry[iInsert+1], nByte); + } + pNode->pg.nEntry--; + if( iInsert==0 || pNode->pg.nEntrypg.nEntry ){ + int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-iInsert); + memmove(&pNode->aEntry[iInsert+1], &pNode->aEntry[iInsert], nByte); + } + pNode->pg.nEntry++; + } + pNode->aEntry[iInsert].iKey = iKey; + pNode->aEntry[iInsert].iChildPg = iChildPg; + pNode->aEntry[iInsert].unused = 0; + } + + return rc; +} + + +/* +** The buffer passed as the first +*/ +static int hctDbFreegap(void *aPg){ + assert( + (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) + || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) + ); + return ((HctDbIndexNode*)aPg)->hdr.nFreeGap; +} + +static int hctDbFreebytes(void *aPg){ + assert( + (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) + || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) + ); + return ((HctDbIndexNode*)aPg)->hdr.nFreeBytes; +} + +static int hctDbInsertOverflow( + HctDatabase *pDb, + HctDbWriter *pWriter, + u8 *aTarget, + int nData, + const u8 *aData, + int *pnWrite, + u32 *ppgOvfl +){ + int rc = SQLITE_OK; + int nLocal = hctDbLocalsize(aTarget, pDb->pgsz, nData); + + if( nLocal==nData ){ + *pnWrite = nData; + *ppgOvfl = 0; + }else{ + const int sz = (pDb->pgsz - sizeof(HctDbPageHdr)); + int nRem; + int nCopy; + u32 iPg = 0; + int nOvfl = 0; + + nRem = nData; + nCopy = (nRem-nLocal) % sz; + if( nCopy==0 ) nCopy = sz; + while( rc==SQLITE_OK && nRem>nLocal ){ + HctFilePage pg; + nOvfl++; + rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &pg); + if( rc==SQLITE_OK ){ + HctDbPageHdr *pPg = (HctDbPageHdr*)pg.aNew; + memset(pPg, 0, sizeof(HctDbPageHdr)); + pPg->iPeerPg = iPg; + pPg->nEntry = nCopy; + hctMemcpy(&pPg[1], &aData[nRem-nCopy], nCopy); + iPg = pg.iNewPg; + sqlite3HctFilePageRelease(&pg); + } + nRem -= nCopy; + nCopy = sz; + } + + *ppgOvfl = iPg; + *pnWrite = nLocal; + + if( rc==SQLITE_OK ){ + rc = hctDbOverflowArrayAppend(&pWriter->insOvfl, iPg, nOvfl); + } + } + + return rc; +} + +static void hctDbRemoveCell( + HctDatabase *pDb, + HctDbWriter *pWriter, + u8 *aTarget, + int iRem +){ + HctDbIndexNode *p = (HctDbIndexNode*)aTarget; + const int eType = hctPagetype(aTarget); + const int nHeight = hctPageheight(aTarget); + const int pgsz = pDb->pgsz; + + int szEntry = 0; /* Size of each entry in aEntry[] array */ + int iArrayOff = 0; /* Offset of aEntry array in aTarget */ + int iData = 0; /* Offset of cell in aTarget[] */ + int nData = 0; /* Local size of cell to remove */ + + /* Populate stack variables szEntry, iArrayOff, iData and nData. */ + assert( eType==HCT_PAGETYPE_INTKEY || eType==HCT_PAGETYPE_INDEX ); + assert( eType==HCT_PAGETYPE_INDEX || nHeight==0 ); + if( eType==HCT_PAGETYPE_INTKEY ){ + HctDbIntkeyEntry *pEntry = &((HctDbIntkeyLeaf*)aTarget)->aEntry[iRem]; + iData = pEntry->iOff; + nData = hctDbIntkeyEntrySize(pEntry, pgsz); + szEntry = sizeof(*pEntry); + iArrayOff = sizeof(HctDbIntkeyLeaf); + }else if( nHeight==0 ){ + HctDbIndexEntry *pEntry = &((HctDbIndexLeaf*)aTarget)->aEntry[iRem]; + iData = pEntry->iOff; + nData = hctDbIndexEntrySize(pEntry, pgsz); + szEntry = sizeof(*pEntry); + iArrayOff = sizeof(HctDbIndexLeaf); + }else{ + HctDbIndexNodeEntry *pEntry = &((HctDbIndexNode*)aTarget)->aEntry[iRem]; + iData = pEntry->iOff; + nData = hctDbIndexNodeEntrySize(pEntry, pgsz); + szEntry = sizeof(*pEntry); + iArrayOff = sizeof(HctDbIndexNode); + } + + /* Remove the aEntry[] array entry */ + if( iRempg.nEntry-1 ){ + u8 *aTo = &aTarget[iArrayOff + iRem*szEntry]; + memmove(aTo, &aTo[szEntry], (p->pg.nEntry-iRem-1) * szEntry); + } + p->pg.nEntry--; + p->hdr.nFreeBytes += szEntry; + p->hdr.nFreeGap += szEntry; + + /* Remove the cell from the data area */ + if( iData==(iArrayOff + szEntry*p->pg.nEntry + p->hdr.nFreeGap) ){ + int ii; + int iFirst = pDb->pgsz; + p->hdr.nFreeGap += nData; + for(ii=0; iipg.nEntry; ii++){ + int iOff = ((HctDbIndexEntry*)&aTarget[iArrayOff + szEntry*ii])->iOff; + if( iOff && iOffhdr.nFreeGap = iFirst - (iArrayOff + szEntry*p->pg.nEntry); + } + p->hdr.nFreeBytes += nData; + +} + + +/* +** This is called as part of a bulk insert of contiguous keys. At present +** this only occurs as part of a migrate, but in the future it could be +** auto-detected. +*/ +static int hctDbBalanceMigrate( + HctDatabase *pDb, + HctDbWriter *p, + HctDbInsertOp *pOp +){ + HctDbLeaf *pLeaf = (HctDbLeaf*)p->writepg.aPg[0].aNew; + int ii = 0; + + assert( p->writepg.nPg==1 ); + assert( p->bAppend==0 ); + assert( p->iHeight==0 ); + assert( pOp->iInsert<=pLeaf->pg.nEntry ); + assert( pOp->eBalance==BALANCE_REQUIRED || pOp->eBalance==BALANCE_OPTIONAL ); + + /* Set nMigrateKey to the number of keys to copy from p->writepg.aPg[0].aOld + ** before flushing the current array of pages to disk. */ + p->nMigrateKey = pLeaf->pg.nEntry - pOp->iInsert; + + /* Remove the last nMigrateKey cells from the page. */ + for(ii=0; iinMigrateKey; ii++){ + hctDbRemoveCell(pDb, 0, (u8*)pLeaf, pLeaf->pg.nEntry-1); + } + p->bAppend = 1; + + /* Use a regular balance to make space for the new key */ + pOp->eBalance = BALANCE_REQUIRED; + return hctDbBalance(pDb, p, pOp, 0); +} + +/* +** Buffer aTarget must contain the image of a page that uses variable +** length records - an intkey leaf, or an index leaf or node. This +** function does part of the job of inserting a new record into the +** page. +** +** Buffer aEntry[], size nEntry bytes, contains the sequence of bytes that +** will be stored in the data area of the page (i.e. any serialized +** tids, the old page number if any, any overflow page number and the +** portion of the database record that will be stored on the main +** page. Parameter iIns specifies the index within the page at which +** the new entry will be inserted. +*/ +static void hctDbInsertEntry( + HctDatabase *pDb, + u8 *aTarget, + int iIns, + const u8 *aEntry, + int nEntry +){ + HctDbIndexNode *p = (HctDbIndexNode*)aTarget; + int szEntry = 0; /* Size of each entry in aEntry[] array */ + int iEntry0 = 0; /* Offset of aEntry array in aTarget */ + int iOff = 0; /* Offset of new cell data in aTarget */ + u8 *aFrom = 0; + + iEntry0 = hctDbEntryArrayDim(aTarget, &szEntry); + + /* This might fail if the db is corrupt */ + assert( p->hdr.nFreeGap>=(nEntry + szEntry) ); + + /* Insert the new zeroed entry into the aEntry[] array */ + aFrom = &aTarget[iEntry0 + szEntry*iIns]; + if( iInspg.nEntry ){ + memmove(&aFrom[szEntry], aFrom, (p->pg.nEntry-iIns) * szEntry); + } + memset(aFrom, 0, szEntry); + p->hdr.nFreeBytes -= szEntry; + p->hdr.nFreeGap -= szEntry; + p->pg.nEntry++; + + /* Insert the cell into the data area */ + iOff = iEntry0 + p->pg.nEntry*szEntry + p->hdr.nFreeGap - nEntry; + hctMemcpy(&aTarget[iOff], aEntry, nEntry); + p->hdr.nFreeBytes -= nEntry; + p->hdr.nFreeGap -= nEntry; + + /* Set the aEntry[].iOff field */ + ((HctDbIndexEntry*)aFrom)->iOff = iOff; +} + + +static int hctDbMigrateReinsertKeys(HctDatabase *pDb, HctDbWriter *p){ + int rc = SQLITE_OK; + if( p->nMigrateKey>0 ){ + assert( p->iHeight==0 ); + + /* Append a page to the write-array */ + rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); + + + if( rc==SQLITE_OK ){ + int ii = 0; + HctDbInsertOp op; + HctDbLeaf *pOld = (HctDbLeaf*)p->writepg.aPg[0].aOld; + HctDbLeaf *pNew = (HctDbLeaf*)p->writepg.aPg[p->writepg.nPg-1].aNew; + + /* TODO: Might this not be a part of ExtendWriteArray() ? */ + pNew->hdr.nFreeBytes = pDb->pgsz - sizeof(HctDbLeaf); + pNew->hdr.nFreeGap = pNew->hdr.nFreeBytes; + + /* Loop through the last nMigrateKey on the old page, copying them + ** to the new page. */ + for(ii=0; iinMigrateKey; ii++){ + int iOld = (pOld->pg.nEntry - p->nMigrateKey) + ii; + HctDbIndexEntry *pOldE = 0; + HctDbIndexEntry *pNewE = 0; + int nEntry = 0; + + pOldE = hctDbEntryEntry(pOld, iOld); + nEntry = hctDbPageRecordSize(pOld, pDb->pgsz, iOld); + hctDbInsertEntry(pDb, (u8*)pNew, ii, &((u8*)pOld)[pOldE->iOff], nEntry); + + pNewE = hctDbEntryEntry(pNew, ii); + pNewE->nSize = pOldE->nSize; + pNewE->flags = pOldE->flags; + if( hctPagetype(pOld)==HCT_PAGETYPE_INTKEY ){ + ((HctDbIntkeyEntry*)pNewE)->iKey = ((HctDbIntkeyEntry*)pOldE)->iKey; + } + } + + memset(&op, 0, sizeof(op)); + op.iPg = p->writepg.nPg-1; + op.iInsert = -1; + op.eBalance = BALANCE_OPTIONAL; + rc = hctDbBalance(pDb, p, &op, 0); + } + } + + return rc; +} + +/* +** Parameter aTarget points to a buffer containing an intkey or index +** internal node. Return the child-page number for entry iInsert on +** that page. +*/ +u32 hctDbGetChildPage(u8 *aTarget, int iInsert){ + const int eType = hctPagetype(aTarget); + u32 iChildPg; + if( eType==HCT_PAGETYPE_INTKEY ){ + iChildPg = ((HctDbIntkeyNode*)aTarget)->aEntry[iInsert].iChildPg; + }else{ + assert( eType==HCT_PAGETYPE_INDEX ); + iChildPg = ((HctDbIndexNode*)aTarget)->aEntry[iInsert].iChildPg; + } + return iChildPg; +} + +static void hctDbClobberEntry( + HctDatabase *pDb, + u8 *aTarget, + HctDbInsertOp *pOp +){ + HctDbIndexEntry *pEntry; /* Entry being clobbered */ + int nOld = hctDbPageRecordSize(aTarget, pDb->pgsz, pOp->iInsert); + + pEntry = hctDbEntryEntry(aTarget, pOp->iInsert); + pEntry->nSize = pOp->nEntrySize; + pEntry->flags = pOp->entryFlags; + + memcpy(&aTarget[pEntry->iOff], pOp->aEntry, pOp->nEntry); + ((HctDbIndexNode*)aTarget)->hdr.nFreeBytes += (nOld - pOp->nEntry); + + pDb->stats.nUpdateInPlace++; +} + +static int hctDbFindOldPage( + HctDatabase *pDb, + HctDbWriter *p, + UnpackedRecord *pKey, + i64 iKey, + u32 *piOld, + const u8 **paOld +){ + HctFilePage *pPg = 0; + int rc = SQLITE_OK; + int iTest; + + for(iTest=p->discardpg.nPg-1; iTest>=0; iTest--){ + pPg = &p->discardpg.aPg[iTest]; + if( pKey ){ + int bGe = 0; + rc = hctDbCompareFPKey(pDb, pKey, pPg->aOld, &bGe); + if( bGe || rc!=SQLITE_OK ) break; + }else{ + i64 iFP = hctDbIntkeyFPKey(pPg->aOld); + if( iKey>=iFP ) break; + } + pPg = 0; + } + + if( pPg==0 ){ + pPg = &p->writepg.aPg[0]; + } + assert( pPg->iOldPg!=0 ); + *piOld = pPg->iOldPg; + *paOld = pPg->aOld; + + return rc; +} + +static u64 hctDbGetRangeTidByIdx(HctDatabase *pDb, u8 *aTarget, int iIdx){ + HctDbCell cell; + hctDbCellGetByIdx(pDb, aTarget, iIdx, &cell); + return cell.iRangeTid; +} + +static u32 hctDbMakeFollowPtr( + int *pRc, + HctDatabase *pDb, + u64 iFollowTid, + u32 iPg +){ + int rc = *pRc; + HctFilePage pg; + u32 iRet = 0; + + memset(&pg, 0, sizeof(pg)); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &pg); + iRet = pg.iNewPg; + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctFileClearPhysInUse(pDb->pFile, iRet, 0); + } + if( rc==SQLITE_OK ){ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aNew; + memset(pFan, 0, sizeof(*pFan)); + pFan->pg.hdrFlags = HCT_PAGETYPE_HISTORY; + pFan->pg.nEntry = 1; + pFan->iRangeTid0 = pDb->iTid; + pFan->iFollowTid0 = iFollowTid; + pFan->pgOld0 = iPg; + rc = sqlite3HctFilePageRelease(&pg); + }else{ + sqlite3HctFilePageUnwrite(&pg); + sqlite3HctFilePageRelease(&pg); + } + + *pRc = rc; + return iRet; +} + +static int hctDbDelete( + HctDatabase *pDb, + HctDbWriter *p, + UnpackedRecord *pRec, + HctDbInsertOp *pOp +){ + u64 iTidOr = (pDb->eMode==HCT_MODE_ROLLBACK ? HCT_TID_ROLLBACK_OVERRIDE : 0); + u64 iSafeTid = sqlite3HctFileSafeTID(pDb->pFile); + u64 iTidValue = pDb->iTid | iTidOr; + u64 iDelRangeTid = 0; + int rc = SQLITE_OK; + u8 *aNull = 0; + int prevFlags = 0; + int nLocalSz = 0; + u8 *aTarget = p->writepg.aPg[pOp->iPg].aNew; + int bLeftmost = (hctIsLeftmost(aTarget) && pOp->iInsert==0); + + HctDbCell prev; /* Previous cell on page */ + + assert( pOp->bFullDel==0 ); + + if( pOp->iInsert==0 && !bLeftmost ){ + /* If deleting the first key on the first page, set the eBalance flag (as + ** deleting a FP key means the parent list must be adjusted) and load peer + ** pages into memory. */ + pOp->eBalance = BALANCE_REQUIRED; + if( pOp->iPg==0 ){ + rc = hctDbLoadPeers(pDb, p, &pOp->iPg); + if( rc!=SQLITE_OK ) return rc; + aTarget = p->writepg.aPg[pOp->iPg].aNew; + } + } + assert_page_is_ok(aTarget, pDb->pgsz); + + /* Deal with the case where the cell we are about to remove (cell iInsert) + ** has a range-tid greater than that of the current transaction (iTid) */ + iDelRangeTid = hctDbGetRangeTidByIdx(pDb, aTarget, pOp->iInsert); + if( (iDelRangeTid & HCT_TID_MASK)>pDb->iTid ){ + iTidValue = iDelRangeTid; + pOp->iOldPg = hctDbMakeFollowPtr(&rc, pDb, iDelRangeTid, pOp->iOldPg); + sqlite3HctFilePageRelease(&p->fanpg); + } + + if( bLeftmost ){ + int nNull = 0; + + memset(&prev, 0, sizeof(prev)); + prev.iTid = LARGEST_TID; + prevFlags |= HCTDB_HAS_TID; + + assert( pOp->iPg==0 ); + if( hctPagetype(aTarget)==HCT_PAGETYPE_INDEX ){ + int nField = p->writecsr.pKeyInfo->nAllField; + int nByte = nField + 9; + aNull = sqlite3HctMalloc(&rc, nByte); + if( rc!=SQLITE_OK ) return rc; + if( nField<=126 ){ + aNull[0] = nField+1; + nNull = nField+1; + } + else if( nField<=16382 ){ + sqlite3PutVarint(aNull, nField+2); + nNull = nField+2; + }else{ + assert( sqlite3VarintLen(nField+3)==3 ); + sqlite3PutVarint(aNull, nField+3); + nNull = nField+3; + } + prev.aPayload = aNull; + } + prev.iTid = LARGEST_TID; + prevFlags |= HCTDB_HAS_TID; + pOp->nEntrySize = nNull; + nLocalSz = hctDbLocalsize(aTarget, pDb->pgsz, pOp->nEntrySize); + + }else{ + HctDbIndexEntry *pPrev = 0; + + /* Remove the cell being deleted from the target page. This must be done + ** after hctDbLoadPeers() is called (if it is called). */ + assert_page_is_ok(aTarget, pDb->pgsz); + hctDbRemoveCell(pDb, p, aTarget, pOp->iInsert); + assert_page_is_ok(aTarget, pDb->pgsz); + if( pOp->iInsert==0 ){ + assert( pOp->iPg>0 ); + pOp->iPg--; + aTarget = p->writepg.aPg[pOp->iPg].aNew; + assert( hctPagenentry(aTarget)>0 ); + pOp->iInsert = ((HctDbPageHdr*)aTarget)->nEntry - 1; + }else{ + pOp->iInsert--; + } + + /* Load the cell immediately before the one just removed */ + pPrev = hctDbEntryEntry(aTarget, pOp->iInsert); + pOp->nEntrySize = pPrev->nSize; + prevFlags = pPrev->flags; + + hctDbCellGet(pDb, &aTarget[pPrev->iOff], pPrev->flags, &prev); + nLocalSz = hctDbLocalsize(aTarget, pDb->pgsz, pOp->nEntrySize); + } + + /* Update the range-tid and range-oldpg fields. There are several + ** possibilities: + ** + ** 1) The left-hand-cell already has the desired range-pointer values + ** (both TID and old-page-number). + ** + ** 2) The left-hand-cell does not have a range-pointer. Or else + ** has a range-pointer so old it can be overwritten with impunity. + ** + ** 3) The left-hand-cell has a range-pointer to a fan-page that was + ** created by the current HctDbWriter batch, and that fan-page + ** is not already full. + ** + ** 4) None of the above are true. A new fan-page must be created. + */ + if( prev.iRangeTid==iTidValue && prev.iRangeOld==pOp->iOldPg ){ + /* Possibility (1) */ + pOp->bFullDel = 1; + pOp->iInsert = -1; + } + else if( prev.iRangeTid==0 || (prev.iRangeTid & HCT_TID_MASK)<=iSafeTid ){ + /* Possibility (2) */ + prev.iRangeTid = iTidValue; + prev.iRangeOld = pOp->iOldPg; + }else if( prev.iRangeOld==p->fanpg.iNewPg ){ + /* Possibility (3) */ + HctDbHistoryFan *pFan = (HctDbHistoryFan*)p->fanpg.aNew; + assert( pFan->iRangeTid1==iTidValue ); + if( pFan->aPgOld1[pFan->pg.nEntry-2]!=pOp->iOldPg ){ + const int nMax = ((pDb->pgsz - sizeof(HctDbHistoryFan))/sizeof(u32)); + assert( pFan->pg.nEntryaPgOld1[pFan->pg.nEntry-1] = pOp->iOldPg; + pFan->pg.nEntry++; + if( pFan->pg.nEntry==nMax ){ + rc = sqlite3HctFilePageRelease(&p->fanpg); + } + } + pOp->bFullDel = 1; + pOp->iInsert = -1; + }else{ + /* Possibility (4) */ + rc = sqlite3HctFilePageRelease(&p->fanpg); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &p->fanpg); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctFileClearPhysInUse(pDb->pFile, p->fanpg.iNewPg, 0); + } + if( rc==SQLITE_OK ){ + int bDummy = 0; + HctDbHistoryFan *pFan = (HctDbHistoryFan*)p->fanpg.aNew; + memset(pFan, 0, pDb->pgsz); + pFan->pg.hdrFlags = HCT_PAGETYPE_HISTORY; + pFan->pg.nEntry = 2; + pFan->iRangeTid0 = prev.iRangeTid; + pFan->iFollowTid0 = prev.iRangeTid; + pFan->pgOld0 = prev.iRangeOld; + rc = hctDbLeafSearch( + pDb, pOp->aOldPg, pOp->iIntkey, pRec, &pFan->iSplit0, &bDummy + ); + assert( bDummy ); + pFan->iRangeTid1 = iTidValue; + pFan->aPgOld1[0] = pOp->iOldPg; + prev.iRangeOld = p->fanpg.iNewPg; + if( (prev.iRangeTid & HCT_TID_MASK)<(iTidValue & HCT_TID_MASK) ){ + prev.iRangeTid = iTidValue; + } + } + } + + if( rc==SQLITE_OK && pOp->bFullDel==0 ){ + prev.iRangeTid |= iTidOr; + pOp->aEntry = pDb->aTmp; + pOp->nEntry = hctDbCellPut(pOp->aEntry, &prev, nLocalSz); + pOp->entryFlags = prevFlags | HCTDB_HAS_RANGETID | HCTDB_HAS_RANGEOLD; + if( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ){ + if( bLeftmost ){ + pOp->iIntkey = SMALLEST_INT64; + }else{ + pOp->iIntkey = ((HctDbIntkeyLeaf*)aTarget)->aEntry[pOp->iInsert].iKey; + } + } + } + + assert_page_is_ok(aTarget, pDb->pgsz); + if( aNull ) sqlite3_free(aNull); + return rc; +} + +static int hctDbInsertFindPosition( + HctDatabase *pDb, + HctDbWriter *p, + u32 iRoot, + UnpackedRecord *pRec, + i64 iKey, + HctDbInsertOp *pOp, + int *pbClobber +){ + const RecordCompare xCompare = pRec ? sqlite3VdbeFindCompare(pRec) : 0; + int rc = SQLITE_OK; + + if( p->writepg.nPg==0 ){ + if( p->writecsr.iRoot!=iRoot ){ + hctDbCsrInit(pDb, iRoot, 0, &p->writecsr); + }else{ + hctDbCsrReset(&p->writecsr); + } + if( pRec ){ + p->writecsr.pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); + } + rc = hctDbCsrSeek( + &p->writecsr, &p->fp, p->iHeight, xCompare, pRec, iKey, pbClobber + ); + if( rc ) return rc; + pOp->iInsert = p->writecsr.iCell; + if( *pbClobber==0 ) pOp->iInsert++; + + p->writepg.aPg[0] = p->writecsr.pg; + memset(&p->writecsr.pg, 0, sizeof(HctFilePage)); + + assert( p->bDoCleanup ); + p->writepg.nPg = 1; + rc = sqlite3HctFilePageWrite(&p->writepg.aPg[0]); + if( rc ) return rc; + hctMemcpy(p->writepg.aPg[0].aNew, p->writepg.aPg[0].aOld, pDb->pgsz); + if( p->fp.iKey==0 ){ + rc = hctDbSetWriteFpKey(pDb, p); + } + if( rc ) return rc; + }else if( pRec ){ + HctBuffer buf = {0,0,0}; + for(pOp->iPg=p->writepg.nPg-1; pOp->iPg>0; pOp->iPg--){ + const u8 *aK; + int nK; + rc = hctDbLoadRecord( + pDb, &buf, p->writepg.aPg[pOp->iPg].aNew, 0, &nK, &aK + ); + if( rc!=SQLITE_OK ){ + sqlite3HctBufferFree(&buf); + return rc; + } + if( xCompare(nK, aK, pRec)<=0 ) break; + } + sqlite3HctBufferFree(&buf); + rc = hctDbIndexSearch(pDb, + p->writepg.aPg[pOp->iPg].aNew, xCompare, pRec, &pOp->iInsert, pbClobber + ); + if( rc!=SQLITE_OK ) return rc; + }else{ + for(pOp->iPg=p->writepg.nPg-1; pOp->iPg>0; pOp->iPg--){ + if( hctDbIntkeyFPKey(p->writepg.aPg[pOp->iPg].aNew)<=iKey ) break; + } + if( p->iHeight==0 ){ + pOp->iInsert = hctDbIntkeyLeafSearch( + p->writepg.aPg[pOp->iPg].aNew, iKey, pbClobber + ); + }else{ + pOp->iInsert = hctDbIntkeyNodeSearch( + p->writepg.aPg[pOp->iPg].aNew, iKey, pbClobber + ); + } + } + + return rc; +} + +static int hctDbWriteWriteConflict( + HctDatabase *pDb, + HctDbWriter *p, + HctDbInsertOp *pOp, + UnpackedRecord *pKey, + i64 iKey, + int bClobber +){ + int rc = SQLITE_OK; + const u8 *aTarget = p->writepg.aPg[pOp->iPg].aNew; + + assert( p->iHeight==0 && pDb->eMode==HCT_MODE_NORMAL ); + + if( bClobber ){ + HctDbIndexEntry *pE; + if( pKey ){ + pE = &((HctDbIndexLeaf*)aTarget)->aEntry[pOp->iInsert]; + }else{ + pE = (HctDbIndexEntry*)&((HctDbIntkeyLeaf*)aTarget)->aEntry[pOp->iInsert]; + } + if( pE->flags & HCTDB_HAS_TID ){ + u64 iTid; + hctMemcpy(&iTid, &aTarget[pE->iOff], sizeof(u64)); + if( hctDbTidIsConflict(pDb, iTid) ){ + rc = HCT_SQLITE_BUSY; + } + } + }else if( pOp->iInsert>0 ){ + int iCell = 0; + int bMerge = 0; + HctRangePtr ptr; + + iCell = (pOp->iInsert - 1); + hctDbGetRange(aTarget, iCell, &ptr); + while( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ + HctFilePage pg; + const u8 *aOld = 0; + + if( ptr.iOld==pDb->pa.fanpg.iNewPg ){ + aOld = pDb->pa.fanpg.aNew; + memset(&pg, 0, sizeof(pg)); + }else{ + rc = hctDbGetPhysical(pDb, ptr.iOld, &pg); + aOld = pg.aOld; + } + + /* assert( bMerge==0 || iRangeTid!=pDb->iTid ); */ + if( rc==SQLITE_OK ){ + int iCell = 0; + if( hctPagetype(aOld)==HCT_PAGETYPE_HISTORY ){ + iCell = hctDbFanSearch(&rc, pDb, aOld, pKey, iKey); + }else{ + int bExact = 0; + rc = hctDbLeafSearch(pDb, aOld, iKey, pKey, &iCell, &bExact); + if( rc==SQLITE_OK && bExact ){ + if( bMerge ){ + HctDbCell cell; + hctDbCellGetByIdx(pDb, aOld, iCell, &cell); + if( hctDbTidIsVisible(pDb, cell.iTid, 0) ) rc = HCT_SQLITE_BUSY; + } + sqlite3HctFilePageRelease(&pg); + break; + }else{ + iCell--; + } + if( rc ){ + sqlite3HctFilePageRelease(&pg); + break; + } + } + + hctDbGetRange(aOld, iCell, &ptr); + sqlite3HctFilePageRelease(&pg); + }else{ + break; + } + } + } + + return rc; +} + +static int hctDbInsert( + HctDatabase *pDb, + HctDbWriter *p, + u32 iRoot, + UnpackedRecord *pRec, /* The key value for index tables */ + i64 iKey, /* For intkey tables, the key value */ + u32 iChildPg, /* For internal node ops, the child pgno */ + int bDel, /* True for a delete operation */ + int nData, const u8 *aData /* Record/key to insert */ +){ + const RecordCompare xCompare = pRec ? sqlite3VdbeFindCompare(pRec) : 0; + int rc = SQLITE_OK; + int bClobber = 0; + u8 *aTarget; /* Page to write new entry to */ + HctDbInsertOp op = {0,0,0,0,0,0,0,0,0,0,0}; + int bUpdateInPlace = 0; + + p->nWriteKey++; + + assert( pDb->eMode==HCT_MODE_NORMAL || pDb->eMode==HCT_MODE_ROLLBACK ); + + /* Check if any existing dirty pages need to be flushed to disk before + ** this key can be inserted. If they do, flush them. */ + assert( p->writepg.nPg==0 || iRoot==p->writecsr.iRoot ); + assert( p->writepg.nPg>0 || p->bAppend==0 ); + if( p->writepg.nPg ){ + assert( p->bDoCleanup ); + if( p->writepg.nPg>HCTDB_MAX_DIRTY + || p->discardpg.nPg>=HCTDB_MAX_DIRTY + || hctDbTestWriteFpKey(p, xCompare, pRec, iKey) + ){ + rc = hctDbInsertFlushWrite(pDb, p); + if( rc ) return rc; + p->nWriteKey = 1; + } + } + + p->bDoCleanup = 1; + rc = hctDbWriterGrow(p); + if( rc ) return rc; + + /* This block sets stack variables: + ** + ** op.iPg: Index of page in HctDbWriter.writepg.aPg[] to write to. + ** op.iInsert: The index of the new, overwritten, or deleted entry + ** within the page. + ** bClobber: True if this write clobbers (or deletes, if bDel) an + ** existing entry. + ** aTarget: The aNew[] buffer of the page that will be written. + ** + ** It also checks if the current key is a write-write conflict. And + ** returns early if so. + */ + if( p->bAppend ){ + assert( bClobber==0 ); + assert( p->writepg.nPg>0 ); + op.iPg = p->writepg.nPg-1; + aTarget = p->writepg.aPg[op.iPg].aNew; + op.iInsert = hctPagenentry(aTarget); + }else{ + /* If the page array is empty, seek the write cursor to find the leaf + ** page on which to insert this new entry or delete key. + ** + ** Otherwise, figure out which page in the HctDbWriter.aWritePg[] array the + ** new entry belongs on. */ + rc = hctDbInsertFindPosition(pDb, p, iRoot, pRec, iKey, &op, &bClobber); + if( rc ) return rc; + aTarget = p->writepg.aPg[op.iPg].aNew; + assert( aTarget ); + + /* If this is a write to a leaf page, and not part of a rollback, + ** check for a write-write conflict here. */ + if( 0==p->iHeight + && pDb->eMode==HCT_MODE_NORMAL + && (rc=hctDbWriteWriteConflict(pDb, p, &op, pRec, iKey, bClobber)) + ){ + return rc; + } + } + + if( bClobber==0 && bDel ){ + return SQLITE_OK; + } + + /* At this point, once the page that will be modified has been loaded + ** and marked as writable, if the operation is on an internal list: + ** + ** 1) For an insert, check if the child page has already been marked + ** as EVICTED by some other client. If so, return early. + ** + ** 2) For a delete, check that there is an entry to delete. And if so, + ** that the value of its child-page field matches iChildPg. If + ** not, return early. Note that the page marked as writable will + ** still be flushed to disk in this case - even though it may be + ** unmodified. + ** + ** This resolves a race condition that may occur if client B starts + ** removing page X from a list before client A has finished inserting + ** the corresponding entry into the parent list. Specifically: + ** + ** + when client A gets here, if the EVICTED flag is not set on page X, + ** then client B will try to delete the corresponding entry from + ** the parent list at some point in the future. This will either + ** occur after client A has updated the list, in which case no + ** problem, or it will cause client A's attempt to flush the modified + ** page to disk to fail. Client A will retry, see the EVICTED flag + ** is set, and continue. + ** + ** + or, if EVICTED is set, then there is no point in writing the + ** entry into the parent list. + */ + assert( rc==SQLITE_OK ); + if( p->iHeight>0 ){ + if( bDel==0 && sqlite3HctFilePageIsEvicted(pDb->pFile, iChildPg) ){ + return SQLITE_OK; + } + if( bDel ){ + u32 iChild = hctDbGetChildPage(aTarget, op.iInsert); + if( iChild!=iChildPg ) return SQLITE_OK; + } + } + + /* Writes to an intkey internal node are handled separately. They are + ** different because they used fixed size key/data pairs. All other types + ** of page use variably sized key/data entries. */ + if( pRec==0 && p->iHeight>0 ){ + return hctDbInsertIntkeyNode( + pDb, p, op.iPg, op.iInsert, iKey, iChildPg, bClobber, bDel + ); + } + + if( p->iHeight>0 ){ + op.bFullDel = bDel; + } + + if( rc ){ + assert( !"is this really possible?" ); + return rc; + } + + /* If this is a clobber or delete operation and the entry being removed + ** has an overflow chain, add an entry to HctDbWriter.delOvfl. */ + if( bClobber ){ + hctDbRemoveOverflow(pDb, p, aTarget, op.iInsert); + } + + /* Populate the following variables: + ** + ** entryFlags + ** aEntry + ** nEntry + ** nEntrySize + ** + ** This block populates the above variables. It also inserts overflow pages. + */ + op.iIntkey = iKey; + if( op.bFullDel==0 ){ + + if( p->iHeight==0 && (bClobber || bDel) ){ + rc = hctDbFindOldPage(pDb, p, pRec, iKey, &op.iOldPg, &op.aOldPg); + if( rc!=SQLITE_OK ) goto insert_out; + assert( op.iOldPg!=0 ); + } + + if( bDel && p->iHeight==0 ){ + assert( bClobber ); + rc = hctDbDelete(pDb, p, pRec, &op); + aTarget = p->writepg.aPg[op.iPg].aNew; + assert_page_is_ok(aTarget, pDb->pgsz); + if( op.bFullDel ) bClobber = 0; + }else{ + HctDbCell cell; + int nLocal = 0; + memset(&cell, 0, sizeof(cell)); + + if( p->iHeight==0 ){ + + /* There should never be a rollback operation while migrating a + ** database. */ + assert( IS_HCT_MIGRATE(pDb)==0 || pDb->eMode!=HCT_MODE_ROLLBACK ); + + if( IS_HCT_MIGRATE(pDb)==0 ){ + cell.iTid = pDb->iTid; + if( pDb->eMode==HCT_MODE_ROLLBACK ){ + cell.iTid |= HCT_TID_ROLLBACK_OVERRIDE; + } + } + + if( bClobber ){ + u64 iOldRangeTid = hctDbGetRangeTidByIdx(pDb, aTarget, op.iInsert); + if( (iOldRangeTid & HCT_TID_MASK)>pDb->iTid ){ + cell.iRangeOld = hctDbMakeFollowPtr(&rc,pDb,iOldRangeTid,op.iOldPg); + cell.iRangeTid = iOldRangeTid; + }else{ + cell.iRangeTid = pDb->iTid; + cell.iRangeOld = op.iOldPg; + } + }else if( op.iInsert>0 ){ + HctDbCell prev; + hctDbCellGetByIdx(pDb, aTarget, op.iInsert-1, &prev); + cell.iRangeTid = prev.iRangeTid; + cell.iRangeOld = prev.iRangeOld; + assert( cell.iRangeTid==0 || cell.iRangeOld!=0 ); + } + } + rc = hctDbInsertOverflow( + pDb, p, aTarget, nData, aData, &nLocal, &cell.iOvfl + ); + cell.aPayload = aData; + + op.aEntry = pDb->aTmp; + op.nEntry = hctDbCellPut(op.aEntry, &cell, nLocal); + op.nEntrySize = nData; + op.entryFlags = hctDbCellToFlags(&cell); + } + + assert( rc!=SQLITE_OK || op.bFullDel || op.aEntry==pDb->aTmp ); + if( rc!=SQLITE_OK ) goto insert_out; + } + + assert( op.aEntry==0 || op.aEntry==pDb->aTmp ); + + /* There are now two choices - either the aTarget[] page can be updated + ** directly (if the new entry fits on the page), or the balance-tree() + ** routine runs to redistribute cells between aTarget[] and its peers, + ** writing the new entry at the same time. A balance is required if: + ** + ** 1) there is insufficient space in the free-gap for any new + ** cell and array entry, or + ** + ** 2) this is a full-delete of the fpkey of the page (iInsert==0), or + ** + ** 3) this operation would leave the page underfull, and it is not + ** the only page in its list. + */ + if( op.eBalance==BALANCE_NONE ){ + int szEntry = hctDbPageEntrySize(aTarget); + int nFree = hctDbFreebytes(aTarget); + int nReq = 0; + int nSpace = 0; /* Space freed by removing cell */ + + if( bClobber ){ + nSpace = hctDbPageRecordSize(aTarget, pDb->pgsz, op.iInsert); + nFree += szEntry; + nFree += nSpace; + } + + if( op.bFullDel==0 ){ + if( nSpace>=op.nEntry ) bUpdateInPlace = 1; + nFree -= op.nEntry; + nFree -= szEntry; + nReq = op.nEntry + (bClobber ? 0 : szEntry); + } + + /* If (a) this is a clobber operation, and (b) either the first + ** key on the page is being deleted or else the page will be less + ** than 1/3 full following the update, and (c) the page is not + ** the only page in its linked list, rebalance! */ + if( (bClobber || bDel) /* (a) */ + && ((op.iInsert==0 && op.bFullDel) || (nFree>(2*pDb->pgsz/3))) /* (b) */ + && (hctIsLeftmost(aTarget)==0 || hctPagePeer(aTarget)!=0) /* (c) */ + ){ + /* Target page will be underfull following this op. Rebalance! */ + op.eBalance = BALANCE_REQUIRED; + bUpdateInPlace = 0; + }else if( hctDbFreegap(aTarget)bAppend ){ + rc = hctDbBalanceAppend(pDb, p, &op); + }else if( IS_HCT_MIGRATE(pDb) && p->iHeight==0 ){ + rc = hctDbBalanceMigrate(pDb, p, &op); + }else{ + rc = hctDbBalance(pDb, p, &op, bClobber); + } + if( rc==SQLITE_OK ) assert_all_pages_ok(pDb, p); + aTarget = p->writepg.aPg[op.iPg].aNew; + }else if( bUpdateInPlace ){ + assert_page_is_ok(aTarget, pDb->pgsz); + hctDbClobberEntry(pDb, aTarget, &op); + assert_page_is_ok(aTarget, pDb->pgsz); + }else if( bClobber ){ + assert_page_is_ok(aTarget, pDb->pgsz); + hctDbRemoveCell(pDb, p, aTarget, op.iInsert); + assert_page_is_ok(aTarget, pDb->pgsz); + } + + /* Unless this is a full-delete operation, update rest of the aEntry[] + ** entry fields for the new cell. */ + if( rc==SQLITE_OK && op.bFullDel==0 ){ + int eType = hctPagetype(aTarget); + assert_page_is_ok(aTarget, pDb->pgsz); + assert( op.iInsert>=0 ); + + /* print_out_page("1", aTarget, pDb->pgsz); */ + if( bUpdateInPlace==0 ){ + hctDbInsertEntry(pDb, aTarget, op.iInsert, op.aEntry, op.nEntry); + } + + assert( (pRec==0)==(eType==HCT_PAGETYPE_INTKEY) ); + if( eType==HCT_PAGETYPE_INTKEY ){ + HctDbIntkeyEntry *pE = &((HctDbIntkeyLeaf*)aTarget)->aEntry[op.iInsert]; + pE->iKey = op.iIntkey; + pE->nSize = op.nEntrySize; + pE->flags = op.entryFlags; + }else if( p->iHeight==0 ){ + HctDbIndexEntry *pE = &((HctDbIndexLeaf*)aTarget)->aEntry[op.iInsert]; + pE->nSize = op.nEntrySize; + pE->flags = op.entryFlags; + }else{ + HctDbIndexNodeEntry *pE = &((HctDbIndexNode*)aTarget)->aEntry[op.iInsert]; + pE->nSize = op.nEntrySize; + pE->flags = op.entryFlags; + pE->iChildPg = iChildPg; + } + + /* print_out_page("2", aTarget, pDb->pgsz); */ + assert_page_is_ok(aTarget, pDb->pgsz); + } + + insert_out: + if( rc==SQLITE_OK ){ + assert_all_pages_ok(pDb, p); + assert_all_pages_nonempty(pDb, p); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbInsert( + HctDatabase *pDb, /* Database to insert into or delete from */ + u32 iRoot, /* Root page of table to modify */ + UnpackedRecord *pRec, /* The key value for index tables */ + i64 iKey, /* For intkey tables, the key value */ + int bDel, /* True for a delete, false for insert */ + int nData, const u8 *aData, /* Record/key to insert */ + int *pnRetry /* OUT: number of operations to retry */ +){ + int rc = SQLITE_OK; + int nRecField = pRec ? pRec->nField : 0; + + /* If this operation is inserting an index entry, figure out how many of + ** the record fields to consider when determining if a potential write + ** collision is found in the data structure. */ + sqlite3HctDbRecordTrim(pRec); + +#if 0 + { + char *zText = sqlite3HctDbRecordToText(0, aData, nData); + sqlite3HctFileDebugPrint(pDb->pFile, + "%p: %s sqlite3HctDbInsert(bDel=%d, iKey=%lld, aData={%s}) iTid=%lld\n", + pDb, + (pDb->eMode==HCT_MODE_ROLLBACK ? "RB" : " "), + bDel, iKey, zText, (i64)pDb->iTid + ); + fflush(stdout); + } +#endif + + assert( pDb->eMode==HCT_MODE_NORMAL + || pDb->eMode==HCT_MODE_ROLLBACK + ); + if( pDb->eMode==HCT_MODE_ROLLBACK ){ + int op = 0; + + pDb->pa.bDoCleanup = 1; + if( pDb->rbackcsr.iRoot!=iRoot ){ + hctDbCsrInit(pDb, iRoot, 0, &pDb->rbackcsr); + if( pRec ){ + pDb->rbackcsr.pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); + } + }else{ + hctDbCsrReset(&pDb->rbackcsr); + } + + rc = sqlite3HctDbCsrRollbackSeek(&pDb->rbackcsr, pRec, iKey, &op); + if( rc==SQLITE_OK ){ + if( op<0 ){ + bDel = 1; + aData = 0; + nData = 0; + }else if( op>0 ){ + rc = sqlite3HctDbCsrData(&pDb->rbackcsr, &nData, &aData); + bDel = 0; + }else{ + /* TODO: It would be nice to assert( op!=0 ) here, but this fails + ** if the original op being rolled back was a no-op delete. If + ** we could note these as they occur, we could bring a form + ** of this assert() back. */ + /* assert( op!=0 ); */ + goto insert_done; + } + } + } + + if( rc==SQLITE_OK ){ + rc = hctDbInsert(pDb, &pDb->pa, iRoot, pRec, iKey, 0, bDel, nData, aData); + if( rc!=SQLITE_OK ){ + hctDbWriterCleanup(pDb, &pDb->pa, 1); + } + } + if( rc==SQLITE_LOCKED || (rc&0xFF)==SQLITE_BUSY ){ + if( rc==SQLITE_LOCKED ){ + rc = SQLITE_OK; + pDb->nCasFail++; + } + *pnRetry = pDb->pa.nWriteKey; + pDb->pa.nWriteKey = 0; + }else{ + *pnRetry = 0; + } + + insert_done: + if( pRec ) pRec->nField = nRecField; + return rc; +} + +/* +** Start the write-phase of a transaction. +*/ +SQLITE_PRIVATE int sqlite3HctDbStartWrite(HctDatabase *p, u64 *piTid){ + int rc = SQLITE_OK; + HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(p->pFile); + + assert( p->iTid==0 ); + assert( p->eMode==HCT_MODE_NORMAL ); + memset(&p->pa, 0, sizeof(p->pa)); + hctDbPageArrayReset(&p->pa.writepg); + hctDbPageArrayReset(&p->pa.discardpg); + + p->nWriteCount = sqlite3HctFileWriteCount(p->pFile); + p->iTid = sqlite3HctFileAllocateTransid(p->pFile); + rc = sqlite3HctTMapNewTID(pTMapClient, p->iTid, &p->pTmap); + *piTid = p->iTid; + return rc; +} + +SQLITE_PRIVATE i64 sqlite3HctDbTid(HctDatabase *p){ + return p->iTid; +} + +/* +** Set HctDatabase.iJrnlWriteCid. +*/ +SQLITE_PRIVATE void sqlite3HctDbJrnlWriteCid(HctDatabase *pDb, u64 iVal){ + pDb->iJrnlWriteCid = iVal; +} + +static u64 *hctDbFindTMapEntry(HctTMap *pTmap, u64 iTid){ + int iMap, iEntry; + assert( pTmap->iFirstTid<=iTid ); + assert( pTmap->iFirstTid+(pTmap->nMap*HCT_TMAP_PAGESIZE)>iTid ); + iMap = (iTid - pTmap->iFirstTid) / HCT_TMAP_PAGESIZE; + iEntry = (iTid - pTmap->iFirstTid) % HCT_TMAP_PAGESIZE; + + iEntry = HCT_TMAP_ENTRYSLOT(iEntry); + return &pTmap->aaMap[iMap][iEntry]; +} + +/* +** This is called once the current transaction has been completely +** written to disk and validated. The CID is passed as the second argument. +** Or, if the transaction was abandoned and rolled back, iCid is passed +** zero. +*/ +SQLITE_PRIVATE int sqlite3HctDbEndWrite(HctDatabase *p, u64 iCid, int bRollback){ + int rc = SQLITE_OK; + u64 *pEntry = hctDbFindTMapEntry(p->pTmap, p->iTid); + + assert( p->eMode==HCT_MODE_NORMAL ); + assert( p->pa.writepg.nPg==0 ); + + HctAtomicStore(pEntry, iCid|(bRollback?HCT_TMAP_ROLLBACK:HCT_TMAP_COMMITTED)); + p->iTid = 0; + return rc; +} + +static void hctDbFreeCsrList(HctDbCsr *pList){ + HctDbCsr *pNext = pList; + while( pNext ){ + HctDbCsr *pDel = pNext; + pNext = pNext->pNextScanner; + hctDbFreeCsr(pDel); + } +} + +SQLITE_PRIVATE int sqlite3HctDbEndRead(HctDatabase *pDb){ + HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); + // assert( (pDb->iSnapshotId==0)==(pDb->pTmap==0) ); + hctDbFreeCsrList(pDb->pScannerList); + pDb->pScannerList = 0; + if( pDb->pTmap ){ + sqlite3HctTMapEnd(pTMapClient, pDb->iSnapshotId); + pDb->pTmap = 0; + pDb->iSnapshotId = 0; + pDb->bConcurrent = 0; + } + return SQLITE_OK; +} + +/* +** If recovery is still required, this function grabs the file-server +** mutex and returns non-zero. Or, if recovery is not required, returns +** zero without grabbing the mutex. +*/ +SQLITE_PRIVATE int sqlite3HctDbStartRecovery(HctDatabase *pDb, int iStage){ + assert( iStage==0 || iStage==1 ); + assert( pDb->eMode==HCT_MODE_NORMAL ); + if( sqlite3HctFileStartRecovery(pDb->pFile, iStage) ){ + memset(&pDb->pa, 0, sizeof(pDb->pa)); + hctDbPageArrayReset(&pDb->pa.writepg); + hctDbPageArrayReset(&pDb->pa.discardpg); + pDb->eMode = HCT_MODE_ROLLBACK; + + /* During recovery the connection should read the latest version of + ** the db - no exceptions. Set these two to the largest possible + ** values to ensure that this happens. */ + pDb->iSnapshotId = LARGEST_TID-1; + pDb->iLocalMinTid = LARGEST_TID-1; + } + return (pDb->eMode==HCT_MODE_ROLLBACK); +} + +SQLITE_PRIVATE void sqlite3HctDbRecoverTid(HctDatabase *pDb, u64 iTid){ + pDb->iTid = iTid; + pDb->iLocalMinTid = iTid ? iTid-1 : 0; +} + +SQLITE_PRIVATE int sqlite3HctDbFinishRecovery(HctDatabase *pDb, int iStage, int rc){ + /* assert( pDb->eMode==HCT_MODE_ROLLBACK ); */ + assert( iStage==0 || iStage==1 ); + assert( pDb->iSnapshotId>0 ); + + pDb->iTid = 0; + pDb->eMode = HCT_MODE_NORMAL; + pDb->iSnapshotId = 0; + pDb->iLocalMinTid = 0; + return sqlite3HctFileFinishRecovery(pDb->pFile, iStage, rc); +} + +/* +** Open a cursor. +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrOpen( + HctDatabase *pDb, + KeyInfo *pKeyInfo, + u32 iRoot, + HctDbCsr **ppCsr +){ + int rc = SQLITE_OK; + HctDbCsr *p; + + assert( pDb->iSnapshotId!=0 ); + + /* Search for an existing cursor that can be reused. */ + HctDbCsr **pp; + for(pp=&pDb->pScannerList; *pp; pp=&(*pp)->pNextScanner){ + if( (*pp)->iRoot==iRoot ){ + *ppCsr = *pp; + *pp = (*pp)->pNextScanner; + return SQLITE_OK; + } + } + + /* If no existing cursor was found, allocate a new one */ + p = (HctDbCsr*)sqlite3MallocZero(sizeof(HctDbCsr)); + if( p==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + p->pDb = pDb; + p->iRoot = iRoot; + p->iCell = -1; + p->pKeyInfo = pKeyInfo; + sqlite3KeyInfoRef(pKeyInfo); + } + *ppCsr = p; + return rc; +} + +/* +** Set the "no-snapshot" flag on the cursor passed as the first argument. +*/ +SQLITE_PRIVATE void sqlite3HctDbCsrNosnap(HctDbCsr *pCsr, int bNosnap){ + if( pCsr ) pCsr->bNosnap = bNosnap; +} + +/* +** Close a cursor opened with sqlite3HctDbCsrOpen(). +*/ +SQLITE_PRIVATE void sqlite3HctDbCsrClose(HctDbCsr *pCsr){ + if( pCsr ){ + HctDatabase *pDb = pCsr->pDb; + hctDbCsrScanFinish(pCsr); + hctDbCsrReset(pCsr); + if( pDb->bConcurrent && pDb->iTid==0 ){ + pCsr->pNextScanner = pDb->pScannerList; + pDb->pScannerList = pCsr; + }else{ + hctDbFreeCsr(pCsr); + } + } +} + +/* +** The cursor passed as the first argument must be open on an intkey +** table and pointed at a valid entry. This function sets output variable +** (*piKey) to the integer key value associated with that entry before +** returning. +*/ +SQLITE_PRIVATE void sqlite3HctDbCsrKey(HctDbCsr *pCsr, i64 *piKey){ + int iCell = 0; + const u8 *aPg = 0; + + aPg = hctDbCsrPageAndCell(pCsr, &iCell); + *piKey = hctDbGetIntkey(aPg, iCell); +} + +/* +** Return true if the cursor is at EOF. Otherwise false. +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrEof(HctDbCsr *pCsr){ + return pCsr==0 || pCsr->iCell<0; +} + +/* +** Set the cursor to point to the first entry in its table. If it is +** stepped, this cursor will be stepped with sqlite3HctDbCsrNext(). +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrFirst(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + + rc = hctDbCsrScanFinish(pCsr); + if( rc==SQLITE_OK ){ + hctDbCsrReset(pCsr); + pCsr->eDir = BTREE_DIR_FORWARD; + rc = hctDbCsrScanStart(pCsr, 0, SMALLEST_INT64); + } + pCsr->eDir = BTREE_DIR_FORWARD; + + if( rc==SQLITE_OK ){ + rc = hctDbCsrFirstValid(pCsr); + } + + return rc; +} + +/* +** Set the cursor to point to the last entry in its table. If it is +** stepped, this cursor will be stepped with sqlite3HctDbCsrPrev(). +*/ +SQLITE_PRIVATE int sqlite3HctDbCsrLast(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + HctFile *pFile = pCsr->pDb->pFile; + u32 iPg = pCsr->iRoot; + HctDbPageHdr *pPg = 0; + HctFilePage pg; + + rc = hctDbCsrScanFinish(pCsr); + if( rc==SQLITE_OK ){ + hctDbCsrReset(pCsr); + pCsr->eDir = BTREE_DIR_REVERSE; + rc = hctDbCsrScanStart(pCsr, 0, LARGEST_INT64); + } + + /* Find the last page in the leaf page list. */ + while( 1 ){ + rc = sqlite3HctFilePageGet(pFile, iPg, &pg); + if( rc!=SQLITE_OK ) break; + + pPg = (HctDbPageHdr*)pg.aOld; + if( pPg->iPeerPg ){ + iPg = pPg->iPeerPg; + }else if( pPg->nHeight==0 ){ + break; + }else if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY ){ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pPg; + iPg = pNode->aEntry[pPg->nEntry-1].iChildPg; + }else{ + HctDbIndexNode *pNode = (HctDbIndexNode*)pPg; + iPg = pNode->aEntry[pPg->nEntry-1].iChildPg; + } + sqlite3HctFilePageRelease(&pg); + } + + /* Set the cursor to point to one position past the last entry on the + ** page located above. Then call sqlite3HctDbCsrPrev() to step back to + ** the first entry visible to the current transaction. */ + if( rc==SQLITE_OK ){ + assert( pPg->nHeight==0 && pPg->iPeerPg==0 ); + hctMemcpy(&pCsr->pg, &pg, sizeof(pg)); + if( pPg->nEntry==0 ){ + pCsr->iCell = -1; + }else{ + pCsr->iCell = pPg->nEntry; + rc = sqlite3HctDbCsrPrev(pCsr); + } + } + + return rc; +} + +/* +** Load the key associated with cell iCell1 on page aPg1[] and compare +** it to pKey2. Return an integer less than, equal to or greater than +** zero if the loaded key is less than, equal to or greater than pKey2, +** respectively. i.e. +** +** ret = key(aPg1, iCell1) - (*pKey2) +*/ +static int hctDbCompareCellKey( + int *pRc, + HctDatabase *pDb, + const u8 *aPg1, + int iCell1, + HctDbKey *pKey2 +){ + int ret = 0; + if( *pRc==SQLITE_OK ){ + + assert( hctPagetype(aPg1)==HCT_PAGETYPE_INTKEY + || hctPagetype(aPg1)==HCT_PAGETYPE_INDEX + ); + if( hctPagetype(aPg1)==HCT_PAGETYPE_INTKEY ){ + i64 iKey = hctDbGetIntkey(aPg1, iCell1); + if( iKeyiKey ){ + ret = -1; + }else if( iKey>pKey2->iKey ){ + ret = +1; + } + }else if( pKey2->pKey==0 ){ + ret = -1; + }else{ + int nRec = 0; + const u8 *aRec = 0; + HctBuffer buf = {0,0,0}; + int rc = hctDbLoadRecord(pDb, &buf, aPg1, iCell1, &nRec, &aRec); + if( rc!=SQLITE_OK ){ + *pRc = rc; + }else{ + ret = sqlite3VdbeRecordCompare(nRec, aRec, pKey2->pKey); + } + sqlite3HctBufferFree(&buf); + } + } + + return ret; +} + + +static int hctDbCsrNext(HctDbCsr *pCsr){ + HctDatabase *pDb = pCsr->pDb; + HctDbPageHdr *pPg = 0; + int rc = SQLITE_OK; + + /* Check if the current cell, be it on the linked list of leaves, or + ** on a history page, has an old-data pointer that should be followed. + ** + ** Except, don't do this if pCsr->iCell is less than zero. In that + ** case this call is supposed to jump to the first cell on the main + ** page. */ + if( pCsr->iCell>=0 ){ + do { + int bMerge = 0; + HctRangePtr ptr; + + hctDbCsrGetRange(pCsr, &ptr); + if( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ + hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); + if( rc==SQLITE_OK ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + if( p->eRange==HCT_RANGE_FAN ){ + p->iCell = -1; + }else{ + int bExact = 0; + hctDbLeafSearch(pDb, + p->pg.aOld, p->lowkey.iKey, p->lowkey.pKey, &p->iCell, &bExact + ); + if( bExact==0 ) p->iCell--; + } + } + } + + while( pCsr->nRange ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + + p->iCell++; + if( p->iCellpg.aOld) && ( + p->eRange==HCT_RANGE_FAN + || hctDbCompareCellKey(&rc, pDb, p->pg.aOld, p->iCell, &p->highkey)<0 + )){ + if( p->eRange==HCT_RANGE_MERGE ){ + return SQLITE_OK; + } + break; + } + sqlite3HctFilePageRelease(&p->pg); + hctDbCsrAscendRange(pCsr); + } + + }while( pCsr->nRange ); + + } + + pPg = (HctDbPageHdr*)pCsr->pg.aOld; + assert( pCsr->iCell>=-1 && pCsr->iCellnEntry ); + assert( pPg->nHeight==0 ); + + pCsr->iCell++; + if( pCsr->iCell==pPg->nEntry ){ + u32 iPeerPg = pPg->iPeerPg; + if( iPeerPg==0 ){ + /* Main cursor is now at EOF */ + pCsr->iCell = -1; + sqlite3HctFilePageRelease(&pCsr->pg); + }else{ + /* Jump to peer page */ + rc = sqlite3HctFilePageRelease(&pCsr->pg); + if( rc==SQLITE_OK ){ + rc = sqlite3HctFilePageGet(pDb->pFile, iPeerPg, &pCsr->pg); + pCsr->iCell = 0; + } + } + } + + return rc; +} + +static int hctDbCsrGoLeft(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + int nHeight = ((HctDbPageHdr*)pCsr->pg.aOld)->nHeight; + + if( pCsr->pKeyInfo ){ + UnpackedRecord *pRec = 0; + rc = hctDbCsrLoadAndDecode(pCsr, 0, &pRec); + if( rc==SQLITE_OK ){ + int bDummy; + HctFilePage pg = pCsr->pg; + memset(&pCsr->pg, 0, sizeof(HctFilePage)); + pRec->default_rc = 1; + hctDbCsrSeek(pCsr, 0, nHeight, 0, pRec, 0, &bDummy); + pRec->default_rc = 0; + sqlite3HctFilePageRelease(&pg); + } + }else if( hctIsLeftmost(pCsr->pg.aOld)==0 ){ + i64 iKey = hctDbIntkeyFPKey(pCsr->pg.aOld); + sqlite3HctFilePageRelease(&pCsr->pg); + rc = hctDbCsrSeek(pCsr, 0, nHeight, 0, 0, iKey-1, 0); + } + + return rc; +} + +static int hctDbCsrPrev(HctDbCsr *pCsr){ + HctDatabase *pDb = pCsr->pDb; + int rc = SQLITE_OK; + /* Advance the cursor */ + + if( pCsr->nRange ){ + HctDbRangeCsr *pRange = &pCsr->aRange[pCsr->nRange-1]; + pRange->iCell--; + }else{ + pCsr->iCell--; + if( pCsr->iCell<0 ){ + rc = hctDbCsrGoLeft(pCsr); + } + } + + if( pCsr->iCell>=0 ){ + do { + HctRangePtr ptr; + int bMerge = 0; + + hctDbCsrGetRange(pCsr, &ptr); + if( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ + do { + hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); + memset(&ptr, 0, sizeof(ptr)); + if( rc==SQLITE_OK ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + if( p->eRange==HCT_RANGE_FAN ){ + p->iCell = ((HctDbPageHdr*)p->pg.aOld)->nEntry-1; + }else{ + int bExact; + hctDbLeafSearch(pDb, p->pg.aOld, + p->highkey.iKey, p->highkey.pKey, &p->iCell, &bExact + ); + p->iCell--; + } + + if( p->iCell>=0 ){ + hctDbCsrGetRange(pCsr, &ptr); + } + } + }while( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ); + } + + while( pCsr->nRange>0 ){ + HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; + if( p->iCell>=0 && ( + p->eRange==HCT_RANGE_FAN + || hctDbCompareCellKey(&rc, pDb, p->pg.aOld, p->iCell, &p->lowkey)>0 + )){ + if( p->eRange==HCT_RANGE_MERGE ){ + return SQLITE_OK; + } + p->iCell--; + break; + } + sqlite3HctFilePageRelease(&p->pg); + hctDbCsrAscendRange(pCsr); + } + }while( pCsr->nRange ); + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbCsrNext(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + + /* Should not be called while committing, validating or doing rollback. */ + assert( pCsr->pDb->iTid==0 && pCsr->pDb->eMode==HCT_MODE_NORMAL ); + + do { + rc = hctDbCsrNext(pCsr); + }while( rc==SQLITE_OK && pCsr->iCell>=0 && hctDbCurrentIsVisible(pCsr)==0 ); + return rc; +} + +SQLITE_PRIVATE int sqlite3HctDbCsrPrev(HctDbCsr *pCsr){ + int rc = SQLITE_OK; + + assert( pCsr->pDb->eMode==HCT_MODE_NORMAL ); + do { + rc = hctDbCsrPrev(pCsr); + }while( rc==SQLITE_OK && pCsr->iCell>=0 && hctDbCurrentIsVisible(pCsr)==0 ); + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbCsrClear(HctDbCsr *pCsr){ + hctDbCsrScanFinish(pCsr); + hctDbCsrReset(pCsr); +} + + +SQLITE_PRIVATE int sqlite3HctDbCsrData(HctDbCsr *pCsr, int *pnData, const u8 **paData){ + const u8 *pPg; + int iCell; + + pPg = hctDbCsrPageAndCell(pCsr, &iCell); + assert( hctPageheight(pPg)==0 ); + +#if 0 + if( pCsr->nRange ){ + printf("%p: data from range page %d (from %d) (snapshotid=%lld)\n", + pCsr->pDb, + (int)pCsr->aRange[pCsr->nRange-1].pg.iOldPg, + (int)pCsr->pg.iOldPg, pCsr->pDb->iSnapshotId + ); + }else{ + printf("%p: data from page %d (snapshotid=%lld)\n", + pCsr->pDb, + (int)pCsr->pg.iOldPg, pCsr->pDb->iSnapshotId + ); + } + fflush(stdout); +#endif + + return hctDbLoadRecord(pCsr->pDb, &pCsr->rec, pPg, iCell, pnData, paData); +} + +static int hctDbValidateEntry(HctDatabase *pDb, HctDbCsr *pCsr){ + int rc = SQLITE_OK; + u8 flags; + + if( pCsr->nRange ){ + /* If the current entry is on a history page, it is not valid (as + ** it has already been deleted). Later: unless of course it was this + ** transaction that deleted it! */ + if( pCsr->aRange[pCsr->nRange-1].iRangeTid!=pDb->iTid ){ + rc = HCT_SQLITE_BUSY; + } + }else{ + int iOff = hctDbCellOffset(pCsr->pg.aOld, pCsr->iCell, &flags); + if( flags & HCTDB_HAS_TID ){ + u64 iTid = hctGetU64(&pCsr->pg.aOld[iOff]); + if( hctDbTidIsConflict(pCsr->pDb, iTid) ){ + rc = HCT_SQLITE_BUSY; + } + } + } + return rc; +} + +static int hctDbValidateIntkey(HctDatabase *pDb, HctDbCsr *pCsr){ + int rc = SQLITE_OK; + HctCsrIntkeyOp *pOpList = pCsr->intkey.pOpList; + HctCsrIntkeyOp *pOp; + + pCsr->intkey.pOpList = 0; + assert( pCsr->intkey.pCurrentOp==0 ); + for(pOp=pOpList; pOp && rc==SQLITE_OK; pOp=pOp->pNextOp){ + int bDum = 0; + assert( pOp->iFirst<=pOp->iLast ); + + if( pOp->iLogical ){ + int bEvict = 0; + + /* If the physical page associated with the logical page containing + ** the current key has not changed, and the logical page has not been + ** evicted, then the current key itself may not have been modified. + ** Jump to the next iteration of the loop in this case. */ + u32 iPhys = sqlite3HctFilePageMapping(pDb->pFile, pOp->iLogical, &bEvict); + if( pOp->iPhysical==iPhys && bEvict==0 ) continue; + + /* Alternatively, if the logical page has not been evicted, load it + ** and seek to the desired key. If the key is found, or if it is not + ** found but the key would reside on the current page, then load + ** the page into the cursor. This is faster than the hctDbCsrSeek() + ** call below. */ + if( bEvict==0 && pOp->iLogical!=pCsr->iRoot ){ + rc = hctDbGetPhysical(pDb, iPhys, &pCsr->pg); + if( rc==SQLITE_OK ){ + pCsr->eDir = BTREE_DIR_FORWARD; + pCsr->iCell = hctDbIntkeyLeafSearch(pCsr->pg.aOld, pOp->iFirst,&bDum); + if( pCsr->iCell>=((HctDbIntkeyLeaf*)pCsr->pg.aOld)->pg.nEntry ){ + hctDbCsrReset(pCsr); + } + } + } + } + + if( pCsr->pg.aOld==0 ){ + if( pOp->iFirst==SMALLEST_INT64 ){ + pCsr->eDir = BTREE_DIR_FORWARD; + rc = hctDbCsrFirst(pCsr); + }else{ + if( pOp->iFirst==pOp->iLast ){ + pCsr->eDir = BTREE_DIR_NONE; + }else{ + pCsr->eDir = BTREE_DIR_FORWARD; + } + rc = hctDbCsrSeekAndDescend(pCsr, 0, pOp->iFirst, 0, &bDum); + } + } + + while( rc==SQLITE_OK && !sqlite3HctDbCsrEof(pCsr) ){ + i64 iKey = 0; + sqlite3HctDbCsrKey(pCsr, &iKey); + if( iKey>=pOp->iFirst && iKey<=pOp->iLast ){ + rc = hctDbValidateEntry(pDb, pCsr); + } + if( rc!=SQLITE_OK || iKey>=pOp->iLast ) break; + rc = hctDbCsrNext(pCsr); + } + hctDbCsrReset(pCsr); + } + assert( pCsr->intkey.pOpList==0 && pCsr->intkey.pCurrentOp==0 ); + pCsr->intkey.pOpList = pOpList; + + return rc; +} + +static int hctDbValidateIndex(HctDatabase *pDb, HctDbCsr *pCsr){ + int rc = SQLITE_OK; + HctCsrIndexOp *pOpList = pCsr->index.pOpList; + HctCsrIndexOp *pOp; + + pCsr->index.pOpList = 0; + assert( pCsr->index.pCurrentOp==0 ); + rc = hctDbCsrAllocateUnpacked(pCsr); + for(pOp=pOpList; pOp && rc==SQLITE_OK; pOp=pOp->pNextOp){ + UnpackedRecord *pRec = pCsr->pRec; + int bDummy = 0; + + if( pOp->iLogical + && pOp->iPhysical==sqlite3HctFilePageMapping(pDb->pFile, pOp->iLogical, &bDummy) + ){ + continue; + } + + hctDbCsrReset(pCsr); + pCsr->eDir = (pOp->pFirst==pOp->pLast) ? BTREE_DIR_NONE : BTREE_DIR_FORWARD; + if( pOp->pFirst==0 ){ + rc = hctDbCsrFirst(pCsr); + }else{ + int bExact = 0; + sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, pOp->nFirst, pOp->pFirst, pRec); + rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, 0, &bExact); + if( rc==SQLITE_OK && bExact==0 ){ + rc = hctDbCsrNext(pCsr); + } + } + if( pOp->pLast && pOp->pLast!=pOp->pFirst ){ + sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, pOp->nLast, pOp->pLast, pRec); + }else{ + pRec = 0; + } + if( rc!=SQLITE_OK ) break; + + if( pOp->pLast==pOp->pFirst ){ + assert( !sqlite3HctDbCsrEof(pCsr) ); + rc = hctDbValidateEntry(pDb, pCsr); + }else{ + while( !sqlite3HctDbCsrEof(pCsr) ){ + int res = -1; + if( pRec ){ + const u8 *aKey = 0; + int nKey = 0; + rc = sqlite3HctDbCsrData(pCsr, &nKey, &aKey); + if( rc!=SQLITE_OK ) break; + res = sqlite3VdbeRecordCompare(nKey, aKey, pRec); + if( res<0 ) break; + } + rc = hctDbValidateEntry(pDb, pCsr); + if( res==0 || rc!=SQLITE_OK ) break; + rc = hctDbCsrNext(pCsr); + if( rc!=SQLITE_OK ) break; + } + } + } + + assert( pCsr->index.pOpList==0 && pCsr->index.pCurrentOp==0 ); + pCsr->index.pOpList = pOpList; + return rc; +} + +SQLITE_PRIVATE void sqlite3HctDbTMapScan(HctDatabase *pDb){ + sqlite3HctTMapScan(sqlite3HctFileTMapClient(pDb->pFile)); +} + +int +__attribute__ ((noinline)) +sqlite3HctDbValidate( + sqlite3 *db, + HctDatabase *pDb, + u64 *piCid, + int *pbTmapscan +){ + HctDbCsr *pCsr = 0; + u64 *pEntry = hctDbFindTMapEntry(pDb->pTmap, pDb->iTid); + u64 iCid = *piCid; + u64 nFinalWrite = 0; + int rc = SQLITE_OK; + int nPageScan = pDb->pConfig->nPageScan; + + /* Set nWrite to the number of pages written by this transaction. This + ** is used for scheduling tmap scans only, so it doesn't matter if it + ** is slightly inaccurate in some cases. */ + int nWrite = sqlite3HctFileWriteCount(pDb->pFile) - pDb->nWriteCount; + assert( nWrite>=0 ); + if( nWrite==0 ) nWrite = 1; + + assert( *pEntry==0 ); + if( iCid==0 ){ + HctAtomicStore(pEntry, HCT_TMAP_VALIDATING); + iCid = sqlite3HctFileAllocateCID(pDb->pFile, 1); + } + HctAtomicStore(pEntry, HCT_TMAP_VALIDATING | iCid); + + nFinalWrite = sqlite3HctFileIncrWriteCount(pDb->pFile, nWrite); + if( (nFinalWrite / nPageScan)!=((nFinalWrite-nWrite) / nPageScan) ){ + *pbTmapscan = 1; + } + + assert( pDb->eMode==HCT_MODE_NORMAL ); + + /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ + if( db->xMtCommit ) db->xMtCommit(db->pMtCommitCtx, 2); + + /* If iCid is one more than pDb->iSnapshotId, then this transaction is + ** being applied against the snapshot that it was run against. In this + ** case we can skip validation entirely. */ + if( iCid!=pDb->iSnapshotId+1 ){ + if( pDb->bConcurrent ){ + pDb->eMode = HCT_MODE_VALIDATE; + if( hctDbValidateMeta(pDb) ){ + rc = HCT_SQLITE_BUSY; + }else{ + for(pCsr=pDb->pScannerList; pCsr; pCsr=pCsr->pNextScanner){ + if( pCsr->pKeyInfo==0 ){ + rc = hctDbValidateIntkey(pDb, pCsr); + }else{ + rc = hctDbValidateIndex(pDb, pCsr); + } + if( rc ) break; + } + } + pDb->eMode = HCT_MODE_NORMAL; + }else{ + rc = HCT_SQLITE_BUSY; + } + } + + *piCid = iCid; + return rc; +} + +/************************************************************************* +************************************************************************** +** Start of integrity-check implementation. +** +** The code here assumes that the database is quiescent. If it is invoked +** concurrently with database writers, false-positive errors may be reported. +*/ + +/* +** Walk the tree structure with logical root page iRoot, visiting every +** page and overflow page currently linked in. +** +** For each page in the tree, the supplied callback is invoked. The first +** argument passed to the callback is a copy of the fourth argument to +** this function. The second and third arguments are the logical and +** physical page number, respectively. If there is no logical page number, +** as for overflow pages, the second parameter is passed zero. +** +** It (presumably) makes little sense to call this function without +** somehow guaranteeing that the tree is not being currently written to. +*/ +SQLITE_PRIVATE int sqlite3HctDbWalkTree( + HctFile *pFile, /* File tree resides in */ + u32 iRoot, /* Root page of tree */ + int (*x)(void*, u32, u32), /* Callback function */ + void *pCtx /* First argument to pass to x() */ +){ + int rc = SQLITE_OK; + u32 pgno = iRoot; + + u32 iPhys = 0; + int dummy = 0; + + /* Special case - the root page is not mapped to any physical page. */ + iPhys = sqlite3HctFilePageMapping(pFile, iRoot, &dummy); + if( iPhys==0 ){ + return x(pCtx, iRoot, 0); + } + + /* This outer loop runs once for each list in the tree structure - once + ** for the list of leaves, once for the list of parent, and so on. + ** Starting from the root page and descending towards the leaves. */ + do { + HctFilePage pg; + int nHeight = 0; + int eType = 0; + u32 pgnoChild = 0; + + /* Load up page pgno - the leftmost of its list. Then, unless this + ** is the list of leaves, set pgnoChild to the leftmost child of + ** the page. Or, if this is a list of leaves, leave pgnoChild set + ** to zero. */ + rc = sqlite3HctFilePageGet(pFile, pgno, &pg); + if( rc!=SQLITE_OK ){ + break; + }else{ + nHeight = hctPageheight(pg.aOld); + eType = hctPagetype(pg.aOld); + if( eType!=HCT_PAGETYPE_INTKEY && eType!=HCT_PAGETYPE_INDEX ){ + rc = SQLITE_CORRUPT_BKPT; + break; + } + else if( nHeight>0 ){ + if( eType==HCT_PAGETYPE_INTKEY ){ + pgnoChild = ((HctDbIntkeyNode*)pg.aOld)->aEntry[0].iChildPg; + }else{ + pgnoChild = ((HctDbIndexNode*)pg.aOld)->aEntry[0].iChildPg; + } + } + } + + while( pg.aOld ){ + u32 iPeerPg = ((HctDbPageHdr*)pg.aOld)->iPeerPg; + u32 iLogic = pg.iPg; + u32 iPhys = pg.iOldPg; + + rc = x(pCtx, iLogic, iPhys); + if( rc!=SQLITE_OK ) break; + + if( nHeight==0 || eType==HCT_PAGETYPE_INDEX ){ + int iCell = 0; + int nEntry = ((HctDbPageHdr*)pg.aOld)->nEntry; + for(iCell=0; iCelliPeerPg; + sqlite3HctFilePageRelease(&ov); + } + } + } + } + + sqlite3HctFilePageRelease(&pg); + if( iPeerPg ){ + rc = sqlite3HctFilePageGet(pFile, iPeerPg, &pg); + if( rc!=SQLITE_OK ) break; + } + } + + pgno = pgnoChild; + }while( rc==SQLITE_OK && pgno!=0 ); + + return rc; +} + +typedef struct IntCheckCtx IntCheckCtx; +struct IntCheckCtx { + u32 nLogic; /* Number of logical pages in db */ + u32 nPhys; /* Number of physical pages in db */ + u8 *aLogic; + u8 *aPhys; + int nErr; + int nMaxErr; + char *zErr; + i64 nEntry; /* Number of entries in table */ +}; + +static void hctDbICError( + IntCheckCtx *p, + char *zFmt, + ... +){ + va_list ap; + char *zErr; + va_start(ap, zFmt); + zErr = sqlite3_vmprintf(zFmt, ap); + p->zErr = sqlite3_mprintf("%z%s%z", p->zErr, (p->zErr ? "\n" : ""), zErr); + p->nErr++; + va_end(ap); +} + +static int hctDbIntegrityCheckCb( + void *pCtx, + u32 iLogic, + u32 iPhys +){ + IntCheckCtx *p = (IntCheckCtx*)pCtx; + if( iLogic ){ + if( p->aLogic[iLogic-1] ){ + hctDbICError(p, "multiple refs to logical page %d", (int)iLogic); + } + p->aLogic[iLogic-1] = 1; + } + if( iPhys ){ + if( p->aPhys[iPhys-1] ){ + hctDbICError(p, "multiple refs to physical page %d", (int)iPhys); + } + p->aPhys[iPhys-1] = 1; + } + + return (p->nErr>=p->nMaxErr) ? -1 : 0; +} + + +SQLITE_PRIVATE char *sqlite3HctDbIntegrityCheck( + HctDatabase *pDb, + u32 *aRoot, + Mem *aCnt, + int nRoot, + int *pnErr +){ + HctFile *pFile = pDb->pFile; + IntCheckCtx c; + u32 *aFileRoot = 0; + int nFileRoot = 0; + + int rc = sqlite3HctFileRootArray(pFile, &aFileRoot, &nFileRoot); + memset(&c, 0, sizeof(c)); + if( rc==SQLITE_OK ){ + c.nErr = *pnErr; + c.nMaxErr = 100; + sqlite3HctFileICArrays(pFile, &c.aLogic, &c.nLogic, &c.aPhys, &c.nPhys); + } + if( !c.aLogic ){ + c.nErr++; + }else{ + int ii; + + for(ii=0; c.nErr==0 && iistats.nBalanceIntkey; + break; + case 1: + *pzStat = "balance_index"; + iVal = pDb->stats.nBalanceIndex; + break; + case 2: + *pzStat = "balance_single"; + iVal = pDb->stats.nBalanceSingle; + break; + case 3: + *pzStat = "tmap_lookup"; + iVal = pDb->stats.nTMapLookup; + break; + case 4: + *pzStat = "update_in_place"; + iVal = pDb->stats.nUpdateInPlace; + break; + case 5: + *pzStat = "internal_retry"; + iVal = pDb->stats.nInternalRetry; + break; + default: + break; + } + + return iVal; +} + +/************************************************************************* +************************************************************************** +** Below are the virtual table implementations. These are debugging +** aids only. +*/ + +typedef struct hctdb_vtab hctdb_vtab; +struct hctdb_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; + +/* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct hctdb_cursor hctdb_cursor; +struct hctdb_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + HctDatabase *pDb; /* Database to report on */ + u64 iMaxPgno; /* Maximum page number for this scan */ + + u64 pgno; /* The page-number/rowid value */ + const char *zPgtype; + u32 iPeerPg; + u32 nEntry; + u32 nHeight; + u32 nFree; + char *zFpKey; +}; + +/* +** The hctdbConnect() method is invoked to create a new +** template virtual table. +** +** Think of this routine as the constructor for hctdb_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the hctdb_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against the virtual table will look like. +*/ +static int hctdbConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + hctdb_vtab *pNew; + int rc; + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(" + "pgno INTEGER, pgtype TEXT, nheight INTEGER, " + "peer INTEGER, nentry INTEGER, nfree INTEGER, fpkey TEXT" + ")" + ); + + if( rc==SQLITE_OK ){ + pNew = sqlite3MallocZero( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + pNew->db = db; + } + return rc; +} + +/* +** This method is the destructor for hctdb_vtab objects. +*/ +static int hctdbDisconnect(sqlite3_vtab *pVtab){ + hctdb_vtab *p = (hctdb_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new hctdb_cursor object. +*/ +static int hctdbOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + hctdb_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a hctdb_cursor. +*/ +static int hctdbClose(sqlite3_vtab_cursor *cur){ + hctdb_cursor *pCur = (hctdb_cursor*)cur; + sqlite3_free(pCur->zFpKey); + sqlite3_free(pCur); + return SQLITE_OK; +} + +static char *hex_encode(const u8 *aIn, int nIn){ + char *zRet = sqlite3MallocZero(nIn*2+1); + if( zRet ){ + static const char aDigit[] = "0123456789ABCDEF"; + int i; + for(i=0; i> 4) ]; + zRet[i*2+1] = aDigit[ (aIn[i] & 0xF) ]; + } + } + return zRet; +} + + +SQLITE_PRIVATE char *sqlite3HctDbRecordToText(sqlite3 *db, const u8 *aRec, int nRec){ + char *zRet = 0; + const char *zSep = ""; + const u8 *pEndHdr; /* Points to one byte past record header */ + const u8 *pHdr; /* Current point in record header */ + const u8 *pBody; /* Current point in record data */ + u64 nHdr; /* Bytes in record header */ + + if( nRec==0 ){ + return sqlite3_mprintf(""); + } + + pHdr = aRec + sqlite3GetVarint(aRec, &nHdr); + pBody = pEndHdr = &aRec[nHdr]; + while( pHdrbase.pVtab)->db; + int eType; + + assert( 0==sqlite3_stricmp("intkey", azType[HCT_PAGETYPE_INTKEY]) ); + assert( 0==sqlite3_stricmp("index", azType[HCT_PAGETYPE_INDEX]) ); + assert( 0==sqlite3_stricmp("overflow", azType[HCT_PAGETYPE_OVERFLOW]) ); + + sqlite3_free(pCur->zFpKey); + pCur->zFpKey = 0; + + eType = hctPagetype(pHdr); + if( eTypezPgtype = azType[hctPagetype(pHdr)]; + }else{ + pCur->zPgtype = "!INVALID!"; + } + pCur->iPeerPg = pHdr->iPeerPg; + pCur->nEntry = pHdr->nEntry; + pCur->nHeight = pHdr->nHeight; + + if( eType==HCT_PAGETYPE_INTKEY ){ + if( pHdr->nHeight==0 ){ + HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)aPg; + char *zFpKey = sqlite3_mprintf("%lld", pLeaf->aEntry[0].iKey); + if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; + pCur->zFpKey = zFpKey; + pCur->nFree = (int)pLeaf->hdr.nFreeBytes; + }else{ + HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPg; + char *zFpKey = sqlite3_mprintf("%lld", pNode->aEntry[0].iKey); + if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; + pCur->zFpKey = zFpKey; + pCur->nFree = ( + hctDbMaxCellsPerIntkeyNode(pCur->pDb->pgsz) - pNode->pg.nEntry + ) * sizeof(HctDbIntkeyNodeEntry); + } + + }else if( eType==HCT_PAGETYPE_INDEX ){ + HctBuffer buf = {0,0,0}; + const u8 *aRec = 0; + int nRec = 0; + + rc = hctDbLoadRecord(pCur->pDb, &buf, aPg, 0, &nRec, &aRec); + if( rc==SQLITE_OK ){ + char *zFpKey = sqlite3HctDbRecordToText(db, aRec, nRec); + if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; + pCur->zFpKey = zFpKey; + } + + pCur->nFree = (int)(((HctDbIndexNode*)pHdr)->hdr.nFreeBytes); + sqlite3HctBufferFree(&buf); + } + return rc; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int hctdbEof(sqlite3_vtab_cursor *cur){ + hctdb_cursor *pCur = (hctdb_cursor*)cur; + return pCur->pgno>pCur->iMaxPgno; +} + +/* +** Advance a hctdb_cursor to its next row of output. +*/ +static int hctdbNext(sqlite3_vtab_cursor *cur){ + hctdb_cursor *pCur = (hctdb_cursor*)cur; + int rc = SQLITE_OK; + HctFilePage pg; + + memset(&pg, 0, sizeof(pg)); + do { + sqlite3HctFilePageRelease(&pg); + pCur->pgno++; + if( hctdbEof(cur) ) return SQLITE_OK; + rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->pgno, &pg); + }while( rc==SQLITE_OK && pg.aOld==0 ); + + if( pg.aOld ){ + rc = hctdbLoadPage(pCur, pg.aOld); + } + return rc; +} + +/* +** Return values of columns for the row at which the hctdb_cursor +** is currently pointing. +*/ +static int hctdbColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + hctdb_cursor *pCur = (hctdb_cursor*)cur; + assert( i>=0 && i<=5 ); + switch( i ){ + case 0: /* pgno */ + sqlite3_result_int64(ctx, (i64)pCur->pgno); + break; + case 1: /* pgtype */ + sqlite3_result_text(ctx, pCur->zPgtype, -1, SQLITE_TRANSIENT); + break; + case 2: /* nHeight */ + sqlite3_result_int64(ctx, (i64)pCur->nHeight); + break; + case 3: /* peer */ + sqlite3_result_int64(ctx, (i64)pCur->iPeerPg); + break; + case 4: /* nEntry */ + sqlite3_result_int64(ctx, (i64)pCur->nEntry); + break; + case 5: /* nfree */ + sqlite3_result_int64(ctx, (i64)pCur->nFree); + break; + case 6: /* fpkey */ + sqlite3_result_text(ctx, pCur->zFpKey, -1, SQLITE_TRANSIENT); + break; + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int hctdbRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + hctdb_cursor *pCur = (hctdb_cursor*)cur; + *pRowid = pCur->pgno; + return SQLITE_OK; +} + +/* +** This method is called to "rewind" the hctdb_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to hctdbColumn() or hctdbRowid() or +** hctdbEof(). +*/ +static int hctdbFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + hctdb_cursor *pCur = (hctdb_cursor*)pVtabCursor; + hctdb_vtab *pTab = (hctdb_vtab*)(pCur->base.pVtab); + + pCur->pDb = sqlite3HctDbFind(pTab->db, 0); + if( argc==1 ){ + u32 iVal = (u32)sqlite3_value_int64(argv[0]); + pCur->iMaxPgno = iVal; + pCur->pgno = iVal-1; + }else{ + pCur->pgno = 0; + pCur->iMaxPgno = sqlite3HctFileMaxpage(pCur->pDb->pFile); + } + return hctdbNext(pVtabCursor); +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int hctdbBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; + pIdxInfo->estimatedCost = (double)10000; + pIdxInfo->estimatedRows = 10000; + + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->iColumn!=0 ) continue; + if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( !p->usable ) continue; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->idxNum = 1; + pIdxInfo->estimatedCost = (double)10; + pIdxInfo->estimatedRows = 10; + break; + } + + return SQLITE_OK; +} + +typedef struct hctentry_vtab hctentry_vtab; +struct hctentry_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; + +/* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct hctentry_cursor hctentry_cursor; +struct hctentry_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + HctDatabase *pDb; /* Database to report on */ + int iEntry; + HctFilePage pg; + u32 iPg; /* Current physical page number */ + u32 iLastPg; /* Last physical page to report on */ +}; + +/* +** The hctentryConnect() method is invoked to create a new +** template virtual table. +** +** Think of this routine as the constructor for hctentry_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the hctentry_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against the virtual table will look like. +*/ +static int hctentryConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + hctentry_vtab *pNew; + int rc; + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(" + "pgno INTEGER, entry INTEGER, " + "ikey INTEGER, size INTEGER, offset INTEGER, " + "child INTEGER, " + "tid INTEGER, rangetid INTEGER, " + /* "oldpg INTEGER, " */ + "rangeoldpg INTEGER, ovfl INTEGER, record TEXT" + ")" + ); + + if( rc==SQLITE_OK ){ + pNew = sqlite3MallocZero( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + pNew->db = db; + } + return rc; +} + +/* +** This method is the destructor for hctentry_vtab objects. +*/ +static int hctentryDisconnect(sqlite3_vtab *pVtab){ + hctentry_vtab *p = (hctentry_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new hctentry_cursor object. +*/ +static int hctentryOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + hctentry_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a hctentry_cursor. +*/ +static int hctentryClose(sqlite3_vtab_cursor *cur){ + hctentry_cursor *pCur = (hctentry_cursor*)cur; + sqlite3HctFilePageRelease(&pCur->pg); + sqlite3_free(pCur); + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int hctentryEof(sqlite3_vtab_cursor *cur){ + hctentry_cursor *pCur = (hctentry_cursor*)cur; + return pCur->pg.aOld==0; +} + +/* +** Advance a hctentry_cursor to its next row of output. +*/ +static int hctentryNext(sqlite3_vtab_cursor *cur){ + int rc = SQLITE_OK; + hctentry_cursor *pCur = (hctentry_cursor*)cur; + + while( rc==SQLITE_OK ){ + HctDbPageHdr *pPg = (HctDbPageHdr*)pCur->pg.aOld; + int eType = hctPagetype(pPg); + if( eType==HCT_PAGETYPE_INTKEY + || eType==HCT_PAGETYPE_INDEX + || eType==HCT_PAGETYPE_HISTORY + ){ + pCur->iEntry++; + if( pCur->iEntrynEntry ) break; + } + pCur->iEntry = -1; + pCur->iPg++; + sqlite3HctFilePageRelease(&pCur->pg); + if( pCur->iPg>pCur->iLastPg ) break; + rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->iPg, &pCur->pg); + } + + return rc; +} + +/* +** Return values of columns for the row at which the hctentry_cursor +** is currently pointing. +*/ +static int hctentryColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + hctentry_cursor *pCur = (hctentry_cursor*)cur; + int eType = hctPagetype(pCur->pg.aOld); + int nHeight = hctPageheight(pCur->pg.aOld); + + HctDbIntkeyEntry *pIntkey = 0; + HctDbIntkeyNodeEntry *pIntkeyNode = 0; + HctDbIndexEntry *pIndex = 0; + HctDbIndexNodeEntry *pIndexNode = 0; + HctDbHistoryFan *pFan = 0; + + switch( eType ){ + case HCT_PAGETYPE_INTKEY: + if( nHeight==0 ){ + pIntkey = &((HctDbIntkeyLeaf*)pCur->pg.aOld)->aEntry[pCur->iEntry]; + }else{ + pIntkeyNode = &((HctDbIntkeyNode*)pCur->pg.aOld)->aEntry[pCur->iEntry]; + } + break; + + case HCT_PAGETYPE_INDEX: + if( nHeight==0 ){ + pIndex = &((HctDbIndexLeaf*)pCur->pg.aOld)->aEntry[pCur->iEntry]; + }else{ + pIndexNode = &((HctDbIndexNode*)pCur->pg.aOld)->aEntry[pCur->iEntry]; + } + break; + + case HCT_PAGETYPE_HISTORY: + pFan = (HctDbHistoryFan*)pCur->pg.aOld; + break; + + } + + switch( i ){ + case 0: /* pgno */ + sqlite3_result_int64(ctx, (i64)pCur->iPg); + break; + case 1: /* iEntry */ + sqlite3_result_int64(ctx, (i64)pCur->iEntry); + break; + case 2: /* ikey */ + if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->iKey); + if( pIntkeyNode ) sqlite3_result_int64(ctx, pIntkeyNode->iKey); + break; + case 3: /* size */ + if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->nSize); + if( pIndex ) sqlite3_result_int64(ctx, pIndex->nSize); + if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->nSize); + break; + case 4: /* offset */ + if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->iOff); + if( pIndex ) sqlite3_result_int64(ctx, pIndex->iOff); + if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->iOff); + break; + case 5: /* child */ + if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->iChildPg); + if( pIntkeyNode ) sqlite3_result_int64(ctx, pIntkeyNode->iChildPg); + break; + + case 6: /* tid */ + case 7: /* rangetid */ + case 8: /* rangeoldpg */ + case 9: /* ovfl */ + if( pIntkey || pIndex || pIndexNode ){ + u8 *aPg = pCur->pg.aOld; + HctDbCell cell; + HctDbIndexEntry *p = hctDbEntryEntry(aPg, pCur->iEntry); + hctDbCellGet(pCur->pDb, &aPg[p->iOff], p->flags, &cell); + + if( i==6 && cell.iTid ){ + i64 iVal = (cell.iTid & HCT_TID_MASK); + if( cell.iTid & HCT_TID_ROLLBACK_OVERRIDE ) iVal = iVal*-1; + sqlite3_result_int64(ctx, iVal); + } + if( i==7 && cell.iRangeTid ){ + i64 iVal = (cell.iRangeTid & HCT_TID_MASK); + if( cell.iRangeTid & HCT_TID_ROLLBACK_OVERRIDE ) iVal = iVal*-1; + sqlite3_result_int64(ctx, iVal); + } + if( i==8 && cell.iRangeOld ){ + sqlite3_result_int64(ctx, (i64)cell.iRangeOld); + } + if( i==9 && cell.iOvfl ){ + sqlite3_result_int64(ctx, (i64)cell.iOvfl); + } + }else if( pFan ){ + if( i==7 ){ /* rangetid */ + u64 iVal = ((pCur->iEntry==0) ? pFan->iRangeTid0 : pFan->iRangeTid1); + if( iVal & HCT_TID_ROLLBACK_OVERRIDE ){ + sqlite3_result_int64(ctx, ((i64)(iVal & HCT_TID_MASK)) * -1); + }else{ + sqlite3_result_int64(ctx, (i64)iVal); + } + }else if( i==8 ){ /* rangeoldpg */ + u32 iRangeOldPg = + ((pCur->iEntry==0) ? pFan->pgOld0 : pFan->aPgOld1[pCur->iEntry-1]); + sqlite3_result_int64(ctx, (i64)iRangeOldPg); + } + } + break; + case 10: /* record */ + if( pIntkey || pIndex || pIndexNode ){ + sqlite3 *db = sqlite3_context_db_handle(ctx); + u8 *aPg = pCur->pg.aOld; + char *zRec; + int sz; + const u8 *aRec = 0; + HctBuffer buf = {0,0,0}; + + hctDbLoadRecord(pCur->pDb, &buf, aPg, pCur->iEntry, &sz, &aRec); + + zRec = sqlite3HctDbRecordToText(db, aRec, sz); + if( zRec ){ + sqlite3_result_text(ctx, zRec, -1, SQLITE_TRANSIENT); + sqlite3_free(zRec); + } + sqlite3HctBufferFree(&buf); + }else if( pFan ){ + char *zRec = sqlite3_mprintf("iSplit0=%d", pFan->iSplit0); + if( zRec ){ + sqlite3_result_text(ctx, zRec, -1, SQLITE_TRANSIENT); + sqlite3_free(zRec); + } + } + break; + } + + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int hctentryRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + hctentry_cursor *pCur = (hctentry_cursor*)cur; + *pRowid = (((i64)pCur->iPg) << 32) + pCur->iEntry; + return SQLITE_OK; +} + +/* +** This method is called to "rewind" the hctentry_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to hctentryColumn() or hctentryRowid() or +** hctentryEof(). +*/ +static int hctentryFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + int rc; + hctentry_cursor *pCur = (hctentry_cursor*)pVtabCursor; + hctentry_vtab *pTab = (hctentry_vtab*)(pCur->base.pVtab); + u32 iLastPg; + + pCur->pDb = sqlite3HctDbFind(pTab->db, 0); + pCur->iEntry = -1; + iLastPg = sqlite3HctFileMaxpage(pCur->pDb->pFile); + + if( idxNum==1 ){ + u32 iPg = (u32)sqlite3_value_int64(argv[0]); + assert( argc==1 ); + if( iPg<1 || iPg>iLastPg ) return SQLITE_OK; + pCur->iPg = pCur->iLastPg = iPg; + }else{ + pCur->iPg = 1; + pCur->iLastPg = iLastPg; + } + + rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->iPg, &pCur->pg); + if( rc!=SQLITE_OK ){ + return rc; + } + return hctentryNext(pVtabCursor); +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int hctentryBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; + int iPgnoEq = -1; + + pIdxInfo->estimatedCost = (double)1000000; + pIdxInfo->estimatedRows = 1000000; + + /* Search for a pgno=? constraint */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + iPgnoEq = i; + } + } + + if( iPgnoEq>=0 ){ + pIdxInfo->aConstraintUsage[iPgnoEq].argvIndex = 1; + pIdxInfo->idxNum = 1; + pIdxInfo->estimatedCost = (double)1000; + pIdxInfo->estimatedRows = 1000; + } + + return SQLITE_OK; +} + +typedef struct hctvalid_vtab hctvalid_vtab; +typedef struct hctvalid_cursor hctvalid_cursor; +struct hctvalid_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; +struct hctvalid_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + HctDatabase *pDb; /* Database to report on */ + int iEntry; /* Current entry (i.e. rowid) */ + + u32 rootpgno; /* Value of rootpgno column */ + char *zFirst; + char *zLast; + char *zPglist; +}; +static int hctvalidConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + hctvalid_vtab *pNew = 0; + int rc = SQLITE_OK; + + *ppVtab = 0; + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(rootpgno, first, last, pglist)" + ); + + if( rc==SQLITE_OK ){ + pNew = sqlite3MallocZero( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + pNew->db = db; + } + return rc; +} +static int hctvalidBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)10000; + pIdxInfo->estimatedRows = 10000; + return SQLITE_OK; +} +static int hctvalidDisconnect(sqlite3_vtab *pVtab){ + hctvalid_vtab *p = (hctvalid_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} +static int hctvalidOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + hctvalid_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} +static int hctvalidClose(sqlite3_vtab_cursor *cur){ + hctvalid_cursor *pCur = (hctvalid_cursor*)cur; + sqlite3_free(pCur); + return SQLITE_OK; +} +static int hctvalidNext(sqlite3_vtab_cursor *cur){ + hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; + hctvalid_vtab *pTab = (hctvalid_vtab*)(pCsr->base.pVtab); + int ii; + HctDbCsr *pDbCsr = 0; + HctCsrIntkeyOp *pIntkeyOp = 0; + HctCsrIndexOp *pIndexOp = 0; + + sqlite3_free(pCsr->zFirst); + sqlite3_free(pCsr->zLast); + sqlite3_free(pCsr->zPglist); + pCsr->zFirst = 0; + pCsr->zLast = 0; + pCsr->zPglist = 0; + pCsr->rootpgno = 0; + pCsr->iEntry++; + pDbCsr = pCsr->pDb->pScannerList; + pIntkeyOp = pDbCsr->intkey.pOpList; + pIndexOp = pDbCsr->index.pOpList; + ii = 0; + if( pIntkeyOp==0 && pIndexOp==0 ) ii--; + for(/*noop*/; pDbCsr && iiiEntry; ii++){ + if( pIntkeyOp ) pIntkeyOp = pIntkeyOp->pNextOp; + if( pIndexOp ) pIndexOp = pIndexOp->pNextOp; + if( pIntkeyOp==0 && pIndexOp==0 ){ + pDbCsr = pDbCsr->pNextScanner; + if( pDbCsr ){ + pIntkeyOp = pDbCsr->intkey.pOpList; + pIndexOp = pDbCsr->index.pOpList; + if( pIntkeyOp==0 && pIndexOp==0 ) ii--; + } + } + } + + if( pDbCsr ){ + pCsr->rootpgno = pDbCsr->iRoot; + if( pIntkeyOp ){ + if( pIntkeyOp->iFirst!=SMALLEST_INT64 ){ + pCsr->zFirst = sqlite3_mprintf("%lld", pIntkeyOp->iFirst); + } + if( pIntkeyOp->iFirst!=LARGEST_INT64 ){ + pCsr->zLast = sqlite3_mprintf("%lld", pIntkeyOp->iLast); + } + if( pIntkeyOp->iLogical ){ + pCsr->zPglist = sqlite3_mprintf( + "%lld/%lld", pIntkeyOp->iLogical, pIntkeyOp->iPhysical + ); + } + }else{ + if( pIndexOp->pFirst ){ + pCsr->zFirst = sqlite3HctDbRecordToText( + pTab->db, pIndexOp->pFirst, pIndexOp->nFirst + ); + } + if( pIndexOp->pLast ){ + pCsr->zLast = sqlite3HctDbRecordToText( + pTab->db, pIndexOp->pLast, pIndexOp->nLast + ); + } + if( pIndexOp->iLogical ){ + pCsr->zPglist = sqlite3_mprintf( + "%lld/%lld", pIndexOp->iLogical, pIndexOp->iPhysical + ); + } + } + } + + return SQLITE_OK; +} +static int hctvalidFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; + hctvalid_vtab *pTab = (hctvalid_vtab*)(pCsr->base.pVtab); + + pCsr->pDb = sqlite3HctDbFind(pTab->db, 0); + pCsr->iEntry = -1; + return hctvalidNext(cur); +} +static int hctvalidEof(sqlite3_vtab_cursor *cur){ + hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; + return (pCsr->rootpgno==0); +} +static int hctvalidColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; + switch( i ){ + case 0: + sqlite3_result_int64(ctx, (i64)pCsr->rootpgno); + break; + case 1: + sqlite3_result_text(ctx, pCsr->zFirst, -1, SQLITE_TRANSIENT); + break; + case 2: + sqlite3_result_text(ctx, pCsr->zLast, -1, SQLITE_TRANSIENT); + break; + case 3: + sqlite3_result_text(ctx, pCsr->zPglist, -1, SQLITE_TRANSIENT); + break; + } + return SQLITE_OK; +} +static int hctvalidRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; + *pRowid = pCsr->iEntry; + return SQLITE_OK; +} + + + +SQLITE_PRIVATE int sqlite3HctVtabInit(sqlite3 *db){ + static sqlite3_module hctdbModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ hctdbConnect, + /* xBestIndex */ hctdbBestIndex, + /* xDisconnect */ hctdbDisconnect, + /* xDestroy */ 0, + /* xOpen */ hctdbOpen, + /* xClose */ hctdbClose, + /* xFilter */ hctdbFilter, + /* xNext */ hctdbNext, + /* xEof */ hctdbEof, + /* xColumn */ hctdbColumn, + /* xRowid */ hctdbRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + static sqlite3_module hctentryModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ hctentryConnect, + /* xBestIndex */ hctentryBestIndex, + /* xDisconnect */ hctentryDisconnect, + /* xDestroy */ 0, + /* xOpen */ hctentryOpen, + /* xClose */ hctentryClose, + /* xFilter */ hctentryFilter, + /* xNext */ hctentryNext, + /* xEof */ hctentryEof, + /* xColumn */ hctentryColumn, + /* xRowid */ hctentryRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + static sqlite3_module hctvalidModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ hctvalidConnect, + /* xBestIndex */ hctvalidBestIndex, + /* xDisconnect */ hctvalidDisconnect, + /* xDestroy */ 0, + /* xOpen */ hctvalidOpen, + /* xClose */ hctvalidClose, + /* xFilter */ hctvalidFilter, + /* xNext */ hctvalidNext, + /* xEof */ hctvalidEof, + /* xColumn */ hctvalidColumn, + /* xRowid */ hctvalidRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + int rc; + + rc = sqlite3_create_module(db, "hctdb", &hctdbModule, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "hctentry", &hctentryModule, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "hctvalid", &hctvalidModule, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctFileVtabInit(db); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctPManVtabInit(db); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctStatsInit(db); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctJrnlInit(db); + } + return rc; +} + +/************** End of hct_database.c ****************************************/ +/************** Begin file hct_tmap.c ****************************************/ +/* +** 2021 February 28 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +/* +** NOTES ON LOCKING +** +** Each time a new HctTMap object is allocated, the locking related +** variables are set: +** +** HctTMap.iMinTid +** HctTMap.iMinCid +** +** New HctTMap objects are always allocated by writers during the +** WRITING phase of a transaction. The iMinCid variable is set to +** the CID value associated with the snapshot on which the writer +** based its transaction. The iMinTid value is set to the largest +** TID value for which it and all smaller TID values map to fully +** committed transactions with CID values smaller than or equal +** to iMinCid. This means that: +** +** * The new object may be used by any client accessing a snapshot +** with a snapshot-id >= iMinCid. +** +** * So long as this object exists, it is not safe to reuse any +** page ids (logical or physical) freed by transactions with +** TID values > iMinTid. +** +** The HctTMap object may then be used to access any snapshot with +** a CID value greater than or equal to iMinCid. While the HctTMap +** is still in use, it is not safe to reuse any logical or physical +** page id freed by a transaction with a TID value greater than +** iMinTid. +** +** A new HctTMap object is created by a writer after it is allocated +** its TID iff: +** +** TODO: This all needs updating!!! +** +** * The expression (iNewTid % HctTMapServer.nTidStep)==0 is true, or +** * The existing transaction map is too small to contain an entry +** for iNewTid. +** +** The first time a client obtains a new HctTMap object, it remembers +** the CID of the first snapshot it accesses using it. The HctTMap +** is released at the end of the first transaction for which the CID is +** greater than or equal to (iFirstCid + HctTMapServer.nTidStep). This +** happens even if a new HctTMap has been obtained since then. TODO: There +** is probably a role for some randomness here. +** +** The above creates a problem - a single dormant connection can prevent +** all reuse of freed logical and physical pages. This is addressed by +** using smart reference objects of type HctTMapRef that support the +** reference being revoked by the server at any time. See comments above +** struct HctTMapRef for details. +*/ + +/* #include "hctInt.h" */ + +typedef struct HctTMapFull HctTMapFull; +typedef struct HctTMapRef HctTMapRef; + +/* +** The following object type represents a reference to an HctTMapFull +** object. The reference is taken and released under the cover of the +** associated HctTMapServer.mutex mutex. +** +** pRefNext/pRefPrev: +** These are used to link this object into the linked list at +** HctTMapFull.pRefList. They may only be accessed under the cover +** of the associated HctTMapServer.mutex mutex. +** +** pMap: +** Pointer to the HctTMapFull object, if any, that this reference +** currently points to. +** +** refMask: +** This may be set to one of four values. It is always modified using +** CAS instructions. +** +** Zero: +** HctTMapRef.pMap is not valid (always NULL). +** +** HCT_TMAPREF_SERVER: +** When the reference is first taken, under cover of the server mutex, +** refMask is set to this value. +** +** HCT_TMAPREF_SERVER|HCT_TMAPREF_CLIENT: +** When a client actually wishes to use the tmap indicated by this +** reference, it uses a CAS instruction to set refMask to this value. +** It may then use the tmap object. This does not require the mutex. +** +** If the client finds that refMask is not HCT_TMAPREF_SERVER, but +** has been set to 0, then the reference has been revoked. In this +** case it is not safe for the client to touch pMap. It must +** reinitialize the HctTmapRef object (under cover of the server +** mutex). +** +** When the read transaction is over, and the client does not need +** need the tmap object, it uses a CAS instruction to set refMask +** back to HCT_TMAPREF_SERVER. If, when doing so, it finds that the +** HCT_TMAPREF_SERVER bit has already been cleared, then it must +** release the reference immediately (under cover of the server +** mutex). +** +** HCT_TMAPREF_CLIENT: +*/ +struct HctTMapRef { + u32 refMask; + HctTMapFull *pMap; + HctTMapRef *pRefNext; + HctTMapRef *pRefPrev; +}; + +/* +** Bits from HctTMapRef.refMask. +*/ +#define HCT_TMAPREF_CLIENT 0x01 +#define HCT_TMAPREF_SERVER 0x02 +#define HCT_TMAPREF_BOTH 0x03 + +/* +** Event counters used by the hctstats virtual table. +*/ +typedef struct HctTMapStats HctTMapStats; +struct HctTMapStats { + i64 nMutex; + i64 nMutexBlock; +}; + + +/* +** iLockValue: +** This field contains two things - a flag and a safe-tid value. The flag +** is set whenever a read transaction is active, and clear otherwise. +** The safe-tid value is set to a TID value for which itself an all smaller +** TID values are included in the connection's transactions - current and +** future. +** +** Pages freed by the transaction with the safe-tid value may be reused +** without disturbing this client. +** +** pNextClient: +** Linked list of all clients associated with pServer. +** +** pBuild: +** This is used by the sqlite3HctTMapRecoveryXXX() API when constructing +** a new tmap object as part of sqlite_hct_journal recovery. +*/ +struct HctTMapClient { + HctTMapServer *pServer; + HctConfig *pConfig; + u64 iLockValue; + HctTMapClient *pNextClient; + HctTMapFull *pMap; + HctTMapStats stats; + + HctTMapFull *pBuild; + u64 iBuildMin; /* Min TID value explicitly set in pBuild */ +}; + +#define HCT_LOCKVALUE_ACTIVE (((u64)0x01) << 56) + +/* +** Values for HctTMapClient.eState +*/ +#define HCT_CLIENT_NONE 0 +#define HCT_CLIENT_OPEN 1 +#define HCT_CLIENT_UP 2 + +/* +** iMinMinTid: +** This value is set only when the mutex is held, using HctAtomicStore(). +** It may be read, using HctAtomicLoad(), at any time. +*/ +struct HctTMapServer { + sqlite3_mutex *pMutex; /* Mutex to protect this object */ + int nClient; /* Number of connected clients */ + u64 iMinMinTid; /* Smallest iMinTid value in pList */ + HctTMapFull *pList; /* List of tmaps. Newest first */ + HctTMapClient *pClientList; /* List of clients */ +}; + +/* +** nRef: +** Number of clients that hold a pointer to this object. +*/ +struct HctTMapFull { + HctTMap m; + int nRef; /* Number of pointers to this object */ + HctTMapFull *pNext; /* Next entry in HctTMapServer.pList */ +}; + +/* +** ENTER_TMAP_MUTEX(pClient) implementation. +** +** Grab the server mutex. And update client-stats as required at the same +** time. +*/ +static void hctTMapMutexEnter(HctTMapClient *pClient){ + sqlite3_mutex *pMutex = pClient->pServer->pMutex; + pClient->stats.nMutex++; + if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ + pClient->stats.nMutexBlock++; + sqlite3_mutex_enter(pMutex); + } +} + +#if 0 +#define ENTER_TMAP_MUTEX(pClient) sqlite3_mutex_enter(pClient->pServer->pMutex) +#endif +#define ENTER_TMAP_MUTEX(pClient) hctTMapMutexEnter(pClient) +#define LEAVE_TMAP_MUTEX(pClient) sqlite3_mutex_leave(pClient->pServer->pMutex) + +/* +** Atomic version of: +** +** if( *pPtr!=iOld ){ +** return 0; +** } +** *pPtr = iNew; +** return 1; +*/ +#if 0 +static int hctTMapBoolCAS32(u32 *pPtr, u32 iOld, u32 iNew){ + return HctCASBool(pPtr, iOld, iNew); +} +#endif +static int hctTMapBoolCAS64(u64 *pPtr, u64 iOld, u64 iNew){ + return HctCASBool(pPtr, iOld, iNew); +} + +/* +** Return a pointer to the slot in pMap associated with TID iTid. +*/ +static u64 *hctTMapFind(HctTMapFull *pMap, u64 iTid){ + int iOff = iTid - pMap->m.iFirstTid; + int iMap = iOff / HCT_TMAP_PAGESIZE; + iOff = HCT_TMAP_ENTRYSLOT( (iOff % HCT_TMAP_PAGESIZE) ); + return &pMap->m.aaMap[iMap][iOff % HCT_TMAP_PAGESIZE]; +} + +/* +** Allocate the initial HctTMapFull object for the server passed as the +** only argument. This is called as part of sqlite3HctTMapServerNew(). +*/ +static int hctTMapInit(HctTMapServer *p, u64 iFirstTid, u64 iLastTid){ + int rc = SQLITE_OK; + int nMap = 0; + int nByte = 0; + u64 iFirst = (iFirstTid / HCT_TMAP_PAGESIZE) * HCT_TMAP_PAGESIZE; + HctTMapFull *pNew = 0; + + assert( p->pList==0 ); + assert( (iFirstTid & HCT_TMAP_CID_MASK)==iFirstTid ); + + nMap = (iLastTid / HCT_TMAP_PAGESIZE) - (iFirst / HCT_TMAP_PAGESIZE) + 3; + nByte = sizeof(HctTMapFull) + sizeof(u64*)*nMap; + pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, nByte); + if( pNew ){ + int i; + pNew->m.iFirstTid = iFirst; + pNew->m.nMap = nMap; + pNew->m.aaMap = (u64**)&pNew[1]; + for(i=0; im.nMap; i++){ + u64 *a = (u64*)sqlite3HctMalloc(&rc, sizeof(u64)*HCT_TMAP_PAGESIZE); + pNew->m.aaMap[i] = a; + } + + if( rc!=SQLITE_OK ){ + assert( 0 ); /* OOM case */ + for(i=0; im.nMap; i++){ + sqlite3_free(pNew->m.aaMap[i]); + } + sqlite3_free(pNew); + }else{ + u64 t; + for(t=iFirst; tpList = pNew; + pNew->nRef = 1; /* Server reference */ + } + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTMapServerNew(u64 iFirstTid, u64 iLastTid, HctTMapServer **pp){ + int rc = SQLITE_OK; + HctTMapServer *pNew; + + pNew = sqlite3MallocZero(sizeof(HctTMapServer)); + if( pNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + pNew->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pNew->pMutex==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + pNew->iMinMinTid = iFirstTid-1; + rc = hctTMapInit(pNew, iFirstTid, iLastTid); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3HctTMapServerFree(pNew); + pNew = 0; + } + + *pp = pNew; + return rc; +} + +SQLITE_PRIVATE int sqlite3HctTMapServerSet(HctTMapServer *pServer, u64 iTid, u64 iCid){ + u64 *pEntry = hctTMapFind(pServer->pList, iTid); + *pEntry = iCid; + return SQLITE_OK; +} + +/* +** Argument pMap is an HctTMapFull object that is currently linked +** into the list at HctTMapServer.pList. This function removes pMap +** from that list and frees all associated allocations. +*/ +static void hctTMapFreeMap(HctTMapServer *p, HctTMapFull *pMap){ + int iFirst = 0; /* First in pMap->m.aaMap[] to free */ + int iSave = 0; /* First in pMap->m.aaMap[] to preserve */ + int ii; + + assert( pMap && pMap->nRef==0 ); + if( pMap==p->pList ){ + if( pMap->pNext==0 ) iSave = pMap->m.nMap; + p->pList = pMap->pNext; + }else{ + HctTMapFull *pPrev; + HctTMapFull *pNext = pMap->pNext; + + for(pPrev=p->pList; pPrev->pNext!=pMap; pPrev=pPrev->pNext); + for(iSave=0; iSavem.nMap; iSave++){ + if( pMap->m.aaMap[iSave]==pPrev->m.aaMap[0] ) break; + } + + if( pNext ){ + u64 *aDoNotDel = pNext->m.aaMap[pNext->m.nMap-1]; + for(iFirst=pMap->m.nMap; iFirst>0; iFirst--){ + if( pMap->m.aaMap[iFirst-1]==aDoNotDel ) break; + } + } + + pPrev->pNext = pMap->pNext; + } + + for(ii=iFirst; iim.aaMap[ii]); + } + sqlite3_free(pMap); + +} + +/* +** Free a tmap-server object. +*/ +SQLITE_PRIVATE void sqlite3HctTMapServerFree(HctTMapServer *p){ + if( p ){ + assert( p->pClientList==0 ); + sqlite3_mutex_free(p->pMutex); + + assert( p->pList==0 || p->pList->nRef==1 ); + if( p->pList ) p->pList->nRef--; + while( p->pList ){ + HctTMapFull *pMap = p->pList; + while( pMap->pNext ) pMap = pMap->pNext; + hctTMapFreeMap(p, pMap); + } + + sqlite3_free(p); + } +} + +SQLITE_PRIVATE int sqlite3HctTMapClientNew( + HctTMapServer *p, + HctConfig *pConfig, + HctTMapClient **ppClient +){ + int rc = SQLITE_OK; + HctTMapClient *pNew; + + pNew = (HctTMapClient*)sqlite3HctMalloc(&rc, sizeof(HctTMapClient)); + if( pNew ){ + pNew->pServer = p; + pNew->pConfig = pConfig; + ENTER_TMAP_MUTEX(pNew); + /* Under cover of the server mutex, link this new client into the + ** list of clients associated with the server. The minimum TID value + ** for the client is set to the current global minimum. */ + pNew->iLockValue = p->iMinMinTid; + pNew->pNextClient = p->pClientList; + pNew->pMap = p->pList; + pNew->pMap->nRef++; + p->pClientList = pNew; + LEAVE_TMAP_MUTEX(pNew); + } + *ppClient = pNew; + return rc; +} + +SQLITE_PRIVATE void sqlite3HctTMapClientFree(HctTMapClient *pClient){ + if( pClient ){ + HctTMapClient **pp; + ENTER_TMAP_MUTEX(pClient); + + pClient->pMap->nRef--; + if( pClient->pMap->nRef==0 ){ + hctTMapFreeMap(pClient->pServer, pClient->pMap); + } + + /* Remove this client from the HctTMapServer.pClientList list */ + for(pp=&pClient->pServer->pClientList;*pp!=pClient;pp=&(*pp)->pNextClient); + *pp = pClient->pNextClient; + + LEAVE_TMAP_MUTEX(pClient); + sqlite3_free(pClient); + } +} + + +SQLITE_PRIVATE int sqlite3HctTMapBegin(HctTMapClient *pClient, u64 iSnapshot, HctTMap **ppMap){ + HctTMapFull *pMap = pClient->pMap; + u64 iEof = pMap->m.iFirstTid + pMap->m.nMap*HCT_TMAP_PAGESIZE; + + while( 1 ){ + u64 iOrigLockValue = HctAtomicLoad(&pClient->iLockValue); + u64 iLockValue; + + /* Find the new "safe-tid" value */ + u64 iSafe = (iOrigLockValue & HCT_TMAP_CID_MASK); + u64 iMinMinTid = HctAtomicLoad(&pClient->pServer->iMinMinTid); + if( iSafeiSnapshot ) break; + iSafe++; + } + + /* Set the lock-value. If this fails, it means some writer process + ** has increased the safe-tid value for us. */ + assert( (iOrigLockValue & HCT_LOCKVALUE_ACTIVE)==0 ); + iLockValue = iSafe | HCT_LOCKVALUE_ACTIVE; + if( hctTMapBoolCAS64(&pClient->iLockValue, iOrigLockValue, iLockValue) ){ + break; + } + } + + *ppMap = (HctTMap*)pMap; + return SQLITE_OK; +} + +SQLITE_PRIVATE u64 sqlite3HctTMapCommitedTID(HctTMapClient *pClient){ + return (pClient->iLockValue & HCT_TMAP_CID_MASK); +} + +static void hctTMapUpdateSafe(HctTMapClient *pClient){ + assert( sqlite3_mutex_held(pClient->pServer->pMutex) ); + if( pClient->pMap!=pClient->pServer->pList ){ + pClient->pMap->nRef--; + if( pClient->pMap->nRef==0 ){ + hctTMapFreeMap(pClient->pServer, pClient->pMap); + } + pClient->pMap = pClient->pServer->pList; + pClient->pMap->nRef++; + } +} + +/* +** This is called by a reader if it needs to look-up a TID for which its +** current HctTMap object is not large enough. This function sets output +** parameter (*ppMap) to point to the latest HctTMap object, which, +** unless the db is corrupt, is guaranteed to be large enough. +** +** SQLITE_OK is returned if successful. +*/ +SQLITE_PRIVATE int sqlite3HctTMapUpdate(HctTMapClient *pClient, HctTMap **ppMap){ + ENTER_TMAP_MUTEX(pClient); + hctTMapUpdateSafe(pClient); + LEAVE_TMAP_MUTEX(pClient); + *ppMap = (HctTMap*)pClient->pMap; + return SQLITE_OK; +} + +/* +** Called to signal the end of a read or write a transaction. Parameter +** iCID is passed the CID of the snapshot on which the transaction was +** based. +*/ +SQLITE_PRIVATE int sqlite3HctTMapEnd(HctTMapClient *pClient, u64 iCID){ + while( 1 ){ + u64 iOrigLockValue = pClient->iLockValue; + u64 iLockValue; + + assert( (iOrigLockValue & HCT_LOCKVALUE_ACTIVE)!=0 ); + iLockValue = (iOrigLockValue & ~HCT_LOCKVALUE_ACTIVE); + if( hctTMapBoolCAS64(&pClient->iLockValue, iOrigLockValue, iLockValue) ){ + break; + } + } + return SQLITE_OK; +} + +/* +** Allocate a new HctTMapFull object and link it into the list +** belonging to server pServer. The new map object is based on +** the server's current newest - pServer->pList. Relative to this +** object, the new map: +** +** * appends one mapping page to the end of the map, and +** +** * may remove one or more mapping pages from the start of the +** map, based on the current value of HctTMapServer.iMinMinTid. +** +** The server mutex must be held to call this function. +*/ +static int hctTMapNewObject(HctTMapServer *pServer){ + u64 iFirst = (pServer->iMinMinTid / HCT_TMAP_PAGESIZE) * HCT_TMAP_PAGESIZE; + HctTMapFull *pOld = pServer->pList; + HctTMapFull *pNew = 0; + int nMap = 0; + int nDiscard = 0; + int nByte = 0; + int rc = SQLITE_OK; + + assert( sqlite3_mutex_held(pServer->pMutex) ); + assert( (iFirst % HCT_TMAP_PAGESIZE)==0 ); + assert( (pOld->m.iFirstTid % HCT_TMAP_PAGESIZE)==0 ); + assert( (pServer->iMinMinTid & HCT_TMAP_CID_MASK)==pServer->iMinMinTid ); + assert( (iFirst & HCT_TMAP_CID_MASK)==iFirst ); + + nDiscard = (iFirst - pOld->m.iFirstTid) / HCT_TMAP_PAGESIZE; + nMap = pOld->m.nMap + 1 - nDiscard; + nByte = sizeof(HctTMapFull) + nMap*sizeof(u64*); + pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, nByte); + + if( pNew ){ + int ii; + pNew->m.iFirstTid = iFirst; + pNew->m.nMap = nMap; + pNew->m.aaMap = (u64**)&pNew[1]; + pNew->nRef = 1; + for(ii=0; ii<(nMap-1); ii++){ + pNew->m.aaMap[ii] = pOld->m.aaMap[ii+nDiscard]; + } + pNew->m.aaMap[ii] = (u64*)sqlite3HctMalloc( + &rc, sizeof(u64)*HCT_TMAP_PAGESIZE + ); + + pServer->pList->nRef--; + if( pServer->pList->nRef==0 ){ + hctTMapFreeMap(pServer, pServer->pList); + } + pNew->pNext = pServer->pList; + pServer->pList = pNew; + } + + return rc; +} + +/* +** Return the largest TID for which it is safe to reuse freed pages. +*/ +SQLITE_PRIVATE u64 sqlite3HctTMapSafeTID(HctTMapClient *p){ + /* TODO: -1? */ + return HctAtomicLoad(&p->pServer->iMinMinTid); +} + +/* +** This is called by write transactions immediately after obtaining +** the transaction's TID value (at the start of the commit process). +*/ +SQLITE_PRIVATE int sqlite3HctTMapNewTID( + HctTMapClient *p, /* Transaction map client */ + u64 iTid, /* TID for write transaction */ + HctTMap **ppMap /* OUT: (possibly) new transaction map */ +){ + int rc = SQLITE_OK; + HctTMapFull *pMap = p->pMap; + u64 iEof = pMap->m.iFirstTid + ((u64)pMap->m.nMap*HCT_TMAP_PAGESIZE); + + /* If it is time to do so, allocate a new transaction-map */ + if( iTid>=iEof || iTid==(iEof - HCT_TMAP_PAGESIZE/2) ){ + ENTER_TMAP_MUTEX(p); + hctTMapUpdateSafe(p); + pMap = p->pMap; + iEof = pMap->m.iFirstTid + ((u64)pMap->m.nMap*HCT_TMAP_PAGESIZE); + if( iTid>=iEof || iTid==(iEof - HCT_TMAP_PAGESIZE/2) ){ + hctTMapNewObject(p->pServer); + hctTMapUpdateSafe(p); + } + LEAVE_TMAP_MUTEX(p); + } + + *ppMap = (HctTMap*)p->pMap; + return rc; +} + +SQLITE_PRIVATE void sqlite3HctTMapScan(HctTMapClient *p){ + HctTMapClient *pClient = 0; + u64 iSafe = p->iLockValue & HCT_TMAP_CID_MASK; + + ENTER_TMAP_MUTEX(p); + for(pClient=p->pServer->pClientList; pClient; pClient=pClient->pNextClient){ + u64 iVal = HctAtomicLoad(&pClient->iLockValue); + u64 iTid = (iVal & HCT_TMAP_CID_MASK); + + if( (iVal & HCT_LOCKVALUE_ACTIVE)==0 && iTidiLockValue, iVal, iSafe); + iVal = HctAtomicLoad(&pClient->iLockValue); + iTid = (iVal & HCT_TMAP_CID_MASK); + } + + iSafe = MIN(iSafe, iTid); + } + HctAtomicStore(&p->pServer->iMinMinTid, iSafe); + LEAVE_TMAP_MUTEX(p); +} + +SQLITE_PRIVATE i64 sqlite3HctTMapStats(sqlite3 *db, int iStat, const char **pzStat){ + HctTMapClient *pClient = 0; + i64 iVal = -1; + + pClient = sqlite3HctFileTMapClient(sqlite3HctDbFile(sqlite3HctDbFind(db, 0))); + switch( iStat ){ + case 0: + *pzStat = "mutex_attempt"; + iVal = pClient->stats.nMutex; + break; + case 1: + *pzStat = "mutex_block"; + iVal = pClient->stats.nMutexBlock; + break; + default: + break; + } + + return iVal; +} + +SQLITE_PRIVATE int sqlite3HctTMapRecoverySet(HctTMapClient *p, u64 iTid, u64 iCid){ + int rc = SQLITE_OK; + HctTMapFull *pNew = p->pBuild; + if( pNew==0 ){ + u64 iFirst = 1; + u64 iEof = p->pServer->pList->m.iFirstTid; + u64 iLast = iEof + (HCT_TMAP_PAGESIZE*2); + int nMap = 0; + if( iTid>=HCT_TMAP_PAGESIZE ){ + iFirst = 1 + ((iTid / HCT_TMAP_PAGESIZE) - 1) * HCT_TMAP_PAGESIZE; + } + nMap = ((iLast - iFirst) + HCT_TMAP_PAGESIZE-1) / HCT_TMAP_PAGESIZE; + assert( nMap>0 ); + + p->pBuild = pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, + sizeof(HctTMapFull) + nMap*sizeof(u64*) + ); + p->iBuildMin = iTid; + if( pNew ){ + int ii; + pNew->m.iFirstTid = iFirst; + pNew->m.nMap = nMap; + pNew->m.aaMap = (u64**)&pNew[1]; + pNew->nRef = 1; + for(ii=0; iim.aaMap[ii] = aMap; + } + if( rc==SQLITE_OK ){ + u64 ee; + for(ee=iFirst; eem.aaMap[iMap][iOff] = ((u64)1 | HCT_TMAP_COMMITTED); + } + } + } + } + p->iBuildMin = MIN(p->iBuildMin, iTid); + + while( rc==SQLITE_OK && pNew->m.iFirstTid>iTid ){ + int ii; + HctTMapFull *pAlloc = 0; + int nMap = pNew->m.nMap + 1; + + pAlloc = (HctTMapFull*)sqlite3HctMalloc(&rc, + sizeof(HctTMapFull) + nMap*sizeof(u64*) + ); + pAlloc->nRef = 1; + pAlloc->m.nMap = nMap; + pAlloc->m.aaMap = (u64**)&pAlloc[1]; + pAlloc->m.iFirstTid = pNew->m.iFirstTid - HCT_TMAP_PAGESIZE; + memcpy(&pAlloc->m.aaMap[1], pNew->m.aaMap, pNew->m.nMap*sizeof(u64*)); + pAlloc->m.aaMap[0] = (u64*)sqlite3HctMalloc(&rc, + sizeof(u64) * HCT_TMAP_PAGESIZE + ); + for(ii=0; iim.aaMap[0][ii] = ((u64)1 | HCT_TMAP_COMMITTED); + } + + assert( pNew->nRef==1 ); + sqlite3_free(pNew); + p->pBuild = pNew = pAlloc; + } + + if( rc==SQLITE_OK ){ + int iMap = (iTid - pNew->m.iFirstTid) / HCT_TMAP_PAGESIZE; + int iOff = (iTid - pNew->m.iFirstTid) % HCT_TMAP_PAGESIZE; + pNew->m.aaMap[iMap][iOff] = (iCid | HCT_TMAP_COMMITTED); + } + + return rc; +} + +SQLITE_PRIVATE void sqlite3HctTMapRecoveryFinish(HctTMapClient *p, int rc){ + HctTMapFull *pNew = p->pBuild; + if( pNew ){ + p->pBuild = 0; + if( rc==SQLITE_OK ){ + pNew->pNext = p->pServer->pList; + p->pServer->pList = pNew; + p->pServer->iMinMinTid = p->iBuildMin; + if( pNew->pNext ){ + pNew->pNext->nRef--; + if( pNew->pNext->nRef==0 ){ + hctTMapFreeMap(p->pServer, pNew->pNext); + } + } + }else{ + int ii; + for(ii=0; iim.nMap; ii++){ + sqlite3_free(pNew->m.aaMap[ii]); + } + sqlite3_free(pNew); + } + p->iBuildMin = 0; + } +} + + +/************** End of hct_tmap.c ********************************************/ +/************** Begin file hct_record.c **************************************/ +/* +** 2022 May 19 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +/* #include "hctInt.h" */ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +/* #include */ +/* #include */ + +/* +** Write the serialized data blob for the value stored in pMem into +** buf. It is assumed that the caller has allocated sufficient space. +** Return the number of bytes written. +** +** nBuf is the amount of space left in buf[]. The caller is responsible +** for allocating enough space to buf[] to hold the entire field, exclusive +** of the pMem->u.nZero bytes for a MEM_Zero value. +** +** Return the number of bytes actually written into buf[]. The number +** of bytes in the zero-filled tail is included in the return value only +** if those bytes were zeroed in buf[]. +*/ +static u32 hctRecordSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ + u32 len; + + /* Integer and Real */ + if( serial_type<=7 && serial_type>0 ){ + u64 v; + u32 i; + if( serial_type==7 ){ + assert( sizeof(v)==sizeof(pMem->u.r) ); + memcpy(&v, &pMem->u.r, sizeof(v)); + swapMixedEndianFloat(v); + }else{ + v = pMem->u.i; + } + len = i = sqlite3SmallTypeSizes[serial_type]; + assert( i>0 ); + do{ + buf[--i] = (u8)(v&0xFF); + v >>= 8; + }while( i ); + return len; + } + + /* String or blob */ + if( serial_type>=12 ){ + assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0) + == (int)sqlite3VdbeSerialTypeLen(serial_type) ); + len = pMem->n; + if( len>0 ) memcpy(buf, pMem->z, len); + return len; + } + + /* NULL or constants 0 or 1 */ + return 0; +} + +/* +** Return the serial-type for the value stored in pMem. +** +** This routine might convert a large MEM_IntReal value into MEM_Real. +*/ +static u32 hctRecordSerialType(Mem *pMem, u32 *pLen){ + int flags = pMem->flags; + u32 n; + + assert( pLen!=0 ); + if( flags&MEM_Null ){ + *pLen = 0; + return 0; + } + if( flags&(MEM_Int|MEM_IntReal) ){ + /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ +# define MAX_6BYTE ((((i64)0x00008000)<<32)-1) + i64 i = pMem->u.i; + u64 u; + testcase( flags & MEM_Int ); + testcase( flags & MEM_IntReal ); + if( i<0 ){ + u = ~i; + }else{ + u = i; + } + if( u<=127 ){ + if( (i&1)==i ){ + *pLen = 0; + return 8+(u32)u; + }else{ + *pLen = 1; + return 1; + } + } + if( u<=32767 ){ *pLen = 2; return 2; } + if( u<=8388607 ){ *pLen = 3; return 3; } + if( u<=2147483647 ){ *pLen = 4; return 4; } + if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } + *pLen = 8; + if( flags&MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pMem->u.r = (double)pMem->u.i; + pMem->flags &= ~MEM_IntReal; + pMem->flags |= MEM_Real; + return 7; + } + return 6; + } + if( flags&MEM_Real ){ + *pLen = 8; + return 7; + } + assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); + assert( pMem->n>=0 ); + n = (u32)pMem->n; + if( flags & MEM_Zero ){ + n += pMem->u.nZero; + } + *pLen = n; + return ((n*2) + 12 + ((flags&MEM_Str)!=0)); +} + + +/* +** +*/ +SQLITE_PRIVATE int sqlite3HctSerializeRecord( + UnpackedRecord *pRec, /* Record to serialize */ + u8 **ppRec, /* OUT: buffer containing serialization */ + int *pnRec /* OUT: size of (*ppRec) in bytes */ +){ + int ii; + int nData = 0; + int nHdr = 0; + u8 *pOut = 0; + int iOffHdr = 0; + int iOffData = 0; + + for(ii=0; iinField; ii++){ + u32 n; + u32 stype = hctRecordSerialType(&pRec->aMem[ii], &n); + nData += n; + nHdr += sqlite3VarintLen(stype); + pRec->aMem[ii].uTemp = stype; + } + + if( nHdr<=126 ){ + /* The common case */ + nHdr += 1; + }else{ + /* Rare case of a really large header */ + int nVarint = sqlite3VarintLen(nHdr); + nHdr += nVarint; + if( nVarintnField; ii++){ + u32 stype = pRec->aMem[ii].uTemp; + iOffHdr += putVarint32(&pOut[iOffHdr], stype); + iOffData += hctRecordSerialPut(&pOut[iOffData], &pRec->aMem[ii], stype); + } + assert( iOffData==(nHdr+nData) ); + + *ppRec = pOut; + *pnRec = iOffData; + + return SQLITE_OK; +} + + +/************** End of hct_record.c ******************************************/ +/************** Begin file hct_stats.c ***************************************/ +/* +** 2022 September 28 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + + +/* #include "hctInt.h" */ + +typedef struct hctstats_vtab hctstats_vtab; +typedef struct hctstats_cursor hctstats_cursor; +struct hctstats_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; +}; +struct hctstats_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + int iSubsys; + int iStat; + + i64 iRowid; + const char *zStat; /* Value for "stat" column. NULL for EOF. */ + i64 iVal; /* Value for "val" column. */ +}; + +typedef struct HctStatsSubsys HctStatsSubsys; +struct HctStatsSubsys { + const char *zSubsys; + i64 (*xStat)(sqlite3*, int iStat, const char **pzStat); +}; + +static HctStatsSubsys aHctStatGlobal[] = { + { "file", sqlite3HctFileStats }, + { "db", sqlite3HctDbStats }, + { "tmap", sqlite3HctTMapStats }, + { "pman", sqlite3HctPManStats }, + { "hct", sqlite3HctMainStats } +}; + +#define HCTSTATS_SCHEMA "CREATE TABLE x(subsys, stat, val)" + +/* +** xConnect() callback for hctstats table. +*/ +static int hctstatsConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + hctstats_vtab *pNew = 0; + int rc = SQLITE_OK; + + *ppVtab = 0; + rc = sqlite3_declare_vtab(db, HCTSTATS_SCHEMA); + + if( rc==SQLITE_OK ){ + pNew = sqlite3MallocZero( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + pNew->db = db; + } + return rc; +} + +/* +** xBestIndex() callback for hctstats table. +*/ +static int hctstatsBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)10000; + pIdxInfo->estimatedRows = 10000; + return SQLITE_OK; +} + +/* +** xDisconnect() callback for hctstats table. Free the vtab handle. +*/ +static int hctstatsDisconnect(sqlite3_vtab *pVtab){ + hctstats_vtab *p = (hctstats_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** xOpen() callback for hctstats table. Free the vtab handle. +*/ +static int hctstatsOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + hctstats_cursor *pCur; + pCur = sqlite3MallocZero(sizeof(*pCur)); + if( pCur==0 ) return SQLITE_NOMEM; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** xClose() callback for hctstats table. Free the vtab handle. +*/ +static int hctstatsClose(sqlite3_vtab_cursor *cur){ + hctstats_cursor *pCur = (hctstats_cursor*)cur; + sqlite3_free(pCur); + return SQLITE_OK; +} + +static int hctstatsNext(sqlite3_vtab_cursor *cur){ + hctstats_cursor *pCsr = (hctstats_cursor*)cur; + hctstats_vtab *pTab = (hctstats_vtab*)(pCsr->base.pVtab); + + pCsr->zStat = 0; + pCsr->iStat++; + + while( pCsr->zStat==0 && pCsr->iSubsysiSubsys]; + pCsr->iVal = p->xStat(pTab->db, pCsr->iStat, &pCsr->zStat); + if( pCsr->zStat==0 ){ + pCsr->iStat = 0; + pCsr->iSubsys++; + } + } + + return SQLITE_OK; +} + +static int hctstatsFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + hctstats_cursor *pCsr = (hctstats_cursor*)cur; + + if( sqlite3HctDbFind(((hctstats_vtab*)cur->pVtab)->db, 0)==0 ){ + /* Main database is not an hctree db */ + return SQLITE_OK; + } + + pCsr->iStat = -1; + pCsr->iSubsys = 0; + pCsr->iRowid = 0; + return hctstatsNext(cur); +} + +static int hctstatsEof(sqlite3_vtab_cursor *cur){ + hctstats_cursor *pCsr = (hctstats_cursor*)cur; + return (pCsr->zStat==0); +} + +static int hctstatsColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + hctstats_cursor *pCsr = (hctstats_cursor*)cur; + + assert( i==0 || i==1 || i==2 ); + switch( i ){ + case 0: { + HctStatsSubsys *p = &aHctStatGlobal[pCsr->iSubsys]; + sqlite3_result_text(ctx, p->zSubsys, -1, SQLITE_STATIC); + break; + } + + case 1: + sqlite3_result_text(ctx, pCsr->zStat, -1, SQLITE_STATIC); + break; + + default: + assert( i==2 ); + sqlite3_result_int64(ctx, pCsr->iVal); + break; + } + return SQLITE_OK; +} + +static int hctstatsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + hctstats_cursor *pCsr = (hctstats_cursor*)cur; + *pRowid = pCsr->iRowid; + return SQLITE_OK; +} + + +/* +** Register the hct_stats virtual table module with the supplied +** SQLite database handle. +*/ +SQLITE_PRIVATE int sqlite3HctStatsInit(sqlite3 *db){ + static sqlite3_module hctstatsModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ hctstatsConnect, + /* xBestIndex */ hctstatsBestIndex, + /* xDisconnect */ hctstatsDisconnect, + /* xDestroy */ 0, + /* xOpen */ hctstatsOpen, + /* xClose */ hctstatsClose, + /* xFilter */ hctstatsFilter, + /* xNext */ hctstatsNext, + /* xEof */ hctstatsEof, + /* xColumn */ hctstatsColumn, + /* xRowid */ hctstatsRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 + }; + + return sqlite3_create_module(db, "hctstats", &hctstatsModule, 0); +} + + + +/************** End of hct_stats.c *******************************************/ +/************** Begin file hct_journal.c *************************************/ +/* +** 2020 October 13 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +/* #include "hctInt.h" */ +/* #include "vdbeInt.h" */ + +#define HCT_JOURNAL_SCHEMA \ +"CREATE TABLE sqlite_hct_journal(" \ + "cid INTEGER PRIMARY KEY," \ + "schema TEXT," \ + "data BLOB," \ + "schemacid INTEGER," \ + "hash BLOB," \ + "tid INTEGER," \ + "validcid INTEGER" \ +");" + + +#define HCT_BASELINE_SCHEMA \ +"CREATE TABLE sqlite_hct_baseline(" \ + "cid INTEGER," \ + "schemacid INTEGER," \ + "hash BLOB" \ +");" + +/* +** In follower mode, it is not possible to call sqlite3_hct_journal_write() +** for the transaction with CID (N + HCT_MAX_LEADING_WRITE) until all +** transactions with CID values of N or less have been committed. +*/ +#define HCT_MAX_LEADING_WRITE (8*1024) + +typedef struct HctJrnlServer HctJrnlServer; +typedef struct HctJrnlPendingHook HctJrnlPendingHook; + +/* +** One object of this type is shared by all connections to the same +** database. Managed by the HctFileServer object (see functions +** sqlite3HctFileGetJrnlPtr() and SetJrnlPtr()). +** +** iSchemaCid: +** This contains the current schema version of the database. Even though +** this value may be concurrently accessed, there is no need for an +** advanced or versioned data structure. Because: +** +** 1) In LEADER mode, this value is only accessed when writing an entry +** to the journal table, from within sqlite3HctJrnlLog(). It is only +** written to if the transaction has modified the database schema. +** +** The call to sqlite3HctJrnlLog() comes after the transaction has been +** successfully validated. And a transaction that modifies the schema +** only passes validation if there have been no writes at all to the +** the database since its snapshot was opened - i.e. if the CID for the +** transaction is one greater than the CID of its snapshot. This +** guarantees that there are no transactions with CID values less than +** that of the schema transaction concurrently accessing iSchemaCid. +** +** Also, since schema transactions modify the schema cookie, and all other +** transactions check the schema cookie during validation, it is +** guaranteed that no transaction started before the schema transaction +** is committed may successfully validate with a CID value greater than +** that of the schema transaction. +** +** Therefore, if a schema transaction has passed validation, it is +** guaranteed exclusive access to the iSchemaCid variable. +** +** 2) In FOLLOWER mode, the value is: +** +** * read from within sqlite3_hct_journal_write(), just after opening +** a snapshot, and +** +** * written from within the same call, following successful validation +** of a schema transaction. +** +** A schema transaction is only started once all transactions with CID +** values less than that of the schema transaction have finished +** committing. This alone ensures that there is at most a single +** writer to the iSchemaCid variable at any one time. +** +** eMode: +** The current database mode - either SQLITE_HCT_JOURNAL_MODE_FOLLOWER or +** SQLITE_HCT_JOURNAL_MODE_LEADER. +** +** iSnapshot: +** This is meaningful in FOLLOWER mode only. +** +** This is set to a CID value for which it and all prior transactions are +** committed. It may be written by any client using an atomic CAS operation, +** but may only be increased, never decreased. No transaction with a CID +** greater than (iSnapshot + HCT_MAX_LEADING_WRITE) may be started - +** iSnapshot must be increased first. +** +** nCommit: +** Size of aCommit[] array. +** +** aCommit: +** This array is only populated if the object is in FOLLOWER mode. +** +** Say the size of the array is N (actually HctJrnlServer.nCommit). Then, +** when transaction X is committed, slot aCommit[X % N] is set to X. Or, +** if transaction X is committed but no snapshot is valid until Y (for Y>X), +** then instead slot aCommit[X % N] is set to Y. +*/ +struct HctJrnlServer { + u64 iSchemaCid; + int eMode; + u64 iSnapshot; + int nSchemaVersionIncr; + int nCommit; + u64 *aCommit; /* Array of size nCommit */ +}; + +struct HctJrnlPendingHook { + u64 iCid; + u64 iSCid; + HctBuffer data; + HctBuffer schema; +}; + +/* +** There is one instance of this structure for each database handle (HBtree*) +** open on a replication-enabled hctree database. +** +** eInWrite: +** Set to true while the database connection is in a call to +** sqlite3_hct_journal_write(). +*/ +struct HctJournal { + u64 iJrnlRoot; /* Root page of journal table */ + u64 iBaseRoot; /* Root page of base table */ + int eInWrite; + u64 iWriteTid; + u64 iWriteCid; + u64 iRollbackSnapshot; + HctDatabase *pDb; + HctTree *pTree; + HctJrnlServer *pServer; + HctJrnlPendingHook pending; +}; + +#define HCT_JOURNAL_NONE 0 +#define HCT_JOURNAL_INWRITE 1 +#define HCT_JOURNAL_INROLLBACK 2 + +static void hctJournalSetDbError( + sqlite3 *db, /* Database on which to set error */ + int rc, /* Error code */ + const char *zFormat, ... /* Printf() error string and arguments */ +){ + char *zErr = 0; + sqlite3_mutex_enter( sqlite3_db_mutex(db) ); + if( zFormat ){ + va_list ap; + va_start(ap, zFormat); + zErr = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + } + if( zErr ){ + sqlite3ErrorWithMsg(db, rc, "%s", zErr); + sqlite3_free(zErr); + }else{ + sqlite3ErrorWithMsg(db, rc, 0, 0); + } + sqlite3_mutex_leave( sqlite3_db_mutex(db) ); +} + +/* +** Initialize the main database for replication. +*/ +SQLITE_API int sqlite3_hct_journal_init(sqlite3 *db){ + const char *zTest1 = "PRAGMA hct_ndbfile"; + const char *zTest2 = "SELECT 1 WHERE (SELECT count(*) FROM sqlite_schema)=0"; + sqlite3_stmt *pTest = 0; + int rc = SQLITE_OK; + + /* Test that there is not already an open transaction on this database. */ + if( sqlite3_get_autocommit(db)==0 ){ + hctJournalSetDbError(db, SQLITE_ERROR, "open transaction on database"); + return SQLITE_ERROR; + } + + /* Test that the main db really is an hct database. Leave rc set to + ** something other than SQLITE_OK and an error message in the database + ** handle if it is not. */ + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, zTest1, -1, &pTest, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_step(pTest); + sqlite3_finalize(pTest); + if( rc==SQLITE_DONE ){ + hctJournalSetDbError(db, SQLITE_ERROR, "not an hct database"); + }else if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + } + } + + /* Open a transaction on the db */ + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); + } + + /* Test that the main db really is empty */ + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, zTest2, -1, &pTest, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_step(pTest); + sqlite3_finalize(pTest); + if( rc==SQLITE_DONE ){ + hctJournalSetDbError(db, SQLITE_ERROR, "not an empty database"); + rc = SQLITE_ERROR; + }else if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + } + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, + "PRAGMA writable_schema = 1;" + HCT_JOURNAL_SCHEMA ";" + HCT_BASELINE_SCHEMA ";" + "INSERT INTO sqlite_hct_baseline VALUES(6, 0, zeroblob(16));" + "PRAGMA writable_schema = 0;" + ,0 ,0 ,0 + ); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); + } + if( rc!=SQLITE_OK ){ + char *zErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + sqlite3_exec(db, "ROLLBACK", 0, 0, 0); + hctJournalSetDbError(db, rc, "%s", zErr); + sqlite3_free(zErr); + }else{ + rc = sqlite3HctDetectJournals(db); + } + + return rc; +} + +/* +** Register a custom validation callback with the database handle. +*/ +SQLITE_API int sqlite3_hct_journal_hook( + sqlite3 *db, + void *pArg, + int(*xValidate)( + void *pCopyOfArg, + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid + ) +){ + db->xValidate = xValidate; + db->pValidateArg = pArg; + return SQLITE_OK; +} + +SQLITE_API void sqlite3_hct_migrate_mode(sqlite3 *db, int bActivate){ + db->bHctMigrate = bActivate; +} + +/* +** Value iVal is to be stored as an integer in an SQLite record. This +** function returns the number of bytes that it will use for storage. +*/ +static int hctJrnlIntSize(u64 iVal){ +#define MAX_6BYTE ((((i64)0x00008000)<<32)-1) + if( iVal<=127 ) return 1; + if( iVal<=32767 ) return 2; + if( iVal<=8388607 ) return 3; + if( iVal<=2147483647 ) return 4; + if( iVal<=MAX_6BYTE ) return 6; + return 8; +} + +/* +** Store an (nByte*8) bit big-endian integer, value iVal, in buffer a[]. +*/ +static void hctJrnlIntPut(u8 *a, u64 iVal, int nByte){ + int i; + for(i=1; i<=nByte; i++){ + a[nByte-i] = (iVal & 0xFF); + iVal = (iVal >> 8); + } +} + +/* +** Return the byte value that should be stored in the SQLite record +** header for an nSize byte integer field. +*/ +static u8 hctJrnlIntHdr(int nSize){ + if( nSize==8 ) return 6; + if( nSize==6 ) return 5; + return nSize; +} + +/* +** Compose an SQLite record suitable for the sqlite_hct_journal table. +*/ +static u8 *hctJrnlComposeRecord( + u64 iCid, + const char *zSchema, + const u8 *pData, int nData, + u64 iSchemaCid, + u64 iTid, + u64 iValidCid, + int *pnRec +){ + u8 *pRec = 0; + int nRec = 0; + int nHdr = 0; + int nBody = 0; + int nSchema = 0; /* Length of zSchema, in bytes */ + int nTidByte = 0; + int nSchemaCidByte = 0; + int nValidCidByte = 0; + u8 aHash[SQLITE_HCT_JOURNAL_HASHSIZE]; + + nSchema = sqlite3Strlen30(zSchema); + nTidByte = hctJrnlIntSize(iTid); + nSchemaCidByte = hctJrnlIntSize(iSchemaCid); + nValidCidByte = hctJrnlIntSize(iValidCid); + + sqlite3_hct_journal_hashentry( + aHash, iCid, zSchema, pData, nData, iSchemaCid + ); + + /* First figure out how large the eventual record will be */ + nHdr = 1 /* size of header varint */ + + 1 /* "cid" - always NULL */ + + sqlite3VarintLen((nSchema * 2) + 13) /* "schema" - TEXT */ + + sqlite3VarintLen((nData * 2) + 12) /* "data" - BLOB */ + + 1 /* "schemacid" - INTEGER */ + + 1 /* "hash" - BLOB */ + + 1 /* "tid" - INTEGER */ + + 1; /* "validcid" - INTEGER */ + + nBody = 0 /* "cid" - always NULL */ + + nSchema /* "schema" - TEXT */ + + nData /* "data" - BLOB */ + + nSchemaCidByte /* "schemacid" - INTEGER */ + + SQLITE_HCT_JOURNAL_HASHSIZE /* "hash" - BLOB */ + + nTidByte /* "tid" - INTEGER */ + + nValidCidByte; /* "validcid" - INTEGER */ + + nRec = nBody+nHdr; + pRec = (u8*)sqlite3_malloc(nRec); + if( pRec ){ + u8 *pHdr = pRec; + u8 *pBody = &pRec[nHdr]; + + *pHdr++ = (u8)nHdr; /* size-of-header varint */ + *pHdr++ = 0x00; /* "cid" - NULL */ + + /* "schema" field - TEXT */ + pHdr += sqlite3PutVarint(pHdr, (nSchema*2) + 13); + if( nSchema>0 ){ + memcpy(pBody, zSchema, nSchema); + pBody += nSchema; + } + + /* "data" field - BLOB */ + pHdr += sqlite3PutVarint(pHdr, (nData*2) + 12); + if( nData>0 ){ + memcpy(pBody, pData, nData); + pBody += nData; + } + + /* "schemacid" field - INTEGER */ + *pHdr++ = hctJrnlIntHdr(nSchemaCidByte); + hctJrnlIntPut(pBody, iSchemaCid, nSchemaCidByte); + pBody += nSchemaCidByte; + + /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ + *pHdr++ = (u8)((SQLITE_HCT_JOURNAL_HASHSIZE * 2) + 12); + memcpy(pBody, aHash, SQLITE_HCT_JOURNAL_HASHSIZE); + pBody += SQLITE_HCT_JOURNAL_HASHSIZE; + + /* "tid" field - INTEGER */ + *pHdr++ = hctJrnlIntHdr(nTidByte); + hctJrnlIntPut(pBody, iTid, nTidByte); + pBody += nTidByte; + + /* "validcid" field - INTEGER */ + *pHdr++ = hctJrnlIntHdr(nValidCidByte); + hctJrnlIntPut(pBody, iValidCid, nValidCidByte); + pBody += nValidCidByte; + + assert( pHdr==&pRec[nHdr] ); + assert( pBody==&pRec[nRec] ); + }else{ + nRec = 0; + } + + *pnRec = nRec; + return pRec; +} + +typedef struct JrnlCtx JrnlCtx; +struct JrnlCtx { + Schema *pSchema; + HctTree *pTree; + HctBuffer *pBuf; + HctBuffer *pSchemaSql; +}; + +typedef struct JrnlTree JrnlTree; +struct JrnlTree { + const char *zName; +}; + +static int hctJrnlFindTree(Schema *pSchema, u32 iRoot, JrnlTree *pJTree){ + HashElem *k; + if( iRoot==1 ) return 0; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pTab = (Table*)sqliteHashData(k); + if( pTab->tnum==iRoot ){ + pJTree->zName = pTab->zName; + return 1; + } + } + return 0; +} + +static void hctJrnlRecordPrefix( + HctBuffer *pBuf, + int nData, /* Size of buffer aData[] in bytes */ + const u8 *aData, /* Buffer containing SQLite record */ + int nField /* Number of prefix fields requested */ +){ + int iHdr = 0; + int iBody = 0; + int ii = 0; + int szHdr = 0; /* Size of output header */ + int szBody = 0; /* Size of output record body */ + u8 *aHdrOut = 0; + u8 *aBodyOut = 0; + + iHdr = getVarint32(aData, iBody); + + /* Figure out the aggregate sizes of the header and body fields for the + ** required number of prefix fields. */ + for(ii=0; ii126 ){ + int nVarint = sqlite3VarintLen(szHdr); + szHdr += nVarint; + if( sqlite3VarintLen(szHdr)!=nVarint ) szHdr++; + } + + /* Size of record field */ + pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], szHdr+szBody); + + aHdrOut = &pBuf->aBuf[pBuf->nBuf]; + aBodyOut = &aHdrOut[szHdr]; + + /* Write the size-of-header field for the output record */ + aHdrOut += sqlite3PutVarint(aHdrOut, szHdr); + + /* Write the other fields to both the header and body of the output record */ + for(ii=0; ii0 ){ + memcpy(aBodyOut, &aData[iBody], nBody); + iBody += nBody; + aBodyOut += nBody; + } + } + + pBuf->nBuf = (aBodyOut - pBuf->aBuf); +} + +static int hctBufferExtend(HctBuffer *pBuf, int nExtend){ + i64 nDesire = pBuf->nBuf + nExtend; + if( pBuf->nAllocaBuf[pBuf->nBuf], zApp, nApp+1); + pBuf->nBuf += nApp; + sqlite3_free(zApp); + return SQLITE_OK; +} + + +static int hctJrnlLogTree(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ + int rc = SQLITE_OK; + JrnlCtx *pJrnl = (JrnlCtx*)pCtx; + HctBuffer *pBuf = pJrnl->pBuf; + + if( iRoot==HCT_TREE_SCHEMAOP_ROOT ){ + HctTreeCsr *pCsr = 0; + rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, iRoot, &pCsr); + if( rc==SQLITE_OK ){ + for(rc=sqlite3HctTreeCsrFirst(pCsr); + rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; + rc=sqlite3HctTreeCsrNext(pCsr) + ){ + int nData = 0; + const u8 *aData = 0; + sqlite3HctTreeCsrData(pCsr, &nData, &aData); + rc = hctBufferAppend(pJrnl->pSchemaSql, "%s%.*s", + (pJrnl->pSchemaSql->nBuf>0 ? ";" : ""), nData, (const char*)aData + ); + } + sqlite3HctTreeCsrClose(pCsr); + } + }else{ + JrnlTree jrnltree; + memset(&jrnltree, 0, sizeof(jrnltree)); + if( hctJrnlFindTree(pJrnl->pSchema, iRoot, &jrnltree) ){ + int nName = sqlite3Strlen30(jrnltree.zName); + + rc = hctBufferExtend(pBuf, 1+nName+1); + if( rc==SQLITE_OK ){ + HctTreeCsr *pCsr = 0; + + pBuf->aBuf[pBuf->nBuf++] = 'T'; + memcpy(&pBuf->aBuf[pBuf->nBuf], jrnltree.zName, nName+1); + pBuf->nBuf += nName+1; + rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, iRoot, &pCsr); + + if( rc==SQLITE_OK ){ + for(rc=sqlite3HctTreeCsrFirst(pCsr); + rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; + rc=sqlite3HctTreeCsrNext(pCsr) + ){ + i64 iKey = 0; + int nData = 0; + const u8 *aData = 0; + int bDel = 0; + + sqlite3HctTreeCsrKey(pCsr, &iKey); + sqlite3HctTreeCsrData(pCsr, &nData, &aData); + bDel = sqlite3HctTreeCsrIsDelete(pCsr); + + rc = hctBufferExtend(pBuf, 1+9+9+nData); + if( rc!=SQLITE_OK ) break; + + if( pKeyInfo==0 ){ + pBuf->aBuf[pBuf->nBuf++] = bDel ? 'd' : 'i'; + pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], iKey); + }else{ + pBuf->aBuf[pBuf->nBuf++] = bDel ? 'D' : 'I'; + if( bDel ){ + hctJrnlRecordPrefix(pBuf, nData, aData, pKeyInfo->nUniqField); + } + } + if( bDel==0 ){ + pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], nData); + memcpy(&pBuf->aBuf[pBuf->nBuf], aData, nData); + pBuf->nBuf += nData; + } + } + } + + sqlite3HctTreeCsrClose(pCsr); + } + } + } + + return rc; +} + +static int hctJrnlWriteRecord( + HctJournal *pJrnl, + u64 iCid, + const char *zSchema, + const void *pData, int nData, + u64 iSchemaCid, + u64 iTid +){ + int rc = SQLITE_OK; + u8 *pRec = 0; + int nRec = 0; + + pRec = hctJrnlComposeRecord( + iCid, zSchema, pData, nData, iSchemaCid, iTid, 0, &nRec + ); + if( pRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + int nRetry = 0; + do { + nRetry = 0; + rc = sqlite3HctDbInsert( + pJrnl->pDb, (u32)pJrnl->iJrnlRoot, 0, iCid, 0, nRec, pRec, &nRetry + ); + if( rc!=SQLITE_OK ) break; + assert( nRetry==0 || nRetry==1 ); + if( nRetry==0 ){ + rc = sqlite3HctDbInsertFlush(pJrnl->pDb, &nRetry); + if( rc!=SQLITE_OK ) break; + } + }while( nRetry ); + } + sqlite3_free(pRec); + + return rc; +} + +SQLITE_PRIVATE int sqlite3HctJrnlWriteEmpty( + HctJournal *pJrnl, + u64 iCid, + u64 iTid, + sqlite3 *db /* If non-NULL, invoke custom validation */ +){ + int rc = SQLITE_OK; + if( pJrnl->eInWrite==HCT_JOURNAL_NONE ){ + rc = hctJrnlWriteRecord(pJrnl, iCid, "", 0, 0, 0, iTid); + + /* If argument db is not NULL and there is a custom validation hook + ** configured, invoke it now. This is just to propagate the empty + ** transaction to any follower databases, not to actually validate + ** an empty transaction - the return code is ignored. */ + if( rc==SQLITE_OK && db && db->xValidate ){ + // (void)db->xValidate(db->pValidateArg, iCid, "", 0, 0, 0); + pJrnl->pending.iCid = iCid; + pJrnl->pending.iSCid = 0; + pJrnl->pending.data.nBuf = 0; + pJrnl->pending.schema.nBuf = 0; + } + } + return rc; +} + +SQLITE_PRIVATE void sqlite3HctJrnlInvokeHook(HctJournal *pJrnl, sqlite3 *db){ + if( pJrnl ){ + HctJrnlPendingHook *pPending = &pJrnl->pending; + if( pPending->iCid>0 ){ + if( db->xValidate ){ + const char *zSchema = ""; + if( pJrnl->pending.schema.nBuf>0 ){ + zSchema = (const char*)pJrnl->pending.schema.aBuf; + } + (void)db->xValidate( + db->pValidateArg, pPending->iCid, + zSchema, pPending->data.aBuf, pPending->data.nBuf, + pPending->iSCid + ); + } + + pPending->iCid = 0; + } + } +} + +SQLITE_PRIVATE int sqlite3HctJrnlLog( + HctJournal *pJrnl, + sqlite3 *db, + Schema *pSchema, + u64 iCid, + u64 iTid, + int *pbValidateCalled +){ + int rc = SQLITE_OK; + JrnlCtx jrnlctx; + const char *zSchema = ""; + u64 iSchemaCid = HctAtomicLoad(&pJrnl->pServer->iSchemaCid); + + assert( *pbValidateCalled==0 ); + if( pJrnl->eInWrite!=HCT_JOURNAL_NONE ) return SQLITE_OK; + + memset(&jrnlctx, 0, sizeof(jrnlctx)); + jrnlctx.pSchema = pSchema; + jrnlctx.pTree = pJrnl->pTree; + jrnlctx.pBuf = &pJrnl->pending.data; + jrnlctx.pSchemaSql = &pJrnl->pending.schema; + + jrnlctx.pBuf->nBuf = 0; + jrnlctx.pSchemaSql->nBuf = 0; + + rc = sqlite3HctTreeForeach(pJrnl->pTree, 1, (void*)&jrnlctx, hctJrnlLogTree); + if( jrnlctx.pSchemaSql->nBuf ){ + zSchema =(const char*)jrnlctx.pSchemaSql->aBuf; + } + + if( rc==SQLITE_OK ){ + rc = hctJrnlWriteRecord(pJrnl, iCid, zSchema, + jrnlctx.pBuf->aBuf, jrnlctx.pBuf->nBuf, iSchemaCid, iTid + ); + } + + /* If one is registered, invoke the validation hook */ + if( rc==SQLITE_OK && db->xValidate ){ +#if 0 + int res = db->xValidate(db->pValidateArg, iCid, zSchema, + jrnlctx.buf.aBuf, jrnlctx.buf.nBuf, iSchemaCid + ); + if( res!=0 ){ + rc = SQLITE_BUSY_SNAPSHOT; + } + *pbValidateCalled = 1; +#endif + pJrnl->pending.iCid = iCid; + pJrnl->pending.iSCid = iSchemaCid; + } + + if( zSchema[0] && rc==SQLITE_OK ){ + HctAtomicStore(&pJrnl->pServer->iSchemaCid, iCid); + } + + return rc; +} + +static void hctJrnlDelServer(void *p){ + if( p ){ + HctJrnlServer *pServer = (HctJrnlServer*)p; + sqlite3_free(pServer->aCommit); + sqlite3_free(pServer); + } +} + +typedef struct HctJournalRecord HctJournalRecord; +struct HctJournalRecord { + i64 iCid; + const char *zSchema; int nSchema; + const void *pData; int nData; + i64 iSchemaCid; + const void *pHash; + i64 iTid; + i64 iValidCid; +}; + +/* +** Structure containing values read from the sqlite_hct_baseline table. +*/ +typedef struct HctBaselineRecord HctBaselineRecord; +struct HctBaselineRecord { + i64 iCid; + u8 aHash[SQLITE_HCT_JOURNAL_HASHSIZE]; + i64 iSchemaCid; +}; + + +typedef struct HctRecordReader HctRecordReader; +struct HctRecordReader { + const u8 *aRec; + int nRec; + int nHdr; + const u8 *pHdr; + const u8 *pBody; +}; + +static void hctJrnlReadInit( + HctRecordReader *p, + int nRec, + const u8 *aRec +){ + memset(p, 0, sizeof(*p)); + p->aRec = aRec; + p->nRec = nRec; + p->pHdr = p->aRec + getVarint32(aRec, p->nHdr); + p->pBody = &p->aRec[p->nHdr]; +} + +static const u8 *hctJrnlReadBlobText( + int *pRc, + HctRecordReader *p, + int bText, + int *pnData +){ + const u8 *pRet = 0; + if( *pRc==SQLITE_OK ){ + u64 iType = 0; + p->pHdr += sqlite3GetVarint(p->pHdr, &iType); + if( iType<12 || (iType % 2)!=bText ){ + *pRc = SQLITE_CORRUPT_BKPT; + }else{ + *pnData = (iType - 12) / 2; + pRet = p->pBody; + p->pBody += (*pnData); + } + } + return pRet; +} + +static const char *hctJrnlReadText( + int *pRc, + HctRecordReader *p, + int *pnText +){ + return (const char*)hctJrnlReadBlobText(pRc, p, 1, pnText); +} +static const u8 *hctJrnlReadBlob( + int *pRc, + HctRecordReader *p, + int *pnText +){ + return hctJrnlReadBlobText(pRc, p, 0, pnText); +} + +static i64 hctJrnlReadInteger(int *pRc, HctRecordReader *p){ + i64 iRet = 0; + if( *pRc==SQLITE_OK ){ + u64 iType = 0; + p->pHdr += sqlite3GetVarint(p->pHdr, &iType); + switch( iType ){ + case 1: + iRet = p->pBody[0]; + p->pBody++; + break; + case 2: + iRet = ((u64)p->pBody[0] << 8) + + ((u64)p->pBody[1] << 0); + p->pBody += 2; + break; + case 3: + iRet = ((u64)p->pBody[0] << 16) + + ((u64)p->pBody[1] << 8) + + ((u64)p->pBody[2] << 0); + p->pBody += 3; + break; + case 4: + iRet = ((u64)p->pBody[0] << 24) + + ((u64)p->pBody[1] << 16) + + ((u64)p->pBody[2] << 8) + + ((u64)p->pBody[3] << 0); + p->pBody += 4; + break; + case 5: + iRet = ((u64)p->pBody[0] << 40) + + ((u64)p->pBody[1] << 32) + + ((u64)p->pBody[2] << 24) + + ((u64)p->pBody[3] << 16) + + ((u64)p->pBody[4] << 8) + + ((u64)p->pBody[5] << 0); + p->pBody += 6; + break; + case 6: + iRet = ((u64)p->pBody[0] << 56) + + ((u64)p->pBody[1] << 48) + + ((u64)p->pBody[2] << 40) + + ((u64)p->pBody[3] << 32) + + ((u64)p->pBody[4] << 24) + + ((u64)p->pBody[5] << 16) + + ((u64)p->pBody[6] << 8) + + ((u64)p->pBody[7] << 0); + p->pBody += 6; + break; + case 8: + iRet = 0; + break; + case 9: + iRet = 1; + break; + default: + *pRc = SQLITE_CORRUPT_BKPT; + break; + } + } + + return iRet; +} + +static void hctJrnlReadHash( + int *pRc, /* IN/OUT: Error code */ + HctRecordReader *p, /* Record reader */ + u8 *aHash /* Pointer to buffer to populate */ +){ + int nHash = 0; + const u8 *a = 0; + a = hctJrnlReadBlob(pRc, p, &nHash); + if( *pRc==SQLITE_OK && nHash!=SQLITE_HCT_JOURNAL_HASHSIZE ){ + *pRc = SQLITE_CORRUPT_BKPT; + } + if( *pRc==SQLITE_OK ){ + memcpy(aHash, a, SQLITE_HCT_JOURNAL_HASHSIZE); + } +} + +static int hctJrnlReadJournalRecord(HctDbCsr *pCsr, HctJournalRecord *pRec){ + int rc = SQLITE_OK; + int nData = 0; + const u8 *aData = 0; + + memset(pRec, 0, sizeof(*pRec)); + + sqlite3HctDbCsrKey(pCsr, (i64*)&pRec->iCid); + rc = sqlite3HctDbCsrData(pCsr, &nData, &aData); + if( rc==SQLITE_OK ){ + int nHash = 0; + HctRecordReader rdr; + hctJrnlReadInit(&rdr, nData, aData); + + /* "cid" field - always NULL */ + if( *rdr.pHdr++!=0 ) return SQLITE_CORRUPT_BKPT; + + /* "schema" field - always TEXT. */ + pRec->zSchema = hctJrnlReadText(&rc, &rdr, &pRec->nSchema); + + /* "data" field - always BLOB */ + pRec->pData = hctJrnlReadBlob(&rc, &rdr, &pRec->nData); + + /* "schemacid" field - always INTEGER */ + pRec->iSchemaCid = hctJrnlReadInteger(&rc, &rdr); + + /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ + pRec->pHash = (const void*)hctJrnlReadBlob(&rc, &rdr, &nHash); + if( nHash!=SQLITE_HCT_JOURNAL_HASHSIZE ) rc = SQLITE_CORRUPT_BKPT; + + /* "tid" field - an INTEGER */ + pRec->iTid = hctJrnlReadInteger(&rc, &rdr); + + /* "valid_cid" field - an INTEGER */ + pRec->iValidCid = hctJrnlReadInteger(&rc, &rdr); + } + return rc; +} + +/* +** Read the contents of the sqlite_hct_baseline table into structure +** (*pRec). Return SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +static int hctJrnlReadBaseline( + HctJournal *pJrnl, /* Database to read from */ + HctBaselineRecord *pRec /* Populate this structure before returning */ +){ + HctDbCsr *pCsr = 0; + int rc = SQLITE_OK; + + memset(pRec, 0, sizeof(HctBaselineRecord)); + + /* Open a cursor on the baseline table */ + rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, (u32)pJrnl->iBaseRoot, &pCsr); + + /* Move the cursor to the first record in the table. */ + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrFirst(pCsr); + } + if( rc==SQLITE_OK && sqlite3HctDbCsrEof(pCsr) ){ + rc = SQLITE_CORRUPT_BKPT; + } + + if( rc==SQLITE_OK ){ + int nData = 0; + const u8 *aData = 0; + + rc = sqlite3HctDbCsrData(pCsr, &nData, &aData); + if( rc==SQLITE_OK ){ + HctRecordReader rdr; + hctJrnlReadInit(&rdr, nData, aData); + + /* "cid" field - an INTEGER */ + pRec->iCid = hctJrnlReadInteger(&rc, &rdr); + + /* "schemacid" field - an INTEGER */ + pRec->iSchemaCid = hctJrnlReadInteger(&rc, &rdr); + + /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ + hctJrnlReadHash(&rc, &rdr, pRec->aHash); + } + } + sqlite3HctDbCsrClose(pCsr); + + return rc; +} + +static int hctJrnlGetJrnlShape( + sqlite3 *db, + i64 *piLast, /* Out: Last entry in journal */ + i64 *piLastCont /* Out: Last contiguous entry in journal */ +){ + const char *z1 = "SELECT max(cid) FROM sqlite_hct_journal"; + const char *z2 = "SELECT cid FROM sqlite_hct_journal ORDER BY 1 DESC"; + + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = 0; + i64 iLast = 0; + i64 iLastCont = 0; + + rc = sqlite3_prepare_v2(db, z1, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + iLast = sqlite3_column_int64(pStmt, 0); + } + rc = sqlite3_finalize(pStmt); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, z2, -1, &pStmt, 0); + } + if( rc==SQLITE_OK ){ + i64 iPrev = iLast; + iLastCont = iLast; + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + i64 iThis = sqlite3_column_int64(pStmt, 0); + if( iThis!=iPrev-1 ){ + iLastCont = iThis; + } + if( (iLast-iThis)>HCT_MAX_LEADING_WRITE*2 ) break; + iPrev = iThis; + } + rc = sqlite3_finalize(pStmt); + } + + *piLast = iLast; + *piLastCont = iLastCont; + return rc; +} + +static sqlite3_stmt *hctPreparePrintf( + int *pRc, + sqlite3 *db, + const char *zFmt, ... +){ + sqlite3_stmt *pRet = 0; + va_list ap; + char *zSql = 0; + + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + + if( *pRc==SQLITE_OK ){ + if( zSql==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + *pRc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0); + } + } + sqlite3_free(zSql); + return pRet; +} + +/* +** Iterator for reading a blob from the "data" column of a journal entry. +*/ +typedef struct HctDataReader HctDataReader; +struct HctDataReader { + const u8 *aData; + int nData; + int iData; + + int bEof; + char eType; + + /* Valid for all values of eType */ + const char *zTab; + + /* For eType==HCT_TYPE_INSERT_ROWID, HCT_TYPE_DELETE_ROWID */ + i64 iRowid; + + /* For eType==HCT_TYPE_INSERT_ROWID */ + int nRecord; + const u8 *aRecord; +}; + +#define HCT_TYPE_TABLE 'T' +#define HCT_TYPE_INSERT_ROWID 'i' +#define HCT_TYPE_DELETE_ROWID 'd' + +static int hctDataReaderNext(HctDataReader *p){ + if( p->iData>=p->nData ){ + p->bEof = 1; + }else{ + p->eType = (char)(p->aData[p->iData++]); + switch( p->eType ){ + case 'T': { + p->zTab = (const char*)&p->aData[p->iData]; + p->iData += sqlite3Strlen30(p->zTab) + 1; + break; + } + + case 'd': { + p->iData += sqlite3GetVarint(&p->aData[p->iData], (u64*)&p->iRowid); + break; + } + + case 'i': { + p->iData += sqlite3GetVarint(&p->aData[p->iData], (u64*)&p->iRowid); + p->iData += getVarint32(&p->aData[p->iData], p->nRecord); + p->aRecord = &p->aData[p->iData]; + p->iData += p->nRecord; + break; + } + + default: { + return SQLITE_CORRUPT_BKPT; + } + } + } + + return SQLITE_OK; +} + +/* +** Initialize an HctDataReader object to iterate through the nData byte +** 'data' blob in buffer pData. Leave the iterator pointing at the first +** entry in the blob. +*/ +static int hctDataReaderInit(const void *pData, int nData, HctDataReader *pRdr){ + memset(pRdr, 0, sizeof(*pRdr)); + pRdr->aData = (const u8*)pData; + pRdr->nData = nData; + return hctDataReaderNext(pRdr); +} + +SQLITE_PRIVATE int sqlite3HctJrnlSavePhysical( + sqlite3 *db, + HctJournal *pJrnl, + int (*xSave)(void*, i64 iPhys), + void *pSave +){ + const char *zSql = "SELECT data FROM sqlite_hct_journal WHERE cid>?"; + int rc = SQLITE_OK; + i64 iLast = 0; + i64 iLastCont = 0; + sqlite3_stmt *pStmt = 0; + + rc = hctJrnlGetJrnlShape(db, &iLast, &iLastCont); + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iLastCont); + while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + const void *pData = sqlite3_column_blob(pStmt, 0); + int nData = sqlite3_column_bytes(pStmt, 0); + sqlite3_stmt *pQuery = 0; + HctDataReader rdr; + + sqlite3HctDbSetSavePhysical(pJrnl->pDb, xSave, pSave); + for(rc=hctDataReaderInit(pData, nData, &rdr); + rc==SQLITE_OK && rdr.bEof==0; + rc=hctDataReaderNext(&rdr) + ){ + switch( rdr.eType ){ + case HCT_TYPE_TABLE: { + rc = sqlite3_finalize(pQuery); + pQuery = hctPreparePrintf( + &rc, db, "SELECT * FROM %Q WHERE _rowid_=?", rdr.zTab + ); + break; + } + + case HCT_TYPE_INSERT_ROWID: + case HCT_TYPE_DELETE_ROWID: { + sqlite3_bind_int64(pQuery, 1, rdr.iRowid); + sqlite3_step(pQuery); + rc = sqlite3_reset(pQuery); + break; + } + + default: assert( 0 ); + } + if( rc ) break; + } + sqlite3HctDbSetSavePhysical(pJrnl->pDb, 0, 0); + sqlite3_finalize(pQuery); + } + rc = sqlite3_finalize(pStmt); + } + + return rc; +} + +/* +** Do special recovery (startup) processing for replication-enabled databases. +** This function is called during stage 1 recovery - after any log files have +** been processed (and the database schema + contents restored), but before the +** free-page-lists are recovered. +*/ +SQLITE_PRIVATE int sqlite3HctJrnlRecovery(HctJournal *pJrnl, HctDatabase *pDb){ + HctBaselineRecord base; /* sqlite_hct_baseline data */ + HctJrnlServer *pServer = 0; + HctFile *pFile = sqlite3HctDbFile(pDb); + int rc = SQLITE_OK; + HctDbCsr *pCsr = 0; + + i64 iMaxCid = 0; + i64 iSchemaCid = 0; + + /* Read the contents of the sqlite_hct_baseline table. */ + rc = hctJrnlReadBaseline(pJrnl, &base); + + /* Allocate the new HctJrnlServer structure */ + pServer = (HctJrnlServer*)sqlite3HctMalloc(&rc, sizeof(HctJrnlServer)); + + /* Read the last record of the sqlite_hct_journal table. Specifically, + ** the value of fields "cid" and "schema_version". Store these values + ** in stack variables iMaxCid and aSchema, respectively. Or, if the + ** sqlite_hct_journal table is empty, populate iMaxCid and aSchema[] with + ** values from the baseline table. */ + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrOpen(pDb, 0, (u32)pJrnl->iJrnlRoot, &pCsr); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrLast(pCsr); + } + if( rc==SQLITE_OK ){ + if( sqlite3HctDbCsrEof(pCsr)==0 ){ + HctJournalRecord rec; + rc = hctJrnlReadJournalRecord(pCsr, &rec); + if( rc==SQLITE_OK ){ + iMaxCid = rec.iCid; + iSchemaCid = (rec.zSchema[0] ? rec.iCid : rec.iSchemaCid); + } + }else{ + iMaxCid = base.iCid; + iSchemaCid = base.iSchemaCid; + } + } + + /* Scan the sqlite_hct_journal table from beginning to end. When + ** the first missing entry is found, calculate the size of the + ** HctJrnlServer.aCommit[] API and allocate it. Then continue + ** scanning the sqlite_hct_journal table, populating aCommit[] along + ** the way. */ + if( rc==SQLITE_OK ){ + HctTMapClient *pTClient = sqlite3HctFileTMapClient(pFile); + i64 iPrev = base.iCid; + int nTrans = 0; + u64 *aCommit = 0; + + /* Scan until the first missing entry. Set nTrans to the number of + ** number of entries between the first missing one and the last + ** present, or to HCT_MAX_LEADING_WRITE, whichever is greater. + ** Set iPrev to the largest CID value for which it and all previous + ** CIDs have been written into the journal table. */ + for(rc = sqlite3HctDbCsrFirst(pCsr); + rc==SQLITE_OK && 0==sqlite3HctDbCsrEof(pCsr); + rc = sqlite3HctDbCsrNext(pCsr) + ){ + i64 iCid = 0; + sqlite3HctDbCsrKey(pCsr, &iCid); + if( iPrev!=0 && iCid!=iPrev+1 ){ + nTrans = iMaxCid - iPrev; + break; + } + iPrev = iCid; + } + nTrans = MAX(HCT_MAX_LEADING_WRITE, nTrans); + + pServer->nCommit = nTrans*2; + aCommit = (u64*)sqlite3HctMalloc(&rc, pServer->nCommit*sizeof(u64)); + pServer->aCommit = aCommit; + pServer->iSnapshot = iPrev; + + /* Scan through whatever is left of the sqlite_hct_journal table, + ** populating the aCommit[] array and the transaction-map (hct_tmap.c) + ** along the way. */ + while( rc==SQLITE_OK && 0==sqlite3HctDbCsrEof(pCsr) ){ + HctJournalRecord rec; + rc = hctJrnlReadJournalRecord(pCsr, &rec); + if( rc==SQLITE_OK ){ + i64 iVal = rec.iValidCid ? rec.iValidCid : rec.iCid; + pServer->aCommit[rec.iCid % pServer->nCommit] = iVal; + rc = sqlite3HctTMapRecoverySet(pTClient, rec.iTid, rec.iCid); + } + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrNext(pCsr); + } + } + sqlite3HctTMapRecoveryFinish(pTClient, rc); + } + + if( rc==SQLITE_OK ){ + HctAtomicStore(&pServer->iSchemaCid, iSchemaCid); + pJrnl->pServer = pServer; + sqlite3HctFileSetJrnlPtr(pFile, (void*)pServer, hctJrnlDelServer); + if( iMaxCid>0 ) sqlite3HctFileSetCID(pFile, iMaxCid); + }else{ + hctJrnlDelServer((void*)pServer); + } + + sqlite3HctDbCsrClose(pCsr); + return rc; +} + +static u64 hctFindRootByName(Schema *pSchema, const char *zName){ + u64 iRet = 0; + Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zName); + if( pTab ){ + iRet = pTab->tnum; + } + return iRet; +} + +SQLITE_PRIVATE int sqlite3HctJournalNewIf( + Schema *pSchema, + HctTree *pTree, + HctDatabase *pDb, + HctJournal **pp +){ + int rc = SQLITE_OK; + u64 iJrnlRoot = hctFindRootByName(pSchema, "sqlite_hct_journal"); + u64 iBaseRoot = hctFindRootByName(pSchema, "sqlite_hct_baseline"); + + assert( *pp==0 ); + + if( (iJrnlRoot==0)!=(iBaseRoot==0) ){ + return SQLITE_CORRUPT_BKPT; + } + if( iJrnlRoot ){ + HctJournal *pNew = sqlite3HctMalloc(&rc, sizeof(HctJournal)); + if( pNew ){ + HctFile *pFile = sqlite3HctDbFile(pDb); + pNew->iJrnlRoot = iJrnlRoot; + pNew->iBaseRoot = iBaseRoot; + pNew->pDb = pDb; + pNew->pTree = pTree; + pNew->pServer = (HctJrnlServer*)sqlite3HctFileGetJrnlPtr(pFile); + *pp = pNew; + } + } + + return rc; +} + +SQLITE_PRIVATE void sqlite3HctJournalClose(HctJournal *pJrnl){ + sqlite3_free(pJrnl); +} + +/* +** See description in hctJrnlInt.h. +*/ +SQLITE_PRIVATE int sqlite3HctJournalIsReadonly( + HctJournal *pJrnl, + u64 iTable, + int *pbNosnap +){ + if( pJrnl ){ + HctJrnlServer *p = pJrnl->pServer; + int bNosnap = (pJrnl->iJrnlRoot==iTable || pJrnl->iBaseRoot==iTable); + *pbNosnap = bNosnap; + return (pJrnl->eInWrite==HCT_JOURNAL_NONE && ( + bNosnap || !p || p->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER + )); + } + return 0; +} + +/* +** Called during log file recovery to remove the entry with "tid" (not CID!) +** value iTid from the sqlite_hct_journal table. +*/ +SQLITE_PRIVATE int sqlite3HctJrnlRollbackEntry(HctJournal *pJrnl, i64 iTid){ + i64 iDel = 0; + HctDbCsr *pCsr = 0; + int rc = SQLITE_OK; + + rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, (u32)pJrnl->iJrnlRoot, &pCsr); + if( rc==SQLITE_OK ){ + HctJournalRecord rec; + sqlite3HctDbCsrNosnap(pCsr, 1); + for(rc=sqlite3HctDbCsrLast(pCsr); + iDel==0 && rc==SQLITE_OK && sqlite3HctDbCsrEof(pCsr)==0; + rc=sqlite3HctDbCsrPrev(pCsr) + ){ + hctJrnlReadJournalRecord(pCsr, &rec); + if( rec.iTid==iTid ) iDel = rec.iCid; + } + + if( iDel!=0 && rc==SQLITE_OK ){ + rc = hctJrnlWriteRecord(pJrnl, iDel, "", 0, 0, 0, iTid); + } + + sqlite3HctDbCsrClose(pCsr); + } + + return rc; +} + +/* +** Find the HctJournal object associated with the "main" database of the +** connection passed as the only argument. If successful, set (*ppJrnl) +** to point to said object and return SQLITE_OK. Or, if the database is +** not a replication-enabled db, set (*ppJrnl) to NULL and return SQLITE_OK. +** Or, if an error occurs, return an SQLite error code. The final value +** of (*ppJrnl) is undefined in this case. +*/ +static int hctJrnlFind(sqlite3 *db, HctJournal **ppJrnl){ + int rc = SQLITE_OK; + HctJournal *pJrnl = sqlite3HctJrnlFind(db); + + if( pJrnl==0 ){ + /* If the journal was not found, it might be because the database is + ** not yet initialized. Run a query to ensure it is, then try to retrieve + ** the journal object again. */ + rc = sqlite3_exec(db, "SELECT 1 FROM sqlite_schema LIMIT 1", 0, 0, 0); + if( rc==SQLITE_OK ){ + pJrnl = sqlite3HctJrnlFind(db); + } + } + + if( rc==SQLITE_OK && pJrnl==0 ){ + hctJournalSetDbError(db, SQLITE_ERROR, "not a journaled hct database"); + rc = SQLITE_ERROR; + } + + *ppJrnl = pJrnl; + return rc; +} + + +/* +** Return the current journal mode - SQLITE_HCT_JOURNAL_MODE_FOLLOWER or +** SQLITE_HCT_JOURNAL_MODE_LEADER - for the main database of the connection +** passed as the only argument. Or, if the main database is not a +** replication-enabled hct database, return -1; +*/ +SQLITE_API int sqlite3_hct_journal_mode(sqlite3 *db){ + int eRet = -1; + HctJournal *pJrnl = sqlite3HctJrnlFind(db); + if( pJrnl ){ + eRet = pJrnl->pServer->eMode; + } + return eRet; +} + +/* +** Return true if the journal is complete - contains no holes. Or false +** otherwise. This function is not threadsafe. Results are undefined +** if there are concurrent transactions running on the database. +*/ +static int hctJrnlIsComplete(HctJournal *pJrnl){ + HctJrnlServer *pServer = pJrnl->pServer; + u64 iSnapshot = pServer->iSnapshot; + int ii; + + assert( pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ); + + /* Set iSnapshot to the CID of the last contiguous commit */ + while( 1 ){ + int iNext = (iSnapshot+1) % pServer->nCommit; + u64 iVal = HctAtomicLoad(&pServer->aCommit[iNext]); + if( iVal<=iSnapshot ) break; + iSnapshot++; + } + + /* See if there are any transactions yet committed with CID values greater + ** than iSnapshot. If there are, then the journal is not complete. */ + for(ii=0; iinCommit; ii++){ + u64 iVal = HctAtomicLoad(&pServer->aCommit[ii]); + if( iVal>iSnapshot ){ + return 0; + } + } + + return 1; +} + +/* +** Set the LEADER/FOLLOWER setting of the main database of the connection +** passed as the first argument. +*/ +SQLITE_API int sqlite3_hct_journal_setmode(sqlite3 *db, int eMode){ + int rc = SQLITE_OK; + HctJournal *pJrnl = sqlite3HctJrnlFind(db); + + if( pJrnl==0 ){ + rc = sqlite3_exec(db, "SELECT 1 FROM sqlite_schema LIMIT 1", 0, 0, 0); + if( rc==SQLITE_OK ){ + pJrnl = sqlite3HctJrnlFind(db); + } + } + + if( rc==SQLITE_OK ){ + if( eMode!=SQLITE_HCT_JOURNAL_MODE_LEADER + && eMode!=SQLITE_HCT_JOURNAL_MODE_FOLLOWER + ){ + return SQLITE_MISUSE_BKPT; + }else if( pJrnl==0 ){ + hctJournalSetDbError(db, SQLITE_ERROR, "not a journaled hct database"); + rc = SQLITE_ERROR; + }else{ + HctFile *pFile = sqlite3HctDbFile(pJrnl->pDb); + HctJrnlServer *pServer = pJrnl->pServer; + if( eMode!=pServer->eMode ){ + if( eMode==SQLITE_HCT_JOURNAL_MODE_LEADER ){ + /* Switch from FOLLOWER to LEADER mode. This is only allowed if + ** there are no holes in the journal. */ + if( hctJrnlIsComplete(pJrnl)==0 ){ + hctJournalSetDbError(db, SQLITE_ERROR, "incomplete journal"); + rc = SQLITE_ERROR; + }else{ + u64 iCid = sqlite3HctJournalSnapshot(pJrnl); + pServer->eMode = SQLITE_HCT_JOURNAL_MODE_LEADER; + if( iCid>0 ){ + sqlite3HctFileSetCID(sqlite3HctDbFile(pJrnl->pDb), iCid); + } + } + pServer->nSchemaVersionIncr++; + }else{ + /* Switch from LEADER to FOLLOWER mode. This is always possible. */ + void *pSchema = sqlite3HctBtreeSchema(db->aDb[0].pBt, 0, 0); + u64 iSnapshotId = sqlite3HctFileGetSnapshotid(pFile); + memset(pServer->aCommit, 0, pServer->nCommit*sizeof(u64)); + pServer->iSnapshot = iSnapshotId; + pServer->eMode = SQLITE_HCT_JOURNAL_MODE_FOLLOWER; + sqlite3HctJournalFixSchema(pJrnl, db, pSchema); + } + } + } + } + + return rc; +} + +static void hctJrnlFixTable(Table *pTab){ + Index *pIdx; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->idxType==SQLITE_IDXTYPE_UNIQUE + || pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY + ){ + pIdx->idxType = SQLITE_IDXTYPE_APPDEF; + } + pIdx->uniqNotNull = 0; + pIdx->onError = OE_None; + } + + +} + +/* +** This function is used to "fix" a schema so that it can be used in +** a FOLLOWER mode database. Specifically: +** +** * All UNIQUE indexes are marked as not-unique. +** * All triggers are removed from the schema. +** * All FK definitions are removed from the schema. +*/ +SQLITE_PRIVATE void sqlite3HctJournalFixSchema(HctJournal *pJrnl, sqlite3 *db, void *pS){ + HctJrnlServer *pServer = pJrnl->pServer; + if( pServer==0 || pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ + Schema *pSchema = (Schema*)pS; + HashElem *k; + + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pTab = (Table*)sqliteHashData(k); + hctJrnlFixTable(pTab); + while( pTab->pTrigger ){ + Trigger *pTrig = pTab->pTrigger; + pTab->pTrigger = pTrig->pNext; + sqlite3DeleteTrigger(db, pTrig); + } + if( IsOrdinaryTable(pTab) ){ + sqlite3FkDelete(db, pTab); + } + } + sqlite3HashClear(&pSchema->trigHash); + } +} + +SQLITE_PRIVATE void sqlite3HctJournalSchemaVersion(HctJournal *pJrnl, u32 *pSchemaVersion){ + if( pJrnl && pJrnl->pServer ){ + *pSchemaVersion += HctAtomicLoad(&pJrnl->pServer->nSchemaVersionIncr); + } +} + +#ifdef SQLITE_DEBUG +/* +** assert() that the schema associated with table pTab has been "fixed", +** according to the definition used by sqlite3HctJournalFixSchema(). +*/ +static void assert_schema_is_fixed(Table *pTab){ + Index *pIdx; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->idxType==SQLITE_IDXTYPE_APPDEF ); + assert( pIdx->uniqNotNull==0 ); + assert( pIdx->onError==OE_None ); + } + assert( pTab->pTrigger==0 ); + assert( pTab->u.tab.pFKey==0 ); +} +#else +# define assert_schema_is_fixed(x) +#endif + +static int hctJrnlGetInsertStmt( + sqlite3 *db, + const char *zTab, + int *piPk, + sqlite3_stmt **ppStmt +){ + sqlite3_str *pStr; + Schema *pSchema = db->aDb[0].pSchema; + Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zTab); + char *zSql = 0; + int rc = SQLITE_OK; + int ii; + + assert( pTab ); + assert_schema_is_fixed(pTab); + + *ppStmt = 0; + pStr = sqlite3_str_new(0); + sqlite3_str_appendf(pStr, "REPLACE INTO main.%Q(", zTab); + if( pTab->iPKey<0 ){ + sqlite3_str_appendf(pStr, "_rowid_, "); + } + for(ii=0; iinCol; ii++){ + const char *zSep = (ii==pTab->nCol-1) ? ") VALUES (" : ","; + sqlite3_str_appendf(pStr, "%Q%s ", pTab->aCol[ii].zCnName, zSep); + } + if( pTab->iPKey<0 ){ + sqlite3_str_appendf(pStr, "?%d, ", pTab->nCol+1); + *piPk = pTab->nCol+1; + }else{ + *piPk = pTab->iPKey+1; + } + for(ii=0; iinCol; ii++){ + const char *zSep = (ii==pTab->nCol-1) ? ")" : ", "; + sqlite3_str_appendf(pStr, "?%d%s", ii+1, zSep); + } + + zSql = sqlite3_str_finish(pStr); + if( zSql==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); + sqlite3_free(zSql); + } + + return rc; +} + +static int hctJrnlGetDeleteStmt( + sqlite3 *db, + const char *zTab, + sqlite3_stmt **ppStmt +){ + Schema *pSchema = db->aDb[0].pSchema; + Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zTab); + int rc = SQLITE_OK; + char *zSql = 0; + const char *zRowid = "_rowid_"; + + assert( pTab ); + assert_schema_is_fixed(pTab); + + if( pTab->iPKey>=0 ){ + zRowid = pTab->aCol[pTab->iPKey].zCnName; + } + + *ppStmt = 0; + zSql = sqlite3_mprintf( + "DELETE FROM main.%Q WHERE main.%Q.%Q = ?", + pTab->zName, pTab->zName, zRowid + ); + if( zSql==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); + sqlite3_free(zSql); + } + + return rc; +} + +/* +** Parameter aData[] points to a record encoded in SQLite format. Bind +** each value in the record to the statement passed as the second argument. +*/ +static int hctJrnlBindRecord(int *pRc, sqlite3_stmt *pStmt, const u8 *aData){ + int rc = *pRc; + int ret = 0; + if( rc==SQLITE_OK ){ + const u8 *pHdr = aData; + const u8 *pData = 0; + int nHdr; + int iBind; + + pHdr += getVarint32(pHdr, nHdr); + pData = &aData[nHdr]; + for(iBind=1; pHdr<&aData[nHdr]; iBind++){ + u32 t; + pHdr += getVarint32(pHdr, t); + switch( t ){ + case 10: + case 11: + case 0: /* NULL */ + sqlite3_bind_null(pStmt, iBind); + break; + + case 1: { /* 1 byte integer */ + i64 iVal = pData[0]; + pData += 1; + sqlite3_bind_int64(pStmt, iBind, iVal); + break; + } + case 2: { /* 2 byte integer */ + i64 iVal = ((i64)pData[0]<<8) + (i64)pData[1]; + pData += 2; + sqlite3_bind_int64(pStmt, iBind, iVal); + break; + } + case 3: { /* 3 byte integer */ + i64 iVal = ((i64)pData[0]<<16) + ((i64)pData[1]<<8) + (i64)pData[2]; + pData += 3; + sqlite3_bind_int64(pStmt, iBind, iVal); + break; + } + case 4: { /* 4 byte integer */ + i64 iVal = ((i64)pData[0]<<24) + + ((i64)pData[1]<<16) + + ((i64)pData[2]<<8) + + (i64)pData[3]; + pData += 4; + sqlite3_bind_int64(pStmt, iBind, iVal); + break; + } + case 5: { /* 6 byte integer */ + i64 iVal = ((i64)pData[0]<<40) + + ((i64)pData[1]<<32) + + ((i64)pData[2]<<24) + + ((i64)pData[3]<<16) + + ((i64)pData[4]<<8) + + (i64)pData[5]; + pData += 6; + sqlite3_bind_int64(pStmt, iBind, iVal); + break; + } + + case 6: case 7: { /* 8 byte integer, 8 byte real value */ + u64 iVal = ((u64)pData[0]<<56) + + ((u64)pData[1]<<48) + + ((u64)pData[2]<<40) + + ((u64)pData[3]<<32) + + ((u64)pData[4]<<24) + + ((u64)pData[5]<<16) + + ((u64)pData[6]<<8) + + (u64)pData[7]; + pData += 8; + if( t==6 ){ + i64 iVal2; + memcpy(&iVal2, &iVal, sizeof(iVal)); + sqlite3_bind_int64(pStmt, iBind, iVal2); + }else{ + double rVal2; + memcpy(&rVal2, &iVal, sizeof(iVal)); + sqlite3_bind_double(pStmt, iBind, rVal2); + } + break; + } + + case 8: /* integer value 0 */ + sqlite3_bind_int(pStmt, iBind, 0); + break; + + case 9: /* integer value 1 */ + sqlite3_bind_int(pStmt, iBind, 1); + break; + + default: { + int nByte = (t - 12) / 2; + if( t & 0x01 ){ + sqlite3_bind_text( + pStmt, iBind, (const char*)pData, nByte, SQLITE_TRANSIENT + ); + }else{ + sqlite3_bind_blob( + pStmt, iBind, (const void*)pData, nByte, SQLITE_TRANSIENT + ); + } + pData += nByte; + break; + }; + } + } + + ret = pData - aData; + } + return ret; +} + +SQLITE_PRIVATE u64 sqlite3HctJrnlWriteTid(HctJournal *pJrnl, u64 *piCid){ + u64 iRet = 0; + assert( *piCid==0 ); + if( pJrnl && pJrnl->eInWrite!=HCT_JOURNAL_NONE ){ + iRet = pJrnl->iWriteTid; + *piCid = pJrnl->iWriteCid; + } + return iRet; +} + +SQLITE_PRIVATE u64 sqlite3HctJournalSnapshot(HctJournal *pJrnl){ + u64 iRet = 0; + if( pJrnl ){ + if( pJrnl->eInWrite==HCT_JOURNAL_INROLLBACK ){ + return pJrnl->iRollbackSnapshot; + } + HctJrnlServer *pServer = pJrnl->pServer; + if( pServer && pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ + u64 iTest = 0; + u64 iValid = 0; + u64 iSnap = HctAtomicLoad(&pServer->iSnapshot); + iRet = iSnap; + for(iTest=iRet+1; 1; iTest++){ + u64 iVal = HctAtomicLoad(&pServer->aCommit[iTest % pServer->nCommit]); + if( iVal=iValid ) iRet = iTest; + }else{ + iValid = MAX(iVal, iValid); + } + } + + /* Update HctJrnlServer.iSnapshot if required */ + if( iRet>=iSnap+16 ){ + (void)HctCASBool(&pServer->iSnapshot, iSnap, iRet); + } + + /* If we are in an sqlite3_hct_journal_write() call, it is fine (and + ** necessary) to read snapshots that are invalid to the application. + ** So ignore any entries in the aCommit[] array that indicate such. */ + if( pJrnl->eInWrite==HCT_JOURNAL_INWRITE ){ + assert( (iTest-1)>=iRet ); + iRet = (iTest-1); + } + } + } + return iRet; +} + +/* +** Set output variable (*piCid) to the CID of the newest available +** database snapshot. Return SQLITE_OK if successful, or an SQLite +** error code if something goes wrong. +*/ +SQLITE_API int sqlite3_hct_journal_snapshot(sqlite3 *db, sqlite3_int64 *piCid){ + int rc = SQLITE_OK; + HctJournal *pJrnl = 0; + + rc = hctJrnlFind(db, &pJrnl); + if( rc==SQLITE_OK ){ + *piCid = (i64)sqlite3HctJournalSnapshot(pJrnl); + }else{ + *piCid = 0; + } + return rc; +} + +static sqlite3_stmt *hctJrnlPrepare(int *pRc, sqlite3 *db, const char *zSql){ + sqlite3_stmt *pStmt = 0; + if( *pRc==SQLITE_OK ){ + *pRc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + } + return pStmt; +} + +static void hctJrnlFinalize(int *pRc, sqlite3_stmt *pStmt){ + int rc = sqlite3_finalize(pStmt); + if( *pRc==SQLITE_OK ){ + *pRc = rc; + } +} + +SQLITE_API int sqlite3_hct_journal_truncate(sqlite3 *db, i64 iMinCid){ + int rc = SQLITE_OK; + HctJournal *pJrnl = 0; + sqlite3_stmt *pSelJrnl = 0; + sqlite3_stmt *pSelBaseline = 0; + sqlite3_stmt *pDelete = 0; + sqlite3_stmt *pUpdate = 0; + + if( 0==sqlite3_get_autocommit(db) ){ + hctJournalSetDbError(db, SQLITE_ERROR, + "cannot truncate journal from within a transaction" + ); + return SQLITE_ERROR; + } + + rc = hctJrnlFind(db, &pJrnl); + if( rc==SQLITE_OK + && pJrnl->pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER + ){ + u64 iCid = sqlite3HctJournalSnapshot(pJrnl); + if( iCideInWrite = HCT_JOURNAL_INWRITE; + rc = sqlite3_exec(db, "BEGIN CONCURRENT", 0, 0, 0); + } + + pSelBaseline = hctJrnlPrepare(&rc, db, + "SELECT cid, schemacid, hash FROM sqlite_hct_baseline" + ); + pSelJrnl = hctJrnlPrepare(&rc, db, + "SELECT cid, schemacid, hash FROM sqlite_hct_journal WHERE cidpDb, &pJrnl->iWriteTid); + pJrnl->iWriteCid = 1; + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3_exec(db, "ROLLBACK", 0, 0, 0); + } + } + + hctJrnlFinalize(&rc, pSelJrnl); + hctJrnlFinalize(&rc, pSelBaseline); + hctJrnlFinalize(&rc, pDelete); + hctJrnlFinalize(&rc, pUpdate); + pJrnl->eInWrite = HCT_JOURNAL_NONE; + pJrnl->iWriteTid = 0; + pJrnl->iWriteCid = 0; + return rc; +} + +static int hctBufferAppendInsert( + HctBuffer *pBuf, + i64 iRowid, + Table *pTab, + sqlite3_stmt *pQuery +){ + int ii; + int rc = SQLITE_OK; + + rc = hctBufferAppend(pBuf, "REPLACE INTO %Q(_rowid_", pTab->zName); + for(ii=0; rc==SQLITE_OK && iinCol; ii++){ + if( ii!=pTab->iPKey ){ + rc = hctBufferAppend(pBuf, ", %Q", pTab->aCol[ii].zCnName); + } + } + + if( rc==SQLITE_OK ){ + rc = hctBufferAppend(pBuf, ") VALUES(%lld", iRowid); + } + + for(ii=0; rc==SQLITE_OK && iinCol; ii++){ + if( ii!=pTab->iPKey ){ + rc = hctBufferAppend(&buf, "%squote(x.%Q)", zSep, pTab->aCol[ii].zCnName); + zSep = ", "; + } + } + if( rc==SQLITE_OK ){ + rc = hctBufferAppend(&buf, "FROM %Q AS x WHERE _rowid_=?", pTab->zName); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, (const char*)buf.aBuf, -1, &pRet, 0); + } + sqlite3_free(buf.aBuf); + + *pRc = rc; + return pRet; +} + +/* +** Rollback transactions that follow the first hole in the journal. +*/ +SQLITE_API int sqlite3_hct_journal_rollback(sqlite3 *db, sqlite3_int64 iCid){ + int rc = SQLITE_OK; + HctJournal *pJrnl = 0; + i64 iLast = 0; + i64 iLastCont = 0; + sqlite3_stmt *pStmt = 0; + Schema *pSchema = 0; + + rc = hctJrnlFind(db, &pJrnl); + if( rc!=SQLITE_OK ) return rc; + pSchema = db->aDb[0].pSchema; + + /* + ** 1. Find the location of the first hole in the journal. + ** + ** 2. Loop through journal entries, from the newest back to the + ** first hole in the journal. + ** + ** 3. Work through each of the transactions identified in step (1). + ** For each, write a log file, make the required modifications to + ** the db and journal file, then delete the log file. + */ + + /* Cannot call this with an open transaction. */ + if( 0==sqlite3_get_autocommit(db) ){ + hctJournalSetDbError(db, SQLITE_ERROR, + "cannot rollback journal from within a transaction" + ); + return SQLITE_ERROR; + } + + /* Cannot call this in LEADER mode. */ + if( pJrnl->pServer->eMode==SQLITE_HCT_JOURNAL_MODE_LEADER ){ + hctJournalSetDbError(db, SQLITE_ERROR, + "cannot rollback journal in leader database" + ); + return SQLITE_ERROR; + } + + /* Find the location of the first hole in the journal. If there are no + ** holes in the journal, this call is a no-op. */ + rc = hctJrnlGetJrnlShape(db, &iLast, &iLastCont); + assert( iLastCont<=iLast ); + if( rc!=SQLITE_OK || iLastCont>=iLast ) return rc; + + /* Loop through all of the journal entries that will be rolled back. + ** For each, extract the primary keys from the "data" blob. Query the + ** current database snapshot for each of these keys, generating an SQL + ** script with a "REPLACE INTO" for each row present in the db and a + ** "DELETE" for each not. */ + rc = sqlite3_prepare_v2(db, + "SELECT data FROM sqlite_hct_journal WHERE cid>?", -1, &pStmt, 0 + ); + if( rc==SQLITE_OK ){ + HctBuffer sql = {0, 0, 0}; + sqlite3_bind_int64(pStmt, 1, iLastCont); + + rc = hctBufferAppend(&sql, "BEGIN CONCURRENT;\n"); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const void *pData = sqlite3_column_blob(pStmt, 0); + int nData = sqlite3_column_bytes(pStmt, 0); + sqlite3_stmt *pQuery = 0; + Table *pTab = 0; + HctDataReader rdr; + + for(rc=hctDataReaderInit(pData, nData, &rdr); + rc==SQLITE_OK && rdr.bEof==0; + rc=hctDataReaderNext(&rdr) + ){ + switch( rdr.eType ){ + case HCT_TYPE_TABLE: { + pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, rdr.zTab); + if( pTab==0 ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = sqlite3_finalize(pQuery); + pQuery = hctGetQuoteQuery(&rc, db, pTab); + } + break; + } + + case HCT_TYPE_INSERT_ROWID: + case HCT_TYPE_DELETE_ROWID: { + sqlite3_bind_int64(pQuery, 1, rdr.iRowid); + if( SQLITE_ROW==sqlite3_step(pQuery) ){ + rc = hctBufferAppendInsert(&sql, rdr.iRowid, pTab, pQuery); + }else{ + rc = hctBufferAppend(&sql, + "DELETE FROM %Q WHERE _rowid_=%lld;\n", rdr.zTab, rdr.iRowid + ); + } + rc = sqlite3_reset(pQuery); + break; + } + + default: assert( 0 ); + } + if( rc ) break; + } + sqlite3_finalize(pQuery); + } + if( rc==SQLITE_OK ){ + rc = hctBufferAppend(&sql, + "DELETE FROM sqlite_hct_journal WHERE cid>%lld;\n", iLastCont + ); + } + + if( rc==SQLITE_OK ){ + assert( pJrnl->eInWrite==HCT_JOURNAL_NONE ); + pJrnl->eInWrite = HCT_JOURNAL_INROLLBACK; + rc = sqlite3_exec(db, (const char*)sql.aBuf, 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbStartWrite(pJrnl->pDb, &pJrnl->iWriteTid); + } + if( rc==SQLITE_OK ){ + pJrnl->iWriteCid = iLastCont; + pJrnl->iRollbackSnapshot = iLast; + rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3_exec(db, "ROLLBACK", 0, 0, 0); + } + pJrnl->eInWrite = HCT_JOURNAL_NONE; + } + + sqlite3_free(sql.aBuf); + sqlite3_finalize(pStmt); + } + + return rc; +} + +static u64 hctJournalFindLastWrite( + int *pRc, /* IN/OUT: Error code */ + HctJournal *pJrnl, /* Journal object */ + u64 iRoot, /* Root page of table */ + i64 iRowid /* Key (for rowid tables) */ +){ + int rc = *pRc; + u64 iRet = 0; + if( rc==SQLITE_OK ){ + HctDbCsr *pCsr = 0; + rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, iRoot, &pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3HctDbCsrFindLastWrite(pCsr, 0, iRowid, &iRet); + sqlite3HctDbCsrClose(pCsr); + } + *pRc = rc; + } + return iRet; +} + +/* +** Write a transaction into the database. +*/ +SQLITE_API int sqlite3_hct_journal_write( + sqlite3 *db, /* Write to "main" db of this handle */ + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid +){ + int rc = SQLITE_OK; + char *zErr = 0; /* Error message, if any */ + HctJournal *pJrnl = 0; + u64 iValidCid = 0; + u64 iSnapshotId = 0; + Btree *pBt = db->aDb[0].pBt; + Schema *pSchema = db->aDb[0].pSchema; + u64 iRoot = 0; /* Root page of zTab */ + HctJrnlServer *pServer = 0; + + HctDataReader rdr; /* For iterating through pData/nData */ + + rc = hctJrnlFind(db, &pJrnl); + if( rc!=SQLITE_OK ) return rc; + pJrnl->eInWrite = HCT_JOURNAL_INWRITE; + pServer = pJrnl->pServer; + + /* Check that the journal is in follower mode */ + if( pServer->eMode!=SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ + hctJournalSetDbError(db, SQLITE_ERROR, "database is not in FOLLOWER mode"); + return SQLITE_ERROR; + } + + /* Check that there is no transaction open on the connection */ + if( rc==SQLITE_OK && sqlite3_get_autocommit(db)==0 ){ + hctJournalSetDbError(db, SQLITE_ERROR, "open transaction on database"); + return SQLITE_ERROR; + } + + /* Open a concurrent transaction on the db handle. Then ensure that the + ** snapshot on the main database has also been opened. */ + rc = sqlite3_exec(db, "BEGIN CONCURRENT", 0, 0, 0); + if( rc==SQLITE_OK ){ + int dummy = 0; + rc = sqlite3BtreeBeginTrans(pBt, 1, &dummy); + } + + /* Check that the snapshot that was just opened has a schema new enough + ** for this transaction to be applied. */ + if( rc==SQLITE_OK ){ + iSnapshotId = sqlite3HctBtreeSnapshotId(pBt); + if( iSchemaCid>iSnapshotId ){ + rc = SQLITE_BUSY; + zErr = sqlite3_mprintf( + "change may not be applied yet (requires newer schema)" + ); + }else if( (iSnapshotId+HCT_MAX_LEADING_WRITE)aDb[0].pBt, iRoot)==0 ){ + iLastCid = hctJournalFindLastWrite(&rc, pJrnl, iRoot, rdr.iRowid); + } + if( iLastCid>iSnapshotId && iLastCidaDb[0].pBt, iRoot)==0 ){ + u64 iLastCid = 0; + iLastCid = hctJournalFindLastWrite(&rc, pJrnl, iRoot, rdr.iRowid); + if( iLastCid>iSnapshotId && iLastCidpDb, &pJrnl->iWriteTid); + sqlite3HctDbJrnlWriteCid(pJrnl->pDb, iCid); + pJrnl->iWriteCid = iCid; + } + + /* Write the sqlite_hct_journal record directly into the HctTree + ** structure. We don't write via the SQL interface here, because + ** writing to the db once sqlite3HctDbStartWrite() has been called + ** causes assert() failures. And we don't write directly to the db + ** either, because the write needs to be rolled back if there is + ** a conflict. */ + if( rc==SQLITE_OK ){ + u8 *pRec = 0; + int nRec = 0; + + /* TODO: "validcid" value */ + pRec = hctJrnlComposeRecord(iCid, zSchema, + pData, nData, iSchemaCid, pJrnl->iWriteTid, iValidCid, &nRec + ); + if( pRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + HctTreeCsr *pCsr = 0; + u64 root = hctFindRootByName(db->aDb[0].pSchema, "sqlite_hct_journal"); + + rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, root, &pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3HctTreeInsert(pCsr, 0, iCid, nRec, pRec, 0); + sqlite3HctTreeCsrClose(pCsr); + } + } + sqlite3_free(pRec); + + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); + } + if( rc==SQLITE_OK ){ + i64 iVal = iValidCid ? iValidCid : iCid; + i64 *pPtr = (i64*)&pServer->aCommit[iCid % pServer->nCommit]; + + /* If this transaction updated the schema, update the Server.iSchemaCid + ** field as well. This field is not used in FOLLOWER mode, but may be + ** if this process switches to LEADER later on. */ + if( zSchema[0] ){ + HctAtomicStore(&pServer->iSchemaCid, iCid); + } + + assert( iVal>=iCid ); + while( 1 ){ + i64 iExist = *pPtr; + if( iExist>=iVal ) break; + if( HctCASBool(pPtr, iExist, iVal) ) break; + } + assert( *pPtr>=iVal ); + + if( HctAtomicLoad(&pServer->iSnapshot)==0 ){ + (void)HctCASBool(&pServer->iSnapshot, (u64)0, (u64)iCid); + } + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_exec(db, "ROLLBACK", 0, 0, 0); + if( zErr ){ + hctJournalSetDbError(db, rc, "%s", zErr); + sqlite3_free(zErr); + }else{ + hctJournalSetDbError(db, rc, 0); + } + } + pJrnl->eInWrite = HCT_JOURNAL_NONE; + sqlite3HctDbJrnlWriteCid(pJrnl->pDb, 0); + return rc; +} + +static int hctBufferAppendIf(HctBuffer *pBuf, const char *zSep){ + int rc = SQLITE_OK; + if( pBuf->nBuf>0 ){ + rc = hctBufferAppend(pBuf, "%s", zSep); + } + return rc; +} + +static void hctJournalEntryFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + sqlite3 *db = sqlite3_context_db_handle(pCtx); + const u8 *aEntry = 0; + int nEntry = 0; + int ii = 0; + HctBuffer buf; + const char *zTab = "!"; + const char *zSep = " "; + + assert( nArg==1 ); + memset(&buf, 0, sizeof(buf)); + + nEntry = sqlite3_value_bytes(apArg[0]); + aEntry = (const u8*)sqlite3_value_blob(apArg[0]); + + while( ii */ + +/* + * If compiled on a machine that doesn't have a 32-bit integer, + * you just set "uint32" to the appropriate datatype for an + * unsigned 32-bit integer. For example: + * + * cc -Duint32='unsigned long' md5.c + * + */ +#ifndef uint32 +# define uint32 unsigned int +#endif + +struct MD5Context { + int isInit; + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; +typedef struct MD5Context MD5Context; + +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse (unsigned char *buf, unsigned longs){ + uint32 t; + do { + t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | + ((unsigned)buf[1]<<8 | buf[0]); + *(uint32 *)buf = t; + buf += 4; + } while (--longs); +} +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(uint32 buf[4], const uint32 in[16]){ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(MD5Context *ctx){ + ctx->isInit = 1; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static +void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = (unsigned char *)ctx->in + t; + + t = 64-t; + if (len < t) { + if( len ) memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(unsigned char digest[16], MD5Context *ctx){ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + memcpy(ctx->in + 14*4, ctx->bits, 8); + + MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse((unsigned char *)ctx->buf, 4); + memcpy(digest, ctx->buf, 16); +} + +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + +/* +** Both arguments are assumed to point to SQLITE_HCT_JOURNAL_HASHSIZE +** byte buffers. This function updates the hash stored in buffer pHash +** based on the contents of buffer pData. +*/ +SQLITE_API void sqlite3_hct_journal_hash(void *pHash, const void *pData){ + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx, pHash, SQLITE_HCT_JOURNAL_HASHSIZE); + MD5Update(&ctx, pData, SQLITE_HCT_JOURNAL_HASHSIZE); + MD5Final(pHash, &ctx); +} + +static void md5U64(MD5Context *pCtx, sqlite3_uint64 iVal){ + u8 aVal[8]; + aVal[0] = (iVal >> 56) & 0xFF; + aVal[1] = (iVal >> 48) & 0xFF; + aVal[2] = (iVal >> 40) & 0xFF; + aVal[3] = (iVal >> 32) & 0xFF; + aVal[4] = (iVal >> 24) & 0xFF; + aVal[5] = (iVal >> 16) & 0xFF; + aVal[6] = (iVal >> 8) & 0xFF; + aVal[7] = (iVal >> 0) & 0xFF; + MD5Update(pCtx, aVal, sizeof(aVal)); +} + +/* +** It is assumed that buffer pHash points to a buffer +** SQLITE_HCT_JOURNAL_HASHSIZE bytes in size. This function populates this +** buffer with a hash based on the remaining arguments. +*/ +SQLITE_API void sqlite3_hct_journal_hashentry( + void *pHash, /* OUT: Hash of other arguments */ + sqlite3_int64 iCid, + const char *zSchema, + const void *pData, int nData, + sqlite3_int64 iSchemaCid +){ + MD5Context ctx; + MD5Init(&ctx); + + md5U64(&ctx, (sqlite3_uint64)iCid); + MD5Update(&ctx, (const u8*)zSchema, sqlite3Strlen30(zSchema)); + MD5Update(&ctx, pData, nData); + md5U64(&ctx, (sqlite3_uint64)iSchemaCid); + + MD5Final(pHash, &ctx); +} + + +/************** End of hct_journalhash.c *************************************/ /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ diff --git a/libstuff/sqlite3.h b/libstuff/sqlite3.h index 90d0bd332..4fbc9e6cd 100644 --- a/libstuff/sqlite3.h +++ b/libstuff/sqlite3.h @@ -148,7 +148,7 @@ extern "C" { */ #define SQLITE_VERSION "3.47.0" #define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-11-01 15:25:34 492a0a85438586a8ccd9629239304f4df3f2c6391ec05dd9837b7a553313d632" +#define SQLITE_SOURCE_ID "2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -5615,15 +5615,6 @@ SQLITE_API int sqlite3_create_window_function( ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. -** -** [[SQLITE_SELFORDER1]]
SQLITE_SELFORDER1
-** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate -** that internally orders the values provided to the first argument. The -** ordered-set aggregate SQL notation with a single ORDER BY term can be -** used to invoke this function. If the ordered-set aggregate notation is -** used on a function that lacks this flag, then an error is raised. Note -** that the ordered-set aggregate syntax is only available if SQLite is -** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option. **
** */ @@ -5632,7 +5623,6 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 -#define SQLITE_SELFORDER1 0x002000000 /* ** CAPI3REF: Deprecated Functions @@ -5830,7 +5820,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** -** Every [application-defined SQL function] that invokes this interface +** Every [application-defined SQL function] that invoke this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() @@ -7437,11 +7427,9 @@ struct sqlite3_module { ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a -** mask of SQLITE_INDEX_SCAN_* flags. One such flag is -** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] -** output to show the idxNum has hex instead of as decimal. Another flag is -** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will -** return at most one row. +** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - +** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite +** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -7505,9 +7493,7 @@ struct sqlite3_index_info { ** [sqlite3_index_info].idxFlags field to some combination of ** these bits. */ -#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */ -#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */ - /* in EXPLAIN QUERY PLAN */ +#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes @@ -8344,7 +8330,6 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ -#define SQLITE_TESTCTRL_GETOPT 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8365,7 +8350,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 -#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 +#define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -10961,6 +10947,9 @@ SQLITE_API int sqlite3_commit_status( # undef double #endif +SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset); +SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); + #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 @@ -13196,10 +13185,6 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** -** In all cases, matches are visited in (column ASC, offset ASC) order. -** i.e. all those in column 0, sorted by offset, followed by those in -** column 1, etc. -** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -13266,32 +13251,9 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. -** -** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the locale associated -** with column iCol of the current row. Usually, there is no associated -** locale, and output parameters (*pzLocale) and (*pnLocale) are set -** to NULL and 0, respectively. However, if the fts5_locale() function -** was used to associate a locale with the value when it was inserted -** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated -** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) -** is set to the size in bytes of the buffer, not including the -** nul-terminator. -** -** If successful, SQLITE_OK is returned. Or, if an error occurs, an -** SQLite error code is returned. The final value of the output parameters -** is undefined in this case. -** -** xTokenize_v2: -** Tokenize text using the tokenizer belonging to the FTS5 table. This -** API is the same as the xTokenize() API, except that it allows a tokenizer -** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 4 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -13333,15 +13295,6 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); - - /* Below this point are iVersion>=4 only */ - int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); - int (*xTokenize_v2)(Fts5Context*, - const char *pText, int nText, /* Text to tokenize */ - const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ - void *pCtx, /* Context passed to xToken() */ - int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ - ); }; /* @@ -13354,7 +13307,6 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting -** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -13363,7 +13315,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer_v2 object +** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -13387,7 +13339,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The third argument indicates the reason that FTS5 is requesting +** The second argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -13411,13 +13363,6 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** -** The sixth and seventh arguments passed to xTokenize() - pLocale and -** nLocale - are a pointer to a buffer containing the locale to use for -** tokenization (e.g. "en_US") and its size in bytes, respectively. The -** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in -** which case nLocale is always 0) to indicate that the tokenizer should -** use its default locale. -** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -13441,30 +13386,6 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** -** If the tokenizer is registered using an fts5_tokenizer_v2 object, -** then the xTokenize() method has two additional arguments - pLocale -** and nLocale. These specify the locale that the tokenizer should use -** for the current request. If pLocale and nLocale are both 0, then the -** tokenizer should use its default locale. Otherwise, pLocale points to -** an nLocale byte buffer containing the name of the locale to use as utf-8 -** text. pLocale is not nul-terminated. -** -** FTS5_TOKENIZER -** -** There is also an fts5_tokenizer object. This is an older, deprecated, -** version of fts5_tokenizer_v2. It is similar except that: -** -**
    -**
  • There is no "iVersion" field, and -**
  • The xTokenize() method does not take a locale argument. -**
-** -** Legacy fts5_tokenizer tokenizers must be registered using the -** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). -** -** Tokenizer implementations registered using either API may be retrieved -** using both xFindTokenizer() and xFindTokenizer_v2(). -** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -13573,33 +13494,6 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; -typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; -struct fts5_tokenizer_v2 { - int iVersion; /* Currently always 2 */ - - int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); - void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, - void *pCtx, - int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, - const char *pLocale, int nLocale, - int (*xToken)( - void *pCtx, /* Copy of 2nd argument to xTokenize() */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Pointer to buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Byte offset of token within input text */ - int iEnd /* Byte offset of end of token within input text */ - ) - ); -}; - -/* -** New code should use the fts5_tokenizer_v2 type to define tokenizer -** implementations. The following type is included for legacy applications -** that still use it. -*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -13619,7 +13513,6 @@ struct fts5_tokenizer { ); }; - /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -13639,7 +13532,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -13666,25 +13559,6 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); - - /* APIs below this point are only available if iVersion>=3 */ - - /* Create a new tokenizer */ - int (*xCreateTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void *pUserData, - fts5_tokenizer_v2 *pTokenizer, - void (*xDestroy)(void*) - ); - - /* Find an existing tokenizer */ - int (*xFindTokenizer_v2)( - fts5_api *pApi, - const char *zName, - void **ppUserData, - fts5_tokenizer_v2 **ppTokenizer - ); }; /* diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index 9824a017f..8bba563f4 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -16,7 +16,7 @@ PortMap BedrockTester::ports; mutex BedrockTester::_testersMutex; set BedrockTester::_testers; -const bool BedrockTester::ENABLE_HCTREE{false}; +const bool BedrockTester::ENABLE_HCTREE{true}; string BedrockTester::getTempFileName(string prefix) { string templateStr = "/tmp/" + prefix + "bedrocktest_XXXXXX.db"; From da8b9156c9ddd7f52f6ce274ca0d7d5155700c36 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Fri, 15 Nov 2024 13:17:11 -0800 Subject: [PATCH 02/11] Newer HCTree --- libstuff/sqlite3.c | 10370 ++++++++++++++++++++++++++----------------- libstuff/sqlite3.h | 207 +- 2 files changed, 6576 insertions(+), 4001 deletions(-) diff --git a/libstuff/sqlite3.c b/libstuff/sqlite3.c index c27032cb5..64b8eca84 100644 --- a/libstuff/sqlite3.c +++ b/libstuff/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.47.0. By combining all the individual C code files into this +** version 3.48.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,8 +18,11 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 0c7b45cfde33ed7f3a9b8ddbe249093968bd. +** ed829bf2b069a48c644ae5706399dad7486e with changes in files: +** +** */ +#ifndef SQLITE_AMALGAMATION #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE @@ -82,6 +85,7 @@ #define SQLITE_ENABLE_HCT 1 #ifdef SQLITE_ENABLE_HCT # define SQLITE_OMIT_SHARED_CACHE 1 +# define SQLITE_ENABLE_PREUPDATE_HOOK 1 #endif #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS @@ -267,10 +271,13 @@ /* ** Macro to disable warnings about missing "break" at the end of a "case". */ -#if GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -#else -# define deliberate_fall_through +#if defined(__has_attribute) +# if __has_attribute(fallthrough) +# define deliberate_fall_through __attribute__((fallthrough)); +# endif +#endif +#if !defined(deliberate_fall_through) +# define deliberate_fall_through #endif /* @@ -470,9 +477,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.47.0" -#define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f" +#define SQLITE_VERSION "3.48.0" +#define SQLITE_VERSION_NUMBER 3048000 +#define SQLITE_SOURCE_ID "2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -976,6 +983,13 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. +** +** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read +** from the database file in amounts that are not a multiple of the +** page size and that do not begin at a page boundary. Without this +** property, SQLite is careful to only do full-page reads and write +** on aligned pages, with the one exception that it will do a sub-page +** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -992,6 +1006,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 +#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -1138,6 +1153,7 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] +**
  • [SQLITE_IOCAP_SUBPAGE_READ] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1415,6 +1431,11 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
  • [[SQLITE_FCNTL_NULL_IO]] +** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor +** or file handle for the [sqlite3_file] object such that it will no longer +** read or write to the database file. +** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1568,6 +1589,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 +#define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2946,10 +2968,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE +** and that if the number of rows modified by the most recent INSERT, UPDATE, ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. +** For the purposes of this interface, a CREATE TABLE AS SELECT statement +** does not count as an INSERT, UPDATE or DELETE statement and hence the rows +** added to the new table by the CREATE TABLE AS SELECT statement are not +** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -4546,13 +4572,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the -** first zero terminator. ^If nByte is positive, then it is the -** number of bytes read from zSql. ^If nByte is zero, then no prepared +** first zero terminator. ^If nByte is positive, then it is the maximum +** number of bytes read from zSql. When nByte is positive, zSql is read +** up to the first zero terminator or until the nByte bytes have been read, +** whichever comes first. ^If nByte is zero, then no prepared ** statement is generated. ** If the caller knows that the supplied string is nul-terminated, then ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. +** Note that nByte measure the length of the input in bytes, not +** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5923,7 +5953,7 @@ SQLITE_API int sqlite3_create_window_function( ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this +** All SQL functions that invoke [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. @@ -5939,6 +5969,15 @@ SQLITE_API int sqlite3_create_window_function( ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. +** +** [[SQLITE_SELFORDER1]]
    SQLITE_SELFORDER1
    +** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate +** that internally orders the values provided to the first argument. The +** ordered-set aggregate SQL notation with a single ORDER BY term can be +** used to invoke this function. If the ordered-set aggregate notation is +** used on a function that lacks this flag, then an error is raised. Note +** that the ordered-set aggregate syntax is only available if SQLite is +** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option. **
    ** */ @@ -5947,6 +5986,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 +#define SQLITE_SELFORDER1 0x002000000 /* ** CAPI3REF: Deprecated Functions @@ -6144,7 +6184,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** -** Every [application-defined SQL function] that invoke this interface +** Every [application-defined SQL function] that invokes this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() @@ -7751,9 +7791,11 @@ struct sqlite3_module { ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a -** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - -** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite -** assumes that the strategy may visit at most one row. +** mask of SQLITE_INDEX_SCAN_* flags. One such flag is +** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] +** output to show the idxNum has hex instead of as decimal. Another flag is +** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will +** return at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -7817,7 +7859,9 @@ struct sqlite3_index_info { ** [sqlite3_index_info].idxFlags field to some combination of ** these bits. */ -#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ +#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */ +#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */ + /* in EXPLAIN QUERY PLAN */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes @@ -8654,6 +8698,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_GETOPT 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8673,7 +8718,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 +#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ #define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 #define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ @@ -9650,6 +9695,16 @@ typedef struct sqlite3_backup sqlite3_backup; ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. +** +** Alternatives To Using The Backup API +** +** Other techniques for safely creating a consistent backup of an SQLite +** database include: +** +**
      +**
    • The [VACUUM INTO] command. +**
    • The [sqlite3_rsync] utility program. +**
    */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ @@ -10849,6 +10904,14 @@ typedef struct sqlite3_snapshot { ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** +** If a read-transaction is opened by this function, then it is guaranteed +** that the returned snapshot object may not be invalidated by a database +** writer or checkpointer until after the read-transaction is closed. This +** is not guaranteed if a read-transaction is already open when this +** function is called. In that case, any subsequent write or checkpoint +** operation on the database may invalidate the returned snapshot handle, +** even while the read-transaction remains open. +** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined @@ -11288,7 +11351,7 @@ SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); #if 0 } /* End of the 'extern "C"' block */ #endif -#endif /* SQLITE3_H */ +/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ /******** Begin file sqlite3rtree.h *********/ /* @@ -13509,6 +13572,10 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** +** In all cases, matches are visited in (column ASC, offset ASC) order. +** i.e. all those in column 0, sorted by offset, followed by those in +** column 1, etc. +** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -13575,9 +13642,32 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. +** +** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) +** If parameter iCol is less than zero, or greater than or equal to the +** number of columns in the table, SQLITE_RANGE is returned. +** +** Otherwise, this function attempts to retrieve the locale associated +** with column iCol of the current row. Usually, there is no associated +** locale, and output parameters (*pzLocale) and (*pnLocale) are set +** to NULL and 0, respectively. However, if the fts5_locale() function +** was used to associate a locale with the value when it was inserted +** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated +** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) +** is set to the size in bytes of the buffer, not including the +** nul-terminator. +** +** If successful, SQLITE_OK is returned. Or, if an error occurs, an +** SQLite error code is returned. The final value of the output parameters +** is undefined in this case. +** +** xTokenize_v2: +** Tokenize text using the tokenizer belonging to the FTS5 table. This +** API is the same as the xTokenize() API, except that it allows a tokenizer +** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 4 */ void *(*xUserData)(Fts5Context*); @@ -13619,6 +13709,15 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); + + /* Below this point are iVersion>=4 only */ + int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xTokenize_v2)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); }; /* @@ -13639,7 +13738,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer object +** pointer provided by the application when the fts5_tokenizer_v2 object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -13663,7 +13762,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The second argument indicates the reason that FTS5 is requesting +** The third argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -13687,6 +13786,13 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** +** The sixth and seventh arguments passed to xTokenize() - pLocale and +** nLocale - are a pointer to a buffer containing the locale to use for +** tokenization (e.g. "en_US") and its size in bytes, respectively. The +** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in +** which case nLocale is always 0) to indicate that the tokenizer should +** use its default locale. +** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -13710,6 +13816,30 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** +** If the tokenizer is registered using an fts5_tokenizer_v2 object, +** then the xTokenize() method has two additional arguments - pLocale +** and nLocale. These specify the locale that the tokenizer should use +** for the current request. If pLocale and nLocale are both 0, then the +** tokenizer should use its default locale. Otherwise, pLocale points to +** an nLocale byte buffer containing the name of the locale to use as utf-8 +** text. pLocale is not nul-terminated. +** +** FTS5_TOKENIZER +** +** There is also an fts5_tokenizer object. This is an older, deprecated, +** version of fts5_tokenizer_v2. It is similar except that: +** +**
      +**
    • There is no "iVersion" field, and +**
    • The xTokenize() method does not take a locale argument. +**
    +** +** Legacy fts5_tokenizer tokenizers must be registered using the +** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). +** +** Tokenizer implementations registered using either API may be retrieved +** using both xFindTokenizer() and xFindTokenizer_v2(). +** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -13818,6 +13948,33 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; +struct fts5_tokenizer_v2 { + int iVersion; /* Currently always 2 */ + + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + const char *pLocale, int nLocale, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* +** New code should use the fts5_tokenizer_v2 type to define tokenizer +** implementations. The following type is included for legacy applications +** that still use it. +*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -13837,6 +13994,7 @@ struct fts5_tokenizer { ); }; + /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -13856,7 +14014,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 2 */ + int iVersion; /* Currently always set to 3 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -13883,6 +14041,25 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); + + /* APIs below this point are only available if iVersion>=3 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void *pUserData, + fts5_tokenizer_v2 *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void **ppUserData, + fts5_tokenizer_v2 **ppTokenizer + ); }; /* @@ -13896,6 +14073,7 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif /* SQLITE3_H */ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -13941,6 +14119,7 @@ struct fts5_api { #ifndef SQLITE_MAX_LENGTH # define SQLITE_MAX_LENGTH 1000000000 #endif +#define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */ /* ** This is the maximum number of @@ -14656,59 +14835,59 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_ID 9 -#define TK_CONCURRENT 10 -#define TK_COMMIT 11 -#define TK_END 12 -#define TK_ROLLBACK 13 -#define TK_SAVEPOINT 14 -#define TK_RELEASE 15 -#define TK_TO 16 -#define TK_TABLE 17 -#define TK_CREATE 18 -#define TK_IF 19 -#define TK_NOT 20 -#define TK_EXISTS 21 -#define TK_TEMP 22 -#define TK_LP 23 -#define TK_RP 24 -#define TK_AS 25 -#define TK_COMMA 26 -#define TK_WITHOUT 27 -#define TK_ABORT 28 -#define TK_ACTION 29 -#define TK_AFTER 30 -#define TK_ANALYZE 31 -#define TK_ASC 32 -#define TK_ATTACH 33 -#define TK_BEFORE 34 -#define TK_BY 35 -#define TK_CASCADE 36 -#define TK_CAST 37 -#define TK_CONFLICT 38 -#define TK_DATABASE 39 -#define TK_DESC 40 -#define TK_DETACH 41 -#define TK_EACH 42 -#define TK_EXCLUSIVE 43 -#define TK_FAIL 44 -#define TK_OR 45 -#define TK_AND 46 -#define TK_IS 47 -#define TK_ISNOT 48 -#define TK_MATCH 49 -#define TK_LIKE_KW 50 -#define TK_BETWEEN 51 -#define TK_IN 52 -#define TK_ISNULL 53 -#define TK_NOTNULL 54 -#define TK_NE 55 -#define TK_EQ 56 -#define TK_GT 57 -#define TK_LE 58 -#define TK_LT 59 -#define TK_GE 60 -#define TK_ESCAPE 61 -#define TK_COLUMNKW 62 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_COMMA 25 +#define TK_WITHOUT 26 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_EXCLUSIVE 42 +#define TK_FAIL 43 +#define TK_OR 44 +#define TK_AND 45 +#define TK_IS 46 +#define TK_ISNOT 47 +#define TK_MATCH 48 +#define TK_LIKE_KW 49 +#define TK_BETWEEN 50 +#define TK_IN 51 +#define TK_ISNULL 52 +#define TK_NOTNULL 53 +#define TK_NE 54 +#define TK_EQ 55 +#define TK_GT 56 +#define TK_LE 57 +#define TK_LT 58 +#define TK_GE 59 +#define TK_ESCAPE 60 +#define TK_COLUMNKW 61 +#define TK_CONCURRENT 62 #define TK_DO 63 #define TK_FOR 64 #define TK_IGNORE 65 @@ -14841,6 +15020,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #include #include #include +#include /* ** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY. @@ -14861,7 +15041,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define float sqlite_int64 -# define LONGDOUBLE_TYPE sqlite_int64 +# define fabs(X) ((X)<0?-(X):(X)) +# define sqlite3IsOverflow(X) 0 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif @@ -15036,9 +15217,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define INT8_TYPE signed char # endif #endif -#ifndef LONGDOUBLE_TYPE -# define LONGDOUBLE_TYPE long double -#endif typedef sqlite_int64 i64; /* 8-byte signed integer */ typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ @@ -15539,6 +15717,7 @@ typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; +typedef struct Subquery Subquery; typedef struct SrcItem SrcItem; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ @@ -16460,6 +16639,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursor( ); SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(Btree*,BtCursor*); +#endif SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -16694,6 +16876,19 @@ typedef struct Vdbe Vdbe; */ typedef struct sqlite3_value Mem; typedef struct SubProgram SubProgram; +typedef struct SubrtnSig SubrtnSig; + +/* +** A signature for a reusable subroutine that materializes the RHS of +** an IN operator. +*/ +struct SubrtnSig { + int selId; /* SELECT-id for the SELECT statement on the RHS */ + char *zAff; /* Affinity of the overall IN expression */ + int iTable; /* Ephemeral table generated by the subroutine */ + int iAddr; /* Subroutine entry address */ + int regReturn; /* Register used to hold return address */ +}; /* ** A single instruction of the virtual machine has an opcode @@ -16722,6 +16917,7 @@ struct VdbeOp { u32 *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ + SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif @@ -16789,6 +16985,7 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ #define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ #define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ +#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -16849,8 +17046,8 @@ typedef struct VdbeOpList VdbeOpList; #define OP_If 16 /* jump */ #define OP_IfNot 17 /* jump */ #define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */ -#define OP_IfNullRow 19 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ -#define OP_Not 20 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ +#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ +#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ #define OP_SeekLT 21 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */ @@ -16874,24 +17071,24 @@ typedef struct VdbeOpList VdbeOpList; #define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxGE 43 /* jump, synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 44 /* jump, synopsis: r[P3]=rowset(P1) */ -#define OP_Or 45 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ -#define OP_And 46 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_Or 44 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 45 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */ #define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Program 48 /* jump0 */ #define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ #define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ #define OP_IfNotZero 51 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 52 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IsNull 53 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ -#define OP_NotNull 54 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ -#define OP_Ne 55 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ -#define OP_Eq 56 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ -#define OP_Gt 57 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ -#define OP_Le 58 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ -#define OP_Lt 59 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ -#define OP_ElseEq 61 /* jump, same as TK_ESCAPE */ +#define OP_IsNull 52 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 53 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 54 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 55 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 56 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 57 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 58 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ +#define OP_ElseEq 60 /* jump, same as TK_ESCAPE */ +#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */ #define OP_IncrVacuum 62 /* jump */ #define OP_VNext 63 /* jump */ #define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ @@ -17036,12 +17233,12 @@ typedef struct VdbeOpList VdbeOpList; #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\ /* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\ -/* 16 */ 0x03, 0x03, 0x01, 0x01, 0x12, 0xc9, 0xc9, 0xc9,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\ /* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\ /* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\ -/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x23, 0x26, 0x26, 0x0b,\ -/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x41,\ +/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x26, 0x26, 0x23, 0x0b,\ +/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x41,\ /* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ @@ -17958,47 +18155,11 @@ struct FuncDefHash { }; #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) -#if defined(SQLITE_USER_AUTHENTICATION) -# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \ - See ext/userauth/user-auth.txt for details." -#endif -#ifdef SQLITE_USER_AUTHENTICATION -/* -** Information held in the "sqlite3" database connection object and used -** to manage user authentication. -*/ -typedef struct sqlite3_userauth sqlite3_userauth; -struct sqlite3_userauth { - u8 authLevel; /* Current authentication level */ - int nAuthPW; /* Size of the zAuthPW in bytes */ - char *zAuthPW; /* Password used to authenticate */ - char *zAuthUser; /* User name used to authenticate */ -}; - -/* Allowed values for sqlite3_userauth.authLevel */ -#define UAUTH_Unknown 0 /* Authentication not yet checked */ -#define UAUTH_Fail 1 /* User authentication failed */ -#define UAUTH_User 2 /* Authenticated as a normal user */ -#define UAUTH_Admin 3 /* Authenticated as an administrator */ - -/* Functions used only by user authorization logic */ -SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); -SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); -SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); -SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); - -#endif /* SQLITE_USER_AUTHENTICATION */ - /* ** typedef for the authorization callback function. */ -#ifdef SQLITE_USER_AUTHENTICATION - typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, - const char*, const char*); -#else - typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, - const char*); -#endif +typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); #ifndef SQLITE_OMIT_DEPRECATED /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing @@ -18161,9 +18322,6 @@ struct sqlite3 { void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif -#ifdef SQLITE_USER_AUTHENTICATION - sqlite3_userauth auth; /* User authentication information */ -#endif #ifndef SQLITE_OMIT_CONCURRENT /* Return values for sqlite3_commit_status() requests: ** SQLITE_COMMIT_CONFLICT_DB, CONFLICT_FRAME and CONFLICT_PGNO. @@ -18182,6 +18340,7 @@ struct sqlite3 { int bHctMigrate; }; + /* ** Candidate values for sqlite3.eConcurrent */ @@ -18309,6 +18468,7 @@ struct sqlite3 { #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ +#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -19297,9 +19457,15 @@ struct AggInfo { ** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg. ** The assert()s that are part of this macro verify that constraint. */ +#ifndef NDEBUG #define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I)) #define AggInfoFuncReg(A,I) \ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I)) +#else +#define AggInfoColumnReg(A,I) ((A)->iFirstReg+(I)) +#define AggInfoFuncReg(A,I) \ + ((A)->iFirstReg+(A)->nColumn+(I)) +#endif /* ** The datatype ynVar is a signed integer, either 16-bit or 32-bit. @@ -19480,7 +19646,7 @@ struct Expr { #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ - /* 0x80000000 // Available */ +#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */ /* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. @@ -19651,6 +19817,16 @@ struct IdList { #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ +/* +** Details of the implementation of a subquery. +*/ +struct Subquery { + Select *pSelect; /* A SELECT statement used in place of a table name */ + int addrFillSub; /* Address of subroutine to initialize a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ + int regResult; /* Registers holding results of a co-routine */ +}; + /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. @@ -19663,29 +19839,40 @@ struct IdList { ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. ** -** Union member validity: +** Aggressive use of "union" helps keep the size of the object small. This +** has been shown to boost performance, in addition to saving memory. +** Access to union elements is gated by the following rules which should +** always be checked, either by an if-statement or by an assert(). ** -** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc -** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy +** Field Only access if this is true +** --------------- ----------------------------------- +** u1.zIndexedBy fg.isIndexedBy +** u1.pFuncArg fg.isTabFunc ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy ** -** u2.pIBIndex fg.isIndexedBy && !fg.isCte -** u2.pCteUse fg.isCte && !fg.isIndexedBy +** u2.pIBIndex fg.isIndexedBy +** u2.pCteUse fg.isCte +** +** u3.pOn !fg.isUsing +** u3.pUsing fg.isUsing +** +** u4.zDatabase !fg.fixedSchema && !fg.isSubquery +** u4.pSchema fg.fixedSchema +** u4.pSubq fg.isSubquery +** +** See also the sqlite3SrcListDelete() routine for assert() statements that +** check invariants on the fields of this object, especially the flags +** inside the fg struct. */ struct SrcItem { - Schema *pSchema; /* Schema to which this item is fixed */ - char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ - Table *pTab; /* An SQL table corresponding to zName */ - Select *pSelect; /* A SELECT statement used in place of a table name */ - int addrFillSub; /* Address of subroutine to manifest a subquery */ - int regReturn; /* Register holding return address of addrFillSub */ - int regResult; /* Registers holding results of a co-routine */ + Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */ struct { u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ + unsigned isSubquery :1; /* True if this term is a subquery */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned isMaterialized:1; /* This is a materialized view */ @@ -19699,12 +19886,10 @@ struct SrcItem { unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */ unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ unsigned rowidUsed :1; /* The ROWID of this table is referenced */ + unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */ + unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ - union { - Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ - IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ - } u3; Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ union { char *zIndexedBy; /* Identifier from "INDEXED BY " clause */ @@ -19715,6 +19900,15 @@ struct SrcItem { Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ } u2; + union { + Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ + IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ + } u3; + union { + Schema *pSchema; /* Schema to which this item is fixed */ + char *zDatabase; /* Name of database holding this table */ + Subquery *pSubq; /* Description of a subquery */ + } u4; }; /* @@ -19974,8 +20168,10 @@ struct Select { #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ #define SF_Correlated 0x20000000 /* True if references the outer context */ -/* True if S exists and has SF_NestedFrom */ -#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) +/* True if SrcItem X is a subquery that has SF_NestedFrom */ +#define IsNestedFrom(X) \ + ((X)->fg.isSubquery && \ + ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined @@ -20005,7 +20201,11 @@ struct Select { ** SRT_Set The result must be a single column. Store each ** row of result as the key in table pDest->iSDParm. ** Apply the affinity pDest->affSdst before storing -** results. Used to implement "IN (SELECT ...)". +** results. if pDest->iSDParm2 is positive, then it is +** a register holding a Bloom filter for the IN operator +** that should be populated in addition to the +** pDest->iSDParm table. This SRT is used to +** implement "IN (SELECT ...)". ** ** SRT_EphemTab Create an temporary table pDest->iSDParm and store ** the result there. The cursor is left open after @@ -20213,6 +20413,7 @@ struct Parse { u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ u8 bHasWith; /* True if statement contains WITH */ + u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif @@ -20600,7 +20801,6 @@ struct Sqlite3Config { u8 bUseCis; /* Use covering indices for full-scans */ u8 bSmallMalloc; /* Avoid large memory allocations if true */ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ - u8 bUseLongDouble; /* Make use of long double */ #ifdef SQLITE_DEBUG u8 bJsonSelfcheck; /* Double-check JSON parsing */ #endif @@ -20975,15 +21175,6 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_ENABLE_FTS3 1 #endif -/* -** The ctype.h header is needed for non-ASCII systems. It is also -** needed by FTS3 when FTS3 is included in the amalgamation. -*/ -#if !defined(SQLITE_ASCII) || \ - (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION)) -# include -#endif - /* ** The following macros mimic the standard library functions toupper(), ** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The @@ -21362,6 +21553,9 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); +SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3*,Subquery*); +SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*); +SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); @@ -21604,7 +21798,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 -SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); +SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar); #endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); @@ -22595,6 +22789,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC "ENABLE_OFFSET_SQL_FUNC", #endif +#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES + "ENABLE_ORDERED_SET_AGGREGATES", +#endif #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif @@ -23064,9 +23261,6 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif -#ifdef SQLITE_USER_AUTHENTICATION - "USER_AUTHENTICATION", -#endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif @@ -23343,7 +23537,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ 0, /* bSmallMalloc */ 1, /* bExtraSchemaChecks */ - sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */ #ifdef SQLITE_DEBUG 0, /* bJsonSelfcheck */ #endif @@ -24063,9 +24256,11 @@ struct PreUpdate { int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ + Mem oldipk; /* Memory cell holding "old" IPK value */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ + sqlite3_value **apDflt; /* Array of default values, if required */ }; /* @@ -24912,8 +25107,8 @@ static void computeJD(DateTime *p){ Y--; M += 12; } - A = Y/100; - B = 2 - A + (A/4); + A = (Y+4800)/100; + B = 38 - A + (A/4); X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); @@ -25097,7 +25292,7 @@ static int validJulianDay(sqlite3_int64 iJD){ ** Compute the Year, Month, and Day from the julian day number. */ static void computeYMD(DateTime *p){ - int Z, A, B, C, D, E, X1; + int Z, alpha, A, B, C, D, E, X1; if( p->validYMD ) return; if( !p->validJD ){ p->Y = 2000; @@ -25108,8 +25303,8 @@ static void computeYMD(DateTime *p){ return; }else{ Z = (int)((p->iJD + 43200000)/86400000); - A = (int)((Z - 1867216.25)/36524.25); - A = Z + 1 + A - (A/4); + alpha = (int)((Z + 32044.75)/36524.25) - 52; + A = Z + 1 + alpha - ((alpha+100)/4) + 25; B = A + 1524; C = (int)((B - 122.1)/365.25); D = (36525*(C&32767))/100; @@ -29511,16 +29706,29 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. +** +** Because these routines raise false-positive alerts in TSAN, disable +** them (make them always return 1) when compiling with TSAN. */ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ +# if defined(__has_feature) +# if __has_feature(thread_sanitizer) + p = 0; +# endif +# endif assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ +# if defined(__has_feature) +# if __has_feature(thread_sanitizer) + p = 0; +# endif +# endif assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } -#endif +#endif /* NDEBUG */ #endif /* !defined(SQLITE_MUTEX_OMIT) */ @@ -32408,16 +32616,19 @@ SQLITE_API void sqlite3_str_vappendf( if( pItem->zAlias && !flag_altform2 ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else if( pItem->zName ){ - if( pItem->zDatabase ){ - sqlite3_str_appendall(pAccum, pItem->zDatabase); + if( pItem->fg.fixedSchema==0 + && pItem->fg.isSubquery==0 + && pItem->u4.zDatabase!=0 + ){ + sqlite3_str_appendall(pAccum, pItem->u4.zDatabase); sqlite3_str_append(pAccum, ".", 1); } sqlite3_str_appendall(pAccum, pItem->zName); }else if( pItem->zAlias ){ sqlite3_str_appendall(pAccum, pItem->zAlias); - }else{ - Select *pSel = pItem->pSelect; - assert( pSel!=0 ); /* Because of tag-20240424-1 */ + }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */ + Select *pSel = pItem->u4.pSubq->pSelect; + assert( pSel!=0 ); if( pSel->selFlags & SF_NestedFrom ){ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); }else if( pSel->selFlags & SF_MultiValue ){ @@ -33199,9 +33410,9 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); - if( pItem->pTab ){ + if( pItem->pSTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s", - pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, + pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab, pItem->colUsed, pItem->fg.rowidUsed ? "+rowid" : ""); } @@ -33232,25 +33443,30 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine"); if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte"); if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom"); + if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema"); + if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema"); + if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inSrc-1); n = 0; - if( pItem->pSelect ) n++; + if( pItem->fg.isSubquery ) n++; if( pItem->fg.isTabFunc ) n++; if( pItem->fg.isUsing ) n++; if( pItem->fg.isUsing ){ sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); } - if( pItem->pSelect ){ - sqlite3TreeViewPush(&pView, i+1nSrc); - if( pItem->pTab ){ - Table *pTab = pItem->pTab; + if( pItem->fg.isSubquery ){ + assert( n==1 ); + if( pItem->pSTab ){ + Table *pTab = pItem->pSTab; sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); } - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); - sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, "SUBQUERY"); sqlite3TreeViewPop(&pView); + sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); @@ -33292,7 +33508,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m n = 1000; }else{ n = 0; - if( p->pSrc && p->pSrc->nSrc ) n++; + if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ) n++; if( p->pWhere ) n++; if( p->pGroupBy ) n++; if( p->pHaving ) n++; @@ -33318,7 +33534,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPop(&pView); } #endif - if( p->pSrc && p->pSrc->nSrc ){ + if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ){ sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, p->pSrc); @@ -34927,7 +35143,7 @@ static const unsigned char sqlite3Utf8Trans1[] = { c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ - while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + while( zIn=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2; + if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2; n++; } return (int)(z-(unsigned char const *)zIn) @@ -35899,6 +36117,8 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ + double rr[2]; + u64 s2; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -36010,68 +36230,41 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en e++; } - if( e==0 ){ - *pResult = s; - }else if( sqlite3Config.bUseLongDouble ){ - LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s; - if( e>0 ){ - while( e>=100 ){ e-=100; r *= 1.0e+100L; } - while( e>=10 ){ e-=10; r *= 1.0e+10L; } - while( e>=1 ){ e-=1; r *= 1.0e+01L; } - }else{ - while( e<=-100 ){ e+=100; r *= 1.0e-100L; } - while( e<=-10 ){ e+=10; r *= 1.0e-10L; } - while( e<=-1 ){ e+=1; r *= 1.0e-01L; } - } - assert( r>=0.0 ); - if( r>+1.7976931348623157081452742373e+308L ){ -#ifdef INFINITY - *pResult = +INFINITY; -#else - *pResult = 1.0e308*10.0; + rr[0] = (double)s; + s2 = (u64)rr[0]; +#if defined(_MSC_VER) && _MSC_VER<1700 + if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } #endif - }else{ - *pResult = (double)r; + rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); + if( e>0 ){ + while( e>=100 ){ + e -= 100; + dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); + } + while( e>=10 ){ + e -= 10; + dekkerMul2(rr, 1.0e+10, 0.0); + } + while( e>=1 ){ + e -= 1; + dekkerMul2(rr, 1.0e+01, 0.0); } }else{ - double rr[2]; - u64 s2; - rr[0] = (double)s; - s2 = (u64)rr[0]; -#if defined(_MSC_VER) && _MSC_VER<1700 - if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } -#endif - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); - if( e>0 ){ - while( e>=100 ){ - e -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( e>=10 ){ - e -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( e>=1 ){ - e -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } - }else{ - while( e<=-100 ){ - e += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( e<=-10 ){ - e += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( e<=-1 ){ - e += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } + while( e<=-100 ){ + e += 100; + dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); + } + while( e<=-10 ){ + e += 10; + dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); + } + while( e<=-1 ){ + e += 1; + dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; } + *pResult = rr[0]+rr[1]; + if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; if( sign<0 ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); @@ -36392,9 +36585,10 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou int i; u64 v; int e, exp = 0; + double rr[2]; + p->isSpecial = 0; p->z = p->zBuf; - assert( mxRound>0 ); /* Convert negative numbers to positive. Deal with Infinity, 0.0, and @@ -36422,62 +36616,45 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou /* Multiply r by powers of ten until it lands somewhere in between ** 1.0e+19 and 1.0e+17. + ** + ** Use Dekker-style double-double computation to increase the + ** precision. + ** + ** The error terms on constants like 1.0e+100 computed using the + ** decimal extension, for example as follows: + ** + ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); */ - if( sqlite3Config.bUseLongDouble ){ - LONGDOUBLE_TYPE rr = r; - if( rr>=1.0e+19 ){ - while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; } - while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; } - while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; } - }else{ - while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; } - while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; } - while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; } + rr[0] = r; + rr[1] = 0.0; + if( rr[0]>9.223372036854774784e+18 ){ + while( rr[0]>9.223372036854774784e+118 ){ + exp += 100; + dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); + } + while( rr[0]>9.223372036854774784e+28 ){ + exp += 10; + dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); + } + while( rr[0]>9.223372036854774784e+18 ){ + exp += 1; + dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); } - v = (u64)rr; }else{ - /* If high-precision floating point is not available using "long double", - ** then use Dekker-style double-double computation to increase the - ** precision. - ** - ** The error terms on constants like 1.0e+100 computed using the - ** decimal extension, for example as follows: - ** - ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); - */ - double rr[2]; - rr[0] = r; - rr[1] = 0.0; - if( rr[0]>9.223372036854774784e+18 ){ - while( rr[0]>9.223372036854774784e+118 ){ - exp += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( rr[0]>9.223372036854774784e+28 ){ - exp += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( rr[0]>9.223372036854774784e+18 ){ - exp += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } - }else{ - while( rr[0]<9.223372036854774784e-83 ){ - exp -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( rr[0]<9.223372036854774784e+07 ){ - exp -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( rr[0]<9.22337203685477478e+17 ){ - exp -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } + while( rr[0]<9.223372036854774784e-83 ){ + exp -= 100; + dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); + } + while( rr[0]<9.223372036854774784e+07 ){ + exp -= 10; + dekkerMul2(rr, 1.0e+10, 0.0); + } + while( rr[0]<9.22337203685477478e+17 ){ + exp -= 1; + dekkerMul2(rr, 1.0e+01, 0.0); } - v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; } - + v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; /* Extract significant digits. */ i = sizeof(p->zBuf)-1; @@ -37248,104 +37425,6 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam return 0; } -/* -** High-resolution hardware timer used for debugging and testing only. -*/ -#if defined(VDBE_PROFILE) \ - || defined(SQLITE_PERFORMANCE_TRACE) \ - || defined(SQLITE_ENABLE_STMT_SCANSTATUS) -/************** Include hwtime.h in the middle of util.c *********************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 and x86_64 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - -/* -** The following routine only works on Pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - /* - ** asm() is needed for hardware timing support. Without asm(), - ** disable the sqlite3Hwtime() routine. - ** - ** sqlite3Hwtime() is only used for some obscure debugging - ** and analysis configurations, not in any deliverable, so this - ** should not be a great loss. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in util.c ***********************/ -#endif - /************** End of util.c ************************************************/ /************** Begin file hash.c ********************************************/ /* @@ -37652,8 +37731,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 16 */ "If" OpHelp(""), /* 17 */ "IfNot" OpHelp(""), /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"), - /* 19 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), - /* 20 */ "Not" OpHelp("r[P2]= !r[P1]"), + /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), + /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"), /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"), @@ -37677,24 +37756,24 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"), /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 43 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 44 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 45 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), - /* 46 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 44 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 45 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), /* 48 */ "Program" OpHelp(""), /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), /* 51 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 52 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 53 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), - /* 54 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), - /* 55 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), - /* 56 */ "Eq" OpHelp("IF r[P3]==r[P1]"), - /* 57 */ "Gt" OpHelp("IF r[P3]>r[P1]"), - /* 58 */ "Le" OpHelp("IF r[P3]<=r[P1]"), - /* 59 */ "Lt" OpHelp("IF r[P3]=r[P1]"), - /* 61 */ "ElseEq" OpHelp(""), + /* 52 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), + /* 53 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), + /* 54 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), + /* 55 */ "Eq" OpHelp("IF r[P3]==r[P1]"), + /* 56 */ "Gt" OpHelp("IF r[P3]>r[P1]"), + /* 57 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 58 */ "Lt" OpHelp("IF r[P3]=r[P1]"), + /* 60 */ "ElseEq" OpHelp(""), + /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), /* 62 */ "IncrVacuum" OpHelp(""), /* 63 */ "VNext" OpHelp(""), /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), @@ -39037,7 +39116,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ # endif #else /* !SQLITE_WASI */ # ifndef HAVE_FCHMOD -# define HAVE_FCHMOD +# define HAVE_FCHMOD 1 # endif #endif /* SQLITE_WASI */ @@ -39146,7 +39225,7 @@ static pid_t randomnessPid = 0; #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ -#ifndef SQLITE_DISABLE_DIRSYNC +#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX) # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ #else # define UNIXFILE_DIRSYNC 0x00 @@ -41307,54 +41386,33 @@ static int robust_flock(int fd, int op){ ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ - int rc = SQLITE_OK; - int reserved = 0; +#ifdef SQLITE_DEBUG unixFile *pFile = (unixFile*)id; +#else + UNUSED_PARAMETER(id); +#endif SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); + assert( pFile->eFileLock<=SHARED_LOCK ); - /* Check if a thread in this process holds such a lock */ - if( pFile->eFileLock>SHARED_LOCK ){ - reserved = 1; - } - - /* Otherwise see if some other process holds it. */ - if( !reserved ){ - /* attempt to get the lock */ - int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); - if( !lrc ){ - /* got the lock, unlock it */ - lrc = robust_flock(pFile->h, LOCK_UN); - if ( lrc ) { - int tErrno = errno; - /* unlock failed with an error */ - lrc = SQLITE_IOERR_UNLOCK; - storeLastErrno(pFile, tErrno); - rc = lrc; - } - } else { - int tErrno = errno; - reserved = 1; - /* someone else might have it reserved */ - lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(lrc) ){ - storeLastErrno(pFile, tErrno); - rc = lrc; - } - } - } - OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); + /* The flock VFS only ever takes exclusive locks (see function flockLock). + ** Therefore, if this connection is holding any lock at all, no other + ** connection may be holding a RESERVED lock. So set *pResOut to 0 + ** in this case. + ** + ** Or, this connection may be holding no lock. In that case, set *pResOut to + ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the + ** db in order to roll the hot journal back. If there is another connection + ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to + ** the user. With other VFS, we try to avoid this, in order to allow a reader + ** to proceed while a writer is preparing its transaction. But that won't + ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is + ** not a problem in this case. */ + *pResOut = 0; -#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & 0xff) == SQLITE_IOERR ){ - rc = SQLITE_OK; - reserved=1; - } -#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ - *pResOut = reserved; - return rc; + return SQLITE_OK; } /* @@ -42851,6 +42909,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + case SQLITE_FCNTL_NULL_IO: { + osClose(pFile->h); + pFile->h = -1; + return SQLITE_OK; + } case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -42997,6 +43060,7 @@ static void setDeviceCharacteristics(unixFile *pFd){ if( pFd->ctrlFlags & UNIXFILE_PSOW ){ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; } + pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ; pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } @@ -43047,7 +43111,7 @@ static void setDeviceCharacteristics(unixFile *pFile){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ - ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | + (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; @@ -43055,7 +43119,7 @@ static void setDeviceCharacteristics(unixFile *pFile){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ - ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | + (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; @@ -50890,6 +50954,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; } #endif + case SQLITE_FCNTL_NULL_IO: { + (void)osCloseHandle(pFile->h); + pFile->h = NULL; + return SQLITE_OK; + } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); @@ -50951,7 +51020,7 @@ static int winSectorSize(sqlite3_file *id){ */ static int winDeviceCharacteristics(sqlite3_file *id){ winFile *p = (winFile*)id; - return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ | ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } @@ -55376,6 +55445,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( pPgHdr->pData = pPage->pBuf; pPgHdr->pExtra = (void *)&pPgHdr[1]; memset(pPgHdr->pExtra, 0, 8); + assert( EIGHT_BYTE_ALIGNMENT( pPgHdr->pExtra ) ); pPgHdr->pCache = pCache; pPgHdr->pgno = pgno; pPgHdr->flags = PGHDR_CLEAN; @@ -56122,7 +56192,8 @@ static int pcache1InitBulk(PCache1 *pCache){ do{ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; pX->page.pBuf = zBulk; - pX->page.pExtra = &pX[1]; + pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); + assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; @@ -56259,7 +56330,8 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ if( pPg==0 ) return 0; p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; p->page.pBuf = pPg; - p->page.pExtra = &p[1]; + p->page.pExtra = (u8*)p + ROUND8(sizeof(*p)); + assert( EIGHT_BYTE_ALIGNMENT( p->page.pExtra ) ); p->isBulkLocal = 0; p->isAnchor = 0; p->pLruPrev = 0; /* Initializing this saves a valgrind error */ @@ -58598,20 +58670,28 @@ static const unsigned char aJournalMagic[] = { ** Return true if page pgno can be read directly from the database file ** by the b-tree layer. This is the case if: ** -** * the database file is open, -** * there are no dirty pages in the cache, and -** * the desired page is not currently in the wal file. +** (1) the database file is open +** (2) the VFS for the database is able to do unaligned sub-page reads +** (3) there are no dirty pages in the cache, and +** (4) the desired page is not currently in the wal file. */ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ - if( pPager->fd->pMethods==0 ) return 0; - if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; + assert( pPager!=0 ); + assert( pPager->fd!=0 ); + if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */ + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */ #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return iRead==0; + return iRead==0; /* Condition (4) */ } #endif + assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); + if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) + & SQLITE_IOCAP_SUBPAGE_READ)==0 ){ + return 0; /* Case (2) */ + } return 1; } #endif @@ -61927,6 +62007,7 @@ static int pagerAcquireMapPage( return SQLITE_NOMEM_BKPT; } p->pExtra = (void *)&p[1]; + assert( EIGHT_BYTE_ALIGNMENT( p->pExtra ) ); p->flags = PGHDR_MMAP; p->nRef = 1; p->pPager = pPager; @@ -65837,7 +65918,7 @@ SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ ** 28: Checksum-2 (second part of checksum for first 24 bytes of header). ** ** Immediately following the wal-header are zero or more frames. Each -** frame consists of a 24-byte frame-header followed by a bytes +** frame consists of a 24-byte frame-header followed by bytes ** of page data. The frame-header is six big-endian 32-bit unsigned ** integer values, as follows: ** @@ -66373,8 +66454,7 @@ static void walidxSetMxFrame(WalIndexHdr *pHdr, int iWal, u32 mxFrame){ assert( walidxGetMxFrame(pHdr, iWal)==mxFrame ); } -#define walidxGetFile(pHdr) ((pHdr)->mxFrame2 >> 31) - +#define walidxGetFile(pHdr) (int)((pHdr)->mxFrame2 >> 31) #define walidxSetFile(pHdr, iWal) ( \ (pHdr)->mxFrame2 = ((pHdr)->mxFrame2 & 0x7FFFFFFF) | (((u32)(iWal))<<31) \ ) @@ -66598,6 +66678,7 @@ struct Wal { #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ + int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */ #endif int bClosing; /* Set to true at start of sqlite3WalClose() */ int bWal2; /* bWal2 flag passed to WalOpen() */ @@ -68840,7 +68921,7 @@ static int walHandleException(Wal *pWal){ /* ** Assert that the Wal.lockMask mask, which indicates the locks held -** by the connenction, is consistent with the Wal.readLock, Wal.writeLock +** by the connection, is consistent with the Wal.readLock, Wal.writeLock ** and Wal.ckptLock variables. To be used as: ** ** assert( walAssertLockmask(pWal) ); @@ -69559,7 +69640,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ u32 mxFrame; /* Wal frame to lock to */ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT - && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0) + && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0) #endif ){ /* The WAL has been completely backfilled (or it is empty). @@ -70384,7 +70465,7 @@ static int walLockForCommit( assert( nLoop==1 || nLoop==2 ); for(iLoop=0; rc==SQLITE_OK && iLoophdr, iWal); aWalData[1] = pWal->hdr.aFrameCksum[0]; aWalData[2] = pWal->hdr.aFrameCksum[1]; - aWalData[3] = isWalMode2(pWal) ? iWal : pWal->nCkpt; + aWalData[3] = isWalMode2(pWal) ? (u32)iWal : pWal->nCkpt; } /* @@ -70693,7 +70774,7 @@ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ int rc = SQLITE_OK; int iWal = walidxGetFile(&pWal->hdr); - int iCmp = isWalMode2(pWal) ? iWal : pWal->nCkpt; + u32 iCmp = isWalMode2(pWal) ? (u32)iWal : pWal->nCkpt; assert( pWal->writeLock || aWalData[0]==pWal->hdr.mxFrame ); assert( isWalMode2(pWal) || iWal==0 ); @@ -70738,7 +70819,7 @@ static int walRestartLog(Wal *pWal){ if( isWalMode2(pWal) ){ int iApp = walidxGetFile(&pWal->hdr); - int nWalSize = WAL_DEFAULT_WALSIZE; + u32 nWalSize = WAL_DEFAULT_WALSIZE; if( pWal->mxWalSize>0 ){ nWalSize = (pWal->mxWalSize-WAL_HDRSIZE+pWal->szPage+WAL_FRAME_HDRSIZE-1) / (pWal->szPage+WAL_FRAME_HDRSIZE); @@ -71513,7 +71594,20 @@ SQLITE_PRIVATE void sqlite3WalSnapshotOpen( Wal *pWal, sqlite3_snapshot *pSnapshot ){ - pWal->pSnapshot = (WalIndexHdr*)pSnapshot; + if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){ + /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In + ** this case set the bGetSnapshot flag so that if the call to + ** sqlite3_snapshot_get() is about to read transaction on this wal + ** file, it does not take read-lock 0 if the wal file has been completely + ** checkpointed. Taking read-lock 0 would work, but then it would be + ** possible for a subsequent writer to destroy the snapshot even while + ** this connection is holding its read-transaction open. This is contrary + ** to user expectations, so we avoid it by not taking read-lock 0. */ + pWal->bGetSnapshot = 1; + }else{ + pWal->pSnapshot = (WalIndexHdr*)pSnapshot; + pWal->bGetSnapshot = 0; + } } /* @@ -78008,6 +78102,25 @@ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ return ROUND8(sizeof(BtCursor)); } +#ifdef SQLITE_DEBUG +/* +** Return true if and only if the Btree object will be automatically +** closed with the BtCursor closes. This is used within assert() statements +** only. +*/ +SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor( + Btree *pBtree, /* the btree object */ + BtCursor *pCur /* Corresponding cursor */ +){ + BtShared *pBt = pBtree->pBt; + if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0; + if( pBt->pCursor!=pCur ) return 0; + if( pCur->pNext!=0 ) return 0; + if( pCur->pBtree!=pBtree ) return 0; + return 1; +} +#endif + /* ** Initialize memory that will be converted into a BtCursor object. ** @@ -79259,7 +79372,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0 && pIdxKey->errCode==SQLITE_OK ){ - pCur->curFlags &= ~BTCF_ValidOvfl; + pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast); if( !pCur->pPage->isInit ){ return SQLITE_CORRUPT_BKPT; } @@ -84804,13 +84917,13 @@ SQLITE_PRIVATE int sqlite3BtreeExclusiveLock(Btree *p){ if( pSchema ){ for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ Table *pTab = (Table *)sqliteHashData(pE); - if( pTab->tnum==(int)pgnoRoot ){ + if( pTab->tnum==pgnoRoot ){ zObj = pTab->zName; zTab = 0; }else{ Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->tnum==(int)pgnoRoot ){ + if( pIdx->tnum==pgnoRoot ){ zObj = pIdx->zName; zTab = pTab->zName; } @@ -87975,7 +88088,8 @@ static int valueFromFunction( goto value_from_function_out; } for(i=0; ia[i].pExpr, enc, aff, &apVal[i]); + rc = sqlite3Stat4ValueFromExpr(pCtx->pParse, pList->a[i].pExpr, aff, + &apVal[i]); if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out; } } @@ -89909,6 +90023,12 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); break; } + case P4_SUBRTNSIG: { + SubrtnSig *pSig = (SubrtnSig*)p4; + sqlite3DbFree(db, pSig->zAff); + sqlite3DbFree(db, pSig); + break; + } } } @@ -90488,6 +90608,11 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ zP4 = pOp->p4.pTab->zName; break; } + case P4_SUBRTNSIG: { + SubrtnSig *pSig = pOp->p4.pSubrtnSig; + sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff); + break; + } default: { zP4 = pOp->p4.z; } @@ -93018,7 +93143,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem ** We must use separate SQLITE_NOINLINE functions here, since otherwise ** optimizer code movement causes gcov to become very confused. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) static int SQLITE_NOINLINE doubleLt(double a, double b){ return ar ); - testcase( x==r ); - return (xr); }else{ i64 y; if( r<-9223372036854775808.0 ) return +1; @@ -94042,6 +94160,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( sqlite3DbFree(db, preupdate.aRecord); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); + sqlite3VdbeMemRelease(&preupdate.oldipk); if( preupdate.aNew ){ int i; for(i=0; inField; i++){ @@ -94049,6 +94168,13 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( } sqlite3DbNNFreeNN(db, preupdate.aNew); } + if( preupdate.apDflt ){ + int i; + for(i=0; inCol; i++){ + sqlite3ValueFree(preupdate.apDflt[i]); + } + sqlite3DbFree(db, preupdate.apDflt); + } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -95677,6 +95803,17 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ ** ** The error code stored in database p->db is overwritten with the return ** value in any case. +** +** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK, +** that means all of the the following will be true: +** +** p!=0 +** p->pVar!=0 +** i>0 +** i<=p->nVar +** +** An assert() is normally added after vdbeUnbind() to help static analyzers +** realize this. */ static int vdbeUnbind(Vdbe *p, unsigned int i){ Mem *pVar; @@ -95734,6 +95871,7 @@ static int bindText( rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ if( zData!=0 ){ pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); @@ -95783,6 +95921,7 @@ SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); sqlite3_mutex_leave(p->db->mutex); } @@ -95796,6 +95935,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); sqlite3_mutex_leave(p->db->mutex); } @@ -95806,6 +95946,7 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3_mutex_leave(p->db->mutex); } return rc; @@ -95821,6 +95962,7 @@ SQLITE_API int sqlite3_bind_pointer( Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); sqlite3_mutex_leave(p->db->mutex); }else if( xDestructor ){ @@ -95902,6 +96044,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ + assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #else @@ -96236,37 +96379,64 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_old_out; } - /* If the old.* record has not yet been loaded into memory, do so now. */ - if( p->pUnpacked==0 ){ - u32 nRec; - u8 *aRec; + if( iIdx==p->pTab->iPKey ){ + *ppValue = pMem = &p->oldipk; + sqlite3VdbeMemSetInt64(pMem, p->iKey1); + }else{ - assert( p->pCsr->eCurType==CURTYPE_BTREE ); - nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); - aRec = sqlite3DbMallocRaw(db, nRec); - if( !aRec ) goto preupdate_old_out; - rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); - if( rc==SQLITE_OK ){ - p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); - if( !p->pUnpacked ) rc = SQLITE_NOMEM; - } - if( rc!=SQLITE_OK ){ - sqlite3DbFree(db, aRec); - goto preupdate_old_out; + /* If the old.* record has not yet been loaded into memory, do so now. */ + if( p->pUnpacked==0 ){ + u32 nRec; + u8 *aRec; + + assert( p->pCsr->eCurType==CURTYPE_BTREE ); + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); + aRec = sqlite3DbMallocRaw(db, nRec); + if( !aRec ) goto preupdate_old_out; + rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); + if( rc==SQLITE_OK ){ + p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + if( !p->pUnpacked ) rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, aRec); + goto preupdate_old_out; + } + p->aRecord = aRec; } - p->aRecord = aRec; - } - pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; - if( iIdx==p->pTab->iPKey ){ - sqlite3VdbeMemSetInt64(pMem, p->iKey1); - }else if( iIdx>=p->pUnpacked->nField ){ - *ppValue = (sqlite3_value *)columnNullValue(); - }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & (MEM_Int|MEM_IntReal) ){ - testcase( pMem->flags & MEM_Int ); - testcase( pMem->flags & MEM_IntReal ); - sqlite3VdbeMemRealify(pMem); + pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; + if( iIdx>=p->pUnpacked->nField ){ + /* This occurs when the table has been extended using ALTER TABLE + ** ADD COLUMN. The value to return is the default value of the column. */ + Column *pCol = &p->pTab->aCol[iIdx]; + if( pCol->iDflt>0 ){ + if( p->apDflt==0 ){ + int nByte = sizeof(sqlite3_value*)*p->pTab->nCol; + p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); + if( p->apDflt==0 ) goto preupdate_old_out; + } + if( p->apDflt[iIdx]==0 ){ + sqlite3_value *pVal = 0; + Expr *pDflt; + assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) ); + pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; + rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal); + if( rc==SQLITE_OK && pVal==0 ){ + rc = SQLITE_CORRUPT_BKPT; + } + p->apDflt[iIdx] = pVal; + } + *ppValue = p->apDflt[iIdx]; + }else{ + *ppValue = (sqlite3_value *)columnNullValue(); + } + }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); + sqlite3VdbeMemRealify(pMem); + } } } @@ -96814,6 +96984,104 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ +/* +** High-resolution hardware timer used for debugging and testing only. +*/ +#if defined(VDBE_PROFILE) \ + || defined(SQLITE_PERFORMANCE_TRACE) \ + || defined(SQLITE_ENABLE_STMT_SCANSTATUS) +/************** Include hwtime.h in the middle of vdbe.c *********************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 and x86_64 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on Pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if !defined(__STRICT_ANSI__) && \ + (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + /* + ** asm() is needed for hardware timing support. Without asm(), + ** disable the sqlite3Hwtime() routine. + ** + ** sqlite3Hwtime() is only used for some obscure debugging + ** and analysis configurations, not in any deliverable, so this + ** should not be a great loss. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in vdbe.c ***********************/ +#endif + /* ** Invoke this macro on memory cells just prior to changing the ** value of the cell. This macro verifies that shallow copies are @@ -98889,7 +99157,7 @@ case OP_RealAffinity: { /* in1 */ } #endif -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE) +#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE) /* Opcode: Cast P1 P2 * * * ** Synopsis: affinity(r[P1]) ** @@ -100747,7 +101015,6 @@ case OP_AutoCommit: { assert( desiredAutoCommit==0 || bConcurrent==0 ); assert( db->autoCommit==0 || db->eConcurrent==CONCURRENT_NONE ); assert( db->nVdbeActive>0 ); /* At least this one VM is active */ - assert( db->nVdbeActive>0 ); /* At least this one VM is active */ assert( p->bIsReader ); if( desiredAutoCommit!=db->autoCommit ){ @@ -101366,8 +101633,13 @@ case OP_OpenEphemeral: { /* ncycle */ } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + assert( p->apCsr[pOp->p1]==pCx ); if( rc ){ + assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); sqlite3BtreeClose(pCx->ub.pBtx); + p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */ + }else{ + assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); } } } @@ -102154,6 +102426,7 @@ case OP_Found: { /* jump, in3, ncycle */ r.pKeyInfo = pC->pKeyInfo; r.default_rc = 0; #ifdef SQLITE_DEBUG + (void)sqlite3FaultSim(50); /* For use by --counter in TH3 */ for(ii=0; iip4type==P4_FUNCDEF ); n = pOp->p5; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) + - (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*))); + + /* Allocate space for (a) the context object and (n-1) extra pointers + ** to append to the sqlite3_context.argv[1] array, and (b) a memory + ** cell in which to store the accumulation. Be careful that the memory + ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits. + ** + ** Note: We could avoid this by using a regular memory cell from aMem[] for + ** the accumulator, instead of allocating one here. */ + nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) ); + pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); if( pCtx==0 ) goto no_mem; - pCtx->pMem = 0; - pCtx->pOut = (Mem*)&(pCtx->argv[n]); + pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); + assert( EIGHT_BYTE_ALIGNMENT(pCtx->pOut) ); + sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); + pCtx->pMem = 0; pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; @@ -105905,7 +106189,7 @@ case OP_ReleaseReg: { ** As with all opcodes, the meanings of the parameters for OP_Explain ** are subject to change from one release to the next. Applications ** should not attempt to interpret or use any of the information -** contined in the OP_Explain opcode. The information provided by this +** contained in the OP_Explain opcode. The information provided by this ** opcode is intended for testing and debugging use only. */ default: { /* This is really OP_Noop, OP_Explain */ @@ -106233,6 +106517,11 @@ SQLITE_API int sqlite3_blob_open( pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } + if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){ + pTab = 0; + sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s", + zTable); + } #ifndef SQLITE_OMIT_VIEW if( pTab && IsView(pTab) ){ pTab = 0; @@ -107140,13 +107429,14 @@ static int vdbePmaReadBlob( while( nRem>0 ){ int rc; /* vdbePmaReadBlob() return code */ int nCopy; /* Number of bytes to copy */ - u8 *aNext; /* Pointer to buffer to copy data from */ + u8 *aNext = 0; /* Pointer to buffer to copy data from */ nCopy = nRem; if( nRem>p->nBuffer ) nCopy = p->nBuffer; rc = vdbePmaReadBlob(p, nCopy, &aNext); if( rc!=SQLITE_OK ) return rc; assert( aNext!=p->aAlloc ); + assert( aNext!=0 ); memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); nRem -= nCopy; } @@ -110416,7 +110706,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ + if( pItem->fg.isSubquery + && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect) + ){ return WRC_Abort; } if( pItem->fg.isTabFunc @@ -110722,7 +111014,7 @@ static void extendFJMatch( if( pNew ){ pNew->iTable = pMatch->iCursor; pNew->iColumn = iColumn; - pNew->y.pTab = pMatch->pTab; + pNew->y.pTab = pMatch->pSTab; assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ); ExprSetProperty(pNew, EP_CanBeNull); *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew); @@ -110853,10 +111145,10 @@ static int lookupName( if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ u8 hCol; - pTab = pItem->pTab; + pTab = pItem->pSTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem)); if( pItem->fg.isNestedFrom ){ /* In this case, pItem is a subquery that has been formed from a ** parenthesized subset of the FROM clause terms. Example: @@ -110865,8 +111157,12 @@ static int lookupName( ** This pItem -------------^ */ int hit = 0; - assert( pItem->pSelect!=0 ); - pEList = pItem->pSelect->pEList; + Select *pSel; + assert( pItem->fg.isSubquery ); + assert( pItem->u4.pSubq!=0 ); + pSel = pItem->u4.pSubq->pSelect; + assert( pSel!=0 ); + pEList = pSel->pEList; assert( pEList!=0 ); assert( pEList->nExpr==pTab->nCol ); for(j=0; jnExpr; j++){ @@ -110989,9 +111285,9 @@ static int lookupName( */ if( cntTab==0 || (cntTab==1 - && ALWAYS(pMatch!=0) - && ALWAYS(pMatch->pTab!=0) - && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 + && pMatch!=0 + && ALWAYS(pMatch->pSTab!=0) + && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0 && (pTab->tabFlags & TF_Ephemeral)==0) ){ cntTab = 1; @@ -111012,7 +111308,7 @@ static int lookupName( if( pMatch ){ pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); - pExpr->y.pTab = pMatch->pTab; + pExpr->y.pTab = pMatch->pSTab; if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } @@ -111054,7 +111350,7 @@ static int lookupName( if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ - pTab = pUpsert->pUpsertSrc->a[0].pTab; + pTab = pUpsert->pUpsertSrc->a[0].pSTab; pExpr->iTable = EXCLUDED_TABLE_NUMBER; } } @@ -111137,11 +111433,11 @@ static int lookupName( && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) - && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) + && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom) ){ cnt = cntTab; #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2 - if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){ + if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){ eNewExprOp = TK_NULL; } #endif @@ -111378,7 +111674,7 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr SrcItem *pItem = &pSrc->a[iSrc]; Table *pTab; assert( ExprUseYTab(p) ); - pTab = p->y.pTab = pItem->pTab; + pTab = p->y.pTab = pItem->pSTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; @@ -111497,7 +111793,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pItem = pSrcList->a; pExpr->op = TK_COLUMN; assert( ExprUseYTab(pExpr) ); - pExpr->y.pTab = pItem->pTab; + pExpr->y.pTab = pItem->pSTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn--; pExpr->affExpr = SQLITE_AFF_INTEGER; @@ -111622,8 +111918,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* Resolve function names */ case TK_FUNCTION: { - ExprList *pList = pExpr->x.pList; /* The argument list */ - int n = pList ? pList->nExpr : 0; /* Number of arguments */ + ExprList *pList; /* The argument list */ + int n; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ @@ -111636,6 +111932,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER ); + pList = pExpr->x.pList; + n = pList ? pList->nExpr : 0; zId = pExpr->u.zToken; pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ @@ -111684,6 +111982,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } } #endif + + /* If the function may call sqlite3_value_subtype(), then set the + ** EP_SubtArg flag on all of its argument expressions. This prevents + ** where.c from replacing the expression with a value read from an + ** index on the same expression, which will not have the correct + ** subtype. Also set the flag if the function expression itself is + ** an EP_SubtArg expression. In this case subtypes are required as + ** the function may return a value with a subtype back to its + ** caller using sqlite3_result_value(). */ + if( (pDef->funcFlags & SQLITE_SUBTYPE) + || ExprHasProperty(pExpr, EP_SubtArg) + ){ + int ii; + for(ii=0; iia[ii].pExpr, EP_SubtArg); + } + } + if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered @@ -111803,9 +112119,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC - if( pWin ){ + if( pWin && pParse->nErr==0 ){ Select *pSel = pNC->pWinSelect; - assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); + assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin ); if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); if( pParse->db->mallocFailed ) break; @@ -112387,7 +112703,11 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** moves the pOrderBy down to the sub-query. It will be moved back ** after the names have been resolved. */ if( p->selFlags & SF_Converted ){ - Select *pSub = p->pSrc->a[0].pSelect; + Select *pSub; + assert( p->pSrc->a[0].fg.isSubquery ); + assert( p->pSrc->a[0].u4.pSubq!=0 ); + pSub = p->pSrc->a[0].u4.pSubq->pSelect; + assert( pSub!=0 ); assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( pSub->pPrior && pSub->pOrderBy==0 ); pSub->pOrderBy = p->pOrderBy; @@ -112399,13 +112719,16 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ if( pOuterNC ) pOuterNC->nNestedSelect++; for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; - assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/ - if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ + assert( pItem->zName!=0 + || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/ + if( pItem->fg.isSubquery + && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0 + ){ int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; if( pItem->zName ) pParse->zAuthContext = pItem->zName; - sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); + sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr ) return WRC_Abort; assert( db->mallocFailed==0 ); @@ -112507,7 +112830,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** These integers will be replaced by copies of the corresponding result ** set expressions by the call to resolveOrderGroupBy() below. */ if( p->selFlags & SF_Converted ){ - Select *pSub = p->pSrc->a[0].pSelect; + Select *pSub; + assert( p->pSrc->a[0].fg.isSubquery ); + pSub = p->pSrc->a[0].u4.pSubq->pSelect; + assert( pSub!=0 ); p->pOrderBy = pSub->pOrderBy; pSub->pOrderBy = 0; } @@ -112661,6 +112987,9 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. +** +** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a +** failure. */ SQLITE_PRIVATE int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ @@ -112669,7 +112998,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( int i; int savedHasAgg = 0; Walker w; - if( pList==0 ) return WRC_Continue; + if( pList==0 ) return SQLITE_OK; w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -112683,7 +113012,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ - return WRC_Abort; + return SQLITE_ERROR; } #endif sqlite3WalkExprNN(&w, pExpr); @@ -112700,10 +113029,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } - if( w.pParse->nErr>0 ) return WRC_Abort; + if( w.pParse->nErr>0 ) return SQLITE_ERROR; } pNC->ncFlags |= savedHasAgg; - return WRC_Continue; + return SQLITE_OK; } /* @@ -112771,7 +113100,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( if( pTab ){ sSrc.nSrc = 1; sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pTab = pTab; + sSrc.a[0].pSTab = pTab; sSrc.a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP @@ -112876,7 +113205,9 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ op = pExpr->op; continue; } - if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break; + if( op!=TK_REGISTER ) break; + op = pExpr->op2; + if( NEVER( op==TK_REGISTER ) ) break; } return pExpr->affExpr; } @@ -114666,15 +114997,30 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla SrcItem *pNewItem = &pNew->a[i]; const SrcItem *pOldItem = &p->a[i]; Table *pTab; - pNewItem->pSchema = pOldItem->pSchema; - pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); + pNewItem->fg = pOldItem->fg; + if( pOldItem->fg.isSubquery ){ + Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery)); + if( pNewSubq==0 ){ + assert( db->mallocFailed ); + pNewItem->fg.isSubquery = 0; + }else{ + memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq)); + pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags); + if( pNewSubq->pSelect==0 ){ + sqlite3DbFree(db, pNewSubq); + pNewSubq = 0; + pNewItem->fg.isSubquery = 0; + } + } + pNewItem->u4.pSubq = pNewSubq; + }else if( pOldItem->fg.fixedSchema ){ + pNewItem->u4.pSchema = pOldItem->u4.pSchema; + }else{ + pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase); + } pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); - pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; - pNewItem->addrFillSub = pOldItem->addrFillSub; - pNewItem->regReturn = pOldItem->regReturn; - pNewItem->regResult = pOldItem->regResult; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); }else if( pNewItem->fg.isTabFunc ){ @@ -114687,11 +115033,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla if( pNewItem->fg.isCte ){ pNewItem->u2.pCteUse->nUse++; } - pTab = pNewItem->pTab = pOldItem->pTab; + pTab = pNewItem->pSTab = pOldItem->pSTab; if( pTab ){ pTab->nTabRef++; } - pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); if( pOldItem->fg.isUsing ){ assert( pNewItem->fg.isUsing ); pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing); @@ -114765,7 +115110,6 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pp = &pNew->pPrior; pNext = pNew; } - return pRet; } #else @@ -115785,8 +116129,8 @@ static Select *isCandidateForInOpt(const Expr *pX){ pSrc = p->pSrc; assert( pSrc!=0 ); if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ - if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ - pTab = pSrc->a[0].pTab; + if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */ + pTab = pSrc->a[0].pSTab; assert( pTab!=0 ); assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ @@ -115969,7 +116313,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ - pTab = p->pSrc->a[0].pTab; + pTab = p->pSrc->a[0].pSTab; /* Code an OP_Transaction and OP_TableLock for
  • . */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -116209,6 +116553,49 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ } } +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Scan all previously generated bytecode looking for an OP_BeginSubrtn +** that is compatible with pExpr. If found, add the y.sub values +** to pExpr and return true. If not found, return false. +*/ +static int findCompatibleInRhsSubrtn( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* IN operator with RHS that we want to reuse */ + SubrtnSig *pNewSig /* Signature for the IN operator */ +){ + VdbeOp *pOp, *pEnd; + SubrtnSig *pSig; + Vdbe *v; + + if( pNewSig==0 ) return 0; + if( (pParse->mSubrtnSig & (1<<(pNewSig->selId&7)))==0 ) return 0; + assert( pExpr->op==TK_IN ); + assert( !ExprUseYSub(pExpr) ); + assert( ExprUseXSelect(pExpr) ); + assert( pExpr->x.pSelect!=0 ); + assert( (pExpr->x.pSelect->selFlags & SF_All)==0 ); + v = pParse->pVdbe; + assert( v!=0 ); + pOp = sqlite3VdbeGetOp(v, 1); + pEnd = sqlite3VdbeGetLastOp(v); + for(; pOpp4type!=P4_SUBRTNSIG ) continue; + assert( pOp->opcode==OP_BeginSubrtn ); + pSig = pOp->p4.pSubrtnSig; + assert( pSig!=0 ); + if( pNewSig->selId!=pSig->selId ) continue; + if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue; + pExpr->y.sub.iAddr = pSig->iAddr; + pExpr->y.sub.regReturn = pSig->regReturn; + pExpr->iTable = pSig->iTable; + ExprSetProperty(pExpr, EP_Subrtn); + return 1; + } + return 0; +} +#endif /* SQLITE_OMIT_SUBQUERY */ + #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that will construct an ephemeral table containing all terms @@ -116258,11 +116645,28 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ - /* Reuse of the RHS is allowed */ - /* If this routine has already been coded, but the previous code - ** might not have been invoked yet, so invoke it now as a subroutine. + /* Reuse of the RHS is allowed + ** + ** Compute a signature for the RHS of the IN operator to facility + ** finding and reusing prior instances of the same IN operator. */ - if( ExprHasProperty(pExpr, EP_Subrtn) ){ + SubrtnSig *pSig = 0; + assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 ); + if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){ + pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0])); + if( pSig ){ + pSig->selId = pExpr->x.pSelect->selId; + pSig->zAff = exprINAffinity(pParse, pExpr); + } + } + + /* Check to see if there is a prior materialization of the RHS of + ** this IN operator. If there is, then make use of that prior + ** materialization rather than recomputing it. + */ + if( ExprHasProperty(pExpr, EP_Subrtn) + || findCompatibleInRhsSubrtn(pParse, pExpr, pSig) + ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); if( ExprUseXSelect(pExpr) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", @@ -116274,6 +116678,10 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( assert( iTab!=pExpr->iTable ); sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); sqlite3VdbeJumpHere(v, addrOnce); + if( pSig ){ + sqlite3DbFree(pParse->db, pSig->zAff); + sqlite3DbFree(pParse->db, pSig); + } return; } @@ -116284,7 +116692,13 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; - + if( pSig ){ + pSig->iAddr = pExpr->y.sub.iAddr; + pSig->regReturn = pExpr->y.sub.regReturn; + pSig->iTable = iTab; + pParse->mSubrtnSig = 1 << (pSig->selId&7); + sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG); + } addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } @@ -116325,15 +116739,30 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( SelectDest dest; int i; int rc; + int addrBloom = 0; sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; + if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ + int regBloom = ++pParse->nMem; + addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); + VdbeComment((v, "Bloom filter")); + dest.iSDParm2 = regBloom; + } testcase( pSelect->selFlags & SF_Distinct ); testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); + if( addrBloom ){ + sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; + if( dest.iSDParm2==0 ){ + sqlite3VdbeChangeToNoop(v, addrBloom); + }else{ + sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; + } + } if( rc ){ sqlite3KeyInfoUnref(pKeyInfo); return; @@ -116631,9 +117060,7 @@ static void sqlite3ExprCodeIN( if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); - aiMap = (int*)sqlite3DbMallocZero( - pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 - ); + aiMap = (int*)sqlite3DbMallocZero(pParse->db, nVector*sizeof(int)); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than @@ -116776,6 +117203,15 @@ static void sqlite3ExprCodeIN( sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); + assert( pOp->opcode==OP_Once || pParse->nErr ); + if( pOp->opcode==OP_Once && pOp->p3>0 ){ + assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); + sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, + rLhs, nVector); VdbeCoverage(v); + } + } sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; @@ -117061,10 +117497,14 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n SQLITE_PRIVATE void sqlite3ExprToRegister(Expr *pExpr, int iReg){ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); if( NEVER(p==0) ) return; - p->op2 = p->op; - p->op = TK_REGISTER; - p->iTable = iReg; - ExprClearProperty(p, EP_Skip); + if( p->op==TK_REGISTER ){ + assert( p->iTable==iReg ); + }else{ + p->op2 = p->op; + p->op = TK_REGISTER; + p->iTable = iReg; + ExprClearProperty(p, EP_Skip); + } } /* @@ -117234,6 +117674,59 @@ static int exprCodeInlineFunction( return target; } +/* +** Expression Node callback for sqlite3ExprCanReturnSubtype(). +** +** Only a function call is able to return a subtype. So if the node +** is not a function call, return WRC_Prune immediately. +** +** A function call is able to return a subtype if it has the +** SQLITE_RESULT_SUBTYPE property. +** +** Assume that every function is able to pass-through a subtype from +** one of its argument (using sqlite3_result_value()). Most functions +** are not this way, but we don't have a mechanism to distinguish those +** that are from those that are not, so assume they all work this way. +** That means that if one of its arguments is another function and that +** other function is able to return a subtype, then this function is +** able to return a subtype. +*/ +static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ + int n; + FuncDef *pDef; + sqlite3 *db; + if( pExpr->op!=TK_FUNCTION ){ + return WRC_Prune; + } + assert( ExprUseXList(pExpr) ); + db = pWalker->pParse->db; + n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ + pWalker->eCode = 1; + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Return TRUE if expression pExpr is able to return a subtype. +** +** A TRUE return does not guarantee that a subtype will be returned. +** It only indicates that a subtype return is possible. False positives +** are acceptable as they only disable an optimization. False negatives, +** on the other hand, can lead to incorrect answers. +*/ +static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ + Walker w; + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = exprNodeCanReturnSubtype; + sqlite3WalkExpr(&w, pExpr); + return w.eCode; +} + + /* ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr. ** If it is, then resolve the expression by reading from the index and @@ -117266,6 +117759,17 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( continue; } + + /* Functions that might set a subtype should not be replaced by the + ** value taken from an expression index if they are themselves an + ** argument to another scalar function or aggregate. + ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */ + if( ExprHasProperty(pExpr, EP_SubtArg) + && sqlite3ExprCanReturnSubtype(pParse, pExpr) + ){ + continue; + } + v = pParse->pVdbe; assert( v!=0 ); if( p->bMaybeNullRow ){ @@ -121265,7 +121769,7 @@ static int renameResolveTrigger(Parse *pParse){ /* ALWAYS() because if the table of the trigger does not exist, the ** error would have been hit before this point */ if( ALWAYS(pParse->pTriggerTab) ){ - rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0; } /* Resolve symbols in WHEN clause */ @@ -121311,8 +121815,9 @@ static int renameResolveTrigger(Parse *pParse){ int i; for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ SrcItem *p = &pStep->pFrom->a[i]; - if( p->pSelect ){ - sqlite3SelectPrep(pParse, p->pSelect, 0); + if( p->fg.isSubquery ){ + assert( p->u4.pSubq!=0 ); + sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0); } } } @@ -121380,8 +121885,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ } if( pStep->pFrom ){ int i; - for(i=0; ipFrom->nSrc; i++){ - sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); + SrcList *pFrom = pStep->pFrom; + for(i=0; inSrc; i++){ + if( pFrom->a[i].fg.isSubquery ){ + assert( pFrom->a[i].u4.pSubq!=0 ); + sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect); + } } } } @@ -121628,7 +122137,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ } for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; - if( pItem->pTab==p->pTab ){ + if( pItem->pSTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } @@ -124056,12 +124565,13 @@ static int loadStatTbl( while( sqlite3_step(pStmt)==SQLITE_ROW ){ int nIdxCol = 1; /* Number of columns in stat4 records */ - char *zIndex; /* Index name */ - Index *pIdx; /* Pointer to the index object */ - int nSample; /* Number of samples */ - int nByte; /* Bytes of space required */ - int i; /* Bytes of space required */ - tRowcnt *pSpace; + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int nSample; /* Number of samples */ + i64 nByte; /* Bytes of space required */ + i64 i; /* Bytes of space required */ + tRowcnt *pSpace; /* Available allocated memory space */ + u8 *pPtr; /* Available memory as a u8 for easier manipulation */ zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; @@ -124081,7 +124591,7 @@ static int loadStatTbl( } pIdx->nSampleCol = nIdxCol; pIdx->mxSample = nSample; - nByte = sizeof(IndexSample) * nSample; + nByte = ROUND8(sizeof(IndexSample) * nSample); nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ @@ -124090,7 +124600,10 @@ static int loadStatTbl( sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; } - pSpace = (tRowcnt*)&pIdx->aSample[nSample]; + pPtr = (u8*)pIdx->aSample; + pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0])); + pSpace = (tRowcnt*)pPtr; + assert( EIGHT_BYTE_ALIGNMENT( pSpace ) ); pIdx->aAvgEq = pSpace; pSpace += nIdxCol; pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; iauth.authLevel ){ - rc = SQLITE_AUTH_USER; - } - } -#endif if( rc ){ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ int iDb = db->nDb - 1; @@ -124758,20 +125262,21 @@ static int fixSelectCb(Walker *p, Select *pSelect){ if( NEVER(pList==0) ) return WRC_Continue; for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pFix->bTemp==0 ){ - if( pItem->zDatabase ){ - if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ + if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){ + if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ + if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", - pFix->zType, pFix->pName, pItem->zDatabase); + pFix->zType, pFix->pName, pItem->u4.zDatabase); return WRC_Abort; } - sqlite3DbFree(db, pItem->zDatabase); - pItem->zDatabase = 0; + sqlite3DbFree(db, pItem->u4.zDatabase); pItem->fg.notCte = 1; + pItem->fg.hadSchema = 1; } - pItem->pSchema = pFix->pSchema; + pItem->u4.pSchema = pFix->pSchema; pItem->fg.fromDDL = 1; + pItem->fg.fixedSchema = 1; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( pList->a[i].fg.isUsing==0 @@ -125011,11 +125516,7 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; - rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext -#ifdef SQLITE_USER_AUTHENTICATION - ,db->auth.zAuthUser -#endif - ); + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); if( rc==SQLITE_DENY ){ char *z = sqlite3_mprintf("%s.%s", zTab, zCol); if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); @@ -125064,7 +125565,7 @@ SQLITE_PRIVATE void sqlite3AuthRead( assert( pTabList ); for(iSrc=0; iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ - pTab = pTabList->a[iSrc].pTab; + pTab = pTabList->a[iSrc].pSTab; break; } } @@ -125122,11 +125623,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( testcase( zArg3==0 ); testcase( pParse->zAuthContext==0 ); - rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext -#ifdef SQLITE_USER_AUTHENTICATION - ,db->auth.zAuthUser -#endif - ); + rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; @@ -125359,17 +125856,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } sqlite3VdbeAddOp0(v, OP_Halt); -#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE) - if( pParse->nTableLock>0 && db->init.busy==0 ){ - sqlite3UserAuthInit(db); - if( db->auth.authLevelrc = SQLITE_AUTH_USER; - return; - } - } -#endif - /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a @@ -125498,16 +125984,6 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested--; } -#if SQLITE_USER_AUTHENTICATION -/* -** Return TRUE if zTable is the name of the system table that stores the -** list of users and their access credentials. -*/ -SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ - return sqlite3_stricmp(zTable, "sqlite_user")==0; -} -#endif - /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -125526,13 +126002,6 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); -#if SQLITE_USER_AUTHENTICATION - /* Only the admin user is allowed to know that the sqlite_user table - ** exists */ - if( db->auth.authLevelnDb; i++){ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; @@ -125667,12 +126136,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( SrcItem *p ){ const char *zDb; - assert( p->pSchema==0 || p->zDatabase==0 ); - if( p->pSchema ){ - int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + if( p->fg.fixedSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); zDb = pParse->db->aDb[iDb].zDbSName; }else{ - zDb = p->zDatabase; + assert( !p->fg.isSubquery ); + zDb = p->u4.zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } @@ -128657,6 +129126,8 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); + assert( pName->a[0].fg.fixedSchema==0 ); + assert( pName->a[0].fg.isSubquery==0 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); @@ -128665,7 +129136,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, if( pTab==0 ){ if( noErr ){ - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); sqlite3ForceNotReadOnly(pParse); } goto exit_drop_table; @@ -129189,9 +129660,6 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 -#if SQLITE_USER_AUTHENTICATION - && sqlite3UserAuthTable(pTab->zName)==0 -#endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -129756,15 +130224,17 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists } assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pName->nSrc==1 ); + assert( pName->a[0].fg.fixedSchema==0 ); + assert( pName->a[0].fg.isSubquery==0 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } - pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); + pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase); if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; @@ -130061,12 +130531,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( if( pDatabase && pDatabase->z==0 ){ pDatabase = 0; } + assert( pItem->fg.fixedSchema==0 ); + assert( pItem->fg.isSubquery==0 ); if( pDatabase ){ pItem->zName = sqlite3NameFromToken(db, pDatabase); - pItem->zDatabase = sqlite3NameFromToken(db, pTable); + pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable); }else{ pItem->zName = sqlite3NameFromToken(db, pTable); - pItem->zDatabase = 0; + pItem->u4.zDatabase = 0; } return pList; } @@ -130082,13 +130554,40 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; - if( pItem->pSelect ){ - sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); + if( pItem->fg.isSubquery ){ + assert( pItem->u4.pSubq!=0 ); + assert( pItem->u4.pSubq->pSelect!=0 ); + assert( pItem->u4.pSubq->pSelect->pSrc!=0 ); + sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc); } } } } +/* +** Delete a Subquery object and its substructure. +*/ +SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){ + assert( pSubq!=0 && pSubq->pSelect!=0 ); + sqlite3SelectDelete(db, pSubq->pSelect); + sqlite3DbFree(db, pSubq); +} + +/* +** Remove a Subquery from a SrcItem. Return the associated Select object. +** The returned Select becomes the responsibility of the caller. +*/ +SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){ + Select *pSel; + assert( pItem!=0 ); + assert( pItem->fg.isSubquery ); + pSel = pItem->u4.pSubq->pSelect; + sqlite3DbFree(db, pItem->u4.pSubq); + pItem->u4.pSubq = 0; + pItem->fg.isSubquery = 0; + return pSel; +} + /* ** Delete an entire SrcList including all its substructure. */ @@ -130098,13 +130597,24 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ assert( db!=0 ); if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ - if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase); + + /* Check invariants on SrcItem */ + assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc ); + assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy ); + assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery ); + assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 && + pItem->u4.pSubq->pSelect!=0) ); + if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); + if( pItem->fg.isSubquery ){ + sqlite3SubqueryDelete(db, pItem->u4.pSubq); + }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ + sqlite3DbNNFreeNN(db, pItem->u4.zDatabase); + } if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); - sqlite3DeleteTable(db, pItem->pTab); - if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); + sqlite3DeleteTable(db, pItem->pSTab); if( pItem->fg.isUsing ){ sqlite3IdListDelete(db, pItem->u3.pUsing); }else if( pItem->u3.pOn ){ @@ -130114,6 +130624,54 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3DbNNFreeNN(db, pList); } +/* +** Attach a Subquery object to pItem->uv.pSubq. Set the +** pSelect value but leave all the other values initialized +** to zero. +** +** A copy of the Select object is made if dupSelect is true, and the +** SrcItem takes responsibility for deleting the copy. If dupSelect is +** false, ownership of the Select passes to the SrcItem. Either way, +** the SrcItem will take responsibility for deleting the Select. +** +** When dupSelect is zero, that means the Select might get deleted right +** away if there is an OOM error. Beware. +** +** Return non-zero on success. Return zero on an OOM error. +*/ +SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery( + Parse *pParse, /* Parsing context */ + SrcItem *pItem, /* Item to which the subquery is to be attached */ + Select *pSelect, /* The subquery SELECT. Must be non-NULL */ + int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/ +){ + Subquery *p; + assert( pSelect!=0 ); + assert( pItem->fg.isSubquery==0 ); + if( pItem->fg.fixedSchema ){ + pItem->u4.pSchema = 0; + pItem->fg.fixedSchema = 0; + }else if( pItem->u4.zDatabase!=0 ){ + sqlite3DbFree(pParse->db, pItem->u4.zDatabase); + pItem->u4.zDatabase = 0; + } + if( dupSelect ){ + pSelect = sqlite3SelectDup(pParse->db, pSelect, 0); + if( pSelect==0 ) return 0; + } + p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery)); + if( p==0 ){ + sqlite3SelectDelete(pParse->db, pSelect); + return 0; + } + pItem->fg.isSubquery = 1; + p->pSelect = pSelect; + assert( offsetof(Subquery, pSelect)==0 ); + memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect)); + return 1; +} + + /* ** This routine is called by the parser to add a new term to the ** end of a growing FROM clause. The "p" parameter is the part of @@ -130163,10 +130721,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } + assert( pSubquery==0 || pDatabase==0 ); if( pSubquery ){ - pItem->pSelect = pSubquery; - if( pSubquery->selFlags & SF_NestedFrom ){ - pItem->fg.isNestedFrom = 1; + if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){ + if( pSubquery->selFlags & SF_NestedFrom ){ + pItem->fg.isNestedFrom = 1; + } } } assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); @@ -131445,8 +132005,8 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ ** ** The following fields are initialized appropriate in pSrc: ** -** pSrc->a[0].pTab Pointer to the Table object -** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one +** pSrc->a[0].spTab Pointer to the Table object +** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one ** */ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ @@ -131454,8 +132014,8 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ Table *pTab; assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); - if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); - pItem->pTab = pTab; + if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab); + pItem->pSTab = pTab; pItem->fg.notCte = 1; if( pTab ){ pTab->nTabRef++; @@ -131496,6 +132056,7 @@ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char * ** is for a top-level SQL statement. */ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ + assert( IsVirtual(pTab) ); if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){ return 1; } @@ -131577,7 +132138,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView( if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 ); + pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].fg.isUsing==0 ); assert( pFrom->a[0].u3.pOn==0 ); } @@ -131639,7 +132201,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( ** ); */ - pTab = pSrc->a[0].pTab; + pTab = pSrc->a[0].pSTab; if( HasRowid(pTab) ){ pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pEList = sqlite3ExprListAppend( @@ -131672,9 +132234,9 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ - pSrc->a[0].pTab = 0; + pSrc->a[0].pSTab = 0; pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); - pSrc->a[0].pTab = pTab; + pSrc->a[0].pSTab = pTab; if( pSrc->a[0].fg.isIndexedBy ){ assert( pSrc->a[0].fg.isCte==0 ); pSrc->a[0].u2.pIBIndex = 0; @@ -134503,7 +135065,11 @@ static void minMaxFinalize(sqlite3_context *context){ ** group_concat(EXPR, ?SEPARATOR?) ** string_agg(EXPR, SEPARATOR) ** -** The SEPARATOR goes before the EXPR string. This is tragic. The +** Content is accumulated in GroupConcatCtx.str with the SEPARATOR +** coming before the EXPR value, except for the first entry which +** omits the SEPARATOR. +** +** It is tragic that the SEPARATOR goes before the EXPR string. The ** groupConcatInverse() implementation would have been easier if the ** SEPARATOR were appended after EXPR. And the order is undocumented, ** so we could change it, in theory. But the old behavior has been @@ -134607,7 +135173,7 @@ static void groupConcatInverse( /* pGCC is always non-NULL since groupConcatStep() will have always ** run first to initialize it */ if( ALWAYS(pGCC) ){ - int nVS; + int nVS; /* Number of characters to remove */ /* Must call sqlite3_value_text() to convert the argument into text prior ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ (void)sqlite3_value_text(argv[0]); @@ -134985,7 +135551,13 @@ static void signFunc( ** Implementation of fpdecode(x,y,z) function. ** ** x is a real number that is to be decoded. y is the precision. -** z is the maximum real precision. +** z is the maximum real precision. Return a string that shows the +** results of the sqlite3FpDecode() function. +** +** Used for testing and debugging only, specifically testing and debugging +** of the sqlite3FpDecode() function. This SQL function does not appear +** in production builds. This function is not an API and is subject to +** modification or removal in future versions of SQLite. */ static void fpdecodeFunc( sqlite3_context *context, @@ -135012,6 +135584,82 @@ static void fpdecodeFunc( } #endif /* SQLITE_DEBUG */ +#ifdef SQLITE_DEBUG +/* +** Implementation of parseuri(uri,flags) function. +** +** Required Arguments: +** "uri" The URI to parse. +** "flags" Bitmask of flags, as if to sqlite3_open_v2(). +** +** Additional arguments beyond the first two make calls to +** sqlite3_uri_key() for integers and sqlite3_uri_parameter for +** anything else. +** +** The result is a string showing the results of calling sqlite3ParseUri(). +** +** Used for testing and debugging only, specifically testing and debugging +** of the sqlite3ParseUri() function. This SQL function does not appear +** in production builds. This function is not an API and is subject to +** modification or removal in future versions of SQLite. +*/ +static void parseuriFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + sqlite3_str *pResult; + const char *zVfs; + const char *zUri; + unsigned int flgs; + int rc; + sqlite3_vfs *pVfs = 0; + char *zFile = 0; + char *zErr = 0; + + if( argc<2 ) return; + pVfs = sqlite3_vfs_find(0); + assert( pVfs ); + zVfs = pVfs->zName; + zUri = (const char*)sqlite3_value_text(argv[0]); + if( zUri==0 ) return; + flgs = (unsigned int)sqlite3_value_int(argv[1]); + rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr); + pResult = sqlite3_str_new(0); + if( pResult ){ + int i; + sqlite3_str_appendf(pResult, "rc=%d", rc); + sqlite3_str_appendf(pResult, ", flags=0x%x", flgs); + sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0); + sqlite3_str_appendf(pResult, ", err=%Q", zErr); + sqlite3_str_appendf(pResult, ", file=%Q", zFile); + if( zFile ){ + const char *z = zFile; + z += sqlite3Strlen30(z)+1; + while( z[0] ){ + sqlite3_str_appendf(pResult, ", %Q", z); + z += sqlite3Strlen30(z)+1; + } + for(i=2; ia; - pItem->pTab = pFKey->pFrom; + pItem->pSTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; - pItem->pTab->nTabRef++; + pItem->pSTab->nTabRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ @@ -136552,7 +137199,8 @@ static Trigger *fkActionTrigger( if( pSrc ){ assert( pSrc->nSrc==1 ); pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); - pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 ); + pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), @@ -137286,8 +137934,11 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ SrcItem *pItem = &pVal->pSrc->a[0]; - sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); - sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1); + assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr ); + if( pItem->fg.isSubquery ){ + sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn); + sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1); + } } } @@ -137415,36 +138066,42 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList if( pRet ){ SelectDest dest; + Subquery *pSubq; pRet->pSrc->nSrc = 1; pRet->pPrior = pLeft->pPrior; pRet->op = pLeft->op; + if( pRet->pPrior ) pRet->selFlags |= SF_Values; pLeft->pPrior = 0; pLeft->op = TK_SELECT; assert( pLeft->pNext==0 ); assert( pRet->pNext==0 ); p = &pRet->pSrc->a[0]; - p->pSelect = pLeft; p->fg.viaCoroutine = 1; - p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; - p->regReturn = ++pParse->nMem; p->iCursor = -1; + assert( !p->fg.isIndexedBy && !p->fg.isTabFunc ); p->u1.nRow = 2; - sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); - sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn); - - /* Allocate registers for the output of the co-routine. Do so so - ** that there are two unused registers immediately before those - ** used by the co-routine. This allows the code in sqlite3Insert() - ** to use these registers directly, instead of copying the output - ** of the co-routine to a separate array for processing. */ - dest.iSdst = pParse->nMem + 3; - dest.nSdst = pLeft->pEList->nExpr; - pParse->nMem += 2 + dest.nSdst; - - pLeft->selFlags |= SF_MultiValue; - sqlite3Select(pParse, pLeft, &dest); - p->regResult = dest.iSdst; - assert( pParse->nErr || dest.iSdst>0 ); + if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){ + pSubq = p->u4.pSubq; + pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; + pSubq->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, + pSubq->regReturn, 0, pSubq->addrFillSub); + sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); + + /* Allocate registers for the output of the co-routine. Do so so + ** that there are two unused registers immediately before those + ** used by the co-routine. This allows the code in sqlite3Insert() + ** to use these registers directly, instead of copying the output + ** of the co-routine to a separate array for processing. */ + dest.iSdst = pParse->nMem + 3; + dest.nSdst = pLeft->pEList->nExpr; + pParse->nMem += 2 + dest.nSdst; + + pLeft->selFlags |= SF_MultiValue; + sqlite3Select(pParse, pLeft, &dest); + pSubq->regResult = dest.iSdst; + assert( pParse->nErr || dest.iSdst>0 ); + } pLeft = pRet; } }else{ @@ -137454,12 +138111,18 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList } if( pParse->nErr==0 ){ + Subquery *pSubq; assert( p!=0 ); - if( p->pSelect->pEList->nExpr!=pRow->nExpr ){ - sqlite3SelectWrongNumTermsError(pParse, p->pSelect); + assert( p->fg.isSubquery ); + pSubq = p->u4.pSubq; + assert( pSubq!=0 ); + assert( pSubq->pSelect!=0 ); + assert( pSubq->pSelect->pEList!=0 ); + if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){ + sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect); }else{ - sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); + sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0); + sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn); } } sqlite3ExprListDelete(pParse->db, pRow); @@ -137810,9 +138473,14 @@ SQLITE_PRIVATE void sqlite3Insert( && pSelect->pPrior==0 ){ SrcItem *pItem = &pSelect->pSrc->a[0]; - dest.iSDParm = pItem->regReturn; - regFromSelect = pItem->regResult; - nColumn = pItem->pSelect->pEList->nExpr; + Subquery *pSubq; + assert( pItem->fg.isSubquery ); + pSubq = pItem->u4.pSubq; + dest.iSDParm = pSubq->regReturn; + regFromSelect = pSubq->regResult; + assert( pSubq->pSelect!=0 ); + assert( pSubq->pSelect->pEList!=0 ); + nColumn = pSubq->pSelect->pEList->nExpr; ExplainQueryPlan((pParse, 0, "SCAN %S", pItem)); if( bIdListInOrder && nColumn==pTab->nCol ){ regData = regFromSelect; @@ -139741,7 +140409,7 @@ static int xferOptimization( if( pSelect->pSrc->nSrc!=1 ){ return 0; /* FROM clause must have exactly one term */ } - if( pSelect->pSrc->a[0].pSelect ){ + if( pSelect->pSrc->a[0].fg.isSubquery ){ return 0; /* FROM clause cannot contain a subquery */ } if( pSelect->pWhere ){ @@ -143697,12 +144365,6 @@ SQLITE_PRIVATE void sqlite3Pragma( ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } -#if SQLITE_USER_AUTHENTICATION - if( db->auth.authLevel==UAUTH_User ){ - /* Do not allow non-admin users to modify the schema arbitrarily */ - mask &= ~(SQLITE_WriteSchema); - } -#endif if( sqlite3GetBoolean(zRight, 0) ){ if( (mask & SQLITE_WriteSchema)==0 @@ -144314,6 +144976,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Make sure sufficient number of registers have been allocated */ sqlite3TouchRegister(pParse, 8+cnt); + sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt); sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ @@ -145938,14 +146601,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #else encoding = SQLITE_UTF8; #endif - if( db->nVdbeActive>0 && encoding!=ENC(db) - && (db->mDbFlags & DBFLAG_Vacuum)==0 - ){ - rc = SQLITE_LOCKED; - goto initone_error_out; - }else{ - sqlite3SetTextEncoding(db, encoding); - } + sqlite3SetTextEncoding(db, encoding); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ @@ -146647,12 +147303,24 @@ static int sqlite3Prepare16( if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } + + /* Make sure nBytes is non-negative and correct. It should be the + ** number of bytes until the end of the input buffer or until the first + ** U+0000 character. If the input nBytes is odd, convert it into + ** an even number. If the input nBytes is negative, then the input + ** must be terminated by at least one U+0000 character */ if( nBytes>=0 ){ int sz; const char *z = (const char*)zSql; for(sz=0; szmutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ @@ -146666,7 +147334,7 @@ static int sqlite3Prepare16( ** the same number of characters into the UTF-16 string. */ int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); - *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); + *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed); } sqlite3DbFree(db, zSql8); rc = sqlite3ApiExit(db, rc); @@ -147060,11 +147728,13 @@ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ */ SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){ assert( pItem!=0 ); - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); if( pItem->fg.isNestedFrom ){ ExprList *pResults; - assert( pItem->pSelect!=0 ); - pResults = pItem->pSelect->pEList; + assert( pItem->fg.isSubquery ); + assert( pItem->u4.pSubq!=0 ); + assert( pItem->u4.pSubq->pSelect!=0 ); + pResults = pItem->u4.pSubq->pSelect->pEList; assert( pResults!=0 ); assert( iCol>=0 && iColnExpr ); pResults->a[iCol].fg.bUsed = 1; @@ -147098,9 +147768,9 @@ static int tableAndColumnIndex( assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ for(i=iStart; i<=iEnd; i++){ - iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); + iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol); if( iCol>=0 - && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) + && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0) ){ if( piTab ){ sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol); @@ -147229,10 +147899,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ - Table *pRightTab = pRight->pTab; + Table *pRightTab = pRight->pSTab; u32 joinType; - if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; + if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue; joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; /* If this is a NATURAL join, synthesize an appropriate USING clause @@ -148105,12 +148775,18 @@ static void selectInnerLoop( ** case the order does matter */ pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); + pDest->iSDParm2 = 0; /* Signal that any Bloom filter is unpopulated */ }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); + if( pDest->iSDParm2 ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, + regResult, nResultCol); + ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); + } sqlite3ReleaseTempReg(pParse, r1); } break; @@ -148653,8 +149329,12 @@ static const char *columnTypeImpl( SrcList *pTabList = pNC->pSrcList; for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( jnSrc ){ - pTab = pTabList->a[j].pTab; - pS = pTabList->a[j].pSelect; + pTab = pTabList->a[j].pSTab; + if( pTabList->a[j].fg.isSubquery ){ + pS = pTabList->a[j].u4.pSubq->pSelect; + }else{ + pS = 0; + } }else{ pNC = pNC->pNext; } @@ -150045,6 +150725,11 @@ static int generateOutputSubroutine( r1, pDest->zAffSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); + if( pDest->iSDParm2>0 ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, + pIn->iSdst, pIn->nSdst); + ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); + } sqlite3ReleaseTempReg(pParse, r1); break; } @@ -150701,7 +151386,9 @@ static void substSelect( pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - substSelect(pSubst, pItem->pSelect, 1); + if( pItem->fg.isSubquery ){ + substSelect(pSubst, pItem->u4.pSubq->pSelect, 1); + } if( pItem->fg.isTabFunc ){ substExprList(pSubst, pItem->u1.pFuncArg); } @@ -150732,7 +151419,7 @@ static void recomputeColumnsUsed( SrcItem *pSrcItem /* Which FROM clause item to recompute */ ){ Walker w; - if( NEVER(pSrcItem->pTab==0) ) return; + if( NEVER(pSrcItem->pSTab==0) ) return; memset(&w, 0, sizeof(w)); w.xExprCallback = recomputeColumnsUsedExpr; w.xSelectCallback = sqlite3SelectWalkNoop; @@ -150772,8 +151459,10 @@ static void srclistRenumberCursors( aCsrMap[pItem->iCursor+1] = pParse->nTab++; } pItem->iCursor = aCsrMap[pItem->iCursor+1]; - for(p=pItem->pSelect; p; p=p->pPrior){ - srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); + if( pItem->fg.isSubquery ){ + for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){ + srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); + } } } } @@ -151084,7 +151773,8 @@ static int flattenSubquery( assert( pSrc && iFrom>=0 && iFromnSrc ); pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; - pSub = pSubitem->pSelect; + assert( pSubitem->fg.isSubquery ); + pSub = pSubitem->u4.pSubq->pSelect; assert( pSub!=0 ); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -151137,7 +151827,7 @@ static int flattenSubquery( */ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( pSubSrc->nSrc>1 /* (3a) */ - || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */ + || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ ){ @@ -151223,14 +151913,18 @@ static int flattenSubquery( pParse->zAuthContext = zSavedAuthContext; /* Delete the transient structures associated with the subquery */ - pSub1 = pSubitem->pSelect; - sqlite3DbFree(db, pSubitem->zDatabase); + + if( ALWAYS(pSubitem->fg.isSubquery) ){ + pSub1 = sqlite3SubqueryDetach(db, pSubitem); + }else{ + pSub1 = 0; + } + assert( pSubitem->fg.isSubquery==0 ); + assert( pSubitem->fg.fixedSchema==0 ); sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zAlias); - pSubitem->zDatabase = 0; pSubitem->zName = 0; pSubitem->zAlias = 0; - pSubitem->pSelect = 0; assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 ); /* If the sub-query is a compound SELECT statement, then (by restrictions @@ -151271,8 +151965,8 @@ static int flattenSubquery( ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; - Table *pItemTab = pSubitem->pTab; - pSubitem->pTab = 0; + Table *pItemTab = pSubitem->pSTab; + pSubitem->pSTab = 0; p->pOrderBy = 0; p->pPrior = 0; p->pLimit = 0; @@ -151280,7 +151974,7 @@ static int flattenSubquery( p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->op = TK_ALL; - pSubitem->pTab = pItemTab; + pSubitem->pSTab = pItemTab; if( pNew==0 ){ p->pPrior = pPrior; }else{ @@ -151295,11 +151989,14 @@ static int flattenSubquery( TREETRACE(0x4,pParse,p,("compound-subquery flattener" " creates %u as peer\n",pNew->selId)); } - assert( pSubitem->pSelect==0 ); + assert( pSubitem->fg.isSubquery==0 ); } sqlite3DbFree(db, aCsrMap); if( db->mallocFailed ){ - pSubitem->pSelect = pSub1; + assert( pSubitem->fg.fixedSchema==0 ); + assert( pSubitem->fg.isSubquery==0 ); + assert( pSubitem->u4.zDatabase==0 ); + sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0); return 1; } @@ -151310,8 +152007,8 @@ static int flattenSubquery( ** ** pSubitem->pTab is always non-NULL by test restrictions and tests above. */ - if( ALWAYS(pSubitem->pTab!=0) ){ - Table *pTabToDel = pSubitem->pTab; + if( ALWAYS(pSubitem->pSTab!=0) ){ + Table *pTabToDel = pSubitem->pSTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); @@ -151319,7 +152016,7 @@ static int flattenSubquery( }else{ pTabToDel->nTabRef--; } - pSubitem->pTab = 0; + pSubitem->pSTab = 0; } /* The following loop runs once for each term in a compound-subquery @@ -151375,8 +152072,11 @@ static int flattenSubquery( */ for(i=0; ia[i+iFrom]; - if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); assert( pItem->fg.isTabFunc==0 ); + assert( pItem->fg.isSubquery + || pItem->fg.fixedSchema + || pItem->u4.zDatabase==0 ); + if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); *pItem = pSubSrc->a[i]; pItem->fg.jointype |= ltorj; iNewParent = pSubSrc->a[i].iCursor; @@ -151795,7 +152495,8 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ ** ** NAME AMBIGUITY ** -** This optimization is called the "WHERE-clause push-down optimization". +** This optimization is called the "WHERE-clause push-down optimization" +** or sometimes the "predicate push-down optimization". ** ** Do not confuse this optimization with another unrelated optimization ** with a similar name: The "MySQL push-down optimization" causes WHERE @@ -152059,10 +152760,10 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){ if( pItem->fg.isCorrelated || pItem->fg.isCte ){ return 0; } - assert( pItem->pTab!=0 ); - pTab = pItem->pTab; - assert( pItem->pSelect!=0 ); - pSub = pItem->pSelect; + assert( pItem->pSTab!=0 ); + pTab = pItem->pSTab; + assert( pItem->fg.isSubquery ); + pSub = pItem->u4.pSubq->pSelect; assert( pSub->pEList->nExpr==pTab->nCol ); for(pX=pSub; pX; pX=pX->pPrior){ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ @@ -152191,13 +152892,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ if( p->pWhere || p->pEList->nExpr!=1 || p->pSrc->nSrc!=1 - || p->pSrc->a[0].pSelect + || p->pSrc->a[0].fg.isSubquery || pAggInfo->nFunc!=1 || p->pHaving ){ return 0; } - pTab = p->pSrc->a[0].pTab; + pTab = p->pSrc->a[0].pSTab; assert( pTab!=0 ); assert( !IsView(pTab) ); if( !IsOrdinaryTable(pTab) ) return 0; @@ -152222,7 +152923,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ ** pFrom->pIndex and return SQLITE_OK. */ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ - Table *pTab = pFrom->pTab; + Table *pTab = pFrom->pSTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; assert( pTab!=0 ); @@ -152299,7 +153000,11 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0); - if( pNewSrc==0 ) return WRC_Abort; + assert( pNewSrc!=0 || pParse->nErr ); + if( pParse->nErr ){ + sqlite3SrcListDelete(db, pNewSrc); + return WRC_Abort; + } *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); @@ -152354,7 +153059,7 @@ static struct Cte *searchWith( ){ const char *zName = pItem->zName; With *p; - assert( pItem->zDatabase==0 ); + assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 ); assert( zName!=0 ); for(p=pWith; p; p=p->pOuter){ int i; @@ -152424,7 +153129,7 @@ static int resolveFromTermToCte( Cte *pCte; /* Matched CTE (or NULL if no match) */ With *pWith; /* The matching WITH */ - assert( pFrom->pTab==0 ); + assert( pFrom->pSTab==0 ); if( pParse->pWith==0 ){ /* There are no WITH clauses in the stack. No match is possible */ return 0; @@ -152434,7 +153139,8 @@ static int resolveFromTermToCte( ** go no further. */ return 0; } - if( pFrom->zDatabase!=0 ){ + assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 ); + if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){ /* The FROM term contains a schema qualifier (ex: main.t1) and so ** it cannot possibly be a CTE reference. */ return 0; @@ -152470,7 +153176,7 @@ static int resolveFromTermToCte( } if( cannotBeFunction(pParse, pFrom) ) return 2; - assert( pFrom->pTab==0 ); + assert( pFrom->pSTab==0 ); pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 2; pCteUse = pCte->pUse; @@ -152484,26 +153190,29 @@ static int resolveFromTermToCte( } pCteUse->eM10d = pCte->eM10d; } - pFrom->pTab = pTab; + pFrom->pSTab = pTab; pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; - pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); + sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1); if( db->mallocFailed ) return 2; - pFrom->pSelect->selFlags |= SF_CopyCte; - assert( pFrom->pSelect ); + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); + pSel = pFrom->u4.pSubq->pSelect; + assert( pSel!=0 ); + pSel->selFlags |= SF_CopyCte; if( pFrom->fg.isIndexedBy ){ sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); return 2; } + assert( !pFrom->fg.isIndexedBy ); pFrom->fg.isCte = 1; pFrom->u2.pCteUse = pCteUse; pCteUse->nUse++; /* Check if this is a recursive CTE. */ - pRecTerm = pSel = pFrom->pSelect; + pRecTerm = pSel; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; @@ -152511,11 +153220,13 @@ static int resolveFromTermToCte( assert( pRecTerm->pPrior!=0 ); for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; - if( pItem->zDatabase==0 - && pItem->zName!=0 + if( pItem->zName!=0 + && !pItem->fg.hadSchema + && ALWAYS( !pItem->fg.isSubquery ) + && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0) && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ - pItem->pTab = pTab; + pItem->pSTab = pTab; pTab->nTabRef++; pItem->fg.isRecursive = 1; if( pRecTerm->selFlags & SF_Recursive ){ @@ -152617,11 +153328,14 @@ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){ ** SQLITE_NOMEM. */ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ - Select *pSel = pFrom->pSelect; + Select *pSel; Table *pTab; + assert( pFrom->fg.isSubquery ); + assert( pFrom->u4.pSubq!=0 ); + pSel = pFrom->u4.pSubq->pSelect; assert( pSel ); - pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); + pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); if( pTab==0 ) return SQLITE_NOMEM; pTab->nTabRef = 1; if( pFrom->zAlias ){ @@ -152741,33 +153455,35 @@ static int selectExpander(Walker *pWalker, Select *p){ */ for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab; - assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); - if( pFrom->pTab ) continue; + assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 ); + if( pFrom->pSTab ) continue; assert( pFrom->fg.isRecursive==0 ); if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY - Select *pSel = pFrom->pSelect; + Select *pSel; + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 ); + pSel = pFrom->u4.pSubq->pSelect; /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); - assert( pFrom->pTab==0 ); + assert( pFrom->pSTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; #endif #ifndef SQLITE_OMIT_CTE }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ if( rc>1 ) return WRC_Abort; - pTab = pFrom->pTab; + pTab = pFrom->pSTab; assert( pTab!=0 ); #endif }else{ /* An ordinary table or view name in the FROM clause */ - assert( pFrom->pTab==0 ); - pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); + assert( pFrom->pSTab==0 ); + pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; if( pTab->nTabRef>=0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); - pFrom->pTab = 0; + pFrom->pSTab = 0; return WRC_Abort; } pTab->nTabRef++; @@ -152779,7 +153495,7 @@ static int selectExpander(Walker *pWalker, Select *p){ i16 nCol; u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; - assert( pFrom->pSelect==0 ); + assert( pFrom->fg.isSubquery==0 ); if( IsView(pTab) ){ if( (db->flags & SQLITE_EnableView)==0 && pTab->pSchema!=db->aDb[1].pSchema @@ -152787,7 +153503,7 @@ static int selectExpander(Walker *pWalker, Select *p){ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", pTab->zName); } - pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); + sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) @@ -152803,7 +153519,9 @@ static int selectExpander(Walker *pWalker, Select *p){ nCol = pTab->nCol; pTab->nCol = -1; pWalker->eCode = 1; /* Turn on Select.selId renumbering */ - sqlite3WalkSelect(pWalker, pFrom->pSelect); + if( pFrom->fg.isSubquery ){ + sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect); + } pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } @@ -152890,7 +153608,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ int nAdd; /* Number of cols including rowid */ - Table *pTab = pFrom->pTab; /* Table for this data source */ + Table *pTab = pFrom->pSTab; /* Table for this data source */ ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ char *zTabName; /* AS name for this data source */ const char *zSchemaName = 0; /* Schema name for this data source */ @@ -152901,10 +153619,11 @@ static int selectExpander(Walker *pWalker, Select *p){ zTabName = pTab->zName; } if( db->mallocFailed ) break; - assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) ); + assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) ); if( pFrom->fg.isNestedFrom ){ - assert( pFrom->pSelect!=0 ); - pNestedFrom = pFrom->pSelect->pEList; + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); + assert( pFrom->u4.pSubq->pSelect!=0 ); + pNestedFrom = pFrom->u4.pSubq->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); @@ -153143,14 +153862,12 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ assert( (p->selFlags & SF_Resolved) ); pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ - Table *pTab = pFrom->pTab; + Table *pTab = pFrom->pSTab; assert( pTab!=0 ); - if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ + if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){ /* A sub-query in the FROM clause of a SELECT */ - Select *pSel = pFrom->pSelect; - if( pSel ){ - sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); - } + Select *pSel = pFrom->u4.pSubq->pSelect; + sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); } } } @@ -153464,6 +154181,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); + if( pParse->nErr ) return; pList = pF->pFExpr->x.pList; if( pF->iOBTab>=0 ){ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs @@ -153673,6 +154391,7 @@ static void updateAccumulator( if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } + if( pParse->nErr ) return; } if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; @@ -153682,6 +154401,7 @@ static void updateAccumulator( } for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i)); + if( pParse->nErr ) return; } pAggInfo->directMode = 0; @@ -153797,25 +154517,28 @@ static SrcItem *isSelfJoinView( int iFirst, int iEnd /* Range of FROM-clause entries to search. */ ){ SrcItem *pItem; - assert( pThis->pSelect!=0 ); - if( pThis->pSelect->selFlags & SF_PushDown ) return 0; + Select *pSel; + assert( pThis->fg.isSubquery ); + pSel = pThis->u4.pSubq->pSelect; + assert( pSel!=0 ); + if( pSel->selFlags & SF_PushDown ) return 0; while( iFirsta[iFirst++]; - if( pItem->pSelect==0 ) continue; + if( !pItem->fg.isSubquery ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; - assert( pItem->pTab!=0 ); - assert( pThis->pTab!=0 ); - if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; + assert( pItem->pSTab!=0 ); + assert( pThis->pSTab!=0 ); + if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; - pS1 = pItem->pSelect; - if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ + pS1 = pItem->u4.pSubq->pSelect; + if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } - if( pItem->pSelect->selFlags & SF_PushDown ){ + if( pS1->selFlags & SF_PushDown ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; @@ -153859,6 +154582,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ Expr *pExpr; Expr *pCount; sqlite3 *db; + SrcItem *pFrom; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ if( p->pWhere ) return 0; @@ -153873,8 +154597,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ - pSub = p->pSrc->a[0].pSelect; - if( pSub==0 ) return 0; /* The FROM is a subquery */ + pFrom = p->pSrc->a; + if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */ + pSub = pFrom->u4.pSubq->pSelect; if( pSub->pPrior==0 ) return 0; /* Must be a compound */ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ do{ @@ -153883,7 +154608,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ assert( pSub->pHaving==0 ); /* Due to the previous */ - pSub = pSub->pPrior; /* Repeat over compound */ + pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ @@ -153891,8 +154616,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ db = pParse->db; pCount = pExpr; pExpr = 0; - pSub = p->pSrc->a[0].pSelect; - p->pSrc->a[0].pSelect = 0; + pSub = sqlite3SubqueryDetach(db, pFrom); sqlite3SrcListDelete(db, p->pSrc); p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); while( pSub ){ @@ -153937,12 +154661,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ for(i=0; inSrc; i++){ SrcItem *p1 = &pSrc->a[i]; if( p1==p0 ) continue; - if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ + if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ return 1; } - if( p1->pSelect - && (p1->pSelect->selFlags & SF_NestedFrom)!=0 - && sameSrcAlias(p0, p1->pSelect->pSrc) + if( p1->fg.isSubquery + && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 + && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc) ){ return 1; } @@ -154007,13 +154731,13 @@ static int fromClauseTermCanBeCoroutine( if( i==0 ) break; i--; pItem--; - if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ + if( pItem->fg.isSubquery ) return 0; /* (1c-i) */ } return 1; } /* -** Generate code for the SELECT statement given in the p argument. +** Generate byte-code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. @@ -154024,6 +154748,40 @@ static int fromClauseTermCanBeCoroutine( ** ** This routine does NOT free the Select structure passed in. The ** calling function needs to do that. +** +** This is a long function. The following is an outline of the processing +** steps, with tags referencing various milestones: +** +** * Resolve names and similar preparation tag-select-0100 +** * Scan of the FROM clause tag-select-0200 +** + OUTER JOIN strength reduction tag-select-0220 +** + Sub-query ORDER BY removal tag-select-0230 +** + Query flattening tag-select-0240 +** * Separate subroutine for compound-SELECT tag-select-0300 +** * WHERE-clause constant propagation tag-select-0330 +** * Count()-of-VIEW optimization tag-select-0350 +** * Scan of the FROM clause again tag-select-0400 +** + Authorize unreferenced tables tag-select-0410 +** + Predicate push-down optimization tag-select-0420 +** + Omit unused subquery columns optimization tag-select-0440 +** + Generate code to implement subqueries tag-select-0480 +** - Co-routines tag-select-0482 +** - Reuse previously computed CTE tag-select-0484 +** - REuse previously computed VIEW tag-select-0486 +** - Materialize a VIEW or CTE tag-select-0488 +** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500 +** * Set up for ORDER BY tag-select-0600 +** * Create output table tag-select-0630 +** * Prepare registers for LIMIT tag-select-0650 +** * Setup for DISTINCT tag-select-0680 +** * Generate code for non-aggregate and non-GROUP BY tag-select-0700 +** * Generate code for aggregate and/or GROUP BY tag-select-0800 +** + GROUP BY queries tag-select-0810 +** + non-GROUP BY queries tag-select-0820 +** - Special case of count() w/o GROUP BY tag-select-0821 +** - General case of non-GROUP BY aggregates tag-select-0822 +** * Sort results, as needed tag-select-0900 +** * Internal self-checks tag-select-1000 */ SQLITE_PRIVATE int sqlite3Select( Parse *pParse, /* The parser context */ @@ -154067,6 +154825,7 @@ SQLITE_PRIVATE int sqlite3Select( } #endif + /* tag-select-0100 */ assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); @@ -154118,7 +154877,7 @@ SQLITE_PRIVATE int sqlite3Select( if( sameSrcAlias(p0, p->pSrc) ){ sqlite3ErrorMsg(pParse, "target object/alias may not appear in FROM clause: %s", - p0->zAlias ? p0->zAlias : p0->pTab->zName + p0->zAlias ? p0->zAlias : p0->pSTab->zName ); goto select_end; } @@ -154153,12 +154912,13 @@ SQLITE_PRIVATE int sqlite3Select( /* Try to do various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query + ** tag-select-0200 */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; - Select *pSub = pItem->pSelect; - Table *pTab = pItem->pTab; + Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0; + Table *pTab = pItem->pSTab; /* The expander should have already created transient Table objects ** even for FROM clause elements such as subqueries that do not correspond @@ -154175,6 +154935,7 @@ SQLITE_PRIVATE int sqlite3Select( ** way that the i-th table cannot be the NULL row of a join, then ** perform the appropriate simplification. This is called ** "OUTER JOIN strength reduction" in the SQLite documentation. + ** tag-select-0220 */ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor, @@ -154245,7 +155006,8 @@ SQLITE_PRIVATE int sqlite3Select( if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); - /* If a FROM-clause subquery has an ORDER BY clause that is not + /* tag-select-0230: + ** If a FROM-clause subquery has an ORDER BY clause that is not ** really doing anything, then delete it now so that it does not ** interfere with query flattening. See the discussion at ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a @@ -154311,6 +155073,7 @@ SQLITE_PRIVATE int sqlite3Select( continue; } + /* tag-select-0240 */ if( flattenSubquery(pParse, p, i, isAgg) ){ if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ @@ -154326,7 +155089,7 @@ SQLITE_PRIVATE int sqlite3Select( #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() - ** procedure. + ** procedure. tag-select-0300 */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); @@ -154342,9 +155105,9 @@ SQLITE_PRIVATE int sqlite3Select( #endif /* Do the WHERE-clause constant propagation optimization if this is - ** a join. No need to speed time on this operation for non-join queries + ** a join. No need to spend time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in - ** sqlite3WhereBegin(). + ** sqlite3WhereBegin(). tag-select-0330 */ if( p->pWhere!=0 && p->pWhere->op==TK_AND @@ -154361,6 +155124,7 @@ SQLITE_PRIVATE int sqlite3Select( TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n")); } + /* tag-select-0350 */ if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) && countOfViewOptimization(pParse, p) ){ @@ -154368,20 +155132,26 @@ SQLITE_PRIVATE int sqlite3Select( pTabList = p->pSrc; } - /* For each term in the FROM clause, do two things: - ** (1) Authorized unreferenced tables - ** (2) Generate code for all sub-queries + /* Loop over all terms in the FROM clause and do two things for each term: + ** + ** (1) Authorize unreferenced tables + ** (2) Generate code for all sub-queries + ** + ** tag-select-0400 */ for(i=0; inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; SrcItem *pPrior; SelectDest dest; + Subquery *pSubq; Select *pSub; #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) const char *zSavedAuthContext; #endif - /* Issue SQLITE_READ authorizations with a fake column name for any + /* Authorized unreferenced tables. tag-select-0410 + ** + ** Issue SQLITE_READ authorizations with a fake column name for any ** tables that are referenced but from which no values are extracted. ** Examples of where these kinds of null SQLITE_READ authorizations ** would occur: @@ -154398,17 +155168,28 @@ SQLITE_PRIVATE int sqlite3Select( ** string for the fake column name seems safer. */ if( pItem->colUsed==0 && pItem->zName!=0 ){ - sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); + const char *zDb; + if( pItem->fg.fixedSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema); + zDb = db->aDb[iDb].zDbSName; + }else if( pItem->fg.isSubquery ){ + zDb = 0; + }else{ + zDb = pItem->u4.zDatabase; + } + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb); } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause */ - pSub = pItem->pSelect; - if( pSub==0 || pItem->addrFillSub!=0 ) continue; + if( pItem->fg.isSubquery==0 ) continue; + pSubq = pItem->u4.pSubq; + assert( pSubq!=0 ); + pSub = pSubq->pSelect; /* The code for a subquery should only be generated once. */ - assert( pItem->addrFillSub==0 ); + if( pSubq->addrFillSub!=0 ) continue; /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select @@ -154421,6 +155202,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. + ** This is the "predicate push-down optimization". tag-select-0420 */ if( OptimizationEnabled(db, SQLITE_PushDown) && (pItem->fg.isCte==0 @@ -154434,13 +155216,14 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3TreeViewSelect(0, p, 0); } #endif - assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); + assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 ); }else{ TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL ** expressions, to avoid unneeded searching and computation. + ** tag-select-0440 */ if( OptimizationEnabled(db, SQLITE_NullUnusedCols) && disableUnusedSubqueryResultColumns(pItem) @@ -154458,32 +155241,33 @@ SQLITE_PRIVATE int sqlite3Select( zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; - /* Generate code to implement the subquery + /* Generate byte-code to implement the subquery tag-select-0480 */ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ /* Implement a co-routine that will return a single row of the result - ** set on each invocation. + ** set on each invocation. tag-select-0482 */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; - pItem->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); + pSubq->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); - pItem->addrFillSub = addrTop; - sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); + pSubq->addrFillSub = addrTop; + sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = pSub->nSelectRow; + pItem->pSTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; - pItem->regResult = dest.iSdst; - sqlite3VdbeEndCoroutine(v, pItem->regReturn); + pSubq->regResult = dest.iSdst; + sqlite3VdbeEndCoroutine(v, pSubq->regReturn); + VdbeComment((v, "end %!S", pItem)); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, - ** the make the pItem->iCursor be a copy of the ephemeral table that - ** holds the result of the materialization. */ + ** then make the pItem->iCursor be a copy of the ephemeral table that + ** holds the result of the materialization. tag-select-0484 */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ @@ -154493,25 +155277,30 @@ SQLITE_PRIVATE int sqlite3Select( pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ /* This view has already been materialized by a prior entry in - ** this same FROM clause. Reuse it. */ - if( pPrior->addrFillSub ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); + ** this same FROM clause. Reuse it. tag-select-0486 */ + Subquery *pPriorSubq; + assert( pPrior->fg.isSubquery ); + pPriorSubq = pPrior->u4.pSubq; + assert( pPriorSubq!=0 ); + if( pPriorSubq->addrFillSub ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn, + pPriorSubq->addrFillSub); } sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); - pSub->nSelectRow = pPrior->pSelect->nSelectRow; + pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow; }else{ /* Materialize the view. If the view is not correlated, generate a ** subroutine to do the materialization so that subsequent uses of - ** the same view can reuse the materialization. */ + ** the same view can reuse the materialization. tag-select-0488 */ int topAddr; int onceAddr = 0; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; #endif - pItem->regReturn = ++pParse->nMem; + pSubq->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp0(v, OP_Goto); - pItem->addrFillSub = topAddr+1; + pSubq->addrFillSub = topAddr+1; pItem->fg.isMaterialized = 1; if( pItem->fg.isCorrelated==0 ){ /* If the subquery is not correlated and if we are not inside of @@ -154526,17 +155315,17 @@ SQLITE_PRIVATE int sqlite3Select( ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = pSub->nSelectRow; + pItem->pSTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); - sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); + sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ CteUse *pCteUse = pItem->u2.pCteUse; - pCteUse->addrM9e = pItem->addrFillSub; - pCteUse->regRtn = pItem->regReturn; + pCteUse->addrM9e = pSubq->addrFillSub; + pCteUse->regRtn = pSubq->regReturn; pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } @@ -154562,7 +155351,9 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and + /* tag-select-0500 + ** + ** 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 ** can be rewritten as a GROUP BY. In other words, this: ** @@ -154612,7 +155403,7 @@ SQLITE_PRIVATE int sqlite3Select( ** If that is the case, then the OP_OpenEphemeral instruction will be ** changed to an OP_Noop once we figure out that the sorting index is ** not needed. The sSort.addrSortIndex variable is used to facilitate - ** that change. + ** that change. tag-select-0600 */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; @@ -154629,6 +155420,7 @@ SQLITE_PRIVATE int sqlite3Select( } /* If the output is destined for a temporary table, open that table. + ** tag-select-0630 */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); @@ -154646,7 +155438,7 @@ SQLITE_PRIVATE int sqlite3Select( } } - /* Set the limiter. + /* Set the limiter. tag-select-0650 */ iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ @@ -154658,7 +155450,7 @@ SQLITE_PRIVATE int sqlite3Select( sSort.sortFlags |= SORTFLAG_UseSorter; } - /* Open an ephemeral index to use for the distinct set. + /* Open an ephemeral index to use for the distinct set. tag-select-0680 */ if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; @@ -154673,7 +155465,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( !isAgg && pGroupBy==0 ){ - /* No aggregate functions and no GROUP BY clause */ + /* No aggregate functions and no GROUP BY clause. tag-select-0700 */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) | (p->selFlags & SF_FixedLimit); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -154746,8 +155538,8 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3WhereEnd(pWInfo); } }else{ - /* This case when there exist aggregate functions or a GROUP BY clause - ** or both */ + /* This case is for when there exist aggregate functions or a GROUP BY + ** clause or both. tag-select-0800 */ 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 */ @@ -154866,7 +155658,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Processing for aggregates with GROUP BY is very different and - ** much more complex than aggregates without a GROUP BY. + ** much more complex than aggregates without a GROUP BY. tag-select-0810 */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ @@ -155065,7 +155857,10 @@ SQLITE_PRIVATE int sqlite3Select( if( iOrderByCol ){ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); - if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN ){ + if( ALWAYS(pBase!=0) + && pBase->op!=TK_AGG_COLUMN + && pBase->op!=TK_REGISTER + ){ sqlite3ExprToRegister(pX, iAMem+j); } } @@ -155160,9 +155955,12 @@ SQLITE_PRIVATE int sqlite3Select( } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { + /* Aggregate functions without GROUP BY. tag-select-0820 */ Table *pTab; if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ - /* If isSimpleCount() returns a pointer to a Table structure, then + /* tag-select-0821 + ** + ** If isSimpleCount() returns a pointer to a Table structure, then ** the SQL statement is of the form: ** ** SELECT count(*) FROM @@ -155221,6 +156019,8 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else{ + /* The general case of an aggregate query without GROUP BY + ** tag-select-0822 */ int regAcc = 0; /* "populate accumulators" flag */ ExprList *pDistinct = 0; u16 distFlag = 0; @@ -155309,7 +156109,7 @@ SQLITE_PRIVATE int sqlite3Select( } /* If there is an ORDER BY clause, then we need to sort the results - ** and send them to the callback one by one. + ** and send them to the callback one by one. tag-select-0900 */ if( sSort.pOrderBy ){ assert( p->pEList==pEList ); @@ -155332,6 +156132,7 @@ SQLITE_PRIVATE int sqlite3Select( assert( db->mallocFailed==0 || pParse->nErr!=0 ); sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG + /* Internal self-checks. tag-select-1000 */ if( pAggInfo && !db->mallocFailed ){ #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20 ){ @@ -155721,8 +156522,10 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( ** name on pTableName if we are reparsing out of the schema table */ if( db->init.busy && iDb!=1 ){ - sqlite3DbFree(db, pTableName->a[0].zDatabase); - pTableName->a[0].zDatabase = 0; + assert( pTableName->a[0].fg.fixedSchema==0 ); + assert( pTableName->a[0].fg.isSubquery==0 ); + sqlite3DbFree(db, pTableName->a[0].u4.zDatabase); + pTableName->a[0].u4.zDatabase = 0; } /* If the trigger name was unqualified, and the table is a temp table, @@ -156200,7 +157003,8 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) } assert( pName->nSrc==1 ); - zDb = pName->a[0].zDatabase; + assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 ); + zDb = pName->a[0].u4.zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ @@ -156437,7 +157241,9 @@ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( Schema *pSchema = pStep->pTrig->pSchema; pSrc->a[0].zName = zName; if( pSchema!=db->aDb[1].pSchema ){ - pSrc->a[0].pSchema = pSchema; + assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 ); + pSrc->a[0].u4.pSchema = pSchema; + pSrc->a[0].fg.fixedSchema = 1; } if( pStep->pFrom ){ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); @@ -156550,7 +157356,7 @@ static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){ pSrc = pSelect->pSrc; assert( pSrc!=0 ); for(i=0; inSrc; i++){ - if( pSrc->a[i].pTab==pWalker->u.pTab ){ + if( pSrc->a[i].pSTab==pWalker->u.pTab ){ testcase( pSelect->selFlags & SF_Correlated ); pSelect->selFlags |= SF_Correlated; pWalker->eCode = 1; @@ -156621,7 +157427,7 @@ static void codeReturningTrigger( sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); sSelect.pSrc = &sFrom; sFrom.nSrc = 1; - sFrom.a[0].pTab = pTab; + sFrom.a[0].pSTab = pTab; sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); @@ -157332,7 +158138,7 @@ static void updateFromSelect( Expr *pLimit2 = 0; ExprList *pOrderBy2 = 0; sqlite3 *db = pParse->db; - Table *pTab = pTabList->a[0].pTab; + Table *pTab = pTabList->a[0].pSTab; SrcList *pSrc; Expr *pWhere2; int eDest; @@ -157356,8 +158162,8 @@ static void updateFromSelect( if( pSrc ){ assert( pSrc->a[0].fg.notCte ); pSrc->a[0].iCursor = -1; - pSrc->a[0].pTab->nTabRef--; - pSrc->a[0].pTab = 0; + pSrc->a[0].pSTab->nTabRef--; + pSrc->a[0].pSTab = 0; } if( pPk ){ for(i=0; inKeyCol; i++){ @@ -158616,7 +159422,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( int nClause = 0; /* Counter of ON CONFLICT clauses */ assert( pTabList->nSrc==1 ); - assert( pTabList->a[0].pTab!=0 ); + assert( pTabList->a[0].pSTab!=0 ); assert( pUpsert!=0 ); assert( pUpsert->pUpsertTarget!=0 ); @@ -158635,7 +159441,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( if( rc ) return rc; /* Check to see if the conflict target matches the rowid. */ - pTab = pTabList->a[0].pTab; + pTab = pTabList->a[0].pSTab; pTarget = pUpsert->pUpsertTarget; iCursor = pTabList->a[0].iCursor; if( HasRowid(pTab) @@ -159006,6 +159812,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( const char *zDbMain; /* Schema name of database to vacuum */ const char *zOut; /* Name of output file */ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */ + u64 iRandom; /* Random value used for zDbVacuum[] */ + char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */ + if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); @@ -159055,27 +159864,29 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( pMain = db->aDb[iDb].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); - /* Attach the temporary database as 'vacuum_db'. The synchronous pragma + /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a ** (possibly synchronous) transaction opened on the main database before ** sqlite3BtreeCopyFile() is called. ** ** An optimization would be to use a non-journaled pager. - ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but + ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but ** that actually made the VACUUM run slower. Very little journalling ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ + sqlite3_randomness(sizeof(iRandom),&iRandom); + sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom); nDb = db->nDb; - rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum); db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; - assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); + assert( strcmp(pDb->zDbSName,zDbVacuum)==0 ); pTemp = pDb->pBt; if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); @@ -159152,11 +159963,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** the contents to the temporary database. */ rc = execSqlF(db, pzErrMsg, - "SELECT'INSERT INTO vacuum_db.'||quote(name)" + "SELECT'INSERT INTO %s.'||quote(name)" "||' SELECT*FROM\"%w\".'||quote(name)" - "FROM vacuum_db.sqlite_schema " + "FROM %s.sqlite_schema " "WHERE type='table'AND coalesce(rootpage,1)>0", - zDbMain + zDbVacuum, zDbMain, zDbVacuum ); assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); db->mDbFlags &= ~DBFLAG_Vacuum; @@ -159168,11 +159979,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** from the schema table. */ rc = execSqlF(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_schema" + "INSERT INTO %s.sqlite_schema" " SELECT*FROM \"%w\".sqlite_schema" " WHERE type IN('view','trigger')" " OR(type='table'AND rootpage=0)", - zDbMain + zDbVacuum, zDbMain ); if( rc ) goto end_of_vacuum; @@ -160137,6 +160948,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; + assert( IsOrdinaryTable(pNew) ); sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); pTab->nNVCol = pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); @@ -160811,11 +161623,13 @@ struct WhereLoop { u16 nTop; /* Size of TOP vector */ u16 nDistinctCol; /* Index columns used to sort for DISTINCT */ Index *pIndex; /* Index used, or NULL */ + ExprList *pOrderBy; /* ORDER BY clause if this is really a subquery */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */ u32 bOmitOffset : 1; /* True to let virtual table handle offset */ + u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */ i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ @@ -161199,9 +162013,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( const WhereInfo *pWInfo, /* WHERE clause */ const WhereLevel *pLevel /* Bloom filter on this level */ ); +SQLITE_PRIVATE void sqlite3WhereAddExplainText( + Parse *pParse, /* Parse context */ + int addr, + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +); #else # define sqlite3WhereExplainOneScan(u,v,w,x) 0 # define sqlite3WhereExplainBloomFilter(u,v,w) 0 +# define sqlite3WhereAddExplainText(u,v,w,x,y) #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -161304,7 +162126,8 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); #define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ #define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ #define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ - /* 0x02000000 -- available for reuse */ +#define WHERE_COROUTINE 0x02000000 /* Implemented by co-routine. + ** NB: False-negatives are possible */ #define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */ #endif /* !defined(SQLITE_WHEREINT_H) */ @@ -161402,38 +162225,38 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ } /* -** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG -** was defined at compile-time. If it is not a no-op, a single OP_Explain -** opcode is added to the output to describe the table scan strategy in pLevel. -** -** If an OP_Explain opcode is added to the VM, its address is returned. -** Otherwise, if no OP_Explain is coded, zero is returned. +** This function sets the P4 value of an existing OP_Explain opcode to +** text describing the loop in pLevel. If the OP_Explain opcode already has +** a P4 value, it is freed before it is overwritten. */ -SQLITE_PRIVATE int sqlite3WhereExplainOneScan( +SQLITE_PRIVATE void sqlite3WhereAddExplainText( Parse *pParse, /* Parse context */ + int addr, /* Address of OP_Explain opcode */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ - int ret = 0; #if !defined(SQLITE_DEBUG) if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) #endif { + VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr); + SrcItem *pItem = &pTabList->a[pLevel->iFrom]; - Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) char *zMsg; /* Text to add to EQP output */ +#endif StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ + if( db->mallocFailed ) return; + pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) @@ -161449,7 +162272,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( assert( pLoop->u.btree.pIndex!=0 ); pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); - if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ + if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){ if( isSearch ){ zFmt = "PRIMARY KEY"; } @@ -161457,7 +162280,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; - }else if( flags & WHERE_IDX_ONLY ){ + }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ zFmt = "COVERING INDEX %s"; }else{ zFmt = "INDEX %s"; @@ -161492,7 +162315,9 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ - sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", + sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX "); + sqlite3_str_appendf(&str, + pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif @@ -161507,11 +162332,50 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( sqlite3_str_append(&str, " (~1 row)", 9); } #endif +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) zMsg = sqlite3StrAccumFinish(&str); sqlite3ExplainBreakpoint("",zMsg); - ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), - pParse->addrExplain, pLoop->rRun, - zMsg, P4_DYNAMIC); +#endif + + assert( pOp->opcode==OP_Explain ); + assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 ); + sqlite3DbFree(db, pOp->p4.z); + pOp->p4type = P4_DYNAMIC; + pOp->p4.z = sqlite3StrAccumFinish(&str); + } +} + + +/* +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN +** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG +** was defined at compile-time. If it is not a no-op, a single OP_Explain +** opcode is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. +*/ +SQLITE_PRIVATE int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +){ + int ret = 0; +#if !defined(SQLITE_DEBUG) + if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) +#endif + { + if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + ){ + Vdbe *v = pParse->pVdbe; + int addr = sqlite3VdbeCurrentAddr(v); + ret = sqlite3VdbeAddOp3( + v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun + ); + sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags); + } } return ret; } @@ -161546,7 +162410,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); pLoop = pLevel->pWLoop; if( pLoop->wsFlags & WHERE_IPK ){ - const Table *pTab = pItem->pTab; + const Table *pTab = pItem->pSTab; if( pTab->iPKey>=0 ){ sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); }else{ @@ -161609,8 +162473,11 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); } }else{ - int addr = pSrclist->a[pLvl->iFrom].addrFillSub; - VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); + int addr; + VdbeOp *pOp; + assert( pSrclist->a[pLvl->iFrom].fg.isSubquery ); + addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub; + pOp = sqlite3VdbeGetOp(v, addr-1); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); @@ -162746,7 +163613,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; - VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); + VdbeModuleComment((v, "Begin WHERE-loop%d: %s", + iLevel, pTabItem->pSTab->zName)); #if WHERETRACE_ENABLED /* 0x4001 */ if( sqlite3WhereTrace & 0x1 ){ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", @@ -162801,11 +163669,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ - int regYield = pTabItem->regReturn; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); + int regYield; + Subquery *pSubq; + assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 ); + pSubq = pTabItem->u4.pSubq; + regYield = pSubq->regReturn; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pSTab->zName)); pLevel->op = OP_Goto; }else @@ -163534,7 +164406,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ - Table *pTab = pTabItem->pTab; + Table *pTab = pTabItem->pSTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); @@ -163993,7 +164865,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** least once. This is accomplished by storing the PK for the row in ** both the iMatch index and the regBloom Bloom filter. */ - pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; + pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab; if( HasRowid(pTab) ){ r = sqlite3GetTempRange(pParse, 2); sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); @@ -164100,7 +164972,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( Bitmask mAll = 0; int k; - ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); + ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName)); sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn, pRJ->regReturn); for(k=0; kpTabList->a[pWInfo->a[k].iFrom]; mAll |= pWInfo->a[k].pWLoop->maskSelf; if( pRight->fg.viaCoroutine ){ + Subquery *pSubq; + assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 ); + pSubq = pRight->u4.pSubq; + assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 ); sqlite3VdbeAddOp3( - v, OP_Null, 0, pRight->regResult, - pRight->regResult + pRight->pSelect->pEList->nExpr-1 + v, OP_Null, 0, pSubq->regResult, + pSubq->regResult + pSubq->pSelect->pEList->nExpr-1 ); } sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); @@ -164150,7 +165026,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( int nPk; int jmp; int addrCont = sqlite3WhereContinueLabel(pSubWInfo); - Table *pTab = pTabItem->pTab; + Table *pTab = pTabItem->pSTab; if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); nPk = 1; @@ -164401,12 +165277,26 @@ static int isLikeOrGlob( z = (u8*)pRight->u.zToken; } if( z ){ - - /* Count the number of prefix characters prior to the first wildcard */ + /* Count the number of prefix bytes prior to the first wildcard. + ** or U+fffd character. If the underlying database has a UTF16LE + ** encoding, then only consider ASCII characters. Note that the + ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in + ** this code, but the database engine itself might be processing + ** content using a different encoding. */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; - if( c==wc[3] && z[cnt]!=0 ) cnt++; + if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){ + cnt++; + }else if( c>=0x80 ){ + const u8 *z2 = z+cnt-1; + if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){ + cnt--; + break; + }else{ + cnt = (int)(z2-z); + } + } } /* The optimization is possible only if (1) the pattern does not begin @@ -164417,11 +165307,11 @@ static int isLikeOrGlob( ** range search. The third is because the caller assumes that the pattern ** consists of at least one character after all escapes have been ** removed. */ - if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){ + if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){ Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ - *pisComplete = c==wc[0] && z[cnt+1]==0; + *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE; /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); @@ -165140,7 +166030,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ if( ALWAYS(pSrc!=0) ){ int i; for(i=0; inSrc; i++){ - mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); + if( pSrc->a[i].fg.isSubquery ){ + mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect); + } if( pSrc->a[i].fg.isUsing==0 ){ mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn); } @@ -165178,7 +166070,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2( int iCur; do{ iCur = pFrom->a[j].iCursor; - for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr==0 ) continue; for(i=0; inKeyCol; i++){ if( pIdx->aiColumn[i]!=XN_EXPR ) continue; @@ -165222,7 +166114,7 @@ static int exprMightBeIndexed( for(i=0; inSrc; i++){ Index *pIdx; - for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr ){ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); } @@ -165810,7 +166702,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */ if( p->pGroupBy==0 && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ - && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ + && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */ ){ ExprList *pOrderBy = p->pOrderBy; int iCsr = p->pSrc->a[0].iCursor; @@ -166031,7 +166923,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( Expr *pColRef; Expr *pTerm; if( pItem->fg.isTabFunc==0 ) return; - pTab = pItem->pTab; + pTab = pItem->pSTab; assert( pTab!=0 ); pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; @@ -166715,7 +167607,7 @@ static int isDistinctRedundant( ** clause is redundant. */ if( pTabList->nSrc!=1 ) return 0; iBase = pTabList->a[0].iCursor; - pTab = pTabList->a[0].pTab; + pTab = pTabList->a[0].pSTab; /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the @@ -166790,6 +167682,12 @@ static void translateColumnToCopy( VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); if( pParse->db->mallocFailed ) return; +#ifdef SQLITE_DEBUG + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ + printf("CHECKING for column-to-copy on cursor %d for %d..%d\n", + iTabCur, iStart, iEnd); + } +#endif for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ @@ -166973,10 +167871,10 @@ static int termCanDriveIndex( assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); leftCol = pTerm->u.x.leftColumn; if( leftCol<0 ) return 0; - aff = pSrc->pTab->aCol[leftCol].affinity; + aff = pSrc->pSTab->aCol[leftCol].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); - return columnIsGoodIndexCandidate(pSrc->pTab, leftCol); + return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol); } #endif @@ -167084,7 +167982,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( nKeyCol = 0; pTabList = pWC->pWInfo->pTabList; pSrc = &pTabList->a[pLevel->iFrom]; - pTable = pSrc->pTab; + pTable = pSrc->pSTab; pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; @@ -167226,12 +168124,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex( /* Fill the automatic index with content */ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); if( pSrc->fg.viaCoroutine ){ - int regYield = pSrc->regReturn; + int regYield; + Subquery *pSubq; + assert( pSrc->fg.isSubquery ); + pSubq = pSrc->u4.pSubq; + assert( pSubq!=0 ); + regYield = pSubq->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of %s", pSrc->pTab->zName)); + VdbeComment((v, "next row of %s", pSrc->pSTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } @@ -167253,11 +168156,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex( sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pSrc->fg.viaCoroutine ){ + assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 ); sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, - pSrc->regResult, pLevel->iIdxCur); + pSrc->u4.pSubq->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pSrc->fg.viaCoroutine = 0; }else{ @@ -167348,7 +168252,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( iSrc = pLevel->iFrom; pItem = &pTabList->a[iSrc]; assert( pItem!=0 ); - pTab = pItem->pTab; + pTab = pItem->pSTab; assert( pTab!=0 ); sz = sqlite3LogEstToInt(pTab->nRowLogEst); if( sz<10000 ){ @@ -167379,7 +168283,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( int r1 = sqlite3GetTempRange(pParse, n); int jj; for(jj=0; jjpTable==pItem->pTab ); + assert( pIdx->pTable==pItem->pSTab ); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); } sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); @@ -167460,7 +168364,7 @@ static sqlite3_index_info *allocateIndexInfo( WhereClause *p; assert( pSrc!=0 ); - pTab = pSrc->pTab; + pTab = pSrc->pSTab; assert( pTab!=0 ); assert( IsVirtual(pTab) ); @@ -167566,6 +168470,19 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->aConstraint = pIdxCons; pIdxInfo->aOrderBy = pIdxOrderBy; pIdxInfo->aConstraintUsage = pUsage; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; + if( HasRowid(pTab)==0 ){ + /* Ensure that all bits associated with PK columns are set. This is to + ** ensure they are available for cases like RIGHT joins or OR loops. */ + Index *pPk = sqlite3PrimaryKeyIndex((Table*)pTab); + assert( pPk!=0 ); + for(i=0; inKeyCol; i++){ + int iCol = pPk->aiColumn[i]; + assert( iCol>=0 ); + if( iCol>=BMS-1 ) iCol = BMS-1; + pIdxInfo->colUsed |= MASKBIT(iCol); + } + } pHidden->pWC = pWC; pHidden->pParse = pParse; pHidden->eDistinct = eDistinct; @@ -167682,9 +168599,11 @@ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ - sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; + sqlite3_vtab *pVtab; + assert( IsVirtual(pTab) ); + pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; whereTraceIndexInfoInputs(p, pTab); pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); @@ -168455,7 +169374,7 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; SrcItem *pItem = pWInfo->pTabList->a + p->iTab; - Table *pTab = pItem->pTab; + Table *pTab = pItem->pSTab; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); @@ -168627,7 +169546,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** and Y has additional constraints that might speed the search that X lacks ** but the cost of running X is not more than the cost of running Y. ** -** In other words, return true if the cost relationwship between X and Y +** In other words, return true if the cost relationship between X and Y ** is inverted and needs to be adjusted. ** ** Case 1: @@ -169443,7 +170362,7 @@ static int whereLoopAddBtreeIndex( ** 2. Stepping forward in the index pNew->nOut times to find all ** additional matching entries. */ - assert( pSrc->pTab->szTabRow>0 ); + assert( pSrc->pSTab->szTabRow>0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* The pProbe->szIdxRow is low for an IPK table since the interior ** pages are small. Thus szIdxRow gives a good estimate of seek cost. @@ -169451,7 +170370,7 @@ static int whereLoopAddBtreeIndex( ** under-estimate the scanning cost. */ rCostIdx = pNew->nOut + 16; }else{ - rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow; } rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx); @@ -169916,9 +170835,9 @@ static int whereLoopAddBtree( pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; - pTab = pSrc->pTab; + pTab = pSrc->pSTab; pWC = pBuilder->pWC; - assert( !IsVirtual(pSrc->pTab) ); + assert( !IsVirtual(pSrc->pSTab) ); if( pSrc->fg.isIndexedBy ){ assert( pSrc->fg.isCte==0 ); @@ -169943,7 +170862,7 @@ static int whereLoopAddBtree( sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; - pFirst = pSrc->pTab->pIndex; + pFirst = pSrc->pSTab->pIndex; if( pSrc->fg.notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ @@ -170033,6 +170952,7 @@ static int whereLoopAddBtree( pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; + pNew->u.btree.pOrderBy = 0; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ @@ -170062,6 +170982,10 @@ static int whereLoopAddBtree( #endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); + if( pSrc->fg.isSubquery ){ + if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; + pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; + } rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -170099,7 +171023,9 @@ static int whereLoopAddBtree( " according to whereIsCoveringIndex()\n", pProbe->zName)); } } - }else if( m==0 ){ + }else if( m==0 + && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) + ){ WHERETRACE(0x200, ("-> %s a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); @@ -170281,11 +171207,10 @@ static int whereLoopAddVirtualOne( pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; - pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; pHidden->mHandleIn = 0; /* Invoke the virtual table xBestIndex() method */ - rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); + rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo); if( rc ){ if( rc==SQLITE_CONSTRAINT ){ /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means @@ -170315,7 +171240,7 @@ static int whereLoopAddVirtualOne( || pNew->aLTerm[iTerm]!=0 || pIdxCons->usable==0 ){ - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); freeIdxStr(pIdxInfo); return SQLITE_ERROR; } @@ -170378,7 +171303,7 @@ static int whereLoopAddVirtualOne( if( pNew->aLTerm[i]==0 ){ /* The non-zero argvIdx values must be contiguous. Raise an ** error if they are not */ - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); freeIdxStr(pIdxInfo); return SQLITE_ERROR; } @@ -170390,6 +171315,7 @@ static int whereLoopAddVirtualOne( pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? pIdxInfo->nOrderBy : 0); + pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0; pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); @@ -170580,7 +171506,7 @@ static int whereLoopAddVirtual( pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; - assert( IsVirtual(pSrc->pTab) ); + assert( IsVirtual(pSrc->pSTab) ); p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; @@ -170594,7 +171520,7 @@ static int whereLoopAddVirtual( } /* First call xBestIndex() with all constraints usable. */ - WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); + WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName)); WHERETRACE(0x800, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry @@ -170676,7 +171602,7 @@ static int whereLoopAddVirtual( } freeIndexInfo(pParse->db, p); - WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); + WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc)); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -170748,7 +171674,7 @@ static int whereLoopAddOr( } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pItem->pTab) ){ + if( IsVirtual(pItem->pSTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif @@ -170862,7 +171788,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pItem->pTab) ){ + if( IsVirtual(pItem->pSTab) ){ SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_OUTER|JT_CROSS)) ){ @@ -170894,6 +171820,97 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ return rc; } +/* Implementation of the order-by-subquery optimization: +** +** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really +** a subquery or CTE that has an ORDER BY clause. See if any of the terms +** in the subquery ORDER BY clause will satisfy pOrderBy from the outer +** query. Mark off all satisfied terms (by setting bits in *pOBSat) and +** return TRUE if they do. If not, return false. +** +** Example: +** +** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b)); +** CREATE TABLE t2(x,y); +** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y) +** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b; +** +** The CTE named "t3" comes out in the natural order of "p", so the first +** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3" +** and sorting only needs to occur on the second term "b". +** +** Limitations: +** +** (1) The optimization is not applied if the outer ORDER BY contains +** a COLLATE clause. The optimization might be applied if the +** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as +** long as the subquery ORDER BY does the same. But if the +** outer ORDER BY uses COLLATE, even a redundant COLLATE, the +** optimization is bypassed. +** +** (2) The subquery ORDER BY terms must exactly match subquery result +** columns, including any COLLATE annotations. This routine relies +** on iOrderByCol to do matching between order by terms and result +** columns, and iOrderByCol will not be set if the result column +** and ORDER BY collations differ. +** +** (3) The subquery and outer ORDER BY can be in opposite directions as +** long as the subquery is materialized. If the subquery is +** implemented as a co-routine, the sort orders must be in the same +** direction because there is no way to run a co-routine backwards. +*/ +static SQLITE_NOINLINE int wherePathMatchSubqueryOB( + WhereInfo *pWInfo, /* The WHERE clause */ + WhereLoop *pLoop, /* The nested loop term that is a subquery */ + int iLoop, /* Which level of the nested loop. 0==outermost */ + int iCur, /* Cursor used by the this loop */ + ExprList *pOrderBy, /* The ORDER BY clause on the whole query */ + Bitmask *pRevMask, /* When loops need to go in reverse order */ + Bitmask *pOBSat /* Which terms of pOrderBy are satisfied so far */ +){ + int iOB; /* Index into pOrderBy->a[] */ + int jSub; /* Index into pSubOB->a[] */ + u8 rev = 0; /* True if iOB and jSub sort in opposite directions */ + u8 revIdx = 0; /* Sort direction for jSub */ + Expr *pOBExpr; /* Current term of outer ORDER BY */ + ExprList *pSubOB; /* Complete ORDER BY on the subquery */ + + pSubOB = pLoop->u.btree.pOrderBy; + assert( pSubOB!=0 ); + for(iOB=0; (MASKBIT(iOB) & *pOBSat)!=0; iOB++){} + for(jSub=0; jSubnExpr && iOBnExpr; jSub++, iOB++){ + if( pSubOB->a[jSub].u.x.iOrderByCol==0 ) break; + pOBExpr = pOrderBy->a[iOB].pExpr; + if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) break; + if( pOBExpr->iTable!=iCur ) break; + if( pOBExpr->iColumn!=pSubOB->a[jSub].u.x.iOrderByCol-1 ) break; + if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + u8 sfOB = pOrderBy->a[iOB].fg.sortFlags; /* sortFlags for iOB */ + u8 sfSub = pSubOB->a[jSub].fg.sortFlags; /* sortFlags for jSub */ + if( (sfSub & KEYINFO_ORDER_BIGNULL) != (sfOB & KEYINFO_ORDER_BIGNULL) ){ + break; + } + revIdx = sfSub & KEYINFO_ORDER_DESC; + if( jSub>0 ){ + if( (rev^revIdx)!=(sfOB & KEYINFO_ORDER_DESC) ){ + break; + } + }else{ + rev = revIdx ^ (sfOB & KEYINFO_ORDER_DESC); + if( rev ){ + if( (pLoop->wsFlags & WHERE_COROUTINE)!=0 ){ + /* Cannot run a co-routine in reverse order */ + break; + } + *pRevMask |= MASKBIT(iLoop); + } + } + } + *pOBSat |= MASKBIT(iOB); + } + return jSub>0; +} + /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 6th ** parameters) to see if it outputs rows in the requested ORDER BY @@ -171039,9 +172056,18 @@ static i8 wherePathSatisfiesOrderBy( if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ + if( pLoop->u.btree.pOrderBy + && OptimizationEnabled(db, SQLITE_OrderBySubq) + && wherePathMatchSubqueryOB(pWInfo,pLoop,iLoop,iCur, + pOrderBy,pRevMask, &obSat) + ){ + nColumn = 0; + isOrderDistinct = 0; + }else{ + nColumn = 1; + } pIndex = 0; nKeyCol = 0; - nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ @@ -171136,7 +172162,7 @@ static i8 wherePathSatisfiesOrderBy( } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and mark that ORDER BY term off + ** of the index and mark that ORDER BY term having been satisfied. */ isMatch = 0; for(i=0; bOnce && ipTabList->a + iLoop; sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", - pItem->zAlias ? pItem->zAlias : pItem->pTab->zName, + pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName, nDep, rDelta); } #endif @@ -171948,7 +172974,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; - pTab = pItem->pTab; + pTab = pItem->pSTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){ testcase( pItem->fg.isIndexedBy ); @@ -172138,6 +173164,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( WhereTerm *pTerm, *pEnd; SrcItem *pItem; WhereLoop *pLoop; + Bitmask m1; pLoop = pWInfo->a[i].pWLoop; pItem = &pWInfo->pTabList->a[pLoop->iTab]; if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue; @@ -172164,7 +173191,10 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( } } if( pTerm drop loop %c not used\n", pLoop->cId)); + WHERETRACE(0xffffffff,("-> omit unused FROM-clause term %c\n",pLoop->cId)); + m1 = MASKBIT(i)-1; + testcase( ((pWInfo->revMask>>1) & ~m1)!=0 ); + pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1); notReady &= ~pLoop->maskSelf; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ @@ -172211,7 +173241,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( WhereLoop *pLoop = pWInfo->a[i].pWLoop; const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; - Table *pTab = pItem->pTab; + Table *pTab = pItem->pSTab; if( (pTab->tabFlags & TF_HasStat1)==0 ) break; pTab->tabFlags |= TF_MaybeReanalyze; if( i>=1 @@ -172235,58 +173265,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } -/* -** Expression Node callback for sqlite3ExprCanReturnSubtype(). -** -** Only a function call is able to return a subtype. So if the node -** is not a function call, return WRC_Prune immediately. -** -** A function call is able to return a subtype if it has the -** SQLITE_RESULT_SUBTYPE property. -** -** Assume that every function is able to pass-through a subtype from -** one of its argument (using sqlite3_result_value()). Most functions -** are not this way, but we don't have a mechanism to distinguish those -** that are from those that are not, so assume they all work this way. -** That means that if one of its arguments is another function and that -** other function is able to return a subtype, then this function is -** able to return a subtype. -*/ -static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ - int n; - FuncDef *pDef; - sqlite3 *db; - if( pExpr->op!=TK_FUNCTION ){ - return WRC_Prune; - } - assert( ExprUseXList(pExpr) ); - db = pWalker->pParse->db; - n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; - pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ - pWalker->eCode = 1; - return WRC_Prune; - } - return WRC_Continue; -} - -/* -** Return TRUE if expression pExpr is able to return a subtype. -** -** A TRUE return does not guarantee that a subtype will be returned. -** It only indicates that a subtype return is possible. False positives -** are acceptable as they only disable an optimization. False negatives, -** on the other hand, can lead to incorrect answers. -*/ -static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ - Walker w; - memset(&w, 0, sizeof(w)); - w.pParse = pParse; - w.xExprCallback = exprNodeCanReturnSubtype; - sqlite3WalkExpr(&w, pExpr); - return w.eCode; -} - /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor @@ -172320,12 +173298,6 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( continue; } if( sqlite3ExprIsConstant(0,pExpr) ) continue; - if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){ - /* Functions that might set a subtype should not be replaced by the - ** value taken from an expression index since the index omits the - ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ - continue; - } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; @@ -172368,8 +173340,8 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){ SrcItem *pItem = &pWInfo->pTabList->a[ii]; if( !pItem->fg.isCte || pItem->u2.pCteUse->eM10d!=M10d_Yes - || NEVER(pItem->pSelect==0) - || pItem->pSelect->pOrderBy==0 + || NEVER(pItem->fg.isSubquery==0) + || pItem->u4.pSubq->pSelect->pOrderBy==0 ){ pWInfo->revMask |= MASKBIT(ii); } @@ -172859,15 +173831,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; - assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); + assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) ); if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) - && !IsVirtual(pTabList->a[0].pTab) + && !IsVirtual(pTabList->a[0].pSTab) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) && OptimizationEnabled(db, SQLITE_OnePass) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; - if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ + if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ bFordelete = OPFLAG_FORDELETE; } @@ -172885,7 +173857,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( SrcItem *pTabItem; pTabItem = &pTabList->a[pLevel->iFrom]; - pTab = pTabItem->pTab; + pTab = pTabItem->pSTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ @@ -172956,7 +173928,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( iIndexCur = pLevel->iTabCur; op = 0; }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ - Index *pJ = pTabItem->pTab->pIndex; + Index *pJ = pTabItem->pSTab->pIndex; iIndexCur = iAuxArg; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ @@ -173023,7 +173995,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); - assert( pTab==pTabItem->pTab ); + assert( pTab==pTabItem->pSTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); @@ -173062,13 +174034,18 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( wsFlags = pLevel->pWLoop->wsFlags; pSrc = &pTabList->a[pLevel->iFrom]; if( pSrc->fg.isMaterialized ){ - if( pSrc->fg.isCorrelated ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); + Subquery *pSubq; + int iOnce = 0; + assert( pSrc->fg.isSubquery ); + pSubq = pSrc->u4.pSubq; + if( pSrc->fg.isCorrelated==0 ){ + iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); }else{ - int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); - sqlite3VdbeJumpHere(v, iOnce); + iOnce = 0; } + sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub); + VdbeComment((v, "materialize %!S", pSrc)); + if( iOnce ) sqlite3VdbeJumpHere(v, iOnce); } assert( pTabList == pWInfo->pTabList ); if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){ @@ -173131,26 +174108,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } #endif -#ifdef SQLITE_DEBUG -/* -** Return true if cursor iCur is opened by instruction k of the -** bytecode. Used inside of assert() only. -*/ -static int cursorIsOpen(Vdbe *v, int iCur, int k){ - while( k>=0 ){ - VdbeOp *pOp = sqlite3VdbeGetOp(v,k--); - if( pOp->p1!=iCur ) continue; - if( pOp->opcode==OP_Close ) return 0; - if( pOp->opcode==OP_OpenRead ) return 1; - if( pOp->opcode==OP_OpenWrite ) return 1; - if( pOp->opcode==OP_OpenDup ) return 1; - if( pOp->opcode==OP_OpenAutoindex ) return 1; - if( pOp->opcode==OP_OpenEphemeral ) return 1; - } - return 0; -} -#endif /* SQLITE_DEBUG */ - /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. @@ -173301,9 +174258,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pLevel->iTabCur==pSrc->iCursor ); if( pSrc->fg.viaCoroutine ){ int m, n; - n = pSrc->regResult; - assert( pSrc->pTab!=0 ); - m = pSrc->pTab->nCol; + assert( pSrc->fg.isSubquery ); + n = pSrc->u4.pSubq->regResult; + assert( pSrc->pSTab!=0 ); + m = pSrc->pSTab->nCol; sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1); } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); @@ -173327,7 +174285,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, addr); } VdbeModuleComment((v, "End WHERE-loop%d: %s", i, - pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); + pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName)); } assert( pWInfo->nLevel<=pTabList->nSrc ); @@ -173336,7 +174294,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeOp *pOp, *pLastOp; Index *pIdx = 0; SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; - Table *pTab = pTabItem->pTab; + Table *pTab = pTabItem->pSTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; @@ -173355,9 +174313,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ */ if( pTabItem->fg.viaCoroutine ){ testcase( pParse->db->mallocFailed ); - assert( pTabItem->regResult>=0 ); + assert( pTabItem->fg.isSubquery ); + assert( pTabItem->u4.pSubq->regResult>=0 ); translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, - pTabItem->regResult, 0); + pTabItem->u4.pSubq->regResult, 0); continue; } @@ -173445,21 +174404,29 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); - }else{ - /* Unable to translate the table reference into an index - ** reference. Verify that this is harmless - that the - ** table being referenced really is open. - */ -#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - || cursorIsOpen(v,pOp->p1,k) - || pOp->opcode==OP_Offset - ); -#else - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - || cursorIsOpen(v,pOp->p1,k) - ); -#endif + }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ + if( pLoop->wsFlags & WHERE_IDX_ONLY ){ + /* An error. pLoop is supposed to be a covering index loop, + ** and yet the VM code refers to a column of the table that + ** is not part of the index. */ + sqlite3ErrorMsg(pParse, "internal query planner error"); + pParse->rc = SQLITE_INTERNAL; + }else{ + /* The WHERE_EXPRIDX flag is set by the planner when it is likely + ** that pLoop is a covering index loop, but it is not possible + ** to be 100% sure. In this case, any OP_Explain opcode + ** corresponding to this loop describes the index as a "COVERING + ** INDEX". But, pOp proves that pLoop is not actually a covering + ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the + ** text that accompanies the OP_Explain opcode, if any. */ + pLoop->wsFlags &= ~WHERE_EXPRIDX; + sqlite3WhereAddExplainText(pParse, + pLevel->addrBody-1, + pTabList, + pLevel, + pWInfo->wctrlFlags + ); + } } }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; @@ -174573,9 +175540,10 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside ** of sqlite3DbMallocRawNN() called from ** sqlite3SrcListAppend() */ - if( p->pSrc ){ + if( p->pSrc==0 ){ + sqlite3SelectDelete(db, pSub); + }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){ Table *pTab2; - p->pSrc->a[0].pSelect = pSub; p->pSrc->a[0].fg.isCorrelated = 1; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded|SF_OrderByReqd; @@ -174589,7 +175557,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; - p->pSrc->a[0].pTab = pTab; + p->pSrc->a[0].pSTab = pTab; pTab = pTab2; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3WindowExtraAggFuncDepth; @@ -174597,8 +175565,6 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ w.xSelectCallback2 = sqlite3WalkerDepthDecrease; sqlite3WalkSelect(&w, pSub); } - }else{ - sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; @@ -174885,10 +175851,15 @@ SQLITE_PRIVATE int sqlite3WindowCompare( ** and initialize registers and cursors used by sqlite3WindowCodeStep(). */ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ - int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; - Window *pMWin = pSelect->pWin; Window *pWin; - Vdbe *v = sqlite3GetVdbe(pParse); + int nEphExpr; + Window *pMWin; + Vdbe *v; + + assert( pSelect->pSrc->a[0].fg.isSubquery ); + nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr; + pMWin = pSelect->pWin; + v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); @@ -175162,6 +176133,7 @@ static void windowAggStep( int regArg; int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; + int addrIf = 0; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); @@ -175178,6 +176150,18 @@ static void windowAggStep( } regArg = reg; + if( pWin->pFilter ){ + int regTmp; + assert( ExprUseXList(pWin->pOwner) ); + assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); + assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); + addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regTmp); + } + if( pMWin->regStartRowid==0 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) @@ -175197,25 +176181,13 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ + assert( pWin->pFilter==0 ); assert( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); }else if( pFunc->xSFunc!=noopStepFunc ){ - int addrIf = 0; - if( pWin->pFilter ){ - int regTmp; - assert( ExprUseXList(pWin->pOwner) ); - assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); - assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); - addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); - VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, regTmp); - } - if( pWin->bExprArgs ){ int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; @@ -175246,8 +176218,9 @@ static void windowAggStep( if( pWin->bExprArgs ){ sqlite3ReleaseTempRange(pParse, regArg, nArg); } - if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } + + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } @@ -176285,7 +177258,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( Vdbe *v = sqlite3GetVdbe(pParse); int csrWrite; /* Cursor used to write to eph. table */ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ - int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ + int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */ int iInput; /* To iterate through sub cols */ int addrNe; /* Address of OP_Ne */ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ @@ -176739,9 +177712,9 @@ static void updateDeleteLimitError( break; } } - if( (p->selFlags & SF_MultiValue)==0 && - (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && - cnt>mxSelect + if( (p->selFlags & (SF_MultiValue|SF_Values))==0 + && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 + && cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } @@ -176855,59 +177828,59 @@ static void updateDeleteLimitError( #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_ID 9 -#define TK_CONCURRENT 10 -#define TK_COMMIT 11 -#define TK_END 12 -#define TK_ROLLBACK 13 -#define TK_SAVEPOINT 14 -#define TK_RELEASE 15 -#define TK_TO 16 -#define TK_TABLE 17 -#define TK_CREATE 18 -#define TK_IF 19 -#define TK_NOT 20 -#define TK_EXISTS 21 -#define TK_TEMP 22 -#define TK_LP 23 -#define TK_RP 24 -#define TK_AS 25 -#define TK_COMMA 26 -#define TK_WITHOUT 27 -#define TK_ABORT 28 -#define TK_ACTION 29 -#define TK_AFTER 30 -#define TK_ANALYZE 31 -#define TK_ASC 32 -#define TK_ATTACH 33 -#define TK_BEFORE 34 -#define TK_BY 35 -#define TK_CASCADE 36 -#define TK_CAST 37 -#define TK_CONFLICT 38 -#define TK_DATABASE 39 -#define TK_DESC 40 -#define TK_DETACH 41 -#define TK_EACH 42 -#define TK_EXCLUSIVE 43 -#define TK_FAIL 44 -#define TK_OR 45 -#define TK_AND 46 -#define TK_IS 47 -#define TK_ISNOT 48 -#define TK_MATCH 49 -#define TK_LIKE_KW 50 -#define TK_BETWEEN 51 -#define TK_IN 52 -#define TK_ISNULL 53 -#define TK_NOTNULL 54 -#define TK_NE 55 -#define TK_EQ 56 -#define TK_GT 57 -#define TK_LE 58 -#define TK_LT 59 -#define TK_GE 60 -#define TK_ESCAPE 61 -#define TK_COLUMNKW 62 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_COMMA 25 +#define TK_WITHOUT 26 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_EXCLUSIVE 42 +#define TK_FAIL 43 +#define TK_OR 44 +#define TK_AND 45 +#define TK_IS 46 +#define TK_ISNOT 47 +#define TK_MATCH 48 +#define TK_LIKE_KW 49 +#define TK_BETWEEN 50 +#define TK_IN 51 +#define TK_ISNULL 52 +#define TK_NOTNULL 53 +#define TK_NE 54 +#define TK_EQ 55 +#define TK_GT 56 +#define TK_LE 57 +#define TK_LT 58 +#define TK_GE 59 +#define TK_ESCAPE 60 +#define TK_COLUMNKW 61 +#define TK_CONCURRENT 62 #define TK_DO 63 #define TK_FOR 64 #define TK_IGNORE 65 @@ -177140,17 +178113,17 @@ typedef union { #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 #define YYNSTATE 587 -#define YYNRULE 410 -#define YYNRULE_WITH_ACTION 345 +#define YYNRULE 409 +#define YYNRULE_WITH_ACTION 344 #define YYNTOKEN 187 #define YY_MAX_SHIFT 586 -#define YY_MIN_SHIFTREDUCE 850 -#define YY_MAX_SHIFTREDUCE 1259 -#define YY_ERROR_ACTION 1260 -#define YY_ACCEPT_ACTION 1261 -#define YY_NO_ACTION 1262 -#define YY_MIN_REDUCE 1263 -#define YY_MAX_REDUCE 1672 +#define YY_MIN_SHIFTREDUCE 849 +#define YY_MAX_SHIFTREDUCE 1257 +#define YY_ERROR_ACTION 1258 +#define YY_ACCEPT_ACTION 1259 +#define YY_NO_ACTION 1260 +#define YY_MIN_REDUCE 1261 +#define YY_MAX_REDUCE 1669 #define YY_MIN_DSTRCTR 206 #define YY_MAX_DSTRCTR 320 /************* End control #defines *******************************************/ @@ -177235,677 +178208,644 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2379) +#define YY_ACTTAB_COUNT (2212) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 1297, 580, 1584, 580, 284, 1629, 7, 130, 127, 234, - /* 10 */ 580, 1210, 580, 1307, 580, 130, 127, 234, 580, 1300, - /* 20 */ 417, 1335, 1299, 1314, 51, 51, 51, 51, 1549, 528, - /* 30 */ 888, 1335, 989, 51, 51, 82, 82, 82, 82, 533, - /* 40 */ 990, 61, 61, 1666, 403, 137, 138, 91, 427, 1234, - /* 50 */ 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, - /* 60 */ 136, 417, 22, 22, 289, 289, 130, 127, 234, 283, - /* 70 */ 283, 1210, 561, 362, 561, 1210, 45, 577, 529, 566, - /* 80 */ 1213, 535, 577, 560, 566, 502, 137, 138, 91, 197, - /* 90 */ 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, - /* 100 */ 136, 136, 487, 1210, 134, 134, 134, 134, 133, 133, - /* 110 */ 132, 132, 132, 131, 128, 455, 1442, 385, 331, 580, - /* 120 */ 1210, 1211, 1210, 1046, 1589, 384, 1591, 6, 383, 1180, - /* 130 */ 425, 1180, 417, 1589, 548, 357, 46, 360, 112, 888, - /* 140 */ 1035, 329, 82, 82, 1034, 134, 134, 134, 134, 133, - /* 150 */ 133, 132, 132, 132, 131, 128, 455, 137, 138, 91, - /* 160 */ 261, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, - /* 170 */ 136, 136, 136, 130, 127, 234, 1034, 1034, 1036, 561, - /* 180 */ 1210, 1211, 1210, 139, 1210, 1211, 1210, 432, 443, 460, - /* 190 */ 1213, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 200 */ 131, 128, 455, 1575, 417, 1194, 492, 136, 136, 136, - /* 210 */ 136, 129, 1210, 1211, 1210, 455, 134, 134, 134, 134, - /* 220 */ 133, 133, 132, 132, 132, 131, 128, 455, 422, 137, - /* 230 */ 138, 91, 1513, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 240 */ 135, 136, 136, 136, 136, 417, 578, 96, 942, 942, - /* 250 */ 94, 48, 386, 93, 134, 134, 134, 134, 133, 133, - /* 260 */ 132, 132, 132, 131, 128, 455, 1210, 574, 574, 574, - /* 270 */ 137, 138, 91, 1575, 1234, 1234, 1069, 1072, 1059, 1059, - /* 280 */ 135, 135, 136, 136, 136, 136, 1635, 1210, 134, 134, - /* 290 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 300 */ 133, 133, 132, 132, 132, 131, 128, 455, 130, 127, - /* 310 */ 234, 136, 136, 136, 136, 1576, 417, 381, 132, 132, - /* 320 */ 132, 131, 128, 455, 427, 1056, 1056, 1070, 1073, 134, - /* 330 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 340 */ 455, 137, 138, 91, 214, 1234, 1234, 1069, 1072, 1059, - /* 350 */ 1059, 135, 135, 136, 136, 136, 136, 405, 134, 134, - /* 360 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 370 */ 1605, 182, 1025, 1175, 464, 1210, 1211, 1210, 257, 468, - /* 380 */ 44, 515, 512, 511, 544, 1577, 1175, 381, 955, 1175, - /* 390 */ 415, 510, 464, 463, 212, 294, 1210, 1211, 1210, 1060, - /* 400 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 410 */ 128, 455, 1442, 1261, 1, 1, 586, 2, 1265, 1609, - /* 420 */ 586, 2, 1265, 321, 417, 155, 348, 321, 364, 155, - /* 430 */ 289, 289, 1348, 1210, 1288, 554, 1348, 320, 571, 44, - /* 440 */ 476, 350, 543, 577, 582, 566, 582, 198, 219, 137, - /* 450 */ 138, 91, 1046, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 460 */ 135, 136, 136, 136, 136, 1288, 464, 289, 289, 1035, - /* 470 */ 1132, 289, 289, 1034, 229, 526, 441, 1286, 465, 580, - /* 480 */ 577, 368, 566, 433, 577, 1133, 566, 469, 527, 527, - /* 490 */ 562, 1025, 1210, 7, 485, 245, 320, 571, 415, 245, - /* 500 */ 1582, 1134, 82, 82, 7, 1034, 1034, 1036, 134, 134, - /* 510 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 520 */ 1210, 585, 928, 1265, 579, 289, 289, 459, 321, 417, - /* 530 */ 155, 459, 929, 516, 1194, 1210, 427, 1348, 577, 561, - /* 540 */ 566, 1210, 1210, 1211, 1210, 348, 471, 334, 563, 40, - /* 550 */ 555, 555, 580, 518, 137, 138, 91, 534, 1234, 1234, - /* 560 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, - /* 570 */ 296, 438, 289, 289, 1210, 82, 82, 274, 292, 376, - /* 580 */ 521, 371, 520, 262, 392, 577, 388, 566, 5, 367, - /* 590 */ 1210, 257, 289, 289, 515, 512, 511, 291, 421, 157, - /* 600 */ 245, 1210, 1211, 1210, 510, 577, 213, 566, 275, 382, - /* 610 */ 264, 231, 540, 134, 134, 134, 134, 133, 133, 132, - /* 620 */ 132, 132, 131, 128, 455, 1210, 1175, 539, 977, 1210, - /* 630 */ 1211, 1210, 459, 1442, 417, 453, 453, 453, 892, 1175, - /* 640 */ 452, 451, 1175, 407, 1210, 1211, 1210, 478, 1575, 1239, - /* 650 */ 1210, 1211, 1210, 502, 1241, 485, 976, 580, 415, 137, - /* 660 */ 138, 91, 1240, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 670 */ 135, 136, 136, 136, 136, 182, 1210, 485, 289, 289, - /* 680 */ 19, 19, 496, 1210, 1211, 1210, 493, 1242, 580, 1242, - /* 690 */ 3, 577, 580, 566, 1175, 430, 50, 303, 1548, 1210, - /* 700 */ 1211, 1210, 1346, 1575, 434, 551, 1284, 1175, 485, 483, - /* 710 */ 1175, 82, 82, 320, 571, 19, 19, 1623, 134, 134, - /* 720 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 730 */ 435, 299, 289, 289, 1210, 1211, 1210, 289, 289, 417, - /* 740 */ 1583, 289, 289, 885, 7, 577, 530, 566, 316, 1210, - /* 750 */ 577, 47, 566, 302, 577, 564, 566, 131, 128, 455, - /* 760 */ 1576, 232, 381, 542, 137, 138, 91, 214, 1234, 1234, - /* 770 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, - /* 780 */ 416, 289, 289, 580, 304, 1210, 1211, 1210, 402, 1255, - /* 790 */ 289, 289, 552, 552, 577, 880, 566, 7, 1575, 390, - /* 800 */ 214, 1518, 307, 577, 307, 566, 19, 19, 396, 160, - /* 810 */ 502, 908, 580, 410, 580, 1576, 580, 381, 580, 1518, - /* 820 */ 1520, 437, 491, 134, 134, 134, 134, 133, 133, 132, - /* 830 */ 132, 132, 131, 128, 455, 19, 19, 19, 19, 19, - /* 840 */ 19, 19, 19, 519, 417, 6, 49, 502, 1193, 1581, - /* 850 */ 306, 909, 442, 7, 206, 1512, 207, 868, 1210, 1211, - /* 860 */ 1210, 1155, 1664, 580, 1664, 580, 1559, 580, 1256, 137, - /* 870 */ 138, 91, 580, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 880 */ 135, 136, 136, 136, 136, 580, 82, 82, 19, 19, - /* 890 */ 82, 82, 1347, 1518, 536, 81, 81, 580, 290, 290, - /* 900 */ 238, 452, 451, 556, 111, 880, 340, 439, 82, 82, - /* 910 */ 1576, 577, 381, 566, 507, 1155, 1665, 474, 1665, 209, - /* 920 */ 82, 82, 298, 317, 475, 402, 1154, 449, 134, 134, - /* 930 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 940 */ 166, 1153, 1442, 261, 44, 450, 1250, 1230, 1242, 417, - /* 950 */ 1242, 1580, 286, 1047, 975, 7, 1175, 454, 391, 491, - /* 960 */ 1091, 10, 1132, 267, 855, 856, 857, 858, 337, 1175, - /* 970 */ 339, 550, 1175, 580, 137, 138, 91, 1133, 1234, 1234, - /* 980 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, - /* 990 */ 549, 108, 537, 1134, 580, 1153, 145, 145, 1505, 1186, - /* 1000 */ 580, 320, 571, 320, 571, 1256, 1111, 580, 1340, 1340, - /* 1010 */ 120, 422, 117, 498, 568, 554, 491, 147, 147, 1318, - /* 1020 */ 538, 989, 580, 66, 66, 1458, 580, 367, 1457, 990, - /* 1030 */ 67, 67, 580, 134, 134, 134, 134, 133, 133, 132, - /* 1040 */ 132, 132, 131, 128, 455, 21, 21, 580, 233, 53, - /* 1050 */ 53, 1186, 338, 580, 417, 68, 68, 1230, 1030, 347, - /* 1060 */ 1116, 1116, 499, 524, 377, 1602, 1230, 377, 1602, 466, - /* 1070 */ 54, 54, 580, 975, 580, 417, 69, 69, 1456, 137, - /* 1080 */ 138, 91, 267, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 1090 */ 135, 136, 136, 136, 136, 70, 70, 71, 71, 580, - /* 1100 */ 137, 138, 91, 580, 1234, 1234, 1069, 1072, 1059, 1059, - /* 1110 */ 135, 135, 136, 136, 136, 136, 305, 377, 1602, 260, - /* 1120 */ 259, 258, 72, 72, 476, 350, 73, 73, 580, 467, - /* 1130 */ 580, 1578, 580, 467, 580, 1338, 1338, 502, 134, 134, - /* 1140 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 1150 */ 580, 55, 55, 56, 56, 57, 57, 59, 59, 134, - /* 1160 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 1170 */ 455, 580, 1352, 60, 60, 580, 1230, 580, 141, 580, - /* 1180 */ 1442, 580, 1343, 580, 577, 297, 566, 580, 417, 297, - /* 1190 */ 379, 1634, 1131, 917, 74, 74, 1375, 315, 75, 75, - /* 1200 */ 76, 76, 20, 20, 77, 77, 143, 143, 536, 417, - /* 1210 */ 144, 144, 502, 137, 138, 91, 115, 1234, 1234, 1069, - /* 1220 */ 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, 436, - /* 1230 */ 580, 379, 580, 1561, 137, 138, 91, 580, 1234, 1234, - /* 1240 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, - /* 1250 */ 557, 447, 975, 78, 78, 62, 62, 355, 1289, 423, - /* 1260 */ 79, 79, 227, 414, 413, 111, 580, 227, 580, 158, - /* 1270 */ 446, 125, 134, 134, 134, 134, 133, 133, 132, 132, - /* 1280 */ 132, 131, 128, 455, 580, 461, 580, 523, 580, 63, - /* 1290 */ 63, 80, 80, 134, 134, 134, 134, 133, 133, 132, - /* 1300 */ 132, 132, 131, 128, 455, 580, 537, 64, 64, 170, - /* 1310 */ 170, 171, 171, 482, 950, 573, 423, 477, 580, 949, - /* 1320 */ 424, 184, 417, 319, 415, 489, 1113, 215, 87, 87, - /* 1330 */ 1113, 288, 231, 950, 415, 97, 218, 108, 949, 1557, - /* 1340 */ 345, 65, 65, 417, 907, 906, 233, 137, 138, 91, - /* 1350 */ 119, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, 136, - /* 1360 */ 136, 136, 136, 497, 417, 23, 538, 899, 137, 138, - /* 1370 */ 91, 975, 1234, 1234, 1069, 1072, 1059, 1059, 135, 135, - /* 1380 */ 136, 136, 136, 136, 481, 222, 161, 109, 16, 137, - /* 1390 */ 126, 91, 557, 1234, 1234, 1069, 1072, 1059, 1059, 135, - /* 1400 */ 135, 136, 136, 136, 136, 428, 134, 134, 134, 134, - /* 1410 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 221, - /* 1420 */ 580, 1229, 580, 490, 1150, 895, 404, 134, 134, 134, - /* 1430 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 580, - /* 1440 */ 293, 83, 83, 146, 146, 84, 84, 38, 134, 134, - /* 1450 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 1460 */ 479, 375, 168, 168, 580, 346, 324, 111, 580, 417, - /* 1470 */ 580, 374, 242, 532, 323, 1027, 484, 266, 266, 486, - /* 1480 */ 39, 266, 351, 300, 111, 914, 915, 148, 148, 580, - /* 1490 */ 417, 142, 142, 169, 169, 138, 91, 1098, 1234, 1234, - /* 1500 */ 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, 136, - /* 1510 */ 992, 993, 162, 162, 508, 325, 263, 91, 1038, 1234, - /* 1520 */ 1234, 1069, 1072, 1059, 1059, 135, 135, 136, 136, 136, - /* 1530 */ 136, 365, 165, 111, 111, 895, 328, 456, 1094, 222, - /* 1540 */ 263, 1387, 980, 580, 266, 580, 1386, 580, 123, 572, - /* 1550 */ 470, 4, 1159, 134, 134, 134, 134, 133, 133, 132, - /* 1560 */ 132, 132, 131, 128, 455, 575, 152, 152, 151, 151, - /* 1570 */ 149, 149, 580, 1564, 134, 134, 134, 134, 133, 133, - /* 1580 */ 132, 132, 132, 131, 128, 455, 580, 341, 1537, 580, - /* 1590 */ 244, 580, 948, 580, 125, 150, 150, 580, 1536, 494, - /* 1600 */ 945, 569, 125, 1110, 878, 1110, 159, 1098, 352, 86, - /* 1610 */ 86, 44, 88, 88, 85, 85, 52, 52, 1383, 1373, - /* 1620 */ 58, 58, 947, 1109, 125, 1109, 356, 359, 1038, 361, - /* 1630 */ 1046, 363, 1331, 1317, 1316, 1315, 121, 121, 370, 380, - /* 1640 */ 1396, 1441, 205, 1596, 122, 1369, 456, 581, 456, 1381, - /* 1650 */ 567, 1034, 1446, 503, 1296, 1287, 1275, 1274, 1276, 1616, - /* 1660 */ 401, 456, 281, 167, 237, 1366, 312, 313, 320, 571, - /* 1670 */ 343, 12, 123, 572, 295, 4, 314, 344, 301, 488, - /* 1680 */ 333, 224, 349, 1034, 1034, 1036, 1037, 35, 1428, 575, - /* 1690 */ 336, 280, 1619, 513, 373, 1433, 1432, 400, 400, 399, - /* 1700 */ 277, 397, 408, 9, 865, 228, 1314, 1509, 1508, 1250, - /* 1710 */ 270, 186, 1194, 1556, 1554, 235, 570, 239, 1378, 327, - /* 1720 */ 1247, 426, 223, 395, 96, 569, 210, 326, 1379, 220, - /* 1730 */ 195, 1377, 211, 140, 1376, 456, 92, 1423, 557, 546, - /* 1740 */ 332, 180, 188, 1416, 545, 473, 123, 572, 335, 4, - /* 1750 */ 472, 506, 190, 247, 1046, 191, 13, 1429, 241, 192, - /* 1760 */ 121, 121, 193, 575, 109, 406, 175, 495, 122, 43, - /* 1770 */ 456, 581, 456, 1435, 1434, 1034, 14, 95, 1514, 480, - /* 1780 */ 1437, 409, 199, 1503, 102, 251, 240, 501, 1525, 282, - /* 1790 */ 253, 203, 354, 504, 358, 254, 411, 1277, 255, 569, - /* 1800 */ 522, 1334, 1333, 440, 1325, 1332, 104, 1034, 1034, 1036, - /* 1810 */ 1037, 35, 1633, 546, 1632, 899, 412, 229, 547, 1304, - /* 1820 */ 1601, 418, 1303, 372, 1302, 1324, 320, 571, 1046, 1631, - /* 1830 */ 444, 445, 531, 310, 121, 121, 1194, 378, 311, 268, - /* 1840 */ 269, 448, 122, 1587, 456, 581, 456, 1586, 11, 1034, - /* 1850 */ 462, 389, 456, 116, 1357, 110, 387, 216, 1401, 1490, - /* 1860 */ 318, 541, 1356, 123, 572, 393, 4, 394, 42, 1400, - /* 1870 */ 583, 1204, 276, 278, 279, 419, 456, 185, 584, 1272, - /* 1880 */ 575, 1034, 1034, 1036, 1037, 35, 1266, 123, 572, 172, - /* 1890 */ 4, 156, 308, 1541, 1542, 851, 457, 1540, 173, 217, - /* 1900 */ 322, 236, 1108, 1539, 575, 154, 225, 226, 174, 89, - /* 1910 */ 1194, 1106, 420, 330, 187, 1229, 569, 176, 189, 243, - /* 1920 */ 931, 246, 342, 1122, 194, 177, 178, 429, 431, 196, - /* 1930 */ 546, 98, 179, 99, 1125, 545, 100, 101, 248, 249, - /* 1940 */ 569, 1121, 163, 24, 250, 1046, 1244, 353, 500, 1114, - /* 1950 */ 266, 121, 121, 200, 252, 201, 15, 867, 505, 122, - /* 1960 */ 256, 456, 581, 456, 374, 202, 1034, 509, 103, 1046, - /* 1970 */ 25, 514, 366, 26, 897, 121, 121, 954, 369, 105, - /* 1980 */ 517, 910, 309, 122, 181, 456, 581, 456, 164, 27, - /* 1990 */ 1034, 106, 525, 107, 1191, 1075, 1161, 17, 1034, 1034, - /* 2000 */ 1036, 1037, 35, 1608, 1198, 458, 1160, 285, 280, 230, - /* 2010 */ 287, 265, 204, 984, 400, 400, 399, 277, 397, 978, - /* 2020 */ 125, 865, 1034, 1034, 1036, 1037, 35, 1194, 28, 1177, - /* 2030 */ 29, 30, 31, 8, 239, 1181, 327, 1179, 1185, 1184, - /* 2040 */ 32, 1166, 41, 553, 326, 33, 456, 208, 111, 1089, - /* 2050 */ 1076, 1194, 113, 114, 1074, 1078, 34, 123, 572, 1079, - /* 2060 */ 4, 565, 118, 1130, 271, 36, 18, 941, 1039, 879, - /* 2070 */ 272, 124, 37, 398, 575, 241, 576, 273, 1624, 183, - /* 2080 */ 153, 1200, 1199, 175, 1262, 1262, 43, 1262, 1262, 1262, - /* 2090 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2100 */ 1262, 1262, 1262, 240, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2110 */ 569, 1262, 1262, 456, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2120 */ 1262, 1262, 1262, 1262, 90, 572, 1262, 4, 1262, 1262, - /* 2130 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 418, 1046, - /* 2140 */ 1262, 575, 1262, 320, 571, 121, 121, 1262, 1262, 1262, - /* 2150 */ 1262, 1262, 1262, 122, 1262, 456, 581, 456, 1198, 458, - /* 2160 */ 1034, 1262, 280, 1262, 1262, 1262, 1262, 462, 400, 400, - /* 2170 */ 399, 277, 397, 1262, 1262, 865, 1262, 569, 1262, 559, - /* 2180 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 239, 1262, - /* 2190 */ 327, 1262, 1034, 1034, 1036, 1037, 35, 1262, 326, 1262, - /* 2200 */ 1262, 1262, 1262, 456, 1262, 1262, 1046, 1262, 1262, 1262, - /* 2210 */ 1262, 1262, 121, 121, 123, 572, 1262, 4, 1262, 1262, - /* 2220 */ 122, 1194, 456, 581, 456, 1262, 1262, 1034, 1262, 241, - /* 2230 */ 1262, 575, 1262, 1262, 1262, 1262, 1262, 175, 1262, 1262, - /* 2240 */ 43, 1262, 1262, 1262, 1262, 1262, 558, 1262, 1262, 1262, - /* 2250 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 240, 1262, 1034, - /* 2260 */ 1034, 1036, 1037, 35, 1262, 1262, 1262, 569, 1262, 1262, - /* 2270 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2280 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1194, 1262, - /* 2290 */ 1262, 1262, 418, 1262, 1262, 1262, 1046, 320, 571, 1262, - /* 2300 */ 1262, 1262, 121, 121, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2310 */ 122, 1262, 456, 581, 456, 1262, 1262, 1034, 1262, 1262, - /* 2320 */ 1262, 462, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2330 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2340 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1034, - /* 2350 */ 1034, 1036, 1037, 35, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2360 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, - /* 2370 */ 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1194, + /* 0 */ 130, 127, 234, 130, 127, 234, 574, 574, 574, 580, + /* 10 */ 1294, 1259, 1, 1, 586, 2, 1263, 580, 502, 417, + /* 20 */ 585, 321, 1263, 155, 1546, 1297, 294, 321, 166, 155, + /* 30 */ 1345, 987, 51, 51, 1626, 987, 1345, 1337, 1337, 988, + /* 40 */ 82, 82, 1304, 988, 137, 138, 91, 534, 1232, 1232, + /* 50 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 60 */ 214, 288, 288, 425, 362, 288, 288, 453, 453, 453, + /* 70 */ 441, 288, 288, 405, 577, 368, 566, 540, 577, 580, + /* 80 */ 566, 1208, 288, 288, 577, 285, 566, 973, 136, 136, + /* 90 */ 136, 136, 129, 245, 491, 577, 329, 566, 275, 245, + /* 100 */ 264, 231, 19, 19, 134, 134, 134, 134, 133, 133, + /* 110 */ 132, 132, 132, 131, 128, 455, 1296, 430, 1606, 586, + /* 120 */ 2, 1263, 460, 385, 417, 459, 321, 357, 155, 360, + /* 130 */ 1111, 459, 1586, 384, 1111, 1345, 134, 134, 134, 134, + /* 140 */ 133, 133, 132, 132, 132, 131, 128, 455, 518, 137, + /* 150 */ 138, 91, 524, 1232, 1232, 1067, 1070, 1057, 1057, 135, + /* 160 */ 135, 136, 136, 136, 136, 580, 438, 1208, 497, 182, + /* 170 */ 288, 288, 274, 291, 376, 521, 371, 520, 262, 130, + /* 180 */ 127, 234, 233, 577, 367, 566, 407, 1510, 51, 51, + /* 190 */ 1208, 1209, 1208, 1178, 298, 1178, 1285, 1572, 245, 133, + /* 200 */ 133, 132, 132, 132, 131, 128, 455, 973, 1283, 134, + /* 210 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, + /* 220 */ 455, 288, 288, 132, 132, 132, 131, 128, 455, 417, + /* 230 */ 459, 1023, 476, 350, 577, 112, 566, 157, 1228, 44, + /* 240 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 250 */ 128, 455, 483, 267, 137, 138, 91, 455, 1232, 1232, + /* 260 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 270 */ 1054, 1054, 1068, 1071, 1208, 1439, 1208, 1209, 1208, 257, + /* 280 */ 580, 139, 515, 512, 511, 348, 527, 527, 1588, 580, + /* 290 */ 383, 7, 510, 487, 1173, 257, 320, 571, 515, 512, + /* 300 */ 511, 417, 1581, 51, 51, 544, 7, 1173, 510, 1574, + /* 310 */ 1173, 381, 82, 82, 134, 134, 134, 134, 133, 133, + /* 320 */ 132, 132, 132, 131, 128, 455, 137, 138, 91, 1632, + /* 330 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, + /* 340 */ 136, 136, 417, 1173, 1173, 1058, 432, 94, 1228, 561, + /* 350 */ 948, 93, 320, 571, 551, 947, 1173, 1173, 535, 1173, + /* 360 */ 1173, 1153, 1661, 543, 1661, 303, 386, 137, 138, 91, + /* 370 */ 1343, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 380 */ 136, 136, 136, 1208, 1209, 1208, 134, 134, 134, 134, + /* 390 */ 133, 133, 132, 132, 132, 131, 128, 455, 973, 421, + /* 400 */ 288, 288, 580, 1586, 548, 288, 288, 466, 136, 136, + /* 410 */ 136, 136, 542, 577, 417, 566, 1153, 1662, 577, 1662, + /* 420 */ 566, 1023, 130, 127, 234, 81, 81, 134, 134, 134, + /* 430 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 137, + /* 440 */ 138, 91, 1151, 1232, 1232, 1067, 1070, 1057, 1057, 135, + /* 450 */ 135, 136, 136, 136, 136, 580, 134, 134, 134, 134, + /* 460 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 282, + /* 470 */ 282, 1208, 580, 261, 1208, 348, 471, 334, 82, 82, + /* 480 */ 1602, 1281, 577, 496, 566, 530, 485, 493, 391, 579, + /* 490 */ 564, 82, 82, 233, 464, 82, 82, 1151, 379, 134, + /* 500 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, + /* 510 */ 455, 485, 464, 463, 214, 561, 288, 288, 973, 417, + /* 520 */ 288, 288, 396, 364, 560, 288, 288, 410, 316, 577, + /* 530 */ 1208, 566, 561, 577, 1315, 566, 45, 436, 577, 417, + /* 540 */ 566, 443, 422, 516, 137, 138, 91, 219, 1232, 1232, + /* 550 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 560 */ 1208, 382, 296, 417, 137, 138, 91, 890, 1232, 1232, + /* 570 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 580 */ 1208, 1209, 1208, 1208, 1209, 1208, 464, 299, 137, 138, + /* 590 */ 91, 485, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, + /* 600 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133, + /* 610 */ 132, 132, 132, 131, 128, 455, 283, 427, 96, 1515, + /* 620 */ 1208, 580, 539, 1208, 134, 134, 134, 134, 133, 133, + /* 630 */ 132, 132, 132, 131, 128, 455, 197, 1515, 1517, 1208, + /* 640 */ 1209, 1208, 452, 451, 82, 82, 320, 571, 134, 134, + /* 650 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 660 */ 1208, 953, 289, 289, 229, 526, 975, 302, 417, 1208, + /* 670 */ 1209, 1208, 883, 198, 1285, 577, 1208, 566, 130, 127, + /* 680 */ 234, 450, 1335, 1335, 582, 46, 582, 331, 417, 1240, + /* 690 */ 227, 1240, 1191, 137, 138, 91, 1455, 1232, 1232, 1067, + /* 700 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 44, + /* 710 */ 232, 1515, 417, 137, 138, 91, 1045, 1232, 1232, 1067, + /* 720 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 1208, + /* 730 */ 1209, 1208, 1208, 1209, 1208, 377, 1599, 137, 138, 91, + /* 740 */ 390, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 750 */ 136, 136, 136, 134, 134, 134, 134, 133, 133, 132, + /* 760 */ 132, 132, 131, 128, 455, 533, 320, 571, 580, 1208, + /* 770 */ 1209, 1208, 580, 134, 134, 134, 134, 133, 133, 132, + /* 780 */ 132, 132, 131, 128, 455, 1208, 1209, 1208, 22, 22, + /* 790 */ 1208, 145, 145, 417, 536, 19, 19, 134, 134, 134, + /* 800 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 222, + /* 810 */ 435, 580, 974, 131, 128, 455, 580, 417, 137, 138, + /* 820 */ 91, 1028, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, + /* 830 */ 136, 136, 136, 136, 147, 147, 491, 417, 1208, 66, + /* 840 */ 66, 1129, 137, 138, 91, 554, 1232, 1232, 1067, 1070, + /* 850 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 578, 44, + /* 860 */ 940, 940, 137, 138, 91, 1556, 1232, 1232, 1067, 1070, + /* 870 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 134, 134, + /* 880 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 890 */ 1558, 182, 108, 537, 1663, 403, 580, 886, 465, 1208, + /* 900 */ 1209, 1208, 134, 134, 134, 134, 133, 133, 132, 132, + /* 910 */ 132, 131, 128, 455, 1439, 1454, 320, 571, 6, 19, + /* 920 */ 19, 538, 134, 134, 134, 134, 133, 133, 132, 132, + /* 930 */ 132, 131, 128, 455, 437, 115, 347, 452, 451, 580, + /* 940 */ 1208, 580, 417, 1372, 315, 1572, 1237, 1208, 1209, 1208, + /* 950 */ 111, 1239, 562, 40, 377, 1599, 1453, 1208, 461, 1238, + /* 960 */ 555, 555, 82, 82, 82, 82, 1572, 137, 138, 91, + /* 970 */ 5, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 980 */ 136, 136, 136, 340, 1240, 433, 1240, 288, 288, 1130, + /* 990 */ 1044, 1439, 209, 48, 580, 377, 1599, 475, 580, 317, + /* 1000 */ 577, 561, 566, 1173, 1131, 528, 886, 1033, 552, 552, + /* 1010 */ 563, 1032, 1349, 7, 50, 1572, 1173, 61, 61, 1173, + /* 1020 */ 1132, 82, 82, 392, 577, 388, 566, 134, 134, 134, + /* 1030 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 1554, + /* 1040 */ 288, 288, 926, 1032, 1032, 1034, 337, 580, 339, 1208, + /* 1050 */ 1209, 1208, 927, 577, 529, 566, 417, 1573, 449, 381, + /* 1060 */ 485, 215, 434, 47, 1208, 427, 1208, 1209, 1208, 427, + /* 1070 */ 67, 67, 1192, 1631, 580, 915, 417, 3, 1573, 502, + /* 1080 */ 381, 137, 138, 91, 119, 1232, 1232, 1067, 1070, 1057, + /* 1090 */ 1057, 135, 135, 136, 136, 136, 136, 82, 82, 580, + /* 1100 */ 491, 137, 138, 91, 1044, 1232, 1232, 1067, 1070, 1057, + /* 1110 */ 1057, 135, 135, 136, 136, 136, 136, 1439, 1332, 214, + /* 1120 */ 1311, 1033, 19, 19, 1545, 1032, 1314, 1573, 1332, 381, + /* 1130 */ 338, 227, 416, 324, 454, 212, 304, 306, 866, 213, + /* 1140 */ 125, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 1150 */ 131, 128, 455, 580, 307, 580, 307, 1032, 1032, 1034, + /* 1160 */ 580, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 1170 */ 131, 128, 455, 1208, 1209, 1208, 19, 19, 19, 19, + /* 1180 */ 477, 417, 536, 19, 19, 1439, 1192, 379, 498, 1228, + /* 1190 */ 1579, 442, 554, 206, 7, 1572, 1313, 523, 207, 474, + /* 1200 */ 305, 417, 10, 345, 267, 1109, 137, 126, 91, 502, + /* 1210 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, + /* 1220 */ 136, 136, 906, 580, 948, 550, 446, 138, 91, 947, + /* 1230 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, + /* 1240 */ 136, 136, 1089, 49, 549, 878, 19, 19, 402, 1253, + /* 1250 */ 507, 402, 1152, 1184, 1509, 519, 447, 109, 160, 580, + /* 1260 */ 1580, 556, 557, 907, 7, 1211, 134, 134, 134, 134, + /* 1270 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 261, + /* 1280 */ 1502, 537, 21, 21, 141, 502, 134, 134, 134, 134, + /* 1290 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1228, + /* 1300 */ 1130, 53, 53, 580, 325, 1184, 417, 1573, 1575, 381, + /* 1310 */ 854, 855, 856, 375, 1578, 1131, 1577, 502, 7, 439, + /* 1320 */ 7, 68, 68, 374, 476, 350, 54, 54, 580, 1254, + /* 1330 */ 1344, 1132, 1254, 91, 6, 1232, 1232, 1067, 1070, 1057, + /* 1340 */ 1057, 135, 135, 136, 136, 136, 136, 456, 422, 580, + /* 1350 */ 557, 69, 69, 568, 580, 878, 580, 123, 572, 580, + /* 1360 */ 4, 580, 1340, 580, 367, 580, 1114, 1114, 499, 158, + /* 1370 */ 414, 413, 70, 70, 575, 1211, 328, 71, 71, 72, + /* 1380 */ 72, 479, 73, 73, 55, 55, 56, 56, 57, 57, + /* 1390 */ 532, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 1400 */ 131, 128, 455, 580, 300, 502, 580, 456, 580, 1286, + /* 1410 */ 423, 569, 580, 492, 580, 573, 423, 123, 572, 580, + /* 1420 */ 4, 44, 260, 259, 258, 481, 59, 59, 580, 60, + /* 1430 */ 60, 74, 74, 111, 575, 75, 75, 76, 76, 580, + /* 1440 */ 1044, 467, 20, 20, 468, 467, 121, 121, 9, 580, + /* 1450 */ 355, 77, 77, 469, 122, 415, 456, 581, 456, 580, + /* 1460 */ 221, 1032, 143, 143, 415, 297, 478, 1227, 580, 297, + /* 1470 */ 1157, 569, 144, 144, 424, 184, 482, 415, 320, 571, + /* 1480 */ 287, 231, 78, 78, 238, 546, 580, 415, 456, 580, + /* 1490 */ 545, 62, 62, 1032, 1032, 1034, 1035, 35, 123, 572, + /* 1500 */ 1044, 4, 580, 97, 218, 580, 121, 121, 242, 79, + /* 1510 */ 79, 580, 63, 63, 122, 575, 456, 581, 456, 108, + /* 1520 */ 319, 1032, 1192, 580, 489, 80, 80, 580, 64, 64, + /* 1530 */ 1248, 415, 456, 1370, 170, 170, 897, 580, 120, 580, + /* 1540 */ 117, 580, 123, 572, 580, 4, 171, 171, 538, 580, + /* 1550 */ 87, 87, 569, 1032, 1032, 1034, 1035, 35, 38, 575, + /* 1560 */ 65, 65, 83, 83, 146, 146, 546, 84, 84, 580, + /* 1570 */ 23, 547, 168, 168, 161, 1384, 16, 1148, 1383, 404, + /* 1580 */ 580, 1044, 1192, 580, 470, 580, 222, 121, 121, 580, + /* 1590 */ 293, 39, 148, 148, 580, 122, 569, 456, 581, 456, + /* 1600 */ 905, 904, 1032, 142, 142, 1561, 169, 169, 162, 162, + /* 1610 */ 546, 428, 152, 152, 346, 545, 111, 151, 151, 1025, + /* 1620 */ 484, 266, 266, 490, 323, 1044, 580, 244, 580, 341, + /* 1630 */ 580, 121, 121, 893, 1032, 1032, 1034, 1035, 35, 122, + /* 1640 */ 1096, 456, 581, 456, 580, 1534, 1032, 456, 580, 149, + /* 1650 */ 149, 150, 150, 86, 86, 912, 913, 123, 572, 486, + /* 1660 */ 4, 266, 351, 1192, 111, 990, 991, 88, 88, 1036, + /* 1670 */ 1533, 85, 85, 205, 575, 580, 494, 290, 1032, 1032, + /* 1680 */ 1034, 1035, 35, 1605, 1196, 458, 580, 508, 292, 263, + /* 1690 */ 946, 352, 125, 400, 400, 399, 277, 397, 52, 52, + /* 1700 */ 863, 1380, 365, 165, 111, 111, 456, 1192, 356, 58, + /* 1710 */ 58, 569, 1092, 239, 263, 327, 123, 572, 978, 4, + /* 1720 */ 266, 359, 943, 326, 125, 1108, 456, 1108, 1107, 876, + /* 1730 */ 1107, 159, 361, 575, 363, 1328, 90, 572, 1312, 4, + /* 1740 */ 1044, 370, 945, 893, 125, 380, 121, 121, 952, 1593, + /* 1750 */ 1096, 1393, 1438, 575, 122, 241, 456, 581, 456, 1366, + /* 1760 */ 1378, 1032, 567, 175, 1443, 503, 43, 1293, 1363, 1284, + /* 1770 */ 569, 1272, 1271, 1273, 1613, 280, 167, 312, 313, 1036, + /* 1780 */ 314, 401, 224, 240, 333, 1425, 12, 237, 336, 295, + /* 1790 */ 569, 343, 344, 1032, 1032, 1034, 1035, 35, 1620, 1044, + /* 1800 */ 349, 1430, 1429, 301, 408, 121, 121, 513, 488, 1311, + /* 1810 */ 373, 1506, 228, 122, 1505, 456, 581, 456, 418, 1044, + /* 1820 */ 1032, 1375, 1192, 320, 571, 121, 121, 1616, 570, 1376, + /* 1830 */ 1374, 395, 1248, 122, 186, 456, 581, 456, 210, 559, + /* 1840 */ 1032, 270, 1553, 211, 223, 1373, 1551, 462, 1245, 235, + /* 1850 */ 195, 426, 1032, 1032, 1034, 1035, 35, 92, 95, 558, + /* 1860 */ 96, 1511, 220, 140, 1420, 557, 332, 180, 13, 1426, + /* 1870 */ 188, 1413, 1032, 1032, 1034, 1035, 35, 335, 1196, 458, + /* 1880 */ 472, 1192, 292, 473, 190, 191, 192, 400, 400, 399, + /* 1890 */ 277, 397, 193, 506, 863, 247, 109, 1432, 406, 480, + /* 1900 */ 456, 1192, 1431, 14, 1434, 409, 199, 239, 102, 327, + /* 1910 */ 123, 572, 251, 4, 1500, 501, 495, 326, 1522, 203, + /* 1920 */ 354, 522, 281, 253, 504, 358, 254, 575, 1274, 255, + /* 1930 */ 440, 411, 1331, 1322, 104, 1330, 1329, 897, 1321, 229, + /* 1940 */ 444, 531, 445, 310, 311, 268, 269, 1630, 1598, 241, + /* 1950 */ 1629, 1301, 412, 372, 1300, 1299, 1628, 175, 1584, 1398, + /* 1960 */ 43, 378, 1583, 448, 569, 11, 1487, 389, 1397, 318, + /* 1970 */ 110, 116, 541, 42, 583, 1202, 276, 240, 278, 1354, + /* 1980 */ 279, 387, 584, 1269, 1264, 185, 1353, 216, 393, 394, + /* 1990 */ 419, 420, 172, 1044, 1538, 850, 1539, 156, 308, 121, + /* 2000 */ 121, 1537, 1536, 173, 174, 457, 89, 122, 225, 456, + /* 2010 */ 581, 456, 418, 226, 1032, 217, 236, 320, 571, 322, + /* 2020 */ 154, 1106, 1104, 330, 187, 176, 929, 189, 1227, 243, + /* 2030 */ 246, 342, 1120, 194, 177, 178, 429, 431, 196, 98, + /* 2040 */ 99, 462, 100, 101, 1123, 179, 1032, 1032, 1034, 1035, + /* 2050 */ 35, 248, 292, 249, 1119, 163, 24, 400, 400, 399, + /* 2060 */ 277, 397, 250, 353, 863, 1112, 266, 200, 500, 1242, + /* 2070 */ 252, 201, 15, 374, 865, 1192, 505, 239, 256, 327, + /* 2080 */ 202, 509, 103, 25, 895, 366, 26, 326, 514, 369, + /* 2090 */ 105, 908, 517, 309, 164, 106, 181, 1189, 525, 230, + /* 2100 */ 27, 1073, 107, 1159, 17, 204, 1158, 284, 286, 976, + /* 2110 */ 1175, 125, 1179, 265, 982, 28, 1177, 8, 1182, 241, + /* 2120 */ 1183, 29, 30, 31, 32, 1164, 41, 175, 208, 553, + /* 2130 */ 43, 111, 33, 113, 114, 1087, 1074, 1072, 1076, 34, + /* 2140 */ 1077, 565, 1128, 118, 271, 36, 18, 240, 1037, 877, + /* 2150 */ 124, 939, 37, 272, 273, 398, 576, 183, 153, 1621, + /* 2160 */ 1198, 1197, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 2170 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 2180 */ 1260, 1260, 418, 1260, 1260, 1260, 1260, 320, 571, 1260, + /* 2190 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 2200 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, + /* 2210 */ 1260, 462, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 218, 195, 313, 195, 215, 217, 317, 277, 278, 279, - /* 10 */ 195, 9, 195, 225, 195, 277, 278, 279, 195, 218, - /* 20 */ 20, 225, 218, 227, 218, 219, 218, 219, 298, 206, - /* 30 */ 9, 235, 32, 218, 219, 218, 219, 218, 219, 195, - /* 40 */ 40, 218, 219, 304, 305, 45, 46, 47, 195, 49, + /* 0 */ 277, 278, 279, 277, 278, 279, 212, 213, 214, 195, + /* 10 */ 218, 187, 188, 189, 190, 191, 192, 195, 195, 19, + /* 20 */ 190, 197, 192, 199, 298, 218, 206, 197, 23, 199, + /* 30 */ 206, 31, 218, 219, 217, 31, 206, 237, 238, 39, + /* 40 */ 218, 219, 225, 39, 44, 45, 46, 206, 48, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 60 */ 60, 20, 218, 219, 241, 242, 277, 278, 279, 241, - /* 70 */ 242, 9, 255, 17, 255, 9, 74, 254, 255, 256, - /* 80 */ 9, 264, 254, 264, 256, 195, 45, 46, 47, 23, - /* 90 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 100 */ 59, 60, 195, 9, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 114, 115, 195, 221, 265, 195, - /* 120 */ 118, 119, 120, 102, 318, 319, 318, 215, 320, 88, - /* 130 */ 240, 90, 20, 318, 319, 79, 74, 81, 26, 118, - /* 140 */ 119, 195, 218, 219, 123, 104, 105, 106, 107, 108, - /* 150 */ 109, 110, 111, 112, 113, 114, 115, 45, 46, 47, - /* 160 */ 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 170 */ 58, 59, 60, 277, 278, 279, 155, 156, 157, 255, - /* 180 */ 118, 119, 120, 71, 118, 119, 120, 266, 264, 299, - /* 190 */ 119, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 200 */ 113, 114, 115, 195, 20, 184, 294, 57, 58, 59, - /* 210 */ 60, 61, 118, 119, 120, 115, 104, 105, 106, 107, - /* 220 */ 108, 109, 110, 111, 112, 113, 114, 115, 117, 45, - /* 230 */ 46, 47, 286, 49, 50, 51, 52, 53, 54, 55, - /* 240 */ 56, 57, 58, 59, 60, 20, 136, 153, 138, 139, - /* 250 */ 25, 243, 221, 69, 104, 105, 106, 107, 108, 109, - /* 260 */ 110, 111, 112, 113, 114, 115, 9, 212, 213, 214, - /* 270 */ 45, 46, 47, 195, 49, 50, 51, 52, 53, 54, - /* 280 */ 55, 56, 57, 58, 59, 60, 232, 9, 104, 105, - /* 290 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 300 */ 108, 109, 110, 111, 112, 113, 114, 115, 277, 278, - /* 310 */ 279, 57, 58, 59, 60, 307, 20, 309, 110, 111, - /* 320 */ 112, 113, 114, 115, 195, 49, 50, 51, 52, 104, - /* 330 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 340 */ 115, 45, 46, 47, 195, 49, 50, 51, 52, 53, - /* 350 */ 54, 55, 56, 57, 58, 59, 60, 208, 104, 105, - /* 360 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 370 */ 195, 195, 75, 78, 195, 118, 119, 120, 121, 246, - /* 380 */ 83, 124, 125, 126, 89, 307, 91, 309, 110, 94, - /* 390 */ 257, 134, 213, 214, 265, 206, 118, 119, 120, 123, - /* 400 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 410 */ 114, 115, 195, 187, 188, 189, 190, 191, 192, 189, - /* 420 */ 190, 191, 192, 197, 20, 199, 129, 197, 24, 199, - /* 430 */ 241, 242, 206, 9, 195, 195, 206, 140, 141, 83, - /* 440 */ 130, 131, 147, 254, 205, 256, 207, 23, 152, 45, - /* 450 */ 46, 47, 102, 49, 50, 51, 52, 53, 54, 55, - /* 460 */ 56, 57, 58, 59, 60, 195, 287, 241, 242, 119, - /* 470 */ 13, 241, 242, 123, 167, 168, 20, 207, 122, 195, - /* 480 */ 254, 25, 256, 266, 254, 28, 256, 246, 312, 313, - /* 490 */ 206, 75, 9, 317, 195, 269, 140, 141, 257, 269, - /* 500 */ 313, 44, 218, 219, 317, 155, 156, 157, 104, 105, - /* 510 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 520 */ 9, 190, 65, 192, 195, 241, 242, 301, 197, 20, - /* 530 */ 199, 301, 75, 24, 184, 9, 195, 206, 254, 255, - /* 540 */ 256, 9, 118, 119, 120, 129, 130, 131, 264, 23, - /* 550 */ 310, 311, 195, 97, 45, 46, 47, 206, 49, 50, - /* 560 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - /* 570 */ 271, 115, 241, 242, 9, 218, 219, 121, 122, 123, - /* 580 */ 124, 125, 126, 127, 251, 254, 253, 256, 23, 133, - /* 590 */ 9, 121, 241, 242, 124, 125, 126, 23, 200, 26, - /* 600 */ 269, 118, 119, 120, 134, 254, 265, 256, 27, 195, - /* 610 */ 259, 260, 255, 104, 105, 106, 107, 108, 109, 110, - /* 620 */ 111, 112, 113, 114, 115, 9, 78, 195, 145, 118, - /* 630 */ 119, 120, 301, 195, 20, 212, 213, 214, 24, 91, - /* 640 */ 108, 109, 94, 206, 118, 119, 120, 246, 195, 117, - /* 650 */ 118, 119, 120, 195, 122, 195, 145, 195, 257, 45, - /* 660 */ 46, 47, 130, 49, 50, 51, 52, 53, 54, 55, - /* 670 */ 56, 57, 58, 59, 60, 195, 9, 195, 241, 242, - /* 680 */ 218, 219, 284, 118, 119, 120, 288, 155, 195, 157, - /* 690 */ 23, 254, 195, 256, 78, 233, 243, 206, 240, 118, - /* 700 */ 119, 120, 206, 195, 266, 89, 206, 91, 195, 272, - /* 710 */ 94, 218, 219, 140, 141, 218, 219, 143, 104, 105, - /* 720 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 730 */ 233, 271, 241, 242, 118, 119, 120, 241, 242, 20, - /* 740 */ 313, 241, 242, 24, 317, 254, 206, 256, 255, 9, - /* 750 */ 254, 243, 256, 271, 254, 206, 256, 113, 114, 115, - /* 760 */ 307, 195, 309, 147, 45, 46, 47, 195, 49, 50, - /* 770 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - /* 780 */ 208, 241, 242, 195, 271, 118, 119, 120, 23, 24, - /* 790 */ 241, 242, 312, 313, 254, 9, 256, 317, 195, 195, - /* 800 */ 195, 195, 230, 254, 232, 256, 218, 219, 203, 23, - /* 810 */ 195, 36, 195, 208, 195, 307, 195, 309, 195, 213, - /* 820 */ 214, 233, 195, 104, 105, 106, 107, 108, 109, 110, - /* 830 */ 111, 112, 113, 114, 115, 218, 219, 218, 219, 218, - /* 840 */ 219, 218, 219, 68, 20, 215, 243, 195, 24, 313, - /* 850 */ 233, 76, 233, 317, 233, 240, 233, 22, 118, 119, - /* 860 */ 120, 23, 24, 195, 26, 195, 195, 195, 103, 45, - /* 870 */ 46, 47, 195, 49, 50, 51, 52, 53, 54, 55, - /* 880 */ 56, 57, 58, 59, 60, 195, 218, 219, 218, 219, - /* 890 */ 218, 219, 240, 287, 20, 218, 219, 195, 241, 242, - /* 900 */ 16, 108, 109, 233, 26, 119, 17, 132, 218, 219, - /* 910 */ 307, 254, 309, 256, 20, 23, 24, 82, 26, 289, - /* 920 */ 218, 219, 295, 255, 294, 23, 24, 255, 104, 105, - /* 930 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 940 */ 24, 103, 195, 49, 83, 255, 62, 9, 155, 20, - /* 950 */ 157, 313, 24, 24, 26, 317, 78, 255, 281, 195, - /* 960 */ 125, 23, 13, 25, 7, 8, 9, 10, 79, 91, - /* 970 */ 81, 68, 94, 195, 45, 46, 47, 28, 49, 50, - /* 980 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - /* 990 */ 87, 117, 118, 44, 195, 103, 218, 219, 163, 96, - /* 1000 */ 195, 140, 141, 140, 141, 103, 12, 195, 237, 238, - /* 1010 */ 160, 117, 162, 266, 65, 195, 195, 218, 219, 228, - /* 1020 */ 146, 32, 195, 218, 219, 276, 195, 133, 276, 40, - /* 1030 */ 218, 219, 195, 104, 105, 106, 107, 108, 109, 110, - /* 1040 */ 111, 112, 113, 114, 115, 218, 219, 195, 120, 218, - /* 1050 */ 219, 148, 163, 195, 20, 218, 219, 119, 24, 295, - /* 1060 */ 129, 130, 131, 147, 315, 316, 9, 315, 316, 272, - /* 1070 */ 218, 219, 195, 145, 195, 20, 218, 219, 276, 45, - /* 1080 */ 46, 47, 25, 49, 50, 51, 52, 53, 54, 55, - /* 1090 */ 56, 57, 58, 59, 60, 218, 219, 218, 219, 195, - /* 1100 */ 45, 46, 47, 195, 49, 50, 51, 52, 53, 54, - /* 1110 */ 55, 56, 57, 58, 59, 60, 295, 315, 316, 129, - /* 1120 */ 130, 131, 218, 219, 130, 131, 218, 219, 195, 263, - /* 1130 */ 195, 311, 195, 267, 195, 237, 238, 195, 104, 105, - /* 1140 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 1150 */ 195, 218, 219, 218, 219, 218, 219, 218, 219, 104, - /* 1160 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 1170 */ 115, 195, 242, 218, 219, 195, 119, 195, 23, 195, - /* 1180 */ 195, 195, 240, 195, 254, 263, 256, 195, 20, 267, - /* 1190 */ 195, 24, 24, 26, 218, 219, 262, 263, 218, 219, - /* 1200 */ 218, 219, 218, 219, 218, 219, 218, 219, 20, 20, - /* 1210 */ 218, 219, 195, 45, 46, 47, 161, 49, 50, 51, - /* 1220 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 234, - /* 1230 */ 195, 195, 195, 195, 45, 46, 47, 195, 49, 50, - /* 1240 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - /* 1250 */ 147, 266, 26, 218, 219, 218, 219, 240, 210, 211, - /* 1260 */ 218, 219, 26, 108, 109, 26, 195, 26, 195, 166, - /* 1270 */ 234, 26, 104, 105, 106, 107, 108, 109, 110, 111, - /* 1280 */ 112, 113, 114, 115, 195, 195, 195, 110, 195, 218, - /* 1290 */ 219, 218, 219, 104, 105, 106, 107, 108, 109, 110, - /* 1300 */ 111, 112, 113, 114, 115, 195, 118, 218, 219, 218, - /* 1310 */ 219, 218, 219, 246, 137, 210, 211, 131, 195, 142, - /* 1320 */ 302, 303, 20, 246, 257, 20, 30, 25, 218, 219, - /* 1330 */ 34, 259, 260, 137, 257, 151, 152, 117, 142, 195, - /* 1340 */ 154, 218, 219, 20, 122, 123, 120, 45, 46, 47, - /* 1350 */ 161, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 1360 */ 58, 59, 60, 67, 20, 23, 146, 128, 45, 46, - /* 1370 */ 47, 145, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1380 */ 57, 58, 59, 60, 117, 144, 23, 151, 25, 45, - /* 1390 */ 46, 47, 147, 49, 50, 51, 52, 53, 54, 55, - /* 1400 */ 56, 57, 58, 59, 60, 63, 104, 105, 106, 107, - /* 1410 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 152, - /* 1420 */ 195, 26, 195, 118, 24, 9, 26, 104, 105, 106, - /* 1430 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 195, - /* 1440 */ 101, 218, 219, 218, 219, 218, 219, 23, 104, 105, - /* 1450 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 1460 */ 131, 123, 218, 219, 195, 24, 195, 26, 195, 20, - /* 1470 */ 195, 133, 25, 20, 135, 24, 24, 26, 26, 24, - /* 1480 */ 56, 26, 24, 154, 26, 7, 8, 218, 219, 195, - /* 1490 */ 20, 218, 219, 218, 219, 46, 47, 9, 49, 50, - /* 1500 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - /* 1510 */ 85, 86, 218, 219, 24, 195, 26, 47, 9, 49, - /* 1520 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 1530 */ 60, 24, 24, 26, 26, 119, 195, 9, 24, 144, - /* 1540 */ 26, 195, 24, 195, 26, 195, 195, 195, 20, 21, - /* 1550 */ 195, 23, 99, 104, 105, 106, 107, 108, 109, 110, - /* 1560 */ 111, 112, 113, 114, 115, 37, 218, 219, 218, 219, - /* 1570 */ 218, 219, 195, 195, 104, 105, 106, 107, 108, 109, - /* 1580 */ 110, 111, 112, 113, 114, 115, 195, 195, 195, 195, - /* 1590 */ 143, 195, 24, 195, 26, 218, 219, 195, 195, 195, - /* 1600 */ 24, 73, 26, 155, 24, 157, 26, 119, 195, 218, - /* 1610 */ 219, 83, 218, 219, 218, 219, 218, 219, 195, 261, - /* 1620 */ 218, 219, 24, 155, 26, 157, 195, 195, 119, 195, - /* 1630 */ 102, 195, 195, 228, 228, 195, 108, 109, 195, 195, - /* 1640 */ 195, 195, 258, 322, 116, 195, 118, 119, 120, 195, - /* 1650 */ 238, 123, 195, 291, 195, 195, 195, 195, 195, 195, - /* 1660 */ 193, 9, 290, 244, 300, 258, 258, 258, 140, 141, - /* 1670 */ 296, 245, 20, 21, 247, 23, 258, 248, 248, 296, - /* 1680 */ 270, 216, 247, 155, 156, 157, 158, 159, 274, 37, - /* 1690 */ 270, 5, 198, 222, 221, 274, 274, 11, 12, 13, - /* 1700 */ 14, 15, 274, 51, 18, 231, 227, 221, 221, 62, - /* 1710 */ 143, 300, 184, 202, 202, 300, 283, 31, 262, 33, - /* 1720 */ 39, 202, 245, 247, 153, 73, 251, 41, 262, 152, - /* 1730 */ 23, 262, 251, 150, 262, 9, 297, 252, 147, 87, - /* 1740 */ 251, 45, 236, 252, 92, 202, 20, 21, 251, 23, - /* 1750 */ 19, 19, 239, 201, 102, 239, 273, 275, 72, 239, - /* 1760 */ 108, 109, 239, 37, 151, 248, 80, 202, 116, 83, - /* 1770 */ 118, 119, 120, 275, 275, 123, 273, 297, 286, 248, - /* 1780 */ 236, 248, 236, 248, 160, 201, 100, 64, 293, 202, - /* 1790 */ 201, 23, 292, 223, 202, 201, 223, 202, 201, 73, - /* 1800 */ 117, 220, 220, 66, 229, 220, 23, 155, 156, 157, - /* 1810 */ 158, 159, 226, 87, 226, 128, 223, 167, 92, 220, - /* 1820 */ 316, 135, 222, 220, 220, 229, 140, 141, 102, 220, - /* 1830 */ 25, 115, 308, 285, 108, 109, 184, 223, 285, 202, - /* 1840 */ 93, 84, 116, 321, 118, 119, 120, 321, 23, 123, - /* 1850 */ 164, 202, 9, 160, 252, 149, 251, 250, 268, 280, - /* 1860 */ 282, 148, 252, 20, 21, 249, 23, 248, 26, 268, - /* 1870 */ 204, 14, 196, 196, 6, 306, 9, 303, 194, 194, - /* 1880 */ 37, 155, 156, 157, 158, 159, 194, 20, 21, 209, - /* 1890 */ 23, 224, 224, 215, 215, 4, 3, 215, 209, 23, - /* 1900 */ 165, 16, 24, 215, 37, 17, 216, 216, 209, 215, - /* 1910 */ 184, 24, 306, 141, 153, 26, 73, 132, 144, 25, - /* 1920 */ 21, 146, 17, 1, 144, 132, 132, 63, 38, 153, - /* 1930 */ 87, 56, 132, 56, 118, 92, 56, 56, 35, 143, - /* 1940 */ 73, 1, 5, 23, 117, 102, 77, 163, 42, 70, - /* 1950 */ 26, 108, 109, 70, 143, 117, 25, 21, 20, 116, - /* 1960 */ 127, 118, 119, 120, 133, 23, 123, 69, 23, 102, - /* 1970 */ 23, 69, 24, 23, 9, 108, 109, 110, 25, 23, - /* 1980 */ 98, 29, 69, 116, 38, 118, 119, 120, 24, 35, - /* 1990 */ 123, 151, 23, 26, 24, 24, 24, 23, 155, 156, - /* 2000 */ 157, 158, 159, 0, 1, 2, 99, 24, 5, 143, - /* 2010 */ 24, 35, 23, 118, 11, 12, 13, 14, 15, 145, - /* 2020 */ 26, 18, 155, 156, 157, 158, 159, 184, 35, 90, - /* 2030 */ 35, 35, 35, 46, 31, 77, 33, 88, 77, 95, - /* 2040 */ 35, 24, 23, 25, 41, 35, 9, 26, 26, 24, - /* 2050 */ 24, 184, 144, 144, 24, 24, 23, 20, 21, 12, - /* 2060 */ 23, 26, 26, 24, 23, 23, 23, 137, 24, 24, - /* 2070 */ 143, 23, 23, 16, 37, 72, 26, 143, 143, 26, - /* 2080 */ 24, 1, 1, 80, 323, 323, 83, 323, 323, 323, - /* 2090 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2100 */ 323, 323, 323, 100, 323, 323, 323, 323, 323, 323, - /* 2110 */ 73, 323, 323, 9, 323, 323, 323, 323, 323, 323, - /* 2120 */ 323, 323, 323, 323, 20, 21, 323, 23, 323, 323, - /* 2130 */ 323, 323, 323, 323, 323, 323, 323, 323, 135, 102, - /* 2140 */ 323, 37, 323, 140, 141, 108, 109, 323, 323, 323, - /* 2150 */ 323, 323, 323, 116, 323, 118, 119, 120, 1, 2, - /* 2160 */ 123, 323, 5, 323, 323, 323, 323, 164, 11, 12, - /* 2170 */ 13, 14, 15, 323, 323, 18, 323, 73, 323, 142, - /* 2180 */ 323, 323, 323, 323, 323, 323, 323, 323, 31, 323, - /* 2190 */ 33, 323, 155, 156, 157, 158, 159, 323, 41, 323, - /* 2200 */ 323, 323, 323, 9, 323, 323, 102, 323, 323, 323, - /* 2210 */ 323, 323, 108, 109, 20, 21, 323, 23, 323, 323, - /* 2220 */ 116, 184, 118, 119, 120, 323, 323, 123, 323, 72, - /* 2230 */ 323, 37, 323, 323, 323, 323, 323, 80, 323, 323, - /* 2240 */ 83, 323, 323, 323, 323, 323, 142, 323, 323, 323, - /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 100, 323, 155, - /* 2260 */ 156, 157, 158, 159, 323, 323, 323, 73, 323, 323, + /* 60 */ 195, 241, 242, 240, 16, 241, 242, 212, 213, 214, + /* 70 */ 19, 241, 242, 208, 254, 24, 256, 255, 254, 195, + /* 80 */ 256, 9, 241, 242, 254, 23, 256, 25, 56, 57, + /* 90 */ 58, 59, 60, 269, 195, 254, 195, 256, 26, 269, + /* 100 */ 259, 260, 218, 219, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 114, 115, 218, 233, 189, 190, + /* 120 */ 191, 192, 299, 221, 19, 301, 197, 79, 199, 81, + /* 130 */ 29, 301, 318, 319, 33, 206, 104, 105, 106, 107, + /* 140 */ 108, 109, 110, 111, 112, 113, 114, 115, 97, 44, + /* 150 */ 45, 46, 147, 48, 49, 50, 51, 52, 53, 54, + /* 160 */ 55, 56, 57, 58, 59, 195, 115, 9, 67, 195, + /* 170 */ 241, 242, 121, 122, 123, 124, 125, 126, 127, 277, + /* 180 */ 278, 279, 120, 254, 133, 256, 206, 286, 218, 219, + /* 190 */ 118, 119, 120, 88, 295, 90, 195, 195, 269, 108, + /* 200 */ 109, 110, 111, 112, 113, 114, 115, 145, 207, 104, + /* 210 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 220 */ 115, 241, 242, 110, 111, 112, 113, 114, 115, 19, + /* 230 */ 301, 75, 130, 131, 254, 25, 256, 25, 9, 83, + /* 240 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + /* 250 */ 114, 115, 272, 24, 44, 45, 46, 115, 48, 49, + /* 260 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 270 */ 48, 49, 50, 51, 9, 195, 118, 119, 120, 121, + /* 280 */ 195, 71, 124, 125, 126, 129, 312, 313, 318, 195, + /* 290 */ 320, 317, 134, 195, 78, 121, 140, 141, 124, 125, + /* 300 */ 126, 19, 313, 218, 219, 89, 317, 91, 134, 307, + /* 310 */ 94, 309, 218, 219, 104, 105, 106, 107, 108, 109, + /* 320 */ 110, 111, 112, 113, 114, 115, 44, 45, 46, 232, + /* 330 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 340 */ 58, 59, 19, 78, 78, 123, 266, 24, 119, 255, + /* 350 */ 137, 69, 140, 141, 89, 142, 91, 91, 264, 94, + /* 360 */ 94, 22, 23, 147, 25, 206, 221, 44, 45, 46, + /* 370 */ 206, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 380 */ 57, 58, 59, 118, 119, 120, 104, 105, 106, 107, + /* 390 */ 108, 109, 110, 111, 112, 113, 114, 115, 25, 200, + /* 400 */ 241, 242, 195, 318, 319, 241, 242, 272, 56, 57, + /* 410 */ 58, 59, 147, 254, 19, 256, 22, 23, 254, 25, + /* 420 */ 256, 75, 277, 278, 279, 218, 219, 104, 105, 106, + /* 430 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 44, + /* 440 */ 45, 46, 103, 48, 49, 50, 51, 52, 53, 54, + /* 450 */ 55, 56, 57, 58, 59, 195, 104, 105, 106, 107, + /* 460 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 241, + /* 470 */ 242, 9, 195, 48, 9, 129, 130, 131, 218, 219, + /* 480 */ 195, 206, 254, 284, 256, 206, 195, 288, 281, 195, + /* 490 */ 206, 218, 219, 120, 195, 218, 219, 103, 195, 104, + /* 500 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 510 */ 115, 195, 213, 214, 195, 255, 241, 242, 145, 19, + /* 520 */ 241, 242, 203, 23, 264, 241, 242, 208, 255, 254, + /* 530 */ 9, 256, 255, 254, 228, 256, 74, 234, 254, 19, + /* 540 */ 256, 264, 117, 23, 44, 45, 46, 152, 48, 49, + /* 550 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 560 */ 9, 195, 271, 19, 44, 45, 46, 23, 48, 49, + /* 570 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 580 */ 118, 119, 120, 118, 119, 120, 287, 271, 44, 45, + /* 590 */ 46, 195, 48, 49, 50, 51, 52, 53, 54, 55, + /* 600 */ 56, 57, 58, 59, 104, 105, 106, 107, 108, 109, + /* 610 */ 110, 111, 112, 113, 114, 115, 215, 195, 153, 195, + /* 620 */ 9, 195, 195, 9, 104, 105, 106, 107, 108, 109, + /* 630 */ 110, 111, 112, 113, 114, 115, 22, 213, 214, 118, + /* 640 */ 119, 120, 108, 109, 218, 219, 140, 141, 104, 105, + /* 650 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 660 */ 9, 110, 241, 242, 167, 168, 145, 271, 19, 118, + /* 670 */ 119, 120, 23, 22, 195, 254, 9, 256, 277, 278, + /* 680 */ 279, 255, 237, 238, 205, 74, 207, 265, 19, 155, + /* 690 */ 25, 157, 23, 44, 45, 46, 276, 48, 49, 50, + /* 700 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 83, + /* 710 */ 195, 287, 19, 44, 45, 46, 23, 48, 49, 50, + /* 720 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 118, + /* 730 */ 119, 120, 118, 119, 120, 315, 316, 44, 45, 46, + /* 740 */ 195, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 750 */ 57, 58, 59, 104, 105, 106, 107, 108, 109, 110, + /* 760 */ 111, 112, 113, 114, 115, 195, 140, 141, 195, 118, + /* 770 */ 119, 120, 195, 104, 105, 106, 107, 108, 109, 110, + /* 780 */ 111, 112, 113, 114, 115, 118, 119, 120, 218, 219, + /* 790 */ 9, 218, 219, 19, 19, 218, 219, 104, 105, 106, + /* 800 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 144, + /* 810 */ 233, 195, 145, 113, 114, 115, 195, 19, 44, 45, + /* 820 */ 46, 23, 48, 49, 50, 51, 52, 53, 54, 55, + /* 830 */ 56, 57, 58, 59, 218, 219, 195, 19, 9, 218, + /* 840 */ 219, 23, 44, 45, 46, 195, 48, 49, 50, 51, + /* 850 */ 52, 53, 54, 55, 56, 57, 58, 59, 136, 83, + /* 860 */ 138, 139, 44, 45, 46, 195, 48, 49, 50, 51, + /* 870 */ 52, 53, 54, 55, 56, 57, 58, 59, 104, 105, + /* 880 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 890 */ 195, 195, 117, 118, 304, 305, 195, 9, 122, 118, + /* 900 */ 119, 120, 104, 105, 106, 107, 108, 109, 110, 111, + /* 910 */ 112, 113, 114, 115, 195, 276, 140, 141, 215, 218, + /* 920 */ 219, 146, 104, 105, 106, 107, 108, 109, 110, 111, + /* 930 */ 112, 113, 114, 115, 233, 161, 295, 108, 109, 195, + /* 940 */ 9, 195, 19, 262, 263, 195, 117, 118, 119, 120, + /* 950 */ 25, 122, 206, 22, 315, 316, 276, 9, 195, 130, + /* 960 */ 310, 311, 218, 219, 218, 219, 195, 44, 45, 46, + /* 970 */ 22, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 980 */ 57, 58, 59, 16, 155, 266, 157, 241, 242, 12, + /* 990 */ 102, 195, 289, 243, 195, 315, 316, 294, 195, 255, + /* 1000 */ 254, 255, 256, 78, 27, 206, 118, 119, 312, 313, + /* 1010 */ 264, 123, 242, 317, 243, 195, 91, 218, 219, 94, + /* 1020 */ 43, 218, 219, 251, 254, 253, 256, 104, 105, 106, + /* 1030 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 195, + /* 1040 */ 241, 242, 65, 155, 156, 157, 79, 195, 81, 118, + /* 1050 */ 119, 120, 75, 254, 255, 256, 19, 307, 255, 309, + /* 1060 */ 195, 24, 266, 243, 9, 195, 118, 119, 120, 195, + /* 1070 */ 218, 219, 184, 23, 195, 25, 19, 22, 307, 195, + /* 1080 */ 309, 44, 45, 46, 161, 48, 49, 50, 51, 52, + /* 1090 */ 53, 54, 55, 56, 57, 58, 59, 218, 219, 195, + /* 1100 */ 195, 44, 45, 46, 102, 48, 49, 50, 51, 52, + /* 1110 */ 53, 54, 55, 56, 57, 58, 59, 195, 225, 195, + /* 1120 */ 227, 119, 218, 219, 240, 123, 228, 307, 235, 309, + /* 1130 */ 163, 25, 208, 195, 255, 265, 271, 233, 21, 265, + /* 1140 */ 25, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1150 */ 113, 114, 115, 195, 230, 195, 232, 155, 156, 157, + /* 1160 */ 195, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1170 */ 113, 114, 115, 118, 119, 120, 218, 219, 218, 219, + /* 1180 */ 131, 19, 19, 218, 219, 195, 184, 195, 266, 9, + /* 1190 */ 313, 233, 195, 233, 317, 195, 228, 110, 233, 82, + /* 1200 */ 295, 19, 22, 154, 24, 11, 44, 45, 46, 195, + /* 1210 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 1220 */ 58, 59, 35, 195, 137, 68, 234, 45, 46, 142, + /* 1230 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 1240 */ 58, 59, 125, 243, 87, 9, 218, 219, 22, 23, + /* 1250 */ 19, 22, 23, 96, 240, 68, 266, 151, 22, 195, + /* 1260 */ 313, 233, 147, 76, 317, 9, 104, 105, 106, 107, + /* 1270 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 48, + /* 1280 */ 163, 118, 218, 219, 22, 195, 104, 105, 106, 107, + /* 1290 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 119, + /* 1300 */ 12, 218, 219, 195, 195, 148, 19, 307, 311, 309, + /* 1310 */ 7, 8, 9, 123, 313, 27, 313, 195, 317, 132, + /* 1320 */ 317, 218, 219, 133, 130, 131, 218, 219, 195, 103, + /* 1330 */ 240, 43, 103, 46, 215, 48, 49, 50, 51, 52, + /* 1340 */ 53, 54, 55, 56, 57, 58, 59, 9, 117, 195, + /* 1350 */ 147, 218, 219, 65, 195, 119, 195, 19, 20, 195, + /* 1360 */ 22, 195, 240, 195, 133, 195, 129, 130, 131, 166, + /* 1370 */ 108, 109, 218, 219, 36, 119, 195, 218, 219, 218, + /* 1380 */ 219, 131, 218, 219, 218, 219, 218, 219, 218, 219, + /* 1390 */ 19, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1400 */ 113, 114, 115, 195, 154, 195, 195, 9, 195, 210, + /* 1410 */ 211, 73, 195, 294, 195, 210, 211, 19, 20, 195, + /* 1420 */ 22, 83, 129, 130, 131, 117, 218, 219, 195, 218, + /* 1430 */ 219, 218, 219, 25, 36, 218, 219, 218, 219, 195, + /* 1440 */ 102, 263, 218, 219, 246, 267, 108, 109, 50, 195, + /* 1450 */ 240, 218, 219, 246, 116, 257, 118, 119, 120, 195, + /* 1460 */ 152, 123, 218, 219, 257, 263, 246, 25, 195, 267, + /* 1470 */ 99, 73, 218, 219, 302, 303, 246, 257, 140, 141, + /* 1480 */ 259, 260, 218, 219, 15, 87, 195, 257, 9, 195, + /* 1490 */ 92, 218, 219, 155, 156, 157, 158, 159, 19, 20, + /* 1500 */ 102, 22, 195, 151, 152, 195, 108, 109, 24, 218, + /* 1510 */ 219, 195, 218, 219, 116, 36, 118, 119, 120, 117, + /* 1520 */ 246, 123, 184, 195, 19, 218, 219, 195, 218, 219, + /* 1530 */ 61, 257, 9, 261, 218, 219, 128, 195, 160, 195, + /* 1540 */ 162, 195, 19, 20, 195, 22, 218, 219, 146, 195, + /* 1550 */ 218, 219, 73, 155, 156, 157, 158, 159, 22, 36, + /* 1560 */ 218, 219, 218, 219, 218, 219, 87, 218, 219, 195, + /* 1570 */ 22, 92, 218, 219, 22, 195, 24, 23, 195, 25, + /* 1580 */ 195, 102, 184, 195, 195, 195, 144, 108, 109, 195, + /* 1590 */ 101, 55, 218, 219, 195, 116, 73, 118, 119, 120, + /* 1600 */ 122, 123, 123, 218, 219, 195, 218, 219, 218, 219, + /* 1610 */ 87, 63, 218, 219, 23, 92, 25, 218, 219, 23, + /* 1620 */ 23, 25, 25, 118, 135, 102, 195, 143, 195, 195, + /* 1630 */ 195, 108, 109, 9, 155, 156, 157, 158, 159, 116, + /* 1640 */ 9, 118, 119, 120, 195, 195, 123, 9, 195, 218, + /* 1650 */ 219, 218, 219, 218, 219, 7, 8, 19, 20, 23, + /* 1660 */ 22, 25, 23, 184, 25, 85, 86, 218, 219, 9, + /* 1670 */ 195, 218, 219, 258, 36, 195, 195, 22, 155, 156, + /* 1680 */ 157, 158, 159, 0, 1, 2, 195, 23, 5, 25, + /* 1690 */ 23, 195, 25, 10, 11, 12, 13, 14, 218, 219, + /* 1700 */ 17, 195, 23, 23, 25, 25, 9, 184, 195, 218, + /* 1710 */ 219, 73, 23, 30, 25, 32, 19, 20, 23, 22, + /* 1720 */ 25, 195, 23, 40, 25, 155, 9, 157, 155, 23, + /* 1730 */ 157, 25, 195, 36, 195, 195, 19, 20, 195, 22, + /* 1740 */ 102, 195, 23, 119, 25, 195, 108, 109, 110, 322, + /* 1750 */ 119, 195, 195, 36, 116, 72, 118, 119, 120, 195, + /* 1760 */ 195, 123, 238, 80, 195, 291, 83, 195, 258, 195, + /* 1770 */ 73, 195, 195, 195, 195, 290, 244, 258, 258, 119, + /* 1780 */ 258, 193, 216, 100, 270, 274, 245, 300, 270, 247, + /* 1790 */ 73, 296, 248, 155, 156, 157, 158, 159, 143, 102, + /* 1800 */ 247, 274, 274, 248, 274, 108, 109, 222, 296, 227, + /* 1810 */ 221, 221, 231, 116, 221, 118, 119, 120, 135, 102, + /* 1820 */ 123, 262, 184, 140, 141, 108, 109, 198, 283, 262, + /* 1830 */ 262, 247, 61, 116, 300, 118, 119, 120, 251, 142, + /* 1840 */ 123, 143, 202, 251, 245, 262, 202, 164, 38, 300, + /* 1850 */ 22, 202, 155, 156, 157, 158, 159, 297, 297, 142, + /* 1860 */ 153, 286, 152, 150, 252, 147, 251, 44, 273, 275, + /* 1870 */ 236, 252, 155, 156, 157, 158, 159, 251, 1, 2, + /* 1880 */ 18, 184, 5, 202, 239, 239, 239, 10, 11, 12, + /* 1890 */ 13, 14, 239, 18, 17, 201, 151, 275, 248, 248, + /* 1900 */ 9, 184, 275, 273, 236, 248, 236, 30, 160, 32, + /* 1910 */ 19, 20, 201, 22, 248, 64, 202, 40, 293, 22, + /* 1920 */ 292, 117, 202, 201, 223, 202, 201, 36, 202, 201, + /* 1930 */ 66, 223, 220, 229, 22, 220, 220, 128, 229, 167, + /* 1940 */ 24, 308, 115, 285, 285, 202, 93, 226, 316, 72, + /* 1950 */ 226, 220, 223, 220, 222, 220, 220, 80, 321, 268, + /* 1960 */ 83, 223, 321, 84, 73, 22, 280, 202, 268, 282, + /* 1970 */ 149, 160, 148, 25, 204, 13, 196, 100, 196, 252, + /* 1980 */ 6, 251, 194, 194, 194, 303, 252, 250, 249, 248, + /* 1990 */ 306, 306, 209, 102, 215, 4, 215, 224, 224, 108, + /* 2000 */ 109, 215, 215, 209, 209, 3, 215, 116, 216, 118, + /* 2010 */ 119, 120, 135, 216, 123, 22, 15, 140, 141, 165, + /* 2020 */ 16, 23, 23, 141, 153, 132, 20, 144, 25, 24, + /* 2030 */ 146, 16, 1, 144, 132, 132, 63, 37, 153, 55, + /* 2040 */ 55, 164, 55, 55, 118, 132, 155, 156, 157, 158, + /* 2050 */ 159, 34, 5, 143, 1, 5, 22, 10, 11, 12, + /* 2060 */ 13, 14, 117, 163, 17, 70, 25, 70, 41, 77, + /* 2070 */ 143, 117, 24, 133, 20, 184, 19, 30, 127, 32, + /* 2080 */ 22, 69, 22, 22, 9, 23, 22, 40, 69, 24, + /* 2090 */ 22, 28, 98, 69, 23, 151, 37, 23, 22, 143, + /* 2100 */ 34, 23, 25, 23, 22, 22, 99, 23, 23, 145, + /* 2110 */ 90, 25, 77, 34, 118, 34, 88, 45, 95, 72, + /* 2120 */ 77, 34, 34, 34, 34, 23, 22, 80, 25, 24, + /* 2130 */ 83, 25, 34, 144, 144, 23, 23, 23, 23, 22, + /* 2140 */ 11, 25, 23, 25, 22, 22, 22, 100, 23, 23, + /* 2150 */ 22, 137, 22, 143, 143, 15, 25, 25, 23, 143, + /* 2160 */ 1, 1, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2170 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2180 */ 323, 323, 135, 323, 323, 323, 323, 140, 141, 323, + /* 2190 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2200 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2210 */ 323, 164, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2220 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2230 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2240 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2260 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2270 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 184, 323, - /* 2290 */ 323, 323, 135, 323, 323, 323, 102, 140, 141, 323, - /* 2300 */ 323, 323, 108, 109, 323, 323, 323, 323, 323, 323, - /* 2310 */ 116, 323, 118, 119, 120, 323, 323, 123, 323, 323, - /* 2320 */ 323, 164, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2290 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2300 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2310 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2320 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2330 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 155, - /* 2350 */ 156, 157, 158, 159, 323, 323, 323, 323, 323, 323, - /* 2360 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2370 */ 323, 323, 323, 323, 323, 323, 323, 323, 184, 323, - /* 2380 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2390 */ 323, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2400 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2410 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2420 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2430 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2440 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2450 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2460 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2470 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2480 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2490 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2500 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2510 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2520 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2530 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2540 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2550 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2560 */ 187, 187, 187, 187, 187, 187, + /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 187, + /* 2350 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2360 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2370 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2380 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2390 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, }; #define YY_SHIFT_COUNT (586) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2194) +#define YY_SHIFT_MAX (2160) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 2157, 2003, 1686, 1528, 1528, 861, 297, 1652, 1726, 1843, - /* 10 */ 2194, 2194, 2194, 356, 861, 861, 861, 861, 861, 0, - /* 20 */ 0, 184, 1323, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 30 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 532, 532, - /* 40 */ 616, 616, 257, 2, 62, 740, 740, 573, 573, 573, - /* 50 */ 573, 41, 112, 225, 296, 404, 509, 614, 719, 824, - /* 60 */ 929, 1034, 1055, 1168, 1189, 1302, 1323, 1323, 1323, 1323, - /* 70 */ 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, - /* 80 */ 1323, 1323, 1323, 1323, 1344, 1323, 1449, 1470, 1470, 1867, - /* 90 */ 2037, 2104, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 100 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 110 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 120 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 130 */ 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, 2194, - /* 140 */ 2194, 2194, 150, 254, 254, 254, 254, 254, 254, 254, - /* 150 */ 87, 192, 208, 581, 740, 835, 894, 740, 740, 793, - /* 160 */ 793, 740, 644, 310, 307, 307, 307, 863, 100, 100, - /* 170 */ 2379, 2379, 456, 456, 456, 94, 66, 66, 66, 66, - /* 180 */ 457, 457, 295, 581, 838, 892, 740, 740, 740, 740, - /* 190 */ 740, 740, 740, 740, 740, 740, 740, 740, 740, 740, - /* 200 */ 740, 740, 740, 740, 740, 874, 878, 878, 740, 994, - /* 210 */ 548, 548, 1188, 1188, 71, 71, 1103, 2379, 2379, 2379, - /* 220 */ 2379, 2379, 2379, 2379, 21, 350, 350, 424, 470, 526, - /* 230 */ 278, 565, 483, 511, 667, 740, 740, 740, 740, 740, - /* 240 */ 740, 740, 740, 740, 740, 416, 740, 740, 740, 740, - /* 250 */ 740, 740, 740, 740, 740, 740, 740, 740, 775, 775, - /* 260 */ 775, 740, 740, 740, 928, 740, 740, 740, 938, 903, - /* 270 */ 740, 949, 740, 740, 740, 740, 740, 740, 740, 740, - /* 280 */ 957, 931, 1296, 110, 1057, 1057, 1057, 1057, 1226, 110, - /* 290 */ 110, 1177, 1155, 884, 1267, 1184, 1241, 1184, 1305, 1236, - /* 300 */ 1267, 1267, 1236, 1267, 1241, 1305, 1239, 1167, 111, 989, - /* 310 */ 989, 989, 1220, 1220, 1220, 1220, 1245, 1245, 850, 1395, - /* 320 */ 1196, 1363, 1647, 1647, 1567, 1567, 1681, 1681, 1567, 1571, - /* 330 */ 1577, 1707, 1583, 1591, 1696, 1583, 1591, 1731, 1731, 1731, - /* 340 */ 1731, 1567, 1732, 1613, 1577, 1577, 1613, 1707, 1696, 1613, - /* 350 */ 1696, 1613, 1567, 1732, 1624, 1723, 1567, 1732, 1768, 1567, - /* 360 */ 1732, 1567, 1732, 1768, 1683, 1683, 1683, 1737, 1783, 1783, - /* 370 */ 1768, 1683, 1687, 1683, 1737, 1683, 1683, 1650, 1805, 1716, - /* 380 */ 1716, 1768, 1567, 1747, 1747, 1757, 1757, 1583, 1591, 1825, - /* 390 */ 1567, 1693, 1583, 1706, 1713, 1613, 1842, 1857, 1857, 1868, - /* 400 */ 1868, 1868, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, - /* 410 */ 2379, 2379, 2379, 2379, 2379, 2379, 2379, 276, 889, 765, - /* 420 */ 902, 56, 990, 786, 1400, 1339, 1424, 1447, 1186, 1329, - /* 430 */ 1441, 1342, 1451, 1452, 1455, 1458, 1490, 1507, 1416, 1222, - /* 440 */ 1478, 1338, 1508, 916, 1453, 1488, 1514, 1518, 1425, 1568, - /* 450 */ 1576, 1448, 1468, 1580, 1598, 1509, 574, 1891, 1893, 1876, - /* 460 */ 1735, 1885, 1888, 1878, 1887, 1772, 1761, 1785, 1889, 1889, - /* 470 */ 1894, 1774, 1899, 1775, 1905, 1922, 1780, 1793, 1889, 1794, - /* 480 */ 1864, 1890, 1889, 1776, 1875, 1877, 1880, 1881, 1800, 1816, - /* 490 */ 1903, 1796, 1940, 1937, 1920, 1827, 1784, 1879, 1924, 1883, - /* 500 */ 1869, 1906, 1811, 1838, 1931, 1936, 1938, 1831, 1833, 1942, - /* 510 */ 1898, 1945, 1947, 1948, 1950, 1902, 1965, 1953, 1882, 1952, - /* 520 */ 1956, 1913, 1946, 1964, 1954, 1840, 1969, 1970, 1971, 1967, - /* 530 */ 1972, 1974, 1907, 1866, 1983, 1986, 1895, 1976, 1989, 1874, - /* 540 */ 1994, 1993, 1995, 1996, 1997, 1939, 1958, 1949, 1987, 1961, - /* 550 */ 1944, 2005, 2017, 2019, 2018, 2021, 2022, 2010, 1908, 1909, - /* 560 */ 2025, 1994, 2026, 2030, 2031, 2033, 2035, 2036, 2039, 2041, - /* 570 */ 2047, 2042, 2043, 2044, 2045, 2048, 2049, 2050, 1930, 1927, - /* 580 */ 1934, 1935, 2053, 2056, 2057, 2080, 2081, + /* 0 */ 1877, 1683, 2047, 1338, 1338, 626, 156, 1398, 1479, 1523, + /* 10 */ 1891, 1891, 1891, 776, 626, 626, 626, 626, 626, 0, + /* 20 */ 0, 282, 1057, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 30 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 829, 829, + /* 40 */ 265, 265, 158, 462, 611, 781, 781, 212, 212, 212, + /* 50 */ 212, 105, 210, 323, 395, 500, 520, 544, 649, 669, + /* 60 */ 693, 798, 774, 818, 923, 1037, 1057, 1057, 1057, 1057, + /* 70 */ 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, + /* 80 */ 1057, 1057, 1057, 1057, 1162, 1057, 1182, 1287, 1287, 1638, + /* 90 */ 1697, 1717, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 100 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 110 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 120 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 130 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, + /* 140 */ 1891, 1891, 32, 352, 352, 352, 352, 352, 352, 352, + /* 150 */ 136, 91, 113, 72, 781, 1117, 1231, 781, 781, 534, + /* 160 */ 534, 781, 700, 102, 497, 497, 497, 506, 142, 142, + /* 170 */ 2212, 2212, 51, 51, 51, 465, 614, 614, 614, 614, + /* 180 */ 977, 977, 216, 72, 339, 394, 781, 781, 781, 781, + /* 190 */ 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, + /* 200 */ 781, 781, 781, 781, 781, 775, 925, 925, 781, 1194, + /* 210 */ 266, 266, 1163, 1163, 1256, 1256, 1203, 2212, 2212, 2212, + /* 220 */ 2212, 2212, 2212, 2212, 888, 1002, 1002, 651, 174, 931, + /* 230 */ 551, 948, 521, 667, 1055, 781, 781, 781, 781, 781, + /* 240 */ 781, 781, 781, 781, 781, 346, 781, 781, 781, 781, + /* 250 */ 781, 781, 781, 781, 781, 781, 781, 781, 1187, 1187, + /* 260 */ 1187, 781, 781, 781, 62, 781, 781, 781, 1180, 1157, + /* 270 */ 781, 1288, 781, 781, 781, 781, 781, 781, 781, 781, + /* 280 */ 1237, 101, 722, 229, 229, 229, 229, 373, 722, 722, + /* 290 */ 1087, 1262, 1303, 1469, 1308, 1352, 665, 1352, 1505, 1106, + /* 300 */ 1308, 1308, 1106, 1308, 665, 1505, 1408, 1050, 425, 4, + /* 310 */ 4, 4, 1402, 1402, 1402, 1402, 1115, 1115, 1378, 1442, + /* 320 */ 213, 1552, 1771, 1771, 1698, 1698, 1810, 1810, 1698, 1707, + /* 330 */ 1710, 1828, 1713, 1718, 1823, 1713, 1718, 1862, 1862, 1862, + /* 340 */ 1862, 1698, 1875, 1745, 1710, 1710, 1745, 1828, 1823, 1745, + /* 350 */ 1823, 1745, 1698, 1875, 1748, 1851, 1698, 1875, 1897, 1698, + /* 360 */ 1875, 1698, 1875, 1897, 1804, 1804, 1804, 1864, 1912, 1912, + /* 370 */ 1897, 1804, 1809, 1804, 1864, 1804, 1804, 1772, 1916, 1827, + /* 380 */ 1827, 1897, 1698, 1853, 1853, 1879, 1879, 1713, 1718, 1943, + /* 390 */ 1698, 1811, 1713, 1821, 1824, 1745, 1948, 1962, 1962, 1974, + /* 400 */ 1974, 1974, 2212, 2212, 2212, 2212, 2212, 2212, 2212, 2212, + /* 410 */ 2212, 2212, 2212, 2212, 2212, 2212, 2212, 222, 967, 1226, + /* 420 */ 1229, 48, 1293, 1236, 1554, 1489, 1536, 1484, 1049, 1250, + /* 430 */ 1591, 1548, 1596, 1597, 1636, 1639, 1664, 1679, 1624, 1478, + /* 440 */ 1648, 1190, 1680, 5, 1371, 1631, 1689, 1695, 1580, 1667, + /* 450 */ 1699, 1570, 1573, 1706, 1719, 1660, 1655, 1991, 2002, 1993, + /* 460 */ 1854, 2001, 2004, 1998, 1999, 1882, 1871, 1893, 2003, 2003, + /* 470 */ 2005, 1883, 2006, 1884, 2015, 2031, 1889, 1902, 2003, 1903, + /* 480 */ 1973, 2000, 2003, 1885, 1984, 1985, 1987, 1988, 1913, 1926, + /* 490 */ 2017, 1910, 2053, 2050, 2034, 1945, 1900, 1995, 2041, 1997, + /* 500 */ 1992, 2027, 1927, 1954, 2048, 2054, 2057, 1940, 1951, 2058, + /* 510 */ 2012, 2060, 2061, 2062, 2064, 2019, 2075, 2065, 1994, 2063, + /* 520 */ 2068, 2024, 2059, 2071, 2066, 1944, 2076, 2074, 2078, 2077, + /* 530 */ 2080, 2082, 2007, 1956, 2084, 2085, 1996, 2079, 2083, 1964, + /* 540 */ 2086, 2081, 2087, 2088, 2089, 2020, 2035, 2028, 2072, 2043, + /* 550 */ 2023, 2090, 2102, 2104, 2105, 2103, 2106, 2098, 1989, 1990, + /* 560 */ 2112, 2086, 2113, 2114, 2115, 2117, 2116, 2118, 2119, 2122, + /* 570 */ 2129, 2123, 2124, 2125, 2126, 2128, 2130, 2131, 2014, 2010, + /* 580 */ 2011, 2016, 2132, 2135, 2140, 2159, 2160, }; #define YY_REDUCE_COUNT (416) -#define YY_REDUCE_MIN (-311) -#define YY_REDUCE_MAX (1699) +#define YY_REDUCE_MIN (-277) +#define YY_REDUCE_MAX (1797) static const short yy_reduce_ofst[] = { - /* 0 */ 226, 230, 331, 284, -177, 351, 437, -194, -192, -185, - /* 10 */ -183, -181, -76, 189, 491, 496, 500, 540, 549, -104, - /* 20 */ 31, -270, -211, 462, 497, 588, 617, 619, 357, 621, - /* 30 */ 623, 493, 668, 670, 672, 677, 690, 702, 179, 606, - /* 40 */ 176, 480, 572, 8, 453, 508, 603, -172, 657, -172, - /* 50 */ 657, -262, -262, -262, -262, -262, -262, -262, -262, -262, - /* 60 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -262, - /* 70 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -262, - /* 80 */ -262, -262, -262, -262, -262, -262, -262, -262, -262, -156, - /* 90 */ 778, 799, 805, 812, 827, 831, 837, 852, 858, 877, - /* 100 */ 879, 904, 908, 933, 935, 937, 939, 955, 976, 980, - /* 110 */ 982, 984, 986, 988, 992, 1035, 1037, 1042, 1071, 1073, - /* 120 */ 1089, 1091, 1093, 1110, 1123, 1223, 1225, 1227, 1244, 1269, - /* 130 */ 1273, 1275, 1294, 1348, 1350, 1352, 1377, 1391, 1394, 1396, - /* 140 */ 1398, 1402, -262, -262, -262, -262, -262, -262, -262, -262, - /* 150 */ -262, -262, -262, 239, -110, 398, -204, 78, 240, 55, - /* 160 */ 423, 605, -262, 630, 749, 752, 802, 930, -262, -262, - /* 170 */ -262, -262, -212, -212, -212, -54, 299, 460, 482, 513, - /* 180 */ 771, 898, -311, 270, -261, -261, 149, -147, 129, 341, - /* 190 */ 458, 615, 652, 942, 627, -79, 764, 217, 438, 821, - /* 200 */ 747, 1017, 995, 1036, 985, 934, 187, 427, 820, -88, - /* 210 */ 536, 638, 866, 922, 1048, 1105, 333, 1018, 133, 241, - /* 220 */ 401, 1067, 1072, 1077, -218, -199, -196, -93, 54, 175, - /* 230 */ 329, 414, 432, 566, 604, 671, 1038, 1090, 1144, 1271, - /* 240 */ 1320, 1341, 1346, 1351, 1355, 797, 1378, 1392, 1393, 1403, - /* 250 */ 1404, 1413, 1423, 1431, 1432, 1434, 1436, 1437, 791, 1405, - /* 260 */ 1406, 1440, 1443, 1444, 1358, 1445, 1446, 1450, 1384, 1321, - /* 270 */ 1454, 1412, 1457, 329, 1459, 1460, 1461, 1462, 1463, 1464, - /* 280 */ 1467, 1362, 1372, 1419, 1407, 1408, 1409, 1418, 1358, 1419, - /* 290 */ 1419, 1426, 1465, 1364, 1414, 1410, 1427, 1420, 1374, 1429, - /* 300 */ 1421, 1422, 1430, 1428, 1435, 1383, 1471, 1474, 1479, 1473, - /* 310 */ 1486, 1487, 1456, 1466, 1469, 1472, 1475, 1481, 1433, 1476, - /* 320 */ 1477, 1494, 1411, 1415, 1511, 1512, 1439, 1480, 1519, 1492, - /* 330 */ 1482, 1483, 1485, 1489, 1506, 1491, 1497, 1513, 1516, 1520, - /* 340 */ 1523, 1543, 1552, 1517, 1498, 1499, 1531, 1503, 1544, 1533, - /* 350 */ 1546, 1535, 1565, 1584, 1495, 1500, 1587, 1589, 1570, 1592, - /* 360 */ 1594, 1595, 1597, 1573, 1581, 1582, 1585, 1575, 1586, 1588, - /* 370 */ 1593, 1599, 1600, 1603, 1596, 1604, 1609, 1504, 1524, 1548, - /* 380 */ 1553, 1614, 1637, 1522, 1526, 1590, 1601, 1602, 1605, 1579, - /* 390 */ 1649, 1578, 1610, 1607, 1616, 1619, 1666, 1676, 1677, 1684, - /* 400 */ 1685, 1692, 1569, 1606, 1574, 1680, 1678, 1679, 1682, 1688, - /* 410 */ 1689, 1667, 1668, 1690, 1691, 1694, 1699, + /* 0 */ -176, -71, -170, 746, 799, -159, -20, -186, -30, 85, + /* 10 */ 94, 260, 277, -180, 159, 164, 275, 279, 284, -98, + /* 20 */ 145, -274, 401, -116, 577, 701, 904, 958, -178, 960, + /* 30 */ 965, 273, 744, 1028, 803, 207, 426, 879, 299, 424, + /* 40 */ -26, 696, 924, 750, 771, 820, 1000, 228, 421, 228, + /* 50 */ 421, -277, -277, -277, -277, -277, -277, -277, -277, -277, + /* 60 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, -277, + /* 70 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, -277, + /* 80 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, 570, + /* 90 */ 573, 616, 621, 852, 1064, 1083, 1103, 1108, 1133, 1154, + /* 100 */ 1159, 1161, 1164, 1166, 1168, 1170, 1208, 1211, 1213, 1217, + /* 110 */ 1219, 1224, 1233, 1244, 1254, 1264, 1273, 1291, 1294, 1307, + /* 120 */ 1310, 1316, 1328, 1332, 1342, 1344, 1346, 1349, 1354, 1374, + /* 130 */ 1385, 1388, 1390, 1394, 1399, 1431, 1433, 1435, 1449, 1453, + /* 140 */ 1480, 1491, -277, -277, -277, -277, -277, -277, -277, -277, + /* 150 */ -277, -277, -277, 479, -177, 199, 893, 2, 650, -206, + /* 160 */ -145, 319, -277, 703, 420, 639, 680, 770, -277, -277, + /* 170 */ -277, -277, -183, -183, -183, -99, 291, 316, 396, 865, + /* 180 */ -200, 445, -11, 1, 590, 590, -135, 422, 870, 874, + /* 190 */ 884, 1014, 1090, 1122, -101, 80, 641, 719, 796, 905, + /* 200 */ 922, 1210, 303, 992, 990, 681, 877, 947, 997, 1119, + /* 210 */ 1001, 1003, 1178, 1202, 1199, 1205, 772, 1172, 1198, 1207, + /* 220 */ 1220, 1230, 1221, 1274, -208, -193, -102, 98, 97, 285, + /* 230 */ 294, 366, 427, 515, 545, 670, 695, 763, 844, 938, + /* 240 */ 1109, 1181, 1380, 1383, 1389, 135, 1410, 1434, 1450, 1475, + /* 250 */ 1481, 1496, 1506, 1513, 1526, 1537, 1539, 1540, 306, 898, + /* 260 */ 968, 1543, 1546, 1550, 1272, 1556, 1557, 1564, 1415, 1427, + /* 270 */ 1565, 1524, 1569, 294, 1572, 1574, 1576, 1577, 1578, 1579, + /* 280 */ 1474, 1485, 1532, 1510, 1519, 1520, 1522, 1272, 1532, 1532, + /* 290 */ 1541, 1566, 1588, 1487, 1511, 1514, 1542, 1518, 1495, 1544, + /* 300 */ 1527, 1528, 1555, 1530, 1553, 1512, 1585, 1581, 1582, 1589, + /* 310 */ 1590, 1593, 1559, 1567, 1568, 1583, 1587, 1592, 1545, 1584, + /* 320 */ 1599, 1629, 1534, 1549, 1640, 1644, 1560, 1561, 1649, 1575, + /* 330 */ 1594, 1595, 1612, 1615, 1634, 1619, 1626, 1645, 1646, 1647, + /* 340 */ 1653, 1681, 1694, 1650, 1622, 1627, 1651, 1630, 1668, 1657, + /* 350 */ 1670, 1666, 1714, 1711, 1625, 1628, 1720, 1722, 1701, 1723, + /* 360 */ 1725, 1726, 1728, 1708, 1712, 1715, 1716, 1704, 1721, 1724, + /* 370 */ 1729, 1731, 1732, 1733, 1709, 1735, 1736, 1632, 1633, 1658, + /* 380 */ 1659, 1738, 1743, 1637, 1641, 1691, 1700, 1727, 1730, 1686, + /* 390 */ 1765, 1687, 1734, 1737, 1739, 1741, 1770, 1780, 1782, 1788, + /* 400 */ 1789, 1790, 1684, 1685, 1682, 1783, 1779, 1781, 1786, 1787, + /* 410 */ 1794, 1773, 1774, 1792, 1797, 1791, 1795, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1670, 1670, 1670, 1498, 1260, 1374, 1260, 1260, 1260, 1260, - /* 10 */ 1498, 1498, 1498, 1260, 1260, 1260, 1260, 1260, 1260, 1404, - /* 20 */ 1404, 1551, 1294, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 30 */ 1260, 1260, 1260, 1260, 1260, 1497, 1260, 1260, 1260, 1260, - /* 40 */ 1585, 1585, 1260, 1260, 1260, 1260, 1260, 1570, 1569, 1260, - /* 50 */ 1260, 1260, 1413, 1260, 1420, 1260, 1260, 1260, 1260, 1260, - /* 60 */ 1499, 1500, 1260, 1260, 1260, 1260, 1550, 1552, 1515, 1427, - /* 70 */ 1426, 1425, 1424, 1533, 1392, 1418, 1411, 1415, 1494, 1495, - /* 80 */ 1493, 1648, 1500, 1499, 1260, 1414, 1462, 1478, 1461, 1260, - /* 90 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 100 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 110 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 120 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 130 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 140 */ 1260, 1260, 1470, 1477, 1476, 1475, 1484, 1474, 1471, 1464, - /* 150 */ 1463, 1465, 1466, 1285, 1260, 1282, 1336, 1260, 1260, 1260, - /* 160 */ 1260, 1260, 1467, 1294, 1455, 1454, 1453, 1260, 1481, 1468, - /* 170 */ 1480, 1479, 1558, 1622, 1621, 1516, 1260, 1260, 1260, 1260, - /* 180 */ 1260, 1260, 1585, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 190 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 200 */ 1260, 1260, 1260, 1260, 1260, 1394, 1585, 1585, 1260, 1294, - /* 210 */ 1585, 1585, 1395, 1395, 1290, 1290, 1398, 1565, 1365, 1365, - /* 220 */ 1365, 1365, 1374, 1365, 1260, 1260, 1260, 1260, 1260, 1260, - /* 230 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1555, - /* 240 */ 1553, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 250 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 260 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1370, 1260, - /* 270 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1615, - /* 280 */ 1267, 1260, 1528, 1350, 1370, 1370, 1370, 1370, 1372, 1351, - /* 290 */ 1349, 1364, 1295, 1662, 1430, 1419, 1371, 1419, 1659, 1417, - /* 300 */ 1430, 1430, 1417, 1430, 1371, 1659, 1311, 1637, 1306, 1404, - /* 310 */ 1404, 1404, 1394, 1394, 1394, 1394, 1398, 1398, 1496, 1371, - /* 320 */ 1364, 1260, 1662, 1662, 1380, 1380, 1661, 1661, 1380, 1516, - /* 330 */ 1645, 1439, 1412, 1398, 1339, 1412, 1398, 1345, 1345, 1345, - /* 340 */ 1345, 1380, 1279, 1417, 1645, 1645, 1417, 1439, 1339, 1417, - /* 350 */ 1339, 1417, 1380, 1279, 1532, 1656, 1380, 1279, 1506, 1380, - /* 360 */ 1279, 1380, 1279, 1506, 1337, 1337, 1337, 1326, 1260, 1260, - /* 370 */ 1506, 1337, 1311, 1337, 1326, 1337, 1337, 1603, 1260, 1510, - /* 380 */ 1510, 1506, 1380, 1595, 1595, 1407, 1407, 1412, 1398, 1501, - /* 390 */ 1380, 1260, 1412, 1410, 1408, 1417, 1329, 1618, 1618, 1614, - /* 400 */ 1614, 1614, 1667, 1667, 1565, 1630, 1294, 1294, 1294, 1294, - /* 410 */ 1630, 1313, 1313, 1295, 1295, 1294, 1630, 1260, 1260, 1260, - /* 420 */ 1260, 1260, 1260, 1625, 1260, 1560, 1517, 1384, 1260, 1260, - /* 430 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 440 */ 1260, 1260, 1260, 1260, 1571, 1260, 1260, 1260, 1260, 1260, - /* 450 */ 1260, 1260, 1260, 1260, 1260, 1260, 1444, 1260, 1263, 1562, - /* 460 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1421, 1422, - /* 470 */ 1385, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1436, 1260, - /* 480 */ 1260, 1260, 1431, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 490 */ 1260, 1658, 1260, 1260, 1260, 1260, 1260, 1260, 1531, 1530, - /* 500 */ 1260, 1260, 1382, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 510 */ 1260, 1260, 1260, 1260, 1260, 1260, 1309, 1260, 1260, 1260, - /* 520 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 530 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 540 */ 1409, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 550 */ 1260, 1260, 1260, 1260, 1260, 1600, 1399, 1260, 1260, 1260, - /* 560 */ 1260, 1649, 1260, 1260, 1260, 1260, 1359, 1260, 1260, 1260, - /* 570 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1641, 1353, 1445, - /* 580 */ 1260, 1448, 1283, 1260, 1273, 1260, 1260, + /* 0 */ 1667, 1667, 1667, 1495, 1258, 1371, 1258, 1258, 1258, 1258, + /* 10 */ 1495, 1495, 1495, 1258, 1258, 1258, 1258, 1258, 1258, 1401, + /* 20 */ 1401, 1548, 1291, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 30 */ 1258, 1258, 1258, 1258, 1258, 1494, 1258, 1258, 1258, 1258, + /* 40 */ 1582, 1582, 1258, 1258, 1258, 1258, 1258, 1567, 1566, 1258, + /* 50 */ 1258, 1258, 1410, 1258, 1417, 1258, 1258, 1258, 1258, 1258, + /* 60 */ 1496, 1497, 1258, 1258, 1258, 1258, 1547, 1549, 1512, 1424, + /* 70 */ 1423, 1422, 1421, 1530, 1389, 1415, 1408, 1412, 1491, 1492, + /* 80 */ 1490, 1645, 1497, 1496, 1258, 1411, 1459, 1475, 1458, 1258, + /* 90 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 100 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 110 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 120 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 130 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 140 */ 1258, 1258, 1467, 1474, 1473, 1472, 1481, 1471, 1468, 1461, + /* 150 */ 1460, 1462, 1463, 1282, 1258, 1279, 1333, 1258, 1258, 1258, + /* 160 */ 1258, 1258, 1464, 1291, 1452, 1451, 1450, 1258, 1478, 1465, + /* 170 */ 1477, 1476, 1555, 1619, 1618, 1513, 1258, 1258, 1258, 1258, + /* 180 */ 1258, 1258, 1582, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 190 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 200 */ 1258, 1258, 1258, 1258, 1258, 1391, 1582, 1582, 1258, 1291, + /* 210 */ 1582, 1582, 1392, 1392, 1287, 1287, 1395, 1562, 1362, 1362, + /* 220 */ 1362, 1362, 1371, 1362, 1258, 1258, 1258, 1258, 1258, 1258, + /* 230 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1552, + /* 240 */ 1550, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 250 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 260 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1367, 1258, + /* 270 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1612, + /* 280 */ 1258, 1525, 1347, 1367, 1367, 1367, 1367, 1369, 1348, 1346, + /* 290 */ 1361, 1292, 1265, 1659, 1427, 1416, 1368, 1416, 1656, 1414, + /* 300 */ 1427, 1427, 1414, 1427, 1368, 1656, 1308, 1634, 1303, 1401, + /* 310 */ 1401, 1401, 1391, 1391, 1391, 1391, 1395, 1395, 1493, 1368, + /* 320 */ 1361, 1258, 1659, 1659, 1377, 1377, 1658, 1658, 1377, 1513, + /* 330 */ 1642, 1436, 1409, 1395, 1336, 1409, 1395, 1342, 1342, 1342, + /* 340 */ 1342, 1377, 1276, 1414, 1642, 1642, 1414, 1436, 1336, 1414, + /* 350 */ 1336, 1414, 1377, 1276, 1529, 1653, 1377, 1276, 1503, 1377, + /* 360 */ 1276, 1377, 1276, 1503, 1334, 1334, 1334, 1323, 1258, 1258, + /* 370 */ 1503, 1334, 1308, 1334, 1323, 1334, 1334, 1600, 1258, 1507, + /* 380 */ 1507, 1503, 1377, 1592, 1592, 1404, 1404, 1409, 1395, 1498, + /* 390 */ 1377, 1258, 1409, 1407, 1405, 1414, 1326, 1615, 1615, 1611, + /* 400 */ 1611, 1611, 1664, 1664, 1562, 1627, 1291, 1291, 1291, 1291, + /* 410 */ 1627, 1310, 1310, 1292, 1292, 1291, 1627, 1258, 1258, 1258, + /* 420 */ 1258, 1258, 1258, 1622, 1258, 1557, 1514, 1381, 1258, 1258, + /* 430 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 440 */ 1258, 1258, 1258, 1258, 1568, 1258, 1258, 1258, 1258, 1258, + /* 450 */ 1258, 1258, 1258, 1258, 1258, 1258, 1441, 1258, 1261, 1559, + /* 460 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1418, 1419, + /* 470 */ 1382, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1433, 1258, + /* 480 */ 1258, 1258, 1428, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 490 */ 1258, 1655, 1258, 1258, 1258, 1258, 1258, 1258, 1528, 1527, + /* 500 */ 1258, 1258, 1379, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 510 */ 1258, 1258, 1258, 1258, 1258, 1258, 1306, 1258, 1258, 1258, + /* 520 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 530 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 540 */ 1406, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, + /* 550 */ 1258, 1258, 1258, 1258, 1258, 1597, 1396, 1258, 1258, 1258, + /* 560 */ 1258, 1646, 1258, 1258, 1258, 1258, 1356, 1258, 1258, 1258, + /* 570 */ 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1638, 1350, 1442, + /* 580 */ 1258, 1445, 1280, 1258, 1270, 1258, 1258, }; /********** End of lemon-generated parsing tables *****************************/ @@ -177935,7 +178875,6 @@ static const YYCODETYPE yyFallback[] = { 9, /* DEFERRED => ID */ 9, /* IMMEDIATE => ID */ 0, /* ID => nothing */ - 9, /* CONCURRENT => ID */ 0, /* COMMIT => nothing */ 9, /* END => ID */ 9, /* ROLLBACK => ID */ @@ -177988,6 +178927,7 @@ static const YYCODETYPE yyFallback[] = { 0, /* GE => nothing */ 0, /* ESCAPE => nothing */ 9, /* COLUMNKW => ID */ + 9, /* CONCURRENT => ID */ 9, /* DO => ID */ 9, /* FOR => ID */ 9, /* IGNORE => ID */ @@ -178205,59 +179145,59 @@ static const char *const yyTokenName[] = { /* 7 */ "DEFERRED", /* 8 */ "IMMEDIATE", /* 9 */ "ID", - /* 10 */ "CONCURRENT", - /* 11 */ "COMMIT", - /* 12 */ "END", - /* 13 */ "ROLLBACK", - /* 14 */ "SAVEPOINT", - /* 15 */ "RELEASE", - /* 16 */ "TO", - /* 17 */ "TABLE", - /* 18 */ "CREATE", - /* 19 */ "IF", - /* 20 */ "NOT", - /* 21 */ "EXISTS", - /* 22 */ "TEMP", - /* 23 */ "LP", - /* 24 */ "RP", - /* 25 */ "AS", - /* 26 */ "COMMA", - /* 27 */ "WITHOUT", - /* 28 */ "ABORT", - /* 29 */ "ACTION", - /* 30 */ "AFTER", - /* 31 */ "ANALYZE", - /* 32 */ "ASC", - /* 33 */ "ATTACH", - /* 34 */ "BEFORE", - /* 35 */ "BY", - /* 36 */ "CASCADE", - /* 37 */ "CAST", - /* 38 */ "CONFLICT", - /* 39 */ "DATABASE", - /* 40 */ "DESC", - /* 41 */ "DETACH", - /* 42 */ "EACH", - /* 43 */ "EXCLUSIVE", - /* 44 */ "FAIL", - /* 45 */ "OR", - /* 46 */ "AND", - /* 47 */ "IS", - /* 48 */ "ISNOT", - /* 49 */ "MATCH", - /* 50 */ "LIKE_KW", - /* 51 */ "BETWEEN", - /* 52 */ "IN", - /* 53 */ "ISNULL", - /* 54 */ "NOTNULL", - /* 55 */ "NE", - /* 56 */ "EQ", - /* 57 */ "GT", - /* 58 */ "LE", - /* 59 */ "LT", - /* 60 */ "GE", - /* 61 */ "ESCAPE", - /* 62 */ "COLUMNKW", + /* 10 */ "COMMIT", + /* 11 */ "END", + /* 12 */ "ROLLBACK", + /* 13 */ "SAVEPOINT", + /* 14 */ "RELEASE", + /* 15 */ "TO", + /* 16 */ "TABLE", + /* 17 */ "CREATE", + /* 18 */ "IF", + /* 19 */ "NOT", + /* 20 */ "EXISTS", + /* 21 */ "TEMP", + /* 22 */ "LP", + /* 23 */ "RP", + /* 24 */ "AS", + /* 25 */ "COMMA", + /* 26 */ "WITHOUT", + /* 27 */ "ABORT", + /* 28 */ "ACTION", + /* 29 */ "AFTER", + /* 30 */ "ANALYZE", + /* 31 */ "ASC", + /* 32 */ "ATTACH", + /* 33 */ "BEFORE", + /* 34 */ "BY", + /* 35 */ "CASCADE", + /* 36 */ "CAST", + /* 37 */ "CONFLICT", + /* 38 */ "DATABASE", + /* 39 */ "DESC", + /* 40 */ "DETACH", + /* 41 */ "EACH", + /* 42 */ "EXCLUSIVE", + /* 43 */ "FAIL", + /* 44 */ "OR", + /* 45 */ "AND", + /* 46 */ "IS", + /* 47 */ "ISNOT", + /* 48 */ "MATCH", + /* 49 */ "LIKE_KW", + /* 50 */ "BETWEEN", + /* 51 */ "IN", + /* 52 */ "ISNULL", + /* 53 */ "NOTNULL", + /* 54 */ "NE", + /* 55 */ "EQ", + /* 56 */ "GT", + /* 57 */ "LE", + /* 58 */ "LT", + /* 59 */ "GE", + /* 60 */ "ESCAPE", + /* 61 */ "COLUMNKW", + /* 62 */ "CONCURRENT", /* 63 */ "DO", /* 64 */ "FOR", /* 65 */ "IGNORE", @@ -178533,408 +179473,407 @@ static const char *const yyRuleName[] = { /* 5 */ "transtype ::= DEFERRED", /* 6 */ "transtype ::= IMMEDIATE", /* 7 */ "transtype ::= ID", - /* 8 */ "transtype ::= CONCURRENT", - /* 9 */ "cmd ::= COMMIT|END trans_opt", - /* 10 */ "cmd ::= ROLLBACK trans_opt", - /* 11 */ "cmd ::= SAVEPOINT nm", - /* 12 */ "cmd ::= RELEASE savepoint_opt nm", - /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", - /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", - /* 15 */ "createkw ::= CREATE", - /* 16 */ "ifnotexists ::=", - /* 17 */ "ifnotexists ::= IF NOT EXISTS", - /* 18 */ "temp ::= TEMP", - /* 19 */ "temp ::=", - /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", - /* 21 */ "create_table_args ::= AS select", - /* 22 */ "table_option_set ::=", - /* 23 */ "table_option_set ::= table_option_set COMMA table_option", - /* 24 */ "table_option ::= WITHOUT nm", - /* 25 */ "table_option ::= nm", - /* 26 */ "columnname ::= nm typetoken", - /* 27 */ "typetoken ::=", - /* 28 */ "typetoken ::= typename LP signed RP", - /* 29 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 30 */ "typename ::= typename ID|STRING", - /* 31 */ "scanpt ::=", - /* 32 */ "scantok ::=", - /* 33 */ "ccons ::= CONSTRAINT nm", - /* 34 */ "ccons ::= DEFAULT scantok term", - /* 35 */ "ccons ::= DEFAULT LP expr RP", - /* 36 */ "ccons ::= DEFAULT PLUS scantok term", - /* 37 */ "ccons ::= DEFAULT MINUS scantok term", - /* 38 */ "ccons ::= DEFAULT scantok ID|INDEXED", - /* 39 */ "ccons ::= NOT NULL onconf", - /* 40 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 41 */ "ccons ::= UNIQUE onconf", - /* 42 */ "ccons ::= CHECK LP expr RP", - /* 43 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 44 */ "ccons ::= defer_subclause", - /* 45 */ "ccons ::= COLLATE ID|STRING", - /* 46 */ "generated ::= LP expr RP", - /* 47 */ "generated ::= LP expr RP ID", - /* 48 */ "autoinc ::=", - /* 49 */ "autoinc ::= AUTOINCR", - /* 50 */ "refargs ::=", - /* 51 */ "refargs ::= refargs refarg", - /* 52 */ "refarg ::= MATCH nm", - /* 53 */ "refarg ::= ON INSERT refact", - /* 54 */ "refarg ::= ON DELETE refact", - /* 55 */ "refarg ::= ON UPDATE refact", - /* 56 */ "refact ::= SET NULL", - /* 57 */ "refact ::= SET DEFAULT", - /* 58 */ "refact ::= CASCADE", - /* 59 */ "refact ::= RESTRICT", - /* 60 */ "refact ::= NO ACTION", - /* 61 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 62 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 63 */ "init_deferred_pred_opt ::=", - /* 64 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 65 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 66 */ "conslist_opt ::=", - /* 67 */ "tconscomma ::= COMMA", - /* 68 */ "tcons ::= CONSTRAINT nm", - /* 69 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 70 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 71 */ "tcons ::= CHECK LP expr RP onconf", - /* 72 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 73 */ "defer_subclause_opt ::=", - /* 74 */ "onconf ::=", - /* 75 */ "onconf ::= ON CONFLICT resolvetype", - /* 76 */ "orconf ::=", - /* 77 */ "orconf ::= OR resolvetype", - /* 78 */ "resolvetype ::= IGNORE", - /* 79 */ "resolvetype ::= REPLACE", - /* 80 */ "cmd ::= DROP TABLE ifexists fullname", - /* 81 */ "ifexists ::= IF EXISTS", - /* 82 */ "ifexists ::=", - /* 83 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 84 */ "cmd ::= DROP VIEW ifexists fullname", - /* 85 */ "cmd ::= select", - /* 86 */ "select ::= WITH wqlist selectnowith", - /* 87 */ "select ::= WITH RECURSIVE wqlist selectnowith", - /* 88 */ "select ::= selectnowith", - /* 89 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 90 */ "multiselect_op ::= UNION", - /* 91 */ "multiselect_op ::= UNION ALL", - /* 92 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 94 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", - /* 95 */ "values ::= VALUES LP nexprlist RP", - /* 96 */ "oneselect ::= mvalues", - /* 97 */ "mvalues ::= values COMMA LP nexprlist RP", - /* 98 */ "mvalues ::= mvalues COMMA LP nexprlist RP", - /* 99 */ "distinct ::= DISTINCT", - /* 100 */ "distinct ::= ALL", - /* 101 */ "distinct ::=", - /* 102 */ "sclp ::=", - /* 103 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 104 */ "selcollist ::= sclp scanpt STAR", - /* 105 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 106 */ "as ::= AS nm", - /* 107 */ "as ::=", - /* 108 */ "from ::=", - /* 109 */ "from ::= FROM seltablist", - /* 110 */ "stl_prefix ::= seltablist joinop", - /* 111 */ "stl_prefix ::=", - /* 112 */ "seltablist ::= stl_prefix nm dbnm as on_using", - /* 113 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", - /* 114 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", - /* 115 */ "seltablist ::= stl_prefix LP select RP as on_using", - /* 116 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", - /* 117 */ "dbnm ::=", - /* 118 */ "dbnm ::= DOT nm", - /* 119 */ "fullname ::= nm", - /* 120 */ "fullname ::= nm DOT nm", - /* 121 */ "xfullname ::= nm", - /* 122 */ "xfullname ::= nm DOT nm", - /* 123 */ "xfullname ::= nm DOT nm AS nm", - /* 124 */ "xfullname ::= nm AS nm", - /* 125 */ "joinop ::= COMMA|JOIN", - /* 126 */ "joinop ::= JOIN_KW JOIN", - /* 127 */ "joinop ::= JOIN_KW nm JOIN", - /* 128 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 129 */ "on_using ::= ON expr", - /* 130 */ "on_using ::= USING LP idlist RP", - /* 131 */ "on_using ::=", - /* 132 */ "indexed_opt ::=", - /* 133 */ "indexed_by ::= INDEXED BY nm", - /* 134 */ "indexed_by ::= NOT INDEXED", - /* 135 */ "orderby_opt ::=", - /* 136 */ "orderby_opt ::= ORDER BY sortlist", - /* 137 */ "sortlist ::= sortlist COMMA expr sortorder nulls", - /* 138 */ "sortlist ::= expr sortorder nulls", - /* 139 */ "sortorder ::= ASC", - /* 140 */ "sortorder ::= DESC", - /* 141 */ "sortorder ::=", - /* 142 */ "nulls ::= NULLS FIRST", - /* 143 */ "nulls ::= NULLS LAST", - /* 144 */ "nulls ::=", - /* 145 */ "groupby_opt ::=", - /* 146 */ "groupby_opt ::= GROUP BY nexprlist", - /* 147 */ "having_opt ::=", - /* 148 */ "having_opt ::= HAVING expr", - /* 149 */ "limit_opt ::=", - /* 150 */ "limit_opt ::= LIMIT expr", - /* 151 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 152 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 153 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt", - /* 154 */ "where_opt ::=", - /* 155 */ "where_opt ::= WHERE expr", - /* 156 */ "where_opt_ret ::=", - /* 157 */ "where_opt_ret ::= WHERE expr", - /* 158 */ "where_opt_ret ::= RETURNING selcollist", - /* 159 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", - /* 160 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt", - /* 161 */ "setlist ::= setlist COMMA nm EQ expr", - /* 162 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 163 */ "setlist ::= nm EQ expr", - /* 164 */ "setlist ::= LP idlist RP EQ expr", - /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", - /* 166 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", - /* 167 */ "upsert ::=", - /* 168 */ "upsert ::= RETURNING selcollist", - /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", - /* 170 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", - /* 171 */ "upsert ::= ON CONFLICT DO NOTHING returning", - /* 172 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", - /* 173 */ "returning ::= RETURNING selcollist", - /* 174 */ "insert_cmd ::= INSERT orconf", - /* 175 */ "insert_cmd ::= REPLACE", - /* 176 */ "idlist_opt ::=", - /* 177 */ "idlist_opt ::= LP idlist RP", - /* 178 */ "idlist ::= idlist COMMA nm", - /* 179 */ "idlist ::= nm", - /* 180 */ "expr ::= LP expr RP", - /* 181 */ "expr ::= ID|INDEXED|JOIN_KW", - /* 182 */ "expr ::= nm DOT nm", - /* 183 */ "expr ::= nm DOT nm DOT nm", - /* 184 */ "term ::= NULL|FLOAT|BLOB", - /* 185 */ "term ::= STRING", - /* 186 */ "term ::= INTEGER", - /* 187 */ "expr ::= VARIABLE", - /* 188 */ "expr ::= expr COLLATE ID|STRING", - /* 189 */ "expr ::= CAST LP expr AS typetoken RP", - /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", - /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", - /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", - /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", - /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", - /* 195 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", - /* 196 */ "term ::= CTIME_KW", - /* 197 */ "expr ::= LP nexprlist COMMA expr RP", - /* 198 */ "expr ::= expr AND expr", - /* 199 */ "expr ::= expr OR expr", - /* 200 */ "expr ::= expr LT|GT|GE|LE expr", - /* 201 */ "expr ::= expr EQ|NE expr", - /* 202 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 203 */ "expr ::= expr PLUS|MINUS expr", - /* 204 */ "expr ::= expr STAR|SLASH|REM expr", - /* 205 */ "expr ::= expr CONCAT expr", - /* 206 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 207 */ "expr ::= expr likeop expr", - /* 208 */ "expr ::= expr likeop expr ESCAPE expr", - /* 209 */ "expr ::= expr ISNULL|NOTNULL", - /* 210 */ "expr ::= expr NOT NULL", - /* 211 */ "expr ::= expr IS expr", - /* 212 */ "expr ::= expr IS NOT expr", - /* 213 */ "expr ::= expr IS NOT DISTINCT FROM expr", - /* 214 */ "expr ::= expr IS DISTINCT FROM expr", - /* 215 */ "expr ::= NOT expr", - /* 216 */ "expr ::= BITNOT expr", - /* 217 */ "expr ::= PLUS|MINUS expr", - /* 218 */ "expr ::= expr PTR expr", - /* 219 */ "between_op ::= BETWEEN", - /* 220 */ "between_op ::= NOT BETWEEN", - /* 221 */ "expr ::= expr between_op expr AND expr", - /* 222 */ "in_op ::= IN", - /* 223 */ "in_op ::= NOT IN", - /* 224 */ "expr ::= expr in_op LP exprlist RP", - /* 225 */ "expr ::= LP select RP", - /* 226 */ "expr ::= expr in_op LP select RP", - /* 227 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 228 */ "expr ::= EXISTS LP select RP", - /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 231 */ "case_exprlist ::= WHEN expr THEN expr", - /* 232 */ "case_else ::= ELSE expr", - /* 233 */ "case_else ::=", - /* 234 */ "case_operand ::=", - /* 235 */ "exprlist ::=", - /* 236 */ "nexprlist ::= nexprlist COMMA expr", - /* 237 */ "nexprlist ::= expr", - /* 238 */ "paren_exprlist ::=", - /* 239 */ "paren_exprlist ::= LP exprlist RP", - /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 241 */ "uniqueflag ::= UNIQUE", - /* 242 */ "uniqueflag ::=", - /* 243 */ "eidlist_opt ::=", - /* 244 */ "eidlist_opt ::= LP eidlist RP", - /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 246 */ "eidlist ::= nm collate sortorder", - /* 247 */ "collate ::=", - /* 248 */ "collate ::= COLLATE ID|STRING", - /* 249 */ "cmd ::= DROP INDEX ifexists fullname", - /* 250 */ "cmd ::= VACUUM vinto", - /* 251 */ "cmd ::= VACUUM nm vinto", - /* 252 */ "vinto ::= INTO expr", - /* 253 */ "vinto ::=", - /* 254 */ "cmd ::= PRAGMA nm dbnm", - /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 256 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 257 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 258 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 259 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 260 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 261 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 262 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 263 */ "trigger_time ::= BEFORE|AFTER", - /* 264 */ "trigger_time ::= INSTEAD OF", - /* 265 */ "trigger_time ::=", - /* 266 */ "trigger_event ::= DELETE|INSERT", - /* 267 */ "trigger_event ::= UPDATE", - /* 268 */ "trigger_event ::= UPDATE OF idlist", - /* 269 */ "when_clause ::=", - /* 270 */ "when_clause ::= WHEN expr", - /* 271 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 272 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 273 */ "trnm ::= nm DOT nm", - /* 274 */ "tridxby ::= INDEXED BY nm", - /* 275 */ "tridxby ::= NOT INDEXED", - /* 276 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 277 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 278 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 279 */ "trigger_cmd ::= scanpt select scanpt", - /* 280 */ "expr ::= RAISE LP IGNORE RP", - /* 281 */ "expr ::= RAISE LP raisetype COMMA expr RP", - /* 282 */ "raisetype ::= ROLLBACK", - /* 283 */ "raisetype ::= ABORT", - /* 284 */ "raisetype ::= FAIL", - /* 285 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 286 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 287 */ "cmd ::= DETACH database_kw_opt expr", - /* 288 */ "key_opt ::=", - /* 289 */ "key_opt ::= KEY expr", - /* 290 */ "cmd ::= REINDEX", - /* 291 */ "cmd ::= REINDEX nm dbnm", - /* 292 */ "cmd ::= ANALYZE", - /* 293 */ "cmd ::= ANALYZE nm dbnm", - /* 294 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 295 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 296 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 297 */ "add_column_fullname ::= fullname", - /* 298 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 299 */ "cmd ::= create_vtab", - /* 300 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 301 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 302 */ "vtabarg ::=", - /* 303 */ "vtabargtoken ::= ANY", - /* 304 */ "vtabargtoken ::= lp anylist RP", - /* 305 */ "lp ::= LP", - /* 306 */ "with ::= WITH wqlist", - /* 307 */ "with ::= WITH RECURSIVE wqlist", - /* 308 */ "wqas ::= AS", - /* 309 */ "wqas ::= AS MATERIALIZED", - /* 310 */ "wqas ::= AS NOT MATERIALIZED", - /* 311 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", - /* 312 */ "withnm ::= nm", - /* 313 */ "wqlist ::= wqitem", - /* 314 */ "wqlist ::= wqlist COMMA wqitem", - /* 315 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 316 */ "windowdefn ::= nm AS LP window RP", - /* 317 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 318 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 319 */ "window ::= ORDER BY sortlist frame_opt", - /* 320 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 321 */ "window ::= nm frame_opt", - /* 322 */ "frame_opt ::=", - /* 323 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 324 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 325 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 326 */ "frame_bound_s ::= frame_bound", - /* 327 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 328 */ "frame_bound_e ::= frame_bound", - /* 329 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 330 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 331 */ "frame_bound ::= CURRENT ROW", - /* 332 */ "frame_exclude_opt ::=", - /* 333 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 334 */ "frame_exclude ::= NO OTHERS", - /* 335 */ "frame_exclude ::= CURRENT ROW", - /* 336 */ "frame_exclude ::= GROUP|TIES", - /* 337 */ "window_clause ::= WINDOW windowdefn_list", - /* 338 */ "filter_over ::= filter_clause over_clause", - /* 339 */ "filter_over ::= over_clause", - /* 340 */ "filter_over ::= filter_clause", - /* 341 */ "over_clause ::= OVER LP window RP", - /* 342 */ "over_clause ::= OVER nm", - /* 343 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 344 */ "term ::= QNUMBER", - /* 345 */ "input ::= cmdlist", - /* 346 */ "cmdlist ::= cmdlist ecmd", - /* 347 */ "cmdlist ::= ecmd", - /* 348 */ "ecmd ::= SEMI", - /* 349 */ "ecmd ::= cmdx SEMI", - /* 350 */ "ecmd ::= explain cmdx SEMI", - /* 351 */ "trans_opt ::=", - /* 352 */ "trans_opt ::= TRANSACTION", - /* 353 */ "trans_opt ::= TRANSACTION nm", - /* 354 */ "savepoint_opt ::= SAVEPOINT", - /* 355 */ "savepoint_opt ::=", - /* 356 */ "cmd ::= create_table create_table_args", - /* 357 */ "table_option_set ::= table_option", - /* 358 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 359 */ "columnlist ::= columnname carglist", - /* 360 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 361 */ "nm ::= STRING", - /* 362 */ "typetoken ::= typename", - /* 363 */ "typename ::= ID|STRING", - /* 364 */ "signed ::= plus_num", - /* 365 */ "signed ::= minus_num", - /* 366 */ "carglist ::= carglist ccons", - /* 367 */ "carglist ::=", - /* 368 */ "ccons ::= NULL onconf", - /* 369 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 370 */ "ccons ::= AS generated", - /* 371 */ "conslist_opt ::= COMMA conslist", - /* 372 */ "conslist ::= conslist tconscomma tcons", - /* 373 */ "conslist ::= tcons", - /* 374 */ "tconscomma ::=", - /* 375 */ "defer_subclause_opt ::= defer_subclause", - /* 376 */ "resolvetype ::= raisetype", - /* 377 */ "selectnowith ::= oneselect", - /* 378 */ "oneselect ::= values", - /* 379 */ "sclp ::= selcollist COMMA", - /* 380 */ "as ::= ID|STRING", - /* 381 */ "indexed_opt ::= indexed_by", - /* 382 */ "returning ::=", - /* 383 */ "expr ::= term", - /* 384 */ "likeop ::= LIKE_KW|MATCH", - /* 385 */ "case_operand ::= expr", - /* 386 */ "exprlist ::= nexprlist", - /* 387 */ "nmnum ::= plus_num", - /* 388 */ "nmnum ::= nm", - /* 389 */ "nmnum ::= ON", - /* 390 */ "nmnum ::= DELETE", - /* 391 */ "nmnum ::= DEFAULT", - /* 392 */ "plus_num ::= INTEGER|FLOAT", - /* 393 */ "foreach_clause ::=", - /* 394 */ "foreach_clause ::= FOR EACH ROW", - /* 395 */ "trnm ::= nm", - /* 396 */ "tridxby ::=", - /* 397 */ "database_kw_opt ::= DATABASE", - /* 398 */ "database_kw_opt ::=", - /* 399 */ "kwcolumn_opt ::=", - /* 400 */ "kwcolumn_opt ::= COLUMNKW", - /* 401 */ "vtabarglist ::= vtabarg", - /* 402 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 403 */ "vtabarg ::= vtabarg vtabargtoken", - /* 404 */ "anylist ::=", - /* 405 */ "anylist ::= anylist LP anylist RP", - /* 406 */ "anylist ::= anylist ANY", - /* 407 */ "with ::=", - /* 408 */ "windowdefn_list ::= windowdefn", - /* 409 */ "window ::= frame_opt", + /* 8 */ "cmd ::= COMMIT|END trans_opt", + /* 9 */ "cmd ::= ROLLBACK trans_opt", + /* 10 */ "cmd ::= SAVEPOINT nm", + /* 11 */ "cmd ::= RELEASE savepoint_opt nm", + /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 14 */ "createkw ::= CREATE", + /* 15 */ "ifnotexists ::=", + /* 16 */ "ifnotexists ::= IF NOT EXISTS", + /* 17 */ "temp ::= TEMP", + /* 18 */ "temp ::=", + /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", + /* 20 */ "create_table_args ::= AS select", + /* 21 */ "table_option_set ::=", + /* 22 */ "table_option_set ::= table_option_set COMMA table_option", + /* 23 */ "table_option ::= WITHOUT nm", + /* 24 */ "table_option ::= nm", + /* 25 */ "columnname ::= nm typetoken", + /* 26 */ "typetoken ::=", + /* 27 */ "typetoken ::= typename LP signed RP", + /* 28 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 29 */ "typename ::= typename ID|STRING", + /* 30 */ "scanpt ::=", + /* 31 */ "scantok ::=", + /* 32 */ "ccons ::= CONSTRAINT nm", + /* 33 */ "ccons ::= DEFAULT scantok term", + /* 34 */ "ccons ::= DEFAULT LP expr RP", + /* 35 */ "ccons ::= DEFAULT PLUS scantok term", + /* 36 */ "ccons ::= DEFAULT MINUS scantok term", + /* 37 */ "ccons ::= DEFAULT scantok ID|INDEXED", + /* 38 */ "ccons ::= NOT NULL onconf", + /* 39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 40 */ "ccons ::= UNIQUE onconf", + /* 41 */ "ccons ::= CHECK LP expr RP", + /* 42 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 43 */ "ccons ::= defer_subclause", + /* 44 */ "ccons ::= COLLATE ID|STRING", + /* 45 */ "generated ::= LP expr RP", + /* 46 */ "generated ::= LP expr RP ID", + /* 47 */ "autoinc ::=", + /* 48 */ "autoinc ::= AUTOINCR", + /* 49 */ "refargs ::=", + /* 50 */ "refargs ::= refargs refarg", + /* 51 */ "refarg ::= MATCH nm", + /* 52 */ "refarg ::= ON INSERT refact", + /* 53 */ "refarg ::= ON DELETE refact", + /* 54 */ "refarg ::= ON UPDATE refact", + /* 55 */ "refact ::= SET NULL", + /* 56 */ "refact ::= SET DEFAULT", + /* 57 */ "refact ::= CASCADE", + /* 58 */ "refact ::= RESTRICT", + /* 59 */ "refact ::= NO ACTION", + /* 60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 62 */ "init_deferred_pred_opt ::=", + /* 63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 65 */ "conslist_opt ::=", + /* 66 */ "tconscomma ::= COMMA", + /* 67 */ "tcons ::= CONSTRAINT nm", + /* 68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 69 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 70 */ "tcons ::= CHECK LP expr RP onconf", + /* 71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 72 */ "defer_subclause_opt ::=", + /* 73 */ "onconf ::=", + /* 74 */ "onconf ::= ON CONFLICT resolvetype", + /* 75 */ "orconf ::=", + /* 76 */ "orconf ::= OR resolvetype", + /* 77 */ "resolvetype ::= IGNORE", + /* 78 */ "resolvetype ::= REPLACE", + /* 79 */ "cmd ::= DROP TABLE ifexists fullname", + /* 80 */ "ifexists ::= IF EXISTS", + /* 81 */ "ifexists ::=", + /* 82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 83 */ "cmd ::= DROP VIEW ifexists fullname", + /* 84 */ "cmd ::= select", + /* 85 */ "select ::= WITH wqlist selectnowith", + /* 86 */ "select ::= WITH RECURSIVE wqlist selectnowith", + /* 87 */ "select ::= selectnowith", + /* 88 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 89 */ "multiselect_op ::= UNION", + /* 90 */ "multiselect_op ::= UNION ALL", + /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 94 */ "values ::= VALUES LP nexprlist RP", + /* 95 */ "oneselect ::= mvalues", + /* 96 */ "mvalues ::= values COMMA LP nexprlist RP", + /* 97 */ "mvalues ::= mvalues COMMA LP nexprlist RP", + /* 98 */ "distinct ::= DISTINCT", + /* 99 */ "distinct ::= ALL", + /* 100 */ "distinct ::=", + /* 101 */ "sclp ::=", + /* 102 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 103 */ "selcollist ::= sclp scanpt STAR", + /* 104 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 105 */ "as ::= AS nm", + /* 106 */ "as ::=", + /* 107 */ "from ::=", + /* 108 */ "from ::= FROM seltablist", + /* 109 */ "stl_prefix ::= seltablist joinop", + /* 110 */ "stl_prefix ::=", + /* 111 */ "seltablist ::= stl_prefix nm dbnm as on_using", + /* 112 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", + /* 113 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", + /* 114 */ "seltablist ::= stl_prefix LP select RP as on_using", + /* 115 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", + /* 116 */ "dbnm ::=", + /* 117 */ "dbnm ::= DOT nm", + /* 118 */ "fullname ::= nm", + /* 119 */ "fullname ::= nm DOT nm", + /* 120 */ "xfullname ::= nm", + /* 121 */ "xfullname ::= nm DOT nm", + /* 122 */ "xfullname ::= nm DOT nm AS nm", + /* 123 */ "xfullname ::= nm AS nm", + /* 124 */ "joinop ::= COMMA|JOIN", + /* 125 */ "joinop ::= JOIN_KW JOIN", + /* 126 */ "joinop ::= JOIN_KW nm JOIN", + /* 127 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 128 */ "on_using ::= ON expr", + /* 129 */ "on_using ::= USING LP idlist RP", + /* 130 */ "on_using ::=", + /* 131 */ "indexed_opt ::=", + /* 132 */ "indexed_by ::= INDEXED BY nm", + /* 133 */ "indexed_by ::= NOT INDEXED", + /* 134 */ "orderby_opt ::=", + /* 135 */ "orderby_opt ::= ORDER BY sortlist", + /* 136 */ "sortlist ::= sortlist COMMA expr sortorder nulls", + /* 137 */ "sortlist ::= expr sortorder nulls", + /* 138 */ "sortorder ::= ASC", + /* 139 */ "sortorder ::= DESC", + /* 140 */ "sortorder ::=", + /* 141 */ "nulls ::= NULLS FIRST", + /* 142 */ "nulls ::= NULLS LAST", + /* 143 */ "nulls ::=", + /* 144 */ "groupby_opt ::=", + /* 145 */ "groupby_opt ::= GROUP BY nexprlist", + /* 146 */ "having_opt ::=", + /* 147 */ "having_opt ::= HAVING expr", + /* 148 */ "limit_opt ::=", + /* 149 */ "limit_opt ::= LIMIT expr", + /* 150 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 151 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 152 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt", + /* 153 */ "where_opt ::=", + /* 154 */ "where_opt ::= WHERE expr", + /* 155 */ "where_opt_ret ::=", + /* 156 */ "where_opt_ret ::= WHERE expr", + /* 157 */ "where_opt_ret ::= RETURNING selcollist", + /* 158 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", + /* 159 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt", + /* 160 */ "setlist ::= setlist COMMA nm EQ expr", + /* 161 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 162 */ "setlist ::= nm EQ expr", + /* 163 */ "setlist ::= LP idlist RP EQ expr", + /* 164 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", + /* 166 */ "upsert ::=", + /* 167 */ "upsert ::= RETURNING selcollist", + /* 168 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", + /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", + /* 170 */ "upsert ::= ON CONFLICT DO NOTHING returning", + /* 171 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", + /* 172 */ "returning ::= RETURNING selcollist", + /* 173 */ "insert_cmd ::= INSERT orconf", + /* 174 */ "insert_cmd ::= REPLACE", + /* 175 */ "idlist_opt ::=", + /* 176 */ "idlist_opt ::= LP idlist RP", + /* 177 */ "idlist ::= idlist COMMA nm", + /* 178 */ "idlist ::= nm", + /* 179 */ "expr ::= LP expr RP", + /* 180 */ "expr ::= ID|INDEXED|JOIN_KW", + /* 181 */ "expr ::= nm DOT nm", + /* 182 */ "expr ::= nm DOT nm DOT nm", + /* 183 */ "term ::= NULL|FLOAT|BLOB", + /* 184 */ "term ::= STRING", + /* 185 */ "term ::= INTEGER", + /* 186 */ "expr ::= VARIABLE", + /* 187 */ "expr ::= expr COLLATE ID|STRING", + /* 188 */ "expr ::= CAST LP expr AS typetoken RP", + /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", + /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", + /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", + /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", + /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", + /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", + /* 195 */ "term ::= CTIME_KW", + /* 196 */ "expr ::= LP nexprlist COMMA expr RP", + /* 197 */ "expr ::= expr AND expr", + /* 198 */ "expr ::= expr OR expr", + /* 199 */ "expr ::= expr LT|GT|GE|LE expr", + /* 200 */ "expr ::= expr EQ|NE expr", + /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 202 */ "expr ::= expr PLUS|MINUS expr", + /* 203 */ "expr ::= expr STAR|SLASH|REM expr", + /* 204 */ "expr ::= expr CONCAT expr", + /* 205 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 206 */ "expr ::= expr likeop expr", + /* 207 */ "expr ::= expr likeop expr ESCAPE expr", + /* 208 */ "expr ::= expr ISNULL|NOTNULL", + /* 209 */ "expr ::= expr NOT NULL", + /* 210 */ "expr ::= expr IS expr", + /* 211 */ "expr ::= expr IS NOT expr", + /* 212 */ "expr ::= expr IS NOT DISTINCT FROM expr", + /* 213 */ "expr ::= expr IS DISTINCT FROM expr", + /* 214 */ "expr ::= NOT expr", + /* 215 */ "expr ::= BITNOT expr", + /* 216 */ "expr ::= PLUS|MINUS expr", + /* 217 */ "expr ::= expr PTR expr", + /* 218 */ "between_op ::= BETWEEN", + /* 219 */ "between_op ::= NOT BETWEEN", + /* 220 */ "expr ::= expr between_op expr AND expr", + /* 221 */ "in_op ::= IN", + /* 222 */ "in_op ::= NOT IN", + /* 223 */ "expr ::= expr in_op LP exprlist RP", + /* 224 */ "expr ::= LP select RP", + /* 225 */ "expr ::= expr in_op LP select RP", + /* 226 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 227 */ "expr ::= EXISTS LP select RP", + /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 230 */ "case_exprlist ::= WHEN expr THEN expr", + /* 231 */ "case_else ::= ELSE expr", + /* 232 */ "case_else ::=", + /* 233 */ "case_operand ::=", + /* 234 */ "exprlist ::=", + /* 235 */ "nexprlist ::= nexprlist COMMA expr", + /* 236 */ "nexprlist ::= expr", + /* 237 */ "paren_exprlist ::=", + /* 238 */ "paren_exprlist ::= LP exprlist RP", + /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 240 */ "uniqueflag ::= UNIQUE", + /* 241 */ "uniqueflag ::=", + /* 242 */ "eidlist_opt ::=", + /* 243 */ "eidlist_opt ::= LP eidlist RP", + /* 244 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 245 */ "eidlist ::= nm collate sortorder", + /* 246 */ "collate ::=", + /* 247 */ "collate ::= COLLATE ID|STRING", + /* 248 */ "cmd ::= DROP INDEX ifexists fullname", + /* 249 */ "cmd ::= VACUUM vinto", + /* 250 */ "cmd ::= VACUUM nm vinto", + /* 251 */ "vinto ::= INTO expr", + /* 252 */ "vinto ::=", + /* 253 */ "cmd ::= PRAGMA nm dbnm", + /* 254 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 255 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 256 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 257 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 258 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 259 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 260 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 261 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 262 */ "trigger_time ::= BEFORE|AFTER", + /* 263 */ "trigger_time ::= INSTEAD OF", + /* 264 */ "trigger_time ::=", + /* 265 */ "trigger_event ::= DELETE|INSERT", + /* 266 */ "trigger_event ::= UPDATE", + /* 267 */ "trigger_event ::= UPDATE OF idlist", + /* 268 */ "when_clause ::=", + /* 269 */ "when_clause ::= WHEN expr", + /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 272 */ "trnm ::= nm DOT nm", + /* 273 */ "tridxby ::= INDEXED BY nm", + /* 274 */ "tridxby ::= NOT INDEXED", + /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", + /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 278 */ "trigger_cmd ::= scanpt select scanpt", + /* 279 */ "expr ::= RAISE LP IGNORE RP", + /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP", + /* 281 */ "raisetype ::= ROLLBACK", + /* 282 */ "raisetype ::= ABORT", + /* 283 */ "raisetype ::= FAIL", + /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 286 */ "cmd ::= DETACH database_kw_opt expr", + /* 287 */ "key_opt ::=", + /* 288 */ "key_opt ::= KEY expr", + /* 289 */ "cmd ::= REINDEX", + /* 290 */ "cmd ::= REINDEX nm dbnm", + /* 291 */ "cmd ::= ANALYZE", + /* 292 */ "cmd ::= ANALYZE nm dbnm", + /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", + /* 296 */ "add_column_fullname ::= fullname", + /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 298 */ "cmd ::= create_vtab", + /* 299 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 301 */ "vtabarg ::=", + /* 302 */ "vtabargtoken ::= ANY", + /* 303 */ "vtabargtoken ::= lp anylist RP", + /* 304 */ "lp ::= LP", + /* 305 */ "with ::= WITH wqlist", + /* 306 */ "with ::= WITH RECURSIVE wqlist", + /* 307 */ "wqas ::= AS", + /* 308 */ "wqas ::= AS MATERIALIZED", + /* 309 */ "wqas ::= AS NOT MATERIALIZED", + /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", + /* 311 */ "withnm ::= nm", + /* 312 */ "wqlist ::= wqitem", + /* 313 */ "wqlist ::= wqlist COMMA wqitem", + /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 315 */ "windowdefn ::= nm AS LP window RP", + /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 318 */ "window ::= ORDER BY sortlist frame_opt", + /* 319 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 320 */ "window ::= nm frame_opt", + /* 321 */ "frame_opt ::=", + /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 325 */ "frame_bound_s ::= frame_bound", + /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 327 */ "frame_bound_e ::= frame_bound", + /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 330 */ "frame_bound ::= CURRENT ROW", + /* 331 */ "frame_exclude_opt ::=", + /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 333 */ "frame_exclude ::= NO OTHERS", + /* 334 */ "frame_exclude ::= CURRENT ROW", + /* 335 */ "frame_exclude ::= GROUP|TIES", + /* 336 */ "window_clause ::= WINDOW windowdefn_list", + /* 337 */ "filter_over ::= filter_clause over_clause", + /* 338 */ "filter_over ::= over_clause", + /* 339 */ "filter_over ::= filter_clause", + /* 340 */ "over_clause ::= OVER LP window RP", + /* 341 */ "over_clause ::= OVER nm", + /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 343 */ "term ::= QNUMBER", + /* 344 */ "input ::= cmdlist", + /* 345 */ "cmdlist ::= cmdlist ecmd", + /* 346 */ "cmdlist ::= ecmd", + /* 347 */ "ecmd ::= SEMI", + /* 348 */ "ecmd ::= cmdx SEMI", + /* 349 */ "ecmd ::= explain cmdx SEMI", + /* 350 */ "trans_opt ::=", + /* 351 */ "trans_opt ::= TRANSACTION", + /* 352 */ "trans_opt ::= TRANSACTION nm", + /* 353 */ "savepoint_opt ::= SAVEPOINT", + /* 354 */ "savepoint_opt ::=", + /* 355 */ "cmd ::= create_table create_table_args", + /* 356 */ "table_option_set ::= table_option", + /* 357 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 358 */ "columnlist ::= columnname carglist", + /* 359 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 360 */ "nm ::= STRING", + /* 361 */ "typetoken ::= typename", + /* 362 */ "typename ::= ID|STRING", + /* 363 */ "signed ::= plus_num", + /* 364 */ "signed ::= minus_num", + /* 365 */ "carglist ::= carglist ccons", + /* 366 */ "carglist ::=", + /* 367 */ "ccons ::= NULL onconf", + /* 368 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 369 */ "ccons ::= AS generated", + /* 370 */ "conslist_opt ::= COMMA conslist", + /* 371 */ "conslist ::= conslist tconscomma tcons", + /* 372 */ "conslist ::= tcons", + /* 373 */ "tconscomma ::=", + /* 374 */ "defer_subclause_opt ::= defer_subclause", + /* 375 */ "resolvetype ::= raisetype", + /* 376 */ "selectnowith ::= oneselect", + /* 377 */ "oneselect ::= values", + /* 378 */ "sclp ::= selcollist COMMA", + /* 379 */ "as ::= ID|STRING", + /* 380 */ "indexed_opt ::= indexed_by", + /* 381 */ "returning ::=", + /* 382 */ "expr ::= term", + /* 383 */ "likeop ::= LIKE_KW|MATCH", + /* 384 */ "case_operand ::= expr", + /* 385 */ "exprlist ::= nexprlist", + /* 386 */ "nmnum ::= plus_num", + /* 387 */ "nmnum ::= nm", + /* 388 */ "nmnum ::= ON", + /* 389 */ "nmnum ::= DELETE", + /* 390 */ "nmnum ::= DEFAULT", + /* 391 */ "plus_num ::= INTEGER|FLOAT", + /* 392 */ "foreach_clause ::=", + /* 393 */ "foreach_clause ::= FOR EACH ROW", + /* 394 */ "trnm ::= nm", + /* 395 */ "tridxby ::=", + /* 396 */ "database_kw_opt ::= DATABASE", + /* 397 */ "database_kw_opt ::=", + /* 398 */ "kwcolumn_opt ::=", + /* 399 */ "kwcolumn_opt ::= COLUMNKW", + /* 400 */ "vtabarglist ::= vtabarg", + /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 402 */ "vtabarg ::= vtabarg vtabargtoken", + /* 403 */ "anylist ::=", + /* 404 */ "anylist ::= anylist LP anylist RP", + /* 405 */ "anylist ::= anylist ANY", + /* 406 */ "with ::=", + /* 407 */ "windowdefn_list ::= windowdefn", + /* 408 */ "window ::= frame_opt", }; #endif /* NDEBUG */ @@ -179459,408 +180398,407 @@ static const YYCODETYPE yyRuleInfoLhs[] = { 193, /* (5) transtype ::= DEFERRED */ 193, /* (6) transtype ::= IMMEDIATE */ 193, /* (7) transtype ::= ID */ - 193, /* (8) transtype ::= CONCURRENT */ - 192, /* (9) cmd ::= COMMIT|END trans_opt */ - 192, /* (10) cmd ::= ROLLBACK trans_opt */ - 192, /* (11) cmd ::= SAVEPOINT nm */ - 192, /* (12) cmd ::= RELEASE savepoint_opt nm */ - 192, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - 197, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - 199, /* (15) createkw ::= CREATE */ - 201, /* (16) ifnotexists ::= */ - 201, /* (17) ifnotexists ::= IF NOT EXISTS */ - 200, /* (18) temp ::= TEMP */ - 200, /* (19) temp ::= */ - 198, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - 198, /* (21) create_table_args ::= AS select */ - 205, /* (22) table_option_set ::= */ - 205, /* (23) table_option_set ::= table_option_set COMMA table_option */ - 207, /* (24) table_option ::= WITHOUT nm */ - 207, /* (25) table_option ::= nm */ - 208, /* (26) columnname ::= nm typetoken */ - 210, /* (27) typetoken ::= */ - 210, /* (28) typetoken ::= typename LP signed RP */ - 210, /* (29) typetoken ::= typename LP signed COMMA signed RP */ - 211, /* (30) typename ::= typename ID|STRING */ - 215, /* (31) scanpt ::= */ - 216, /* (32) scantok ::= */ - 217, /* (33) ccons ::= CONSTRAINT nm */ - 217, /* (34) ccons ::= DEFAULT scantok term */ - 217, /* (35) ccons ::= DEFAULT LP expr RP */ - 217, /* (36) ccons ::= DEFAULT PLUS scantok term */ - 217, /* (37) ccons ::= DEFAULT MINUS scantok term */ - 217, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */ - 217, /* (39) ccons ::= NOT NULL onconf */ - 217, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - 217, /* (41) ccons ::= UNIQUE onconf */ - 217, /* (42) ccons ::= CHECK LP expr RP */ - 217, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */ - 217, /* (44) ccons ::= defer_subclause */ - 217, /* (45) ccons ::= COLLATE ID|STRING */ - 226, /* (46) generated ::= LP expr RP */ - 226, /* (47) generated ::= LP expr RP ID */ - 222, /* (48) autoinc ::= */ - 222, /* (49) autoinc ::= AUTOINCR */ - 224, /* (50) refargs ::= */ - 224, /* (51) refargs ::= refargs refarg */ - 227, /* (52) refarg ::= MATCH nm */ - 227, /* (53) refarg ::= ON INSERT refact */ - 227, /* (54) refarg ::= ON DELETE refact */ - 227, /* (55) refarg ::= ON UPDATE refact */ - 228, /* (56) refact ::= SET NULL */ - 228, /* (57) refact ::= SET DEFAULT */ - 228, /* (58) refact ::= CASCADE */ - 228, /* (59) refact ::= RESTRICT */ - 228, /* (60) refact ::= NO ACTION */ - 225, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - 225, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 229, /* (63) init_deferred_pred_opt ::= */ - 229, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - 229, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 204, /* (66) conslist_opt ::= */ - 231, /* (67) tconscomma ::= COMMA */ - 232, /* (68) tcons ::= CONSTRAINT nm */ - 232, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - 232, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */ - 232, /* (71) tcons ::= CHECK LP expr RP onconf */ - 232, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 235, /* (73) defer_subclause_opt ::= */ - 220, /* (74) onconf ::= */ - 220, /* (75) onconf ::= ON CONFLICT resolvetype */ - 236, /* (76) orconf ::= */ - 236, /* (77) orconf ::= OR resolvetype */ - 237, /* (78) resolvetype ::= IGNORE */ - 237, /* (79) resolvetype ::= REPLACE */ - 192, /* (80) cmd ::= DROP TABLE ifexists fullname */ - 239, /* (81) ifexists ::= IF EXISTS */ - 239, /* (82) ifexists ::= */ - 192, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - 192, /* (84) cmd ::= DROP VIEW ifexists fullname */ - 192, /* (85) cmd ::= select */ - 206, /* (86) select ::= WITH wqlist selectnowith */ - 206, /* (87) select ::= WITH RECURSIVE wqlist selectnowith */ - 206, /* (88) select ::= selectnowith */ - 241, /* (89) selectnowith ::= selectnowith multiselect_op oneselect */ - 244, /* (90) multiselect_op ::= UNION */ - 244, /* (91) multiselect_op ::= UNION ALL */ - 244, /* (92) multiselect_op ::= EXCEPT|INTERSECT */ - 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - 242, /* (94) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - 254, /* (95) values ::= VALUES LP nexprlist RP */ - 242, /* (96) oneselect ::= mvalues */ - 256, /* (97) mvalues ::= values COMMA LP nexprlist RP */ - 256, /* (98) mvalues ::= mvalues COMMA LP nexprlist RP */ - 245, /* (99) distinct ::= DISTINCT */ - 245, /* (100) distinct ::= ALL */ - 245, /* (101) distinct ::= */ - 257, /* (102) sclp ::= */ - 246, /* (103) selcollist ::= sclp scanpt expr scanpt as */ - 246, /* (104) selcollist ::= sclp scanpt STAR */ - 246, /* (105) selcollist ::= sclp scanpt nm DOT STAR */ - 258, /* (106) as ::= AS nm */ - 258, /* (107) as ::= */ - 247, /* (108) from ::= */ - 247, /* (109) from ::= FROM seltablist */ - 260, /* (110) stl_prefix ::= seltablist joinop */ - 260, /* (111) stl_prefix ::= */ - 259, /* (112) seltablist ::= stl_prefix nm dbnm as on_using */ - 259, /* (113) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - 259, /* (114) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - 259, /* (115) seltablist ::= stl_prefix LP select RP as on_using */ - 259, /* (116) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 202, /* (117) dbnm ::= */ - 202, /* (118) dbnm ::= DOT nm */ - 240, /* (119) fullname ::= nm */ - 240, /* (120) fullname ::= nm DOT nm */ - 265, /* (121) xfullname ::= nm */ - 265, /* (122) xfullname ::= nm DOT nm */ - 265, /* (123) xfullname ::= nm DOT nm AS nm */ - 265, /* (124) xfullname ::= nm AS nm */ - 261, /* (125) joinop ::= COMMA|JOIN */ - 261, /* (126) joinop ::= JOIN_KW JOIN */ - 261, /* (127) joinop ::= JOIN_KW nm JOIN */ - 261, /* (128) joinop ::= JOIN_KW nm nm JOIN */ - 262, /* (129) on_using ::= ON expr */ - 262, /* (130) on_using ::= USING LP idlist RP */ - 262, /* (131) on_using ::= */ - 267, /* (132) indexed_opt ::= */ - 263, /* (133) indexed_by ::= INDEXED BY nm */ - 263, /* (134) indexed_by ::= NOT INDEXED */ - 251, /* (135) orderby_opt ::= */ - 251, /* (136) orderby_opt ::= ORDER BY sortlist */ - 233, /* (137) sortlist ::= sortlist COMMA expr sortorder nulls */ - 233, /* (138) sortlist ::= expr sortorder nulls */ - 221, /* (139) sortorder ::= ASC */ - 221, /* (140) sortorder ::= DESC */ - 221, /* (141) sortorder ::= */ - 268, /* (142) nulls ::= NULLS FIRST */ - 268, /* (143) nulls ::= NULLS LAST */ - 268, /* (144) nulls ::= */ - 249, /* (145) groupby_opt ::= */ - 249, /* (146) groupby_opt ::= GROUP BY nexprlist */ - 250, /* (147) having_opt ::= */ - 250, /* (148) having_opt ::= HAVING expr */ - 252, /* (149) limit_opt ::= */ - 252, /* (150) limit_opt ::= LIMIT expr */ - 252, /* (151) limit_opt ::= LIMIT expr OFFSET expr */ - 252, /* (152) limit_opt ::= LIMIT expr COMMA expr */ - 192, /* (153) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ - 248, /* (154) where_opt ::= */ - 248, /* (155) where_opt ::= WHERE expr */ - 270, /* (156) where_opt_ret ::= */ - 270, /* (157) where_opt_ret ::= WHERE expr */ - 270, /* (158) where_opt_ret ::= RETURNING selcollist */ - 270, /* (159) where_opt_ret ::= WHERE expr RETURNING selcollist */ - 192, /* (160) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ - 271, /* (161) setlist ::= setlist COMMA nm EQ expr */ - 271, /* (162) setlist ::= setlist COMMA LP idlist RP EQ expr */ - 271, /* (163) setlist ::= nm EQ expr */ - 271, /* (164) setlist ::= LP idlist RP EQ expr */ - 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - 192, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 274, /* (167) upsert ::= */ - 274, /* (168) upsert ::= RETURNING selcollist */ - 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - 274, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - 274, /* (171) upsert ::= ON CONFLICT DO NOTHING returning */ - 274, /* (172) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - 275, /* (173) returning ::= RETURNING selcollist */ - 272, /* (174) insert_cmd ::= INSERT orconf */ - 272, /* (175) insert_cmd ::= REPLACE */ - 273, /* (176) idlist_opt ::= */ - 273, /* (177) idlist_opt ::= LP idlist RP */ - 266, /* (178) idlist ::= idlist COMMA nm */ - 266, /* (179) idlist ::= nm */ - 219, /* (180) expr ::= LP expr RP */ - 219, /* (181) expr ::= ID|INDEXED|JOIN_KW */ - 219, /* (182) expr ::= nm DOT nm */ - 219, /* (183) expr ::= nm DOT nm DOT nm */ - 218, /* (184) term ::= NULL|FLOAT|BLOB */ - 218, /* (185) term ::= STRING */ - 218, /* (186) term ::= INTEGER */ - 219, /* (187) expr ::= VARIABLE */ - 219, /* (188) expr ::= expr COLLATE ID|STRING */ - 219, /* (189) expr ::= CAST LP expr AS typetoken RP */ - 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - 219, /* (195) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - 218, /* (196) term ::= CTIME_KW */ - 219, /* (197) expr ::= LP nexprlist COMMA expr RP */ - 219, /* (198) expr ::= expr AND expr */ - 219, /* (199) expr ::= expr OR expr */ - 219, /* (200) expr ::= expr LT|GT|GE|LE expr */ - 219, /* (201) expr ::= expr EQ|NE expr */ - 219, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 219, /* (203) expr ::= expr PLUS|MINUS expr */ - 219, /* (204) expr ::= expr STAR|SLASH|REM expr */ - 219, /* (205) expr ::= expr CONCAT expr */ - 277, /* (206) likeop ::= NOT LIKE_KW|MATCH */ - 219, /* (207) expr ::= expr likeop expr */ - 219, /* (208) expr ::= expr likeop expr ESCAPE expr */ - 219, /* (209) expr ::= expr ISNULL|NOTNULL */ - 219, /* (210) expr ::= expr NOT NULL */ - 219, /* (211) expr ::= expr IS expr */ - 219, /* (212) expr ::= expr IS NOT expr */ - 219, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */ - 219, /* (214) expr ::= expr IS DISTINCT FROM expr */ - 219, /* (215) expr ::= NOT expr */ - 219, /* (216) expr ::= BITNOT expr */ - 219, /* (217) expr ::= PLUS|MINUS expr */ - 219, /* (218) expr ::= expr PTR expr */ - 278, /* (219) between_op ::= BETWEEN */ - 278, /* (220) between_op ::= NOT BETWEEN */ - 219, /* (221) expr ::= expr between_op expr AND expr */ - 279, /* (222) in_op ::= IN */ - 279, /* (223) in_op ::= NOT IN */ - 219, /* (224) expr ::= expr in_op LP exprlist RP */ - 219, /* (225) expr ::= LP select RP */ - 219, /* (226) expr ::= expr in_op LP select RP */ - 219, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */ - 219, /* (228) expr ::= EXISTS LP select RP */ - 219, /* (229) expr ::= CASE case_operand case_exprlist case_else END */ - 282, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 282, /* (231) case_exprlist ::= WHEN expr THEN expr */ - 283, /* (232) case_else ::= ELSE expr */ - 283, /* (233) case_else ::= */ - 281, /* (234) case_operand ::= */ - 264, /* (235) exprlist ::= */ - 255, /* (236) nexprlist ::= nexprlist COMMA expr */ - 255, /* (237) nexprlist ::= expr */ - 280, /* (238) paren_exprlist ::= */ - 280, /* (239) paren_exprlist ::= LP exprlist RP */ - 192, /* (240) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 284, /* (241) uniqueflag ::= UNIQUE */ - 284, /* (242) uniqueflag ::= */ - 223, /* (243) eidlist_opt ::= */ - 223, /* (244) eidlist_opt ::= LP eidlist RP */ - 234, /* (245) eidlist ::= eidlist COMMA nm collate sortorder */ - 234, /* (246) eidlist ::= nm collate sortorder */ - 285, /* (247) collate ::= */ - 285, /* (248) collate ::= COLLATE ID|STRING */ - 192, /* (249) cmd ::= DROP INDEX ifexists fullname */ - 192, /* (250) cmd ::= VACUUM vinto */ - 192, /* (251) cmd ::= VACUUM nm vinto */ - 286, /* (252) vinto ::= INTO expr */ - 286, /* (253) vinto ::= */ - 192, /* (254) cmd ::= PRAGMA nm dbnm */ - 192, /* (255) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 192, /* (256) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 192, /* (257) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 192, /* (258) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 213, /* (259) plus_num ::= PLUS INTEGER|FLOAT */ - 214, /* (260) minus_num ::= MINUS INTEGER|FLOAT */ - 192, /* (261) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 288, /* (262) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 290, /* (263) trigger_time ::= BEFORE|AFTER */ - 290, /* (264) trigger_time ::= INSTEAD OF */ - 290, /* (265) trigger_time ::= */ - 291, /* (266) trigger_event ::= DELETE|INSERT */ - 291, /* (267) trigger_event ::= UPDATE */ - 291, /* (268) trigger_event ::= UPDATE OF idlist */ - 293, /* (269) when_clause ::= */ - 293, /* (270) when_clause ::= WHEN expr */ - 289, /* (271) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 289, /* (272) trigger_cmd_list ::= trigger_cmd SEMI */ - 295, /* (273) trnm ::= nm DOT nm */ - 296, /* (274) tridxby ::= INDEXED BY nm */ - 296, /* (275) tridxby ::= NOT INDEXED */ - 294, /* (276) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 294, /* (277) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 294, /* (278) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 294, /* (279) trigger_cmd ::= scanpt select scanpt */ - 219, /* (280) expr ::= RAISE LP IGNORE RP */ - 219, /* (281) expr ::= RAISE LP raisetype COMMA expr RP */ - 238, /* (282) raisetype ::= ROLLBACK */ - 238, /* (283) raisetype ::= ABORT */ - 238, /* (284) raisetype ::= FAIL */ - 192, /* (285) cmd ::= DROP TRIGGER ifexists fullname */ - 192, /* (286) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 192, /* (287) cmd ::= DETACH database_kw_opt expr */ - 298, /* (288) key_opt ::= */ - 298, /* (289) key_opt ::= KEY expr */ - 192, /* (290) cmd ::= REINDEX */ - 192, /* (291) cmd ::= REINDEX nm dbnm */ - 192, /* (292) cmd ::= ANALYZE */ - 192, /* (293) cmd ::= ANALYZE nm dbnm */ - 192, /* (294) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 192, /* (295) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 192, /* (296) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 299, /* (297) add_column_fullname ::= fullname */ - 192, /* (298) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 192, /* (299) cmd ::= create_vtab */ - 192, /* (300) cmd ::= create_vtab LP vtabarglist RP */ - 301, /* (301) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 303, /* (302) vtabarg ::= */ - 304, /* (303) vtabargtoken ::= ANY */ - 304, /* (304) vtabargtoken ::= lp anylist RP */ - 305, /* (305) lp ::= LP */ - 269, /* (306) with ::= WITH wqlist */ - 269, /* (307) with ::= WITH RECURSIVE wqlist */ - 308, /* (308) wqas ::= AS */ - 308, /* (309) wqas ::= AS MATERIALIZED */ - 308, /* (310) wqas ::= AS NOT MATERIALIZED */ - 307, /* (311) wqitem ::= withnm eidlist_opt wqas LP select RP */ - 309, /* (312) withnm ::= nm */ - 243, /* (313) wqlist ::= wqitem */ - 243, /* (314) wqlist ::= wqlist COMMA wqitem */ - 310, /* (315) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 311, /* (316) windowdefn ::= nm AS LP window RP */ - 312, /* (317) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (318) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (319) window ::= ORDER BY sortlist frame_opt */ - 312, /* (320) window ::= nm ORDER BY sortlist frame_opt */ - 312, /* (321) window ::= nm frame_opt */ - 313, /* (322) frame_opt ::= */ - 313, /* (323) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 313, /* (324) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 317, /* (325) range_or_rows ::= RANGE|ROWS|GROUPS */ - 319, /* (326) frame_bound_s ::= frame_bound */ - 319, /* (327) frame_bound_s ::= UNBOUNDED PRECEDING */ - 320, /* (328) frame_bound_e ::= frame_bound */ - 320, /* (329) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 318, /* (330) frame_bound ::= expr PRECEDING|FOLLOWING */ - 318, /* (331) frame_bound ::= CURRENT ROW */ - 321, /* (332) frame_exclude_opt ::= */ - 321, /* (333) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 322, /* (334) frame_exclude ::= NO OTHERS */ - 322, /* (335) frame_exclude ::= CURRENT ROW */ - 322, /* (336) frame_exclude ::= GROUP|TIES */ - 253, /* (337) window_clause ::= WINDOW windowdefn_list */ - 276, /* (338) filter_over ::= filter_clause over_clause */ - 276, /* (339) filter_over ::= over_clause */ - 276, /* (340) filter_over ::= filter_clause */ - 316, /* (341) over_clause ::= OVER LP window RP */ - 316, /* (342) over_clause ::= OVER nm */ - 315, /* (343) filter_clause ::= FILTER LP WHERE expr RP */ - 218, /* (344) term ::= QNUMBER */ - 187, /* (345) input ::= cmdlist */ - 188, /* (346) cmdlist ::= cmdlist ecmd */ - 188, /* (347) cmdlist ::= ecmd */ - 189, /* (348) ecmd ::= SEMI */ - 189, /* (349) ecmd ::= cmdx SEMI */ - 189, /* (350) ecmd ::= explain cmdx SEMI */ - 194, /* (351) trans_opt ::= */ - 194, /* (352) trans_opt ::= TRANSACTION */ - 194, /* (353) trans_opt ::= TRANSACTION nm */ - 196, /* (354) savepoint_opt ::= SAVEPOINT */ - 196, /* (355) savepoint_opt ::= */ - 192, /* (356) cmd ::= create_table create_table_args */ - 205, /* (357) table_option_set ::= table_option */ - 203, /* (358) columnlist ::= columnlist COMMA columnname carglist */ - 203, /* (359) columnlist ::= columnname carglist */ - 195, /* (360) nm ::= ID|INDEXED|JOIN_KW */ - 195, /* (361) nm ::= STRING */ - 210, /* (362) typetoken ::= typename */ - 211, /* (363) typename ::= ID|STRING */ - 212, /* (364) signed ::= plus_num */ - 212, /* (365) signed ::= minus_num */ - 209, /* (366) carglist ::= carglist ccons */ - 209, /* (367) carglist ::= */ - 217, /* (368) ccons ::= NULL onconf */ - 217, /* (369) ccons ::= GENERATED ALWAYS AS generated */ - 217, /* (370) ccons ::= AS generated */ - 204, /* (371) conslist_opt ::= COMMA conslist */ - 230, /* (372) conslist ::= conslist tconscomma tcons */ - 230, /* (373) conslist ::= tcons */ - 231, /* (374) tconscomma ::= */ - 235, /* (375) defer_subclause_opt ::= defer_subclause */ - 237, /* (376) resolvetype ::= raisetype */ - 241, /* (377) selectnowith ::= oneselect */ - 242, /* (378) oneselect ::= values */ - 257, /* (379) sclp ::= selcollist COMMA */ - 258, /* (380) as ::= ID|STRING */ - 267, /* (381) indexed_opt ::= indexed_by */ - 275, /* (382) returning ::= */ - 219, /* (383) expr ::= term */ - 277, /* (384) likeop ::= LIKE_KW|MATCH */ - 281, /* (385) case_operand ::= expr */ - 264, /* (386) exprlist ::= nexprlist */ - 287, /* (387) nmnum ::= plus_num */ - 287, /* (388) nmnum ::= nm */ - 287, /* (389) nmnum ::= ON */ - 287, /* (390) nmnum ::= DELETE */ - 287, /* (391) nmnum ::= DEFAULT */ - 213, /* (392) plus_num ::= INTEGER|FLOAT */ - 292, /* (393) foreach_clause ::= */ - 292, /* (394) foreach_clause ::= FOR EACH ROW */ - 295, /* (395) trnm ::= nm */ - 296, /* (396) tridxby ::= */ - 297, /* (397) database_kw_opt ::= DATABASE */ - 297, /* (398) database_kw_opt ::= */ - 300, /* (399) kwcolumn_opt ::= */ - 300, /* (400) kwcolumn_opt ::= COLUMNKW */ - 302, /* (401) vtabarglist ::= vtabarg */ - 302, /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ - 303, /* (403) vtabarg ::= vtabarg vtabargtoken */ - 306, /* (404) anylist ::= */ - 306, /* (405) anylist ::= anylist LP anylist RP */ - 306, /* (406) anylist ::= anylist ANY */ - 269, /* (407) with ::= */ - 310, /* (408) windowdefn_list ::= windowdefn */ - 312, /* (409) window ::= frame_opt */ + 192, /* (8) cmd ::= COMMIT|END trans_opt */ + 192, /* (9) cmd ::= ROLLBACK trans_opt */ + 192, /* (10) cmd ::= SAVEPOINT nm */ + 192, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 192, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 197, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 199, /* (14) createkw ::= CREATE */ + 201, /* (15) ifnotexists ::= */ + 201, /* (16) ifnotexists ::= IF NOT EXISTS */ + 200, /* (17) temp ::= TEMP */ + 200, /* (18) temp ::= */ + 198, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + 198, /* (20) create_table_args ::= AS select */ + 205, /* (21) table_option_set ::= */ + 205, /* (22) table_option_set ::= table_option_set COMMA table_option */ + 207, /* (23) table_option ::= WITHOUT nm */ + 207, /* (24) table_option ::= nm */ + 208, /* (25) columnname ::= nm typetoken */ + 210, /* (26) typetoken ::= */ + 210, /* (27) typetoken ::= typename LP signed RP */ + 210, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + 211, /* (29) typename ::= typename ID|STRING */ + 215, /* (30) scanpt ::= */ + 216, /* (31) scantok ::= */ + 217, /* (32) ccons ::= CONSTRAINT nm */ + 217, /* (33) ccons ::= DEFAULT scantok term */ + 217, /* (34) ccons ::= DEFAULT LP expr RP */ + 217, /* (35) ccons ::= DEFAULT PLUS scantok term */ + 217, /* (36) ccons ::= DEFAULT MINUS scantok term */ + 217, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + 217, /* (38) ccons ::= NOT NULL onconf */ + 217, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 217, /* (40) ccons ::= UNIQUE onconf */ + 217, /* (41) ccons ::= CHECK LP expr RP */ + 217, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + 217, /* (43) ccons ::= defer_subclause */ + 217, /* (44) ccons ::= COLLATE ID|STRING */ + 226, /* (45) generated ::= LP expr RP */ + 226, /* (46) generated ::= LP expr RP ID */ + 222, /* (47) autoinc ::= */ + 222, /* (48) autoinc ::= AUTOINCR */ + 224, /* (49) refargs ::= */ + 224, /* (50) refargs ::= refargs refarg */ + 227, /* (51) refarg ::= MATCH nm */ + 227, /* (52) refarg ::= ON INSERT refact */ + 227, /* (53) refarg ::= ON DELETE refact */ + 227, /* (54) refarg ::= ON UPDATE refact */ + 228, /* (55) refact ::= SET NULL */ + 228, /* (56) refact ::= SET DEFAULT */ + 228, /* (57) refact ::= CASCADE */ + 228, /* (58) refact ::= RESTRICT */ + 228, /* (59) refact ::= NO ACTION */ + 225, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 225, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 229, /* (62) init_deferred_pred_opt ::= */ + 229, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 229, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 204, /* (65) conslist_opt ::= */ + 231, /* (66) tconscomma ::= COMMA */ + 232, /* (67) tcons ::= CONSTRAINT nm */ + 232, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 232, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + 232, /* (70) tcons ::= CHECK LP expr RP onconf */ + 232, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 235, /* (72) defer_subclause_opt ::= */ + 220, /* (73) onconf ::= */ + 220, /* (74) onconf ::= ON CONFLICT resolvetype */ + 236, /* (75) orconf ::= */ + 236, /* (76) orconf ::= OR resolvetype */ + 237, /* (77) resolvetype ::= IGNORE */ + 237, /* (78) resolvetype ::= REPLACE */ + 192, /* (79) cmd ::= DROP TABLE ifexists fullname */ + 239, /* (80) ifexists ::= IF EXISTS */ + 239, /* (81) ifexists ::= */ + 192, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 192, /* (83) cmd ::= DROP VIEW ifexists fullname */ + 192, /* (84) cmd ::= select */ + 206, /* (85) select ::= WITH wqlist selectnowith */ + 206, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + 206, /* (87) select ::= selectnowith */ + 241, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + 244, /* (89) multiselect_op ::= UNION */ + 244, /* (90) multiselect_op ::= UNION ALL */ + 244, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + 242, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 254, /* (94) values ::= VALUES LP nexprlist RP */ + 242, /* (95) oneselect ::= mvalues */ + 256, /* (96) mvalues ::= values COMMA LP nexprlist RP */ + 256, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ + 245, /* (98) distinct ::= DISTINCT */ + 245, /* (99) distinct ::= ALL */ + 245, /* (100) distinct ::= */ + 257, /* (101) sclp ::= */ + 246, /* (102) selcollist ::= sclp scanpt expr scanpt as */ + 246, /* (103) selcollist ::= sclp scanpt STAR */ + 246, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ + 258, /* (105) as ::= AS nm */ + 258, /* (106) as ::= */ + 247, /* (107) from ::= */ + 247, /* (108) from ::= FROM seltablist */ + 260, /* (109) stl_prefix ::= seltablist joinop */ + 260, /* (110) stl_prefix ::= */ + 259, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ + 259, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + 259, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + 259, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ + 259, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 202, /* (116) dbnm ::= */ + 202, /* (117) dbnm ::= DOT nm */ + 240, /* (118) fullname ::= nm */ + 240, /* (119) fullname ::= nm DOT nm */ + 265, /* (120) xfullname ::= nm */ + 265, /* (121) xfullname ::= nm DOT nm */ + 265, /* (122) xfullname ::= nm DOT nm AS nm */ + 265, /* (123) xfullname ::= nm AS nm */ + 261, /* (124) joinop ::= COMMA|JOIN */ + 261, /* (125) joinop ::= JOIN_KW JOIN */ + 261, /* (126) joinop ::= JOIN_KW nm JOIN */ + 261, /* (127) joinop ::= JOIN_KW nm nm JOIN */ + 262, /* (128) on_using ::= ON expr */ + 262, /* (129) on_using ::= USING LP idlist RP */ + 262, /* (130) on_using ::= */ + 267, /* (131) indexed_opt ::= */ + 263, /* (132) indexed_by ::= INDEXED BY nm */ + 263, /* (133) indexed_by ::= NOT INDEXED */ + 251, /* (134) orderby_opt ::= */ + 251, /* (135) orderby_opt ::= ORDER BY sortlist */ + 233, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ + 233, /* (137) sortlist ::= expr sortorder nulls */ + 221, /* (138) sortorder ::= ASC */ + 221, /* (139) sortorder ::= DESC */ + 221, /* (140) sortorder ::= */ + 268, /* (141) nulls ::= NULLS FIRST */ + 268, /* (142) nulls ::= NULLS LAST */ + 268, /* (143) nulls ::= */ + 249, /* (144) groupby_opt ::= */ + 249, /* (145) groupby_opt ::= GROUP BY nexprlist */ + 250, /* (146) having_opt ::= */ + 250, /* (147) having_opt ::= HAVING expr */ + 252, /* (148) limit_opt ::= */ + 252, /* (149) limit_opt ::= LIMIT expr */ + 252, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ + 252, /* (151) limit_opt ::= LIMIT expr COMMA expr */ + 192, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + 248, /* (153) where_opt ::= */ + 248, /* (154) where_opt ::= WHERE expr */ + 270, /* (155) where_opt_ret ::= */ + 270, /* (156) where_opt_ret ::= WHERE expr */ + 270, /* (157) where_opt_ret ::= RETURNING selcollist */ + 270, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ + 192, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + 271, /* (160) setlist ::= setlist COMMA nm EQ expr */ + 271, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 271, /* (162) setlist ::= nm EQ expr */ + 271, /* (163) setlist ::= LP idlist RP EQ expr */ + 192, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 274, /* (166) upsert ::= */ + 274, /* (167) upsert ::= RETURNING selcollist */ + 274, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + 274, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ + 274, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + 275, /* (172) returning ::= RETURNING selcollist */ + 272, /* (173) insert_cmd ::= INSERT orconf */ + 272, /* (174) insert_cmd ::= REPLACE */ + 273, /* (175) idlist_opt ::= */ + 273, /* (176) idlist_opt ::= LP idlist RP */ + 266, /* (177) idlist ::= idlist COMMA nm */ + 266, /* (178) idlist ::= nm */ + 219, /* (179) expr ::= LP expr RP */ + 219, /* (180) expr ::= ID|INDEXED|JOIN_KW */ + 219, /* (181) expr ::= nm DOT nm */ + 219, /* (182) expr ::= nm DOT nm DOT nm */ + 218, /* (183) term ::= NULL|FLOAT|BLOB */ + 218, /* (184) term ::= STRING */ + 218, /* (185) term ::= INTEGER */ + 219, /* (186) expr ::= VARIABLE */ + 219, /* (187) expr ::= expr COLLATE ID|STRING */ + 219, /* (188) expr ::= CAST LP expr AS typetoken RP */ + 219, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + 218, /* (195) term ::= CTIME_KW */ + 219, /* (196) expr ::= LP nexprlist COMMA expr RP */ + 219, /* (197) expr ::= expr AND expr */ + 219, /* (198) expr ::= expr OR expr */ + 219, /* (199) expr ::= expr LT|GT|GE|LE expr */ + 219, /* (200) expr ::= expr EQ|NE expr */ + 219, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 219, /* (202) expr ::= expr PLUS|MINUS expr */ + 219, /* (203) expr ::= expr STAR|SLASH|REM expr */ + 219, /* (204) expr ::= expr CONCAT expr */ + 277, /* (205) likeop ::= NOT LIKE_KW|MATCH */ + 219, /* (206) expr ::= expr likeop expr */ + 219, /* (207) expr ::= expr likeop expr ESCAPE expr */ + 219, /* (208) expr ::= expr ISNULL|NOTNULL */ + 219, /* (209) expr ::= expr NOT NULL */ + 219, /* (210) expr ::= expr IS expr */ + 219, /* (211) expr ::= expr IS NOT expr */ + 219, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ + 219, /* (213) expr ::= expr IS DISTINCT FROM expr */ + 219, /* (214) expr ::= NOT expr */ + 219, /* (215) expr ::= BITNOT expr */ + 219, /* (216) expr ::= PLUS|MINUS expr */ + 219, /* (217) expr ::= expr PTR expr */ + 278, /* (218) between_op ::= BETWEEN */ + 278, /* (219) between_op ::= NOT BETWEEN */ + 219, /* (220) expr ::= expr between_op expr AND expr */ + 279, /* (221) in_op ::= IN */ + 279, /* (222) in_op ::= NOT IN */ + 219, /* (223) expr ::= expr in_op LP exprlist RP */ + 219, /* (224) expr ::= LP select RP */ + 219, /* (225) expr ::= expr in_op LP select RP */ + 219, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ + 219, /* (227) expr ::= EXISTS LP select RP */ + 219, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ + 282, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 282, /* (230) case_exprlist ::= WHEN expr THEN expr */ + 283, /* (231) case_else ::= ELSE expr */ + 283, /* (232) case_else ::= */ + 281, /* (233) case_operand ::= */ + 264, /* (234) exprlist ::= */ + 255, /* (235) nexprlist ::= nexprlist COMMA expr */ + 255, /* (236) nexprlist ::= expr */ + 280, /* (237) paren_exprlist ::= */ + 280, /* (238) paren_exprlist ::= LP exprlist RP */ + 192, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 284, /* (240) uniqueflag ::= UNIQUE */ + 284, /* (241) uniqueflag ::= */ + 223, /* (242) eidlist_opt ::= */ + 223, /* (243) eidlist_opt ::= LP eidlist RP */ + 234, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ + 234, /* (245) eidlist ::= nm collate sortorder */ + 285, /* (246) collate ::= */ + 285, /* (247) collate ::= COLLATE ID|STRING */ + 192, /* (248) cmd ::= DROP INDEX ifexists fullname */ + 192, /* (249) cmd ::= VACUUM vinto */ + 192, /* (250) cmd ::= VACUUM nm vinto */ + 286, /* (251) vinto ::= INTO expr */ + 286, /* (252) vinto ::= */ + 192, /* (253) cmd ::= PRAGMA nm dbnm */ + 192, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 192, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 192, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 192, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 213, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ + 214, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ + 192, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 288, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 290, /* (262) trigger_time ::= BEFORE|AFTER */ + 290, /* (263) trigger_time ::= INSTEAD OF */ + 290, /* (264) trigger_time ::= */ + 291, /* (265) trigger_event ::= DELETE|INSERT */ + 291, /* (266) trigger_event ::= UPDATE */ + 291, /* (267) trigger_event ::= UPDATE OF idlist */ + 293, /* (268) when_clause ::= */ + 293, /* (269) when_clause ::= WHEN expr */ + 289, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 289, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ + 295, /* (272) trnm ::= nm DOT nm */ + 296, /* (273) tridxby ::= INDEXED BY nm */ + 296, /* (274) tridxby ::= NOT INDEXED */ + 294, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + 294, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 294, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 294, /* (278) trigger_cmd ::= scanpt select scanpt */ + 219, /* (279) expr ::= RAISE LP IGNORE RP */ + 219, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ + 238, /* (281) raisetype ::= ROLLBACK */ + 238, /* (282) raisetype ::= ABORT */ + 238, /* (283) raisetype ::= FAIL */ + 192, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ + 192, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 192, /* (286) cmd ::= DETACH database_kw_opt expr */ + 298, /* (287) key_opt ::= */ + 298, /* (288) key_opt ::= KEY expr */ + 192, /* (289) cmd ::= REINDEX */ + 192, /* (290) cmd ::= REINDEX nm dbnm */ + 192, /* (291) cmd ::= ANALYZE */ + 192, /* (292) cmd ::= ANALYZE nm dbnm */ + 192, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 192, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 192, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 299, /* (296) add_column_fullname ::= fullname */ + 192, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 192, /* (298) cmd ::= create_vtab */ + 192, /* (299) cmd ::= create_vtab LP vtabarglist RP */ + 301, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 303, /* (301) vtabarg ::= */ + 304, /* (302) vtabargtoken ::= ANY */ + 304, /* (303) vtabargtoken ::= lp anylist RP */ + 305, /* (304) lp ::= LP */ + 269, /* (305) with ::= WITH wqlist */ + 269, /* (306) with ::= WITH RECURSIVE wqlist */ + 308, /* (307) wqas ::= AS */ + 308, /* (308) wqas ::= AS MATERIALIZED */ + 308, /* (309) wqas ::= AS NOT MATERIALIZED */ + 307, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ + 309, /* (311) withnm ::= nm */ + 243, /* (312) wqlist ::= wqitem */ + 243, /* (313) wqlist ::= wqlist COMMA wqitem */ + 310, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 311, /* (315) windowdefn ::= nm AS LP window RP */ + 312, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 312, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 312, /* (318) window ::= ORDER BY sortlist frame_opt */ + 312, /* (319) window ::= nm ORDER BY sortlist frame_opt */ + 312, /* (320) window ::= nm frame_opt */ + 313, /* (321) frame_opt ::= */ + 313, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 313, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 317, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ + 319, /* (325) frame_bound_s ::= frame_bound */ + 319, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ + 320, /* (327) frame_bound_e ::= frame_bound */ + 320, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 318, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ + 318, /* (330) frame_bound ::= CURRENT ROW */ + 321, /* (331) frame_exclude_opt ::= */ + 321, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 322, /* (333) frame_exclude ::= NO OTHERS */ + 322, /* (334) frame_exclude ::= CURRENT ROW */ + 322, /* (335) frame_exclude ::= GROUP|TIES */ + 253, /* (336) window_clause ::= WINDOW windowdefn_list */ + 276, /* (337) filter_over ::= filter_clause over_clause */ + 276, /* (338) filter_over ::= over_clause */ + 276, /* (339) filter_over ::= filter_clause */ + 316, /* (340) over_clause ::= OVER LP window RP */ + 316, /* (341) over_clause ::= OVER nm */ + 315, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ + 218, /* (343) term ::= QNUMBER */ + 187, /* (344) input ::= cmdlist */ + 188, /* (345) cmdlist ::= cmdlist ecmd */ + 188, /* (346) cmdlist ::= ecmd */ + 189, /* (347) ecmd ::= SEMI */ + 189, /* (348) ecmd ::= cmdx SEMI */ + 189, /* (349) ecmd ::= explain cmdx SEMI */ + 194, /* (350) trans_opt ::= */ + 194, /* (351) trans_opt ::= TRANSACTION */ + 194, /* (352) trans_opt ::= TRANSACTION nm */ + 196, /* (353) savepoint_opt ::= SAVEPOINT */ + 196, /* (354) savepoint_opt ::= */ + 192, /* (355) cmd ::= create_table create_table_args */ + 205, /* (356) table_option_set ::= table_option */ + 203, /* (357) columnlist ::= columnlist COMMA columnname carglist */ + 203, /* (358) columnlist ::= columnname carglist */ + 195, /* (359) nm ::= ID|INDEXED|JOIN_KW */ + 195, /* (360) nm ::= STRING */ + 210, /* (361) typetoken ::= typename */ + 211, /* (362) typename ::= ID|STRING */ + 212, /* (363) signed ::= plus_num */ + 212, /* (364) signed ::= minus_num */ + 209, /* (365) carglist ::= carglist ccons */ + 209, /* (366) carglist ::= */ + 217, /* (367) ccons ::= NULL onconf */ + 217, /* (368) ccons ::= GENERATED ALWAYS AS generated */ + 217, /* (369) ccons ::= AS generated */ + 204, /* (370) conslist_opt ::= COMMA conslist */ + 230, /* (371) conslist ::= conslist tconscomma tcons */ + 230, /* (372) conslist ::= tcons */ + 231, /* (373) tconscomma ::= */ + 235, /* (374) defer_subclause_opt ::= defer_subclause */ + 237, /* (375) resolvetype ::= raisetype */ + 241, /* (376) selectnowith ::= oneselect */ + 242, /* (377) oneselect ::= values */ + 257, /* (378) sclp ::= selcollist COMMA */ + 258, /* (379) as ::= ID|STRING */ + 267, /* (380) indexed_opt ::= indexed_by */ + 275, /* (381) returning ::= */ + 219, /* (382) expr ::= term */ + 277, /* (383) likeop ::= LIKE_KW|MATCH */ + 281, /* (384) case_operand ::= expr */ + 264, /* (385) exprlist ::= nexprlist */ + 287, /* (386) nmnum ::= plus_num */ + 287, /* (387) nmnum ::= nm */ + 287, /* (388) nmnum ::= ON */ + 287, /* (389) nmnum ::= DELETE */ + 287, /* (390) nmnum ::= DEFAULT */ + 213, /* (391) plus_num ::= INTEGER|FLOAT */ + 292, /* (392) foreach_clause ::= */ + 292, /* (393) foreach_clause ::= FOR EACH ROW */ + 295, /* (394) trnm ::= nm */ + 296, /* (395) tridxby ::= */ + 297, /* (396) database_kw_opt ::= DATABASE */ + 297, /* (397) database_kw_opt ::= */ + 300, /* (398) kwcolumn_opt ::= */ + 300, /* (399) kwcolumn_opt ::= COLUMNKW */ + 302, /* (400) vtabarglist ::= vtabarg */ + 302, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ + 303, /* (402) vtabarg ::= vtabarg vtabargtoken */ + 306, /* (403) anylist ::= */ + 306, /* (404) anylist ::= anylist LP anylist RP */ + 306, /* (405) anylist ::= anylist ANY */ + 269, /* (406) with ::= */ + 310, /* (407) windowdefn_list ::= windowdefn */ + 312, /* (408) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -179874,408 +180812,407 @@ static const signed char yyRuleInfoNRhs[] = { -1, /* (5) transtype ::= DEFERRED */ -1, /* (6) transtype ::= IMMEDIATE */ -1, /* (7) transtype ::= ID */ - -1, /* (8) transtype ::= CONCURRENT */ - -2, /* (9) cmd ::= COMMIT|END trans_opt */ - -2, /* (10) cmd ::= ROLLBACK trans_opt */ - -2, /* (11) cmd ::= SAVEPOINT nm */ - -3, /* (12) cmd ::= RELEASE savepoint_opt nm */ - -5, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - -6, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - -1, /* (15) createkw ::= CREATE */ - 0, /* (16) ifnotexists ::= */ - -3, /* (17) ifnotexists ::= IF NOT EXISTS */ - -1, /* (18) temp ::= TEMP */ - 0, /* (19) temp ::= */ - -5, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - -2, /* (21) create_table_args ::= AS select */ - 0, /* (22) table_option_set ::= */ - -3, /* (23) table_option_set ::= table_option_set COMMA table_option */ - -2, /* (24) table_option ::= WITHOUT nm */ - -1, /* (25) table_option ::= nm */ - -2, /* (26) columnname ::= nm typetoken */ - 0, /* (27) typetoken ::= */ - -4, /* (28) typetoken ::= typename LP signed RP */ - -6, /* (29) typetoken ::= typename LP signed COMMA signed RP */ - -2, /* (30) typename ::= typename ID|STRING */ - 0, /* (31) scanpt ::= */ - 0, /* (32) scantok ::= */ - -2, /* (33) ccons ::= CONSTRAINT nm */ - -3, /* (34) ccons ::= DEFAULT scantok term */ - -4, /* (35) ccons ::= DEFAULT LP expr RP */ - -4, /* (36) ccons ::= DEFAULT PLUS scantok term */ - -4, /* (37) ccons ::= DEFAULT MINUS scantok term */ - -3, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */ - -3, /* (39) ccons ::= NOT NULL onconf */ - -5, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - -2, /* (41) ccons ::= UNIQUE onconf */ - -4, /* (42) ccons ::= CHECK LP expr RP */ - -4, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */ - -1, /* (44) ccons ::= defer_subclause */ - -2, /* (45) ccons ::= COLLATE ID|STRING */ - -3, /* (46) generated ::= LP expr RP */ - -4, /* (47) generated ::= LP expr RP ID */ - 0, /* (48) autoinc ::= */ - -1, /* (49) autoinc ::= AUTOINCR */ - 0, /* (50) refargs ::= */ - -2, /* (51) refargs ::= refargs refarg */ - -2, /* (52) refarg ::= MATCH nm */ - -3, /* (53) refarg ::= ON INSERT refact */ - -3, /* (54) refarg ::= ON DELETE refact */ - -3, /* (55) refarg ::= ON UPDATE refact */ - -2, /* (56) refact ::= SET NULL */ - -2, /* (57) refact ::= SET DEFAULT */ - -1, /* (58) refact ::= CASCADE */ - -1, /* (59) refact ::= RESTRICT */ - -2, /* (60) refact ::= NO ACTION */ - -3, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - -2, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 0, /* (63) init_deferred_pred_opt ::= */ - -2, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - -2, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 0, /* (66) conslist_opt ::= */ - -1, /* (67) tconscomma ::= COMMA */ - -2, /* (68) tcons ::= CONSTRAINT nm */ - -7, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - -5, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */ - -5, /* (71) tcons ::= CHECK LP expr RP onconf */ - -10, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 0, /* (73) defer_subclause_opt ::= */ - 0, /* (74) onconf ::= */ - -3, /* (75) onconf ::= ON CONFLICT resolvetype */ - 0, /* (76) orconf ::= */ - -2, /* (77) orconf ::= OR resolvetype */ - -1, /* (78) resolvetype ::= IGNORE */ - -1, /* (79) resolvetype ::= REPLACE */ - -4, /* (80) cmd ::= DROP TABLE ifexists fullname */ - -2, /* (81) ifexists ::= IF EXISTS */ - 0, /* (82) ifexists ::= */ - -9, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - -4, /* (84) cmd ::= DROP VIEW ifexists fullname */ - -1, /* (85) cmd ::= select */ - -3, /* (86) select ::= WITH wqlist selectnowith */ - -4, /* (87) select ::= WITH RECURSIVE wqlist selectnowith */ - -1, /* (88) select ::= selectnowith */ - -3, /* (89) selectnowith ::= selectnowith multiselect_op oneselect */ - -1, /* (90) multiselect_op ::= UNION */ - -2, /* (91) multiselect_op ::= UNION ALL */ - -1, /* (92) multiselect_op ::= EXCEPT|INTERSECT */ - -9, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - -10, /* (94) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - -4, /* (95) values ::= VALUES LP nexprlist RP */ - -1, /* (96) oneselect ::= mvalues */ - -5, /* (97) mvalues ::= values COMMA LP nexprlist RP */ - -5, /* (98) mvalues ::= mvalues COMMA LP nexprlist RP */ - -1, /* (99) distinct ::= DISTINCT */ - -1, /* (100) distinct ::= ALL */ - 0, /* (101) distinct ::= */ - 0, /* (102) sclp ::= */ - -5, /* (103) selcollist ::= sclp scanpt expr scanpt as */ - -3, /* (104) selcollist ::= sclp scanpt STAR */ - -5, /* (105) selcollist ::= sclp scanpt nm DOT STAR */ - -2, /* (106) as ::= AS nm */ - 0, /* (107) as ::= */ - 0, /* (108) from ::= */ - -2, /* (109) from ::= FROM seltablist */ - -2, /* (110) stl_prefix ::= seltablist joinop */ - 0, /* (111) stl_prefix ::= */ - -5, /* (112) seltablist ::= stl_prefix nm dbnm as on_using */ - -6, /* (113) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - -8, /* (114) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - -6, /* (115) seltablist ::= stl_prefix LP select RP as on_using */ - -6, /* (116) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 0, /* (117) dbnm ::= */ - -2, /* (118) dbnm ::= DOT nm */ - -1, /* (119) fullname ::= nm */ - -3, /* (120) fullname ::= nm DOT nm */ - -1, /* (121) xfullname ::= nm */ - -3, /* (122) xfullname ::= nm DOT nm */ - -5, /* (123) xfullname ::= nm DOT nm AS nm */ - -3, /* (124) xfullname ::= nm AS nm */ - -1, /* (125) joinop ::= COMMA|JOIN */ - -2, /* (126) joinop ::= JOIN_KW JOIN */ - -3, /* (127) joinop ::= JOIN_KW nm JOIN */ - -4, /* (128) joinop ::= JOIN_KW nm nm JOIN */ - -2, /* (129) on_using ::= ON expr */ - -4, /* (130) on_using ::= USING LP idlist RP */ - 0, /* (131) on_using ::= */ - 0, /* (132) indexed_opt ::= */ - -3, /* (133) indexed_by ::= INDEXED BY nm */ - -2, /* (134) indexed_by ::= NOT INDEXED */ - 0, /* (135) orderby_opt ::= */ - -3, /* (136) orderby_opt ::= ORDER BY sortlist */ - -5, /* (137) sortlist ::= sortlist COMMA expr sortorder nulls */ - -3, /* (138) sortlist ::= expr sortorder nulls */ - -1, /* (139) sortorder ::= ASC */ - -1, /* (140) sortorder ::= DESC */ - 0, /* (141) sortorder ::= */ - -2, /* (142) nulls ::= NULLS FIRST */ - -2, /* (143) nulls ::= NULLS LAST */ - 0, /* (144) nulls ::= */ - 0, /* (145) groupby_opt ::= */ - -3, /* (146) groupby_opt ::= GROUP BY nexprlist */ - 0, /* (147) having_opt ::= */ - -2, /* (148) having_opt ::= HAVING expr */ - 0, /* (149) limit_opt ::= */ - -2, /* (150) limit_opt ::= LIMIT expr */ - -4, /* (151) limit_opt ::= LIMIT expr OFFSET expr */ - -4, /* (152) limit_opt ::= LIMIT expr COMMA expr */ - -8, /* (153) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ - 0, /* (154) where_opt ::= */ - -2, /* (155) where_opt ::= WHERE expr */ - 0, /* (156) where_opt_ret ::= */ - -2, /* (157) where_opt_ret ::= WHERE expr */ - -2, /* (158) where_opt_ret ::= RETURNING selcollist */ - -4, /* (159) where_opt_ret ::= WHERE expr RETURNING selcollist */ - -11, /* (160) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ - -5, /* (161) setlist ::= setlist COMMA nm EQ expr */ - -7, /* (162) setlist ::= setlist COMMA LP idlist RP EQ expr */ - -3, /* (163) setlist ::= nm EQ expr */ - -5, /* (164) setlist ::= LP idlist RP EQ expr */ - -7, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - -8, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 0, /* (167) upsert ::= */ - -2, /* (168) upsert ::= RETURNING selcollist */ - -12, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - -9, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - -5, /* (171) upsert ::= ON CONFLICT DO NOTHING returning */ - -8, /* (172) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - -2, /* (173) returning ::= RETURNING selcollist */ - -2, /* (174) insert_cmd ::= INSERT orconf */ - -1, /* (175) insert_cmd ::= REPLACE */ - 0, /* (176) idlist_opt ::= */ - -3, /* (177) idlist_opt ::= LP idlist RP */ - -3, /* (178) idlist ::= idlist COMMA nm */ - -1, /* (179) idlist ::= nm */ - -3, /* (180) expr ::= LP expr RP */ - -1, /* (181) expr ::= ID|INDEXED|JOIN_KW */ - -3, /* (182) expr ::= nm DOT nm */ - -5, /* (183) expr ::= nm DOT nm DOT nm */ - -1, /* (184) term ::= NULL|FLOAT|BLOB */ - -1, /* (185) term ::= STRING */ - -1, /* (186) term ::= INTEGER */ - -1, /* (187) expr ::= VARIABLE */ - -3, /* (188) expr ::= expr COLLATE ID|STRING */ - -6, /* (189) expr ::= CAST LP expr AS typetoken RP */ - -5, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - -8, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - -4, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - -6, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - -9, /* (194) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - -5, /* (195) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - -1, /* (196) term ::= CTIME_KW */ - -5, /* (197) expr ::= LP nexprlist COMMA expr RP */ - -3, /* (198) expr ::= expr AND expr */ - -3, /* (199) expr ::= expr OR expr */ - -3, /* (200) expr ::= expr LT|GT|GE|LE expr */ - -3, /* (201) expr ::= expr EQ|NE expr */ - -3, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - -3, /* (203) expr ::= expr PLUS|MINUS expr */ - -3, /* (204) expr ::= expr STAR|SLASH|REM expr */ - -3, /* (205) expr ::= expr CONCAT expr */ - -2, /* (206) likeop ::= NOT LIKE_KW|MATCH */ - -3, /* (207) expr ::= expr likeop expr */ - -5, /* (208) expr ::= expr likeop expr ESCAPE expr */ - -2, /* (209) expr ::= expr ISNULL|NOTNULL */ - -3, /* (210) expr ::= expr NOT NULL */ - -3, /* (211) expr ::= expr IS expr */ - -4, /* (212) expr ::= expr IS NOT expr */ - -6, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */ - -5, /* (214) expr ::= expr IS DISTINCT FROM expr */ - -2, /* (215) expr ::= NOT expr */ - -2, /* (216) expr ::= BITNOT expr */ - -2, /* (217) expr ::= PLUS|MINUS expr */ - -3, /* (218) expr ::= expr PTR expr */ - -1, /* (219) between_op ::= BETWEEN */ - -2, /* (220) between_op ::= NOT BETWEEN */ - -5, /* (221) expr ::= expr between_op expr AND expr */ - -1, /* (222) in_op ::= IN */ - -2, /* (223) in_op ::= NOT IN */ - -5, /* (224) expr ::= expr in_op LP exprlist RP */ - -3, /* (225) expr ::= LP select RP */ - -5, /* (226) expr ::= expr in_op LP select RP */ - -5, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */ - -4, /* (228) expr ::= EXISTS LP select RP */ - -5, /* (229) expr ::= CASE case_operand case_exprlist case_else END */ - -5, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - -4, /* (231) case_exprlist ::= WHEN expr THEN expr */ - -2, /* (232) case_else ::= ELSE expr */ - 0, /* (233) case_else ::= */ - 0, /* (234) case_operand ::= */ - 0, /* (235) exprlist ::= */ - -3, /* (236) nexprlist ::= nexprlist COMMA expr */ - -1, /* (237) nexprlist ::= expr */ - 0, /* (238) paren_exprlist ::= */ - -3, /* (239) paren_exprlist ::= LP exprlist RP */ - -12, /* (240) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - -1, /* (241) uniqueflag ::= UNIQUE */ - 0, /* (242) uniqueflag ::= */ - 0, /* (243) eidlist_opt ::= */ - -3, /* (244) eidlist_opt ::= LP eidlist RP */ - -5, /* (245) eidlist ::= eidlist COMMA nm collate sortorder */ - -3, /* (246) eidlist ::= nm collate sortorder */ - 0, /* (247) collate ::= */ - -2, /* (248) collate ::= COLLATE ID|STRING */ - -4, /* (249) cmd ::= DROP INDEX ifexists fullname */ - -2, /* (250) cmd ::= VACUUM vinto */ - -3, /* (251) cmd ::= VACUUM nm vinto */ - -2, /* (252) vinto ::= INTO expr */ - 0, /* (253) vinto ::= */ - -3, /* (254) cmd ::= PRAGMA nm dbnm */ - -5, /* (255) cmd ::= PRAGMA nm dbnm EQ nmnum */ - -6, /* (256) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - -5, /* (257) cmd ::= PRAGMA nm dbnm EQ minus_num */ - -6, /* (258) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - -2, /* (259) plus_num ::= PLUS INTEGER|FLOAT */ - -2, /* (260) minus_num ::= MINUS INTEGER|FLOAT */ - -5, /* (261) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - -11, /* (262) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - -1, /* (263) trigger_time ::= BEFORE|AFTER */ - -2, /* (264) trigger_time ::= INSTEAD OF */ - 0, /* (265) trigger_time ::= */ - -1, /* (266) trigger_event ::= DELETE|INSERT */ - -1, /* (267) trigger_event ::= UPDATE */ - -3, /* (268) trigger_event ::= UPDATE OF idlist */ - 0, /* (269) when_clause ::= */ - -2, /* (270) when_clause ::= WHEN expr */ - -3, /* (271) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - -2, /* (272) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (273) trnm ::= nm DOT nm */ - -3, /* (274) tridxby ::= INDEXED BY nm */ - -2, /* (275) tridxby ::= NOT INDEXED */ - -9, /* (276) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (277) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (278) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (279) trigger_cmd ::= scanpt select scanpt */ - -4, /* (280) expr ::= RAISE LP IGNORE RP */ - -6, /* (281) expr ::= RAISE LP raisetype COMMA expr RP */ - -1, /* (282) raisetype ::= ROLLBACK */ - -1, /* (283) raisetype ::= ABORT */ - -1, /* (284) raisetype ::= FAIL */ - -4, /* (285) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (286) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (287) cmd ::= DETACH database_kw_opt expr */ - 0, /* (288) key_opt ::= */ - -2, /* (289) key_opt ::= KEY expr */ - -1, /* (290) cmd ::= REINDEX */ - -3, /* (291) cmd ::= REINDEX nm dbnm */ - -1, /* (292) cmd ::= ANALYZE */ - -3, /* (293) cmd ::= ANALYZE nm dbnm */ - -6, /* (294) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (295) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - -6, /* (296) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (297) add_column_fullname ::= fullname */ - -8, /* (298) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (299) cmd ::= create_vtab */ - -4, /* (300) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (301) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (302) vtabarg ::= */ - -1, /* (303) vtabargtoken ::= ANY */ - -3, /* (304) vtabargtoken ::= lp anylist RP */ - -1, /* (305) lp ::= LP */ - -2, /* (306) with ::= WITH wqlist */ - -3, /* (307) with ::= WITH RECURSIVE wqlist */ - -1, /* (308) wqas ::= AS */ - -2, /* (309) wqas ::= AS MATERIALIZED */ - -3, /* (310) wqas ::= AS NOT MATERIALIZED */ - -6, /* (311) wqitem ::= withnm eidlist_opt wqas LP select RP */ - -1, /* (312) withnm ::= nm */ - -1, /* (313) wqlist ::= wqitem */ - -3, /* (314) wqlist ::= wqlist COMMA wqitem */ - -3, /* (315) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (316) windowdefn ::= nm AS LP window RP */ - -5, /* (317) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (318) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (319) window ::= ORDER BY sortlist frame_opt */ - -5, /* (320) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (321) window ::= nm frame_opt */ - 0, /* (322) frame_opt ::= */ - -3, /* (323) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (324) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (325) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (326) frame_bound_s ::= frame_bound */ - -2, /* (327) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (328) frame_bound_e ::= frame_bound */ - -2, /* (329) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (330) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (331) frame_bound ::= CURRENT ROW */ - 0, /* (332) frame_exclude_opt ::= */ - -2, /* (333) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (334) frame_exclude ::= NO OTHERS */ - -2, /* (335) frame_exclude ::= CURRENT ROW */ - -1, /* (336) frame_exclude ::= GROUP|TIES */ - -2, /* (337) window_clause ::= WINDOW windowdefn_list */ - -2, /* (338) filter_over ::= filter_clause over_clause */ - -1, /* (339) filter_over ::= over_clause */ - -1, /* (340) filter_over ::= filter_clause */ - -4, /* (341) over_clause ::= OVER LP window RP */ - -2, /* (342) over_clause ::= OVER nm */ - -5, /* (343) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (344) term ::= QNUMBER */ - -1, /* (345) input ::= cmdlist */ - -2, /* (346) cmdlist ::= cmdlist ecmd */ - -1, /* (347) cmdlist ::= ecmd */ - -1, /* (348) ecmd ::= SEMI */ - -2, /* (349) ecmd ::= cmdx SEMI */ - -3, /* (350) ecmd ::= explain cmdx SEMI */ - 0, /* (351) trans_opt ::= */ - -1, /* (352) trans_opt ::= TRANSACTION */ - -2, /* (353) trans_opt ::= TRANSACTION nm */ - -1, /* (354) savepoint_opt ::= SAVEPOINT */ - 0, /* (355) savepoint_opt ::= */ - -2, /* (356) cmd ::= create_table create_table_args */ - -1, /* (357) table_option_set ::= table_option */ - -4, /* (358) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (359) columnlist ::= columnname carglist */ - -1, /* (360) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (361) nm ::= STRING */ - -1, /* (362) typetoken ::= typename */ - -1, /* (363) typename ::= ID|STRING */ - -1, /* (364) signed ::= plus_num */ - -1, /* (365) signed ::= minus_num */ - -2, /* (366) carglist ::= carglist ccons */ - 0, /* (367) carglist ::= */ - -2, /* (368) ccons ::= NULL onconf */ - -4, /* (369) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (370) ccons ::= AS generated */ - -2, /* (371) conslist_opt ::= COMMA conslist */ - -3, /* (372) conslist ::= conslist tconscomma tcons */ - -1, /* (373) conslist ::= tcons */ - 0, /* (374) tconscomma ::= */ - -1, /* (375) defer_subclause_opt ::= defer_subclause */ - -1, /* (376) resolvetype ::= raisetype */ - -1, /* (377) selectnowith ::= oneselect */ - -1, /* (378) oneselect ::= values */ - -2, /* (379) sclp ::= selcollist COMMA */ - -1, /* (380) as ::= ID|STRING */ - -1, /* (381) indexed_opt ::= indexed_by */ - 0, /* (382) returning ::= */ - -1, /* (383) expr ::= term */ - -1, /* (384) likeop ::= LIKE_KW|MATCH */ - -1, /* (385) case_operand ::= expr */ - -1, /* (386) exprlist ::= nexprlist */ - -1, /* (387) nmnum ::= plus_num */ - -1, /* (388) nmnum ::= nm */ - -1, /* (389) nmnum ::= ON */ - -1, /* (390) nmnum ::= DELETE */ - -1, /* (391) nmnum ::= DEFAULT */ - -1, /* (392) plus_num ::= INTEGER|FLOAT */ - 0, /* (393) foreach_clause ::= */ - -3, /* (394) foreach_clause ::= FOR EACH ROW */ - -1, /* (395) trnm ::= nm */ - 0, /* (396) tridxby ::= */ - -1, /* (397) database_kw_opt ::= DATABASE */ - 0, /* (398) database_kw_opt ::= */ - 0, /* (399) kwcolumn_opt ::= */ - -1, /* (400) kwcolumn_opt ::= COLUMNKW */ - -1, /* (401) vtabarglist ::= vtabarg */ - -3, /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (403) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (404) anylist ::= */ - -4, /* (405) anylist ::= anylist LP anylist RP */ - -2, /* (406) anylist ::= anylist ANY */ - 0, /* (407) with ::= */ - -1, /* (408) windowdefn_list ::= windowdefn */ - -1, /* (409) window ::= frame_opt */ + -2, /* (8) cmd ::= COMMIT|END trans_opt */ + -2, /* (9) cmd ::= ROLLBACK trans_opt */ + -2, /* (10) cmd ::= SAVEPOINT nm */ + -3, /* (11) cmd ::= RELEASE savepoint_opt nm */ + -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + -1, /* (14) createkw ::= CREATE */ + 0, /* (15) ifnotexists ::= */ + -3, /* (16) ifnotexists ::= IF NOT EXISTS */ + -1, /* (17) temp ::= TEMP */ + 0, /* (18) temp ::= */ + -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + -2, /* (20) create_table_args ::= AS select */ + 0, /* (21) table_option_set ::= */ + -3, /* (22) table_option_set ::= table_option_set COMMA table_option */ + -2, /* (23) table_option ::= WITHOUT nm */ + -1, /* (24) table_option ::= nm */ + -2, /* (25) columnname ::= nm typetoken */ + 0, /* (26) typetoken ::= */ + -4, /* (27) typetoken ::= typename LP signed RP */ + -6, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + -2, /* (29) typename ::= typename ID|STRING */ + 0, /* (30) scanpt ::= */ + 0, /* (31) scantok ::= */ + -2, /* (32) ccons ::= CONSTRAINT nm */ + -3, /* (33) ccons ::= DEFAULT scantok term */ + -4, /* (34) ccons ::= DEFAULT LP expr RP */ + -4, /* (35) ccons ::= DEFAULT PLUS scantok term */ + -4, /* (36) ccons ::= DEFAULT MINUS scantok term */ + -3, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + -3, /* (38) ccons ::= NOT NULL onconf */ + -5, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + -2, /* (40) ccons ::= UNIQUE onconf */ + -4, /* (41) ccons ::= CHECK LP expr RP */ + -4, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + -1, /* (43) ccons ::= defer_subclause */ + -2, /* (44) ccons ::= COLLATE ID|STRING */ + -3, /* (45) generated ::= LP expr RP */ + -4, /* (46) generated ::= LP expr RP ID */ + 0, /* (47) autoinc ::= */ + -1, /* (48) autoinc ::= AUTOINCR */ + 0, /* (49) refargs ::= */ + -2, /* (50) refargs ::= refargs refarg */ + -2, /* (51) refarg ::= MATCH nm */ + -3, /* (52) refarg ::= ON INSERT refact */ + -3, /* (53) refarg ::= ON DELETE refact */ + -3, /* (54) refarg ::= ON UPDATE refact */ + -2, /* (55) refact ::= SET NULL */ + -2, /* (56) refact ::= SET DEFAULT */ + -1, /* (57) refact ::= CASCADE */ + -1, /* (58) refact ::= RESTRICT */ + -2, /* (59) refact ::= NO ACTION */ + -3, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + -2, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 0, /* (62) init_deferred_pred_opt ::= */ + -2, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + -2, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 0, /* (65) conslist_opt ::= */ + -1, /* (66) tconscomma ::= COMMA */ + -2, /* (67) tcons ::= CONSTRAINT nm */ + -7, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + -5, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + -5, /* (70) tcons ::= CHECK LP expr RP onconf */ + -10, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 0, /* (72) defer_subclause_opt ::= */ + 0, /* (73) onconf ::= */ + -3, /* (74) onconf ::= ON CONFLICT resolvetype */ + 0, /* (75) orconf ::= */ + -2, /* (76) orconf ::= OR resolvetype */ + -1, /* (77) resolvetype ::= IGNORE */ + -1, /* (78) resolvetype ::= REPLACE */ + -4, /* (79) cmd ::= DROP TABLE ifexists fullname */ + -2, /* (80) ifexists ::= IF EXISTS */ + 0, /* (81) ifexists ::= */ + -9, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + -4, /* (83) cmd ::= DROP VIEW ifexists fullname */ + -1, /* (84) cmd ::= select */ + -3, /* (85) select ::= WITH wqlist selectnowith */ + -4, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + -1, /* (87) select ::= selectnowith */ + -3, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + -1, /* (89) multiselect_op ::= UNION */ + -2, /* (90) multiselect_op ::= UNION ALL */ + -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + -4, /* (94) values ::= VALUES LP nexprlist RP */ + -1, /* (95) oneselect ::= mvalues */ + -5, /* (96) mvalues ::= values COMMA LP nexprlist RP */ + -5, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ + -1, /* (98) distinct ::= DISTINCT */ + -1, /* (99) distinct ::= ALL */ + 0, /* (100) distinct ::= */ + 0, /* (101) sclp ::= */ + -5, /* (102) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (103) selcollist ::= sclp scanpt STAR */ + -5, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (105) as ::= AS nm */ + 0, /* (106) as ::= */ + 0, /* (107) from ::= */ + -2, /* (108) from ::= FROM seltablist */ + -2, /* (109) stl_prefix ::= seltablist joinop */ + 0, /* (110) stl_prefix ::= */ + -5, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ + -6, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + -8, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + -6, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ + -6, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 0, /* (116) dbnm ::= */ + -2, /* (117) dbnm ::= DOT nm */ + -1, /* (118) fullname ::= nm */ + -3, /* (119) fullname ::= nm DOT nm */ + -1, /* (120) xfullname ::= nm */ + -3, /* (121) xfullname ::= nm DOT nm */ + -5, /* (122) xfullname ::= nm DOT nm AS nm */ + -3, /* (123) xfullname ::= nm AS nm */ + -1, /* (124) joinop ::= COMMA|JOIN */ + -2, /* (125) joinop ::= JOIN_KW JOIN */ + -3, /* (126) joinop ::= JOIN_KW nm JOIN */ + -4, /* (127) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (128) on_using ::= ON expr */ + -4, /* (129) on_using ::= USING LP idlist RP */ + 0, /* (130) on_using ::= */ + 0, /* (131) indexed_opt ::= */ + -3, /* (132) indexed_by ::= INDEXED BY nm */ + -2, /* (133) indexed_by ::= NOT INDEXED */ + 0, /* (134) orderby_opt ::= */ + -3, /* (135) orderby_opt ::= ORDER BY sortlist */ + -5, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ + -3, /* (137) sortlist ::= expr sortorder nulls */ + -1, /* (138) sortorder ::= ASC */ + -1, /* (139) sortorder ::= DESC */ + 0, /* (140) sortorder ::= */ + -2, /* (141) nulls ::= NULLS FIRST */ + -2, /* (142) nulls ::= NULLS LAST */ + 0, /* (143) nulls ::= */ + 0, /* (144) groupby_opt ::= */ + -3, /* (145) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (146) having_opt ::= */ + -2, /* (147) having_opt ::= HAVING expr */ + 0, /* (148) limit_opt ::= */ + -2, /* (149) limit_opt ::= LIMIT expr */ + -4, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (151) limit_opt ::= LIMIT expr COMMA expr */ + -8, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + 0, /* (153) where_opt ::= */ + -2, /* (154) where_opt ::= WHERE expr */ + 0, /* (155) where_opt_ret ::= */ + -2, /* (156) where_opt_ret ::= WHERE expr */ + -2, /* (157) where_opt_ret ::= RETURNING selcollist */ + -4, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ + -11, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + -5, /* (160) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (162) setlist ::= nm EQ expr */ + -5, /* (163) setlist ::= LP idlist RP EQ expr */ + -7, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -8, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 0, /* (166) upsert ::= */ + -2, /* (167) upsert ::= RETURNING selcollist */ + -12, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + -9, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + -5, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ + -8, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + -2, /* (172) returning ::= RETURNING selcollist */ + -2, /* (173) insert_cmd ::= INSERT orconf */ + -1, /* (174) insert_cmd ::= REPLACE */ + 0, /* (175) idlist_opt ::= */ + -3, /* (176) idlist_opt ::= LP idlist RP */ + -3, /* (177) idlist ::= idlist COMMA nm */ + -1, /* (178) idlist ::= nm */ + -3, /* (179) expr ::= LP expr RP */ + -1, /* (180) expr ::= ID|INDEXED|JOIN_KW */ + -3, /* (181) expr ::= nm DOT nm */ + -5, /* (182) expr ::= nm DOT nm DOT nm */ + -1, /* (183) term ::= NULL|FLOAT|BLOB */ + -1, /* (184) term ::= STRING */ + -1, /* (185) term ::= INTEGER */ + -1, /* (186) expr ::= VARIABLE */ + -3, /* (187) expr ::= expr COLLATE ID|STRING */ + -6, /* (188) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + -8, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + -4, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + -6, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + -9, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + -5, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + -1, /* (195) term ::= CTIME_KW */ + -5, /* (196) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (197) expr ::= expr AND expr */ + -3, /* (198) expr ::= expr OR expr */ + -3, /* (199) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (200) expr ::= expr EQ|NE expr */ + -3, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (202) expr ::= expr PLUS|MINUS expr */ + -3, /* (203) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (204) expr ::= expr CONCAT expr */ + -2, /* (205) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (206) expr ::= expr likeop expr */ + -5, /* (207) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (208) expr ::= expr ISNULL|NOTNULL */ + -3, /* (209) expr ::= expr NOT NULL */ + -3, /* (210) expr ::= expr IS expr */ + -4, /* (211) expr ::= expr IS NOT expr */ + -6, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ + -5, /* (213) expr ::= expr IS DISTINCT FROM expr */ + -2, /* (214) expr ::= NOT expr */ + -2, /* (215) expr ::= BITNOT expr */ + -2, /* (216) expr ::= PLUS|MINUS expr */ + -3, /* (217) expr ::= expr PTR expr */ + -1, /* (218) between_op ::= BETWEEN */ + -2, /* (219) between_op ::= NOT BETWEEN */ + -5, /* (220) expr ::= expr between_op expr AND expr */ + -1, /* (221) in_op ::= IN */ + -2, /* (222) in_op ::= NOT IN */ + -5, /* (223) expr ::= expr in_op LP exprlist RP */ + -3, /* (224) expr ::= LP select RP */ + -5, /* (225) expr ::= expr in_op LP select RP */ + -5, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (227) expr ::= EXISTS LP select RP */ + -5, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (230) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (231) case_else ::= ELSE expr */ + 0, /* (232) case_else ::= */ + 0, /* (233) case_operand ::= */ + 0, /* (234) exprlist ::= */ + -3, /* (235) nexprlist ::= nexprlist COMMA expr */ + -1, /* (236) nexprlist ::= expr */ + 0, /* (237) paren_exprlist ::= */ + -3, /* (238) paren_exprlist ::= LP exprlist RP */ + -12, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (240) uniqueflag ::= UNIQUE */ + 0, /* (241) uniqueflag ::= */ + 0, /* (242) eidlist_opt ::= */ + -3, /* (243) eidlist_opt ::= LP eidlist RP */ + -5, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (245) eidlist ::= nm collate sortorder */ + 0, /* (246) collate ::= */ + -2, /* (247) collate ::= COLLATE ID|STRING */ + -4, /* (248) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (249) cmd ::= VACUUM vinto */ + -3, /* (250) cmd ::= VACUUM nm vinto */ + -2, /* (251) vinto ::= INTO expr */ + 0, /* (252) vinto ::= */ + -3, /* (253) cmd ::= PRAGMA nm dbnm */ + -5, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (262) trigger_time ::= BEFORE|AFTER */ + -2, /* (263) trigger_time ::= INSTEAD OF */ + 0, /* (264) trigger_time ::= */ + -1, /* (265) trigger_event ::= DELETE|INSERT */ + -1, /* (266) trigger_event ::= UPDATE */ + -3, /* (267) trigger_event ::= UPDATE OF idlist */ + 0, /* (268) when_clause ::= */ + -2, /* (269) when_clause ::= WHEN expr */ + -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (272) trnm ::= nm DOT nm */ + -3, /* (273) tridxby ::= INDEXED BY nm */ + -2, /* (274) tridxby ::= NOT INDEXED */ + -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (278) trigger_cmd ::= scanpt select scanpt */ + -4, /* (279) expr ::= RAISE LP IGNORE RP */ + -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ + -1, /* (281) raisetype ::= ROLLBACK */ + -1, /* (282) raisetype ::= ABORT */ + -1, /* (283) raisetype ::= FAIL */ + -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (286) cmd ::= DETACH database_kw_opt expr */ + 0, /* (287) key_opt ::= */ + -2, /* (288) key_opt ::= KEY expr */ + -1, /* (289) cmd ::= REINDEX */ + -3, /* (290) cmd ::= REINDEX nm dbnm */ + -1, /* (291) cmd ::= ANALYZE */ + -3, /* (292) cmd ::= ANALYZE nm dbnm */ + -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + -1, /* (296) add_column_fullname ::= fullname */ + -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (298) cmd ::= create_vtab */ + -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (301) vtabarg ::= */ + -1, /* (302) vtabargtoken ::= ANY */ + -3, /* (303) vtabargtoken ::= lp anylist RP */ + -1, /* (304) lp ::= LP */ + -2, /* (305) with ::= WITH wqlist */ + -3, /* (306) with ::= WITH RECURSIVE wqlist */ + -1, /* (307) wqas ::= AS */ + -2, /* (308) wqas ::= AS MATERIALIZED */ + -3, /* (309) wqas ::= AS NOT MATERIALIZED */ + -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ + -1, /* (311) withnm ::= nm */ + -1, /* (312) wqlist ::= wqitem */ + -3, /* (313) wqlist ::= wqlist COMMA wqitem */ + -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (315) windowdefn ::= nm AS LP window RP */ + -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (318) window ::= ORDER BY sortlist frame_opt */ + -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (320) window ::= nm frame_opt */ + 0, /* (321) frame_opt ::= */ + -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (325) frame_bound_s ::= frame_bound */ + -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (327) frame_bound_e ::= frame_bound */ + -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (330) frame_bound ::= CURRENT ROW */ + 0, /* (331) frame_exclude_opt ::= */ + -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (333) frame_exclude ::= NO OTHERS */ + -2, /* (334) frame_exclude ::= CURRENT ROW */ + -1, /* (335) frame_exclude ::= GROUP|TIES */ + -2, /* (336) window_clause ::= WINDOW windowdefn_list */ + -2, /* (337) filter_over ::= filter_clause over_clause */ + -1, /* (338) filter_over ::= over_clause */ + -1, /* (339) filter_over ::= filter_clause */ + -4, /* (340) over_clause ::= OVER LP window RP */ + -2, /* (341) over_clause ::= OVER nm */ + -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (343) term ::= QNUMBER */ + -1, /* (344) input ::= cmdlist */ + -2, /* (345) cmdlist ::= cmdlist ecmd */ + -1, /* (346) cmdlist ::= ecmd */ + -1, /* (347) ecmd ::= SEMI */ + -2, /* (348) ecmd ::= cmdx SEMI */ + -3, /* (349) ecmd ::= explain cmdx SEMI */ + 0, /* (350) trans_opt ::= */ + -1, /* (351) trans_opt ::= TRANSACTION */ + -2, /* (352) trans_opt ::= TRANSACTION nm */ + -1, /* (353) savepoint_opt ::= SAVEPOINT */ + 0, /* (354) savepoint_opt ::= */ + -2, /* (355) cmd ::= create_table create_table_args */ + -1, /* (356) table_option_set ::= table_option */ + -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (358) columnlist ::= columnname carglist */ + -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (360) nm ::= STRING */ + -1, /* (361) typetoken ::= typename */ + -1, /* (362) typename ::= ID|STRING */ + -1, /* (363) signed ::= plus_num */ + -1, /* (364) signed ::= minus_num */ + -2, /* (365) carglist ::= carglist ccons */ + 0, /* (366) carglist ::= */ + -2, /* (367) ccons ::= NULL onconf */ + -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (369) ccons ::= AS generated */ + -2, /* (370) conslist_opt ::= COMMA conslist */ + -3, /* (371) conslist ::= conslist tconscomma tcons */ + -1, /* (372) conslist ::= tcons */ + 0, /* (373) tconscomma ::= */ + -1, /* (374) defer_subclause_opt ::= defer_subclause */ + -1, /* (375) resolvetype ::= raisetype */ + -1, /* (376) selectnowith ::= oneselect */ + -1, /* (377) oneselect ::= values */ + -2, /* (378) sclp ::= selcollist COMMA */ + -1, /* (379) as ::= ID|STRING */ + -1, /* (380) indexed_opt ::= indexed_by */ + 0, /* (381) returning ::= */ + -1, /* (382) expr ::= term */ + -1, /* (383) likeop ::= LIKE_KW|MATCH */ + -1, /* (384) case_operand ::= expr */ + -1, /* (385) exprlist ::= nexprlist */ + -1, /* (386) nmnum ::= plus_num */ + -1, /* (387) nmnum ::= nm */ + -1, /* (388) nmnum ::= ON */ + -1, /* (389) nmnum ::= DELETE */ + -1, /* (390) nmnum ::= DEFAULT */ + -1, /* (391) plus_num ::= INTEGER|FLOAT */ + 0, /* (392) foreach_clause ::= */ + -3, /* (393) foreach_clause ::= FOR EACH ROW */ + -1, /* (394) trnm ::= nm */ + 0, /* (395) tridxby ::= */ + -1, /* (396) database_kw_opt ::= DATABASE */ + 0, /* (397) database_kw_opt ::= */ + 0, /* (398) kwcolumn_opt ::= */ + -1, /* (399) kwcolumn_opt ::= COLUMNKW */ + -1, /* (400) vtabarglist ::= vtabarg */ + -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (402) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (403) anylist ::= */ + -4, /* (404) anylist ::= anylist LP anylist RP */ + -2, /* (405) anylist ::= anylist ANY */ + 0, /* (406) with ::= */ + -1, /* (407) windowdefn_list ::= windowdefn */ + -1, /* (408) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -180334,8 +181271,7 @@ static YYACTIONTYPE yy_reduce( break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); - case 8: /* transtype ::= CONCURRENT */ yytestcase(yyruleno==8); - case 325: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==325); + case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); {yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/} break; case 7: /* transtype ::= ID */ @@ -180350,68 +181286,68 @@ static YYACTIONTYPE yy_reduce( } } break; - case 9: /* cmd ::= COMMIT|END trans_opt */ - case 10: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==10); + case 8: /* cmd ::= COMMIT|END trans_opt */ + case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); {sqlite3EndTransaction(pParse,yymsp[-1].major);} break; - case 11: /* cmd ::= SAVEPOINT nm */ + case 10: /* cmd ::= SAVEPOINT nm */ { sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); } break; - case 12: /* cmd ::= RELEASE savepoint_opt nm */ + case 11: /* cmd ::= RELEASE savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); } break; - case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; - case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy502,0,0,yymsp[-2].minor.yy502); } break; - case 15: /* createkw ::= CREATE */ + case 14: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; - case 16: /* ifnotexists ::= */ - case 19: /* temp ::= */ yytestcase(yyruleno==19); - case 48: /* autoinc ::= */ yytestcase(yyruleno==48); - case 63: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==63); - case 73: /* defer_subclause_opt ::= */ yytestcase(yyruleno==73); - case 82: /* ifexists ::= */ yytestcase(yyruleno==82); - case 101: /* distinct ::= */ yytestcase(yyruleno==101); - case 247: /* collate ::= */ yytestcase(yyruleno==247); + case 15: /* ifnotexists ::= */ + case 18: /* temp ::= */ yytestcase(yyruleno==18); + case 47: /* autoinc ::= */ yytestcase(yyruleno==47); + case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62); + case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); + case 81: /* ifexists ::= */ yytestcase(yyruleno==81); + case 100: /* distinct ::= */ yytestcase(yyruleno==100); + case 246: /* collate ::= */ yytestcase(yyruleno==246); {yymsp[1].minor.yy502 = 0;} break; - case 17: /* ifnotexists ::= IF NOT EXISTS */ + case 16: /* ifnotexists ::= IF NOT EXISTS */ {yymsp[-2].minor.yy502 = 1;} break; - case 18: /* temp ::= TEMP */ + case 17: /* temp ::= TEMP */ {yymsp[0].minor.yy502 = pParse->db->init.busy==0;} break; - case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy9,0); } break; - case 21: /* create_table_args ::= AS select */ + case 20: /* create_table_args ::= AS select */ { sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy637); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); } break; - case 22: /* table_option_set ::= */ + case 21: /* table_option_set ::= */ {yymsp[1].minor.yy9 = 0;} break; - case 23: /* table_option_set ::= table_option_set COMMA table_option */ + case 22: /* table_option_set ::= table_option_set COMMA table_option */ {yylhsminor.yy9 = yymsp[-2].minor.yy9|yymsp[0].minor.yy9;} yymsp[-2].minor.yy9 = yylhsminor.yy9; break; - case 24: /* table_option ::= WITHOUT nm */ + case 23: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ yymsp[-1].minor.yy9 = TF_WithoutRowid | TF_NoVisibleRowid; @@ -180421,7 +181357,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 25: /* table_option ::= nm */ + case 24: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ yylhsminor.yy9 = TF_Strict; @@ -180432,59 +181368,59 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy9 = yylhsminor.yy9; break; - case 26: /* columnname ::= nm typetoken */ + case 25: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} break; - case 27: /* typetoken ::= */ - case 66: /* conslist_opt ::= */ yytestcase(yyruleno==66); - case 107: /* as ::= */ yytestcase(yyruleno==107); + case 26: /* typetoken ::= */ + case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); + case 106: /* as ::= */ yytestcase(yyruleno==106); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; - case 28: /* typetoken ::= typename LP signed RP */ + case 27: /* typetoken ::= typename LP signed RP */ { yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); } break; - case 29: /* typetoken ::= typename LP signed COMMA signed RP */ + case 28: /* typetoken ::= typename LP signed COMMA signed RP */ { yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); } break; - case 30: /* typename ::= typename ID|STRING */ + case 29: /* typename ::= typename ID|STRING */ {yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; - case 31: /* scanpt ::= */ + case 30: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy342 = yyLookaheadToken.z; } break; - case 32: /* scantok ::= */ + case 31: /* scantok ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy0 = yyLookaheadToken; } break; - case 33: /* ccons ::= CONSTRAINT nm */ - case 68: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==68); + case 32: /* ccons ::= CONSTRAINT nm */ + case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 34: /* ccons ::= DEFAULT scantok term */ + case 33: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 35: /* ccons ::= DEFAULT LP expr RP */ + case 34: /* ccons ::= DEFAULT LP expr RP */ {sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; - case 36: /* ccons ::= DEFAULT PLUS scantok term */ + case 35: /* ccons ::= DEFAULT PLUS scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 37: /* ccons ::= DEFAULT MINUS scantok term */ + case 36: /* ccons ::= DEFAULT MINUS scantok term */ { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy590, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; - case 38: /* ccons ::= DEFAULT scantok ID|INDEXED */ + case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */ { Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); if( p ){ @@ -180494,150 +181430,154 @@ static YYACTIONTYPE yy_reduce( sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; - case 39: /* ccons ::= NOT NULL onconf */ + case 38: /* ccons ::= NOT NULL onconf */ {sqlite3AddNotNull(pParse, yymsp[0].minor.yy502);} break; - case 40: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ + case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy502,yymsp[0].minor.yy502,yymsp[-2].minor.yy502);} break; - case 41: /* ccons ::= UNIQUE onconf */ + case 40: /* ccons ::= UNIQUE onconf */ {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy502,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 42: /* ccons ::= CHECK LP expr RP */ + case 41: /* ccons ::= CHECK LP expr RP */ {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; - case 43: /* ccons ::= REFERENCES nm eidlist_opt refargs */ + case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy402,yymsp[0].minor.yy502);} break; - case 44: /* ccons ::= defer_subclause */ + case 43: /* ccons ::= defer_subclause */ {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy502);} break; - case 45: /* ccons ::= COLLATE ID|STRING */ + case 44: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 46: /* generated ::= LP expr RP */ + case 45: /* generated ::= LP expr RP */ {sqlite3AddGenerated(pParse,yymsp[-1].minor.yy590,0);} break; - case 47: /* generated ::= LP expr RP ID */ + case 46: /* generated ::= LP expr RP ID */ {sqlite3AddGenerated(pParse,yymsp[-2].minor.yy590,&yymsp[0].minor.yy0);} break; - case 49: /* autoinc ::= AUTOINCR */ + case 48: /* autoinc ::= AUTOINCR */ {yymsp[0].minor.yy502 = 1;} break; - case 50: /* refargs ::= */ + case 49: /* refargs ::= */ { yymsp[1].minor.yy502 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 51: /* refargs ::= refargs refarg */ + case 50: /* refargs ::= refargs refarg */ { yymsp[-1].minor.yy502 = (yymsp[-1].minor.yy502 & ~yymsp[0].minor.yy481.mask) | yymsp[0].minor.yy481.value; } break; - case 52: /* refarg ::= MATCH nm */ + case 51: /* refarg ::= MATCH nm */ { yymsp[-1].minor.yy481.value = 0; yymsp[-1].minor.yy481.mask = 0x000000; } break; - case 53: /* refarg ::= ON INSERT refact */ + case 52: /* refarg ::= ON INSERT refact */ { yymsp[-2].minor.yy481.value = 0; yymsp[-2].minor.yy481.mask = 0x000000; } break; - case 54: /* refarg ::= ON DELETE refact */ + case 53: /* refarg ::= ON DELETE refact */ { yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502; yymsp[-2].minor.yy481.mask = 0x0000ff; } break; - case 55: /* refarg ::= ON UPDATE refact */ + case 54: /* refarg ::= ON UPDATE refact */ { yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502<<8; yymsp[-2].minor.yy481.mask = 0x00ff00; } break; - case 56: /* refact ::= SET NULL */ + case 55: /* refact ::= SET NULL */ { yymsp[-1].minor.yy502 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 57: /* refact ::= SET DEFAULT */ + case 56: /* refact ::= SET DEFAULT */ { yymsp[-1].minor.yy502 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 58: /* refact ::= CASCADE */ + case 57: /* refact ::= CASCADE */ { yymsp[0].minor.yy502 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 59: /* refact ::= RESTRICT */ + case 58: /* refact ::= RESTRICT */ { yymsp[0].minor.yy502 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 60: /* refact ::= NO ACTION */ + case 59: /* refact ::= NO ACTION */ { yymsp[-1].minor.yy502 = OE_None; /* EV: R-33326-45252 */} break; - case 61: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ {yymsp[-2].minor.yy502 = 0;} break; - case 62: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 77: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==77); - case 174: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==174); + case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); + case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173); {yymsp[-1].minor.yy502 = yymsp[0].minor.yy502;} break; - case 64: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 81: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==81); - case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220); - case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223); - case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248); + case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); + case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219); + case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222); + case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247); {yymsp[-1].minor.yy502 = 1;} break; - case 65: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ {yymsp[-1].minor.yy502 = 0;} break; - case 67: /* tconscomma ::= COMMA */ + case 66: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 69: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);} break; - case 70: /* tcons ::= UNIQUE LP sortlist RP onconf */ + case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy402,yymsp[0].minor.yy502,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 71: /* tcons ::= CHECK LP expr RP onconf */ + case 70: /* tcons ::= CHECK LP expr RP onconf */ {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy590,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; - case 72: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy402, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[-1].minor.yy502); sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy502); } break; - case 74: /* onconf ::= */ - case 76: /* orconf ::= */ yytestcase(yyruleno==76); + case 73: /* onconf ::= */ + case 75: /* orconf ::= */ yytestcase(yyruleno==75); {yymsp[1].minor.yy502 = OE_Default;} break; - case 75: /* onconf ::= ON CONFLICT resolvetype */ + case 74: /* onconf ::= ON CONFLICT resolvetype */ {yymsp[-2].minor.yy502 = yymsp[0].minor.yy502;} break; - case 78: /* resolvetype ::= IGNORE */ + case 77: /* resolvetype ::= IGNORE */ {yymsp[0].minor.yy502 = OE_Ignore;} break; - case 79: /* resolvetype ::= REPLACE */ - case 175: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==175); + case 78: /* resolvetype ::= REPLACE */ + case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174); {yymsp[0].minor.yy502 = OE_Replace;} break; - case 80: /* cmd ::= DROP TABLE ifexists fullname */ + case 79: /* cmd ::= DROP TABLE ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy563, 0, yymsp[-1].minor.yy502); } break; - case 83: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[0].minor.yy637, yymsp[-7].minor.yy502, yymsp[-5].minor.yy502); } break; - case 84: /* cmd ::= DROP VIEW ifexists fullname */ + case 83: /* cmd ::= DROP VIEW ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy563, 1, yymsp[-1].minor.yy502); } break; - case 85: /* cmd ::= select */ + case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); + if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0 + || sqlite3ReadSchema(pParse)==SQLITE_OK + ){ + sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); + } sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); } break; - case 86: /* select ::= WITH wqlist selectnowith */ + case 85: /* select ::= WITH wqlist selectnowith */ {yymsp[-2].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} break; - case 87: /* select ::= WITH RECURSIVE wqlist selectnowith */ + case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ {yymsp[-3].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} break; - case 88: /* select ::= selectnowith */ + case 87: /* select ::= selectnowith */ { Select *p = yymsp[0].minor.yy637; if( p ){ @@ -180645,7 +181585,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 89: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ { Select *pRhs = yymsp[0].minor.yy637; Select *pLhs = yymsp[-2].minor.yy637; @@ -180669,19 +181609,19 @@ static YYACTIONTYPE yy_reduce( yymsp[-2].minor.yy637 = pRhs; } break; - case 90: /* multiselect_op ::= UNION */ - case 92: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==92); + case 89: /* multiselect_op ::= UNION */ + case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); {yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 91: /* multiselect_op ::= UNION ALL */ + case 90: /* multiselect_op ::= UNION ALL */ {yymsp[-1].minor.yy502 = TK_ALL;} break; - case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { yymsp[-8].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy402,yymsp[-5].minor.yy563,yymsp[-4].minor.yy590,yymsp[-3].minor.yy402,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[-7].minor.yy502,yymsp[0].minor.yy590); } break; - case 94: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { yymsp[-9].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy402,yymsp[-6].minor.yy563,yymsp[-5].minor.yy590,yymsp[-4].minor.yy402,yymsp[-3].minor.yy590,yymsp[-1].minor.yy402,yymsp[-8].minor.yy502,yymsp[0].minor.yy590); if( yymsp[-9].minor.yy637 ){ @@ -180691,51 +181631,51 @@ static YYACTIONTYPE yy_reduce( } } break; - case 95: /* values ::= VALUES LP nexprlist RP */ + case 94: /* values ::= VALUES LP nexprlist RP */ { yymsp[-3].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy402,0,0,0,0,0,SF_Values,0); } break; - case 96: /* oneselect ::= mvalues */ + case 95: /* oneselect ::= mvalues */ { sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy637); } break; - case 97: /* mvalues ::= values COMMA LP nexprlist RP */ - case 98: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==98); + case 96: /* mvalues ::= values COMMA LP nexprlist RP */ + case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97); { yymsp[-4].minor.yy637 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy637, yymsp[-1].minor.yy402); } break; - case 99: /* distinct ::= DISTINCT */ + case 98: /* distinct ::= DISTINCT */ {yymsp[0].minor.yy502 = SF_Distinct;} break; - case 100: /* distinct ::= ALL */ + case 99: /* distinct ::= ALL */ {yymsp[0].minor.yy502 = SF_All;} break; - case 102: /* sclp ::= */ - case 135: /* orderby_opt ::= */ yytestcase(yyruleno==135); - case 145: /* groupby_opt ::= */ yytestcase(yyruleno==145); - case 235: /* exprlist ::= */ yytestcase(yyruleno==235); - case 238: /* paren_exprlist ::= */ yytestcase(yyruleno==238); - case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243); + case 101: /* sclp ::= */ + case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134); + case 144: /* groupby_opt ::= */ yytestcase(yyruleno==144); + case 234: /* exprlist ::= */ yytestcase(yyruleno==234); + case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237); + case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242); {yymsp[1].minor.yy402 = 0;} break; - case 103: /* selcollist ::= sclp scanpt expr scanpt as */ + case 102: /* selcollist ::= sclp scanpt expr scanpt as */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[0].minor.yy0, 1); sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy402,yymsp[-3].minor.yy342,yymsp[-1].minor.yy342); } break; - case 104: /* selcollist ::= sclp scanpt STAR */ + case 103: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy402, p); } break; - case 105: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 104: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight, *pLeft, *pDot; pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); @@ -180745,50 +181685,50 @@ static YYACTIONTYPE yy_reduce( yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, pDot); } break; - case 106: /* as ::= AS nm */ - case 118: /* dbnm ::= DOT nm */ yytestcase(yyruleno==118); - case 259: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==259); - case 260: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==260); + case 105: /* as ::= AS nm */ + case 117: /* dbnm ::= DOT nm */ yytestcase(yyruleno==117); + case 258: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==258); + case 259: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==259); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 108: /* from ::= */ - case 111: /* stl_prefix ::= */ yytestcase(yyruleno==111); + case 107: /* from ::= */ + case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110); {yymsp[1].minor.yy563 = 0;} break; - case 109: /* from ::= FROM seltablist */ + case 108: /* from ::= FROM seltablist */ { yymsp[-1].minor.yy563 = yymsp[0].minor.yy563; sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy563); } break; - case 110: /* stl_prefix ::= seltablist joinop */ + case 109: /* stl_prefix ::= seltablist joinop */ { if( ALWAYS(yymsp[-1].minor.yy563 && yymsp[-1].minor.yy563->nSrc>0) ) yymsp[-1].minor.yy563->a[yymsp[-1].minor.yy563->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy502; } break; - case 112: /* seltablist ::= stl_prefix nm dbnm as on_using */ + case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */ { yymsp[-4].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy563,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); } break; - case 113: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ { yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy421); sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-1].minor.yy0); } break; - case 114: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ { yymsp[-7].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy563,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy563, yymsp[-3].minor.yy402); } break; - case 115: /* seltablist ::= stl_prefix LP select RP as on_using */ + case 114: /* seltablist ::= stl_prefix LP select RP as on_using */ { yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy637,&yymsp[0].minor.yy421); } break; - case 116: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ + case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ { if( yymsp[-5].minor.yy563==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy421.pOn==0 && yymsp[0].minor.yy421.pUsing==0 ){ yymsp[-5].minor.yy563 = yymsp[-3].minor.yy563; @@ -180797,11 +181737,21 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-5].minor.yy563 ){ SrcItem *pNew = &yymsp[-5].minor.yy563->a[yymsp[-5].minor.yy563->nSrc-1]; SrcItem *pOld = yymsp[-3].minor.yy563->a; + assert( pOld->fg.fixedSchema==0 ); pNew->zName = pOld->zName; - pNew->zDatabase = pOld->zDatabase; - pNew->pSelect = pOld->pSelect; - if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ - pNew->fg.isNestedFrom = 1; + assert( pOld->fg.fixedSchema==0 ); + if( pOld->fg.isSubquery ){ + pNew->fg.isSubquery = 1; + pNew->u4.pSubq = pOld->u4.pSubq; + pOld->u4.pSubq = 0; + pOld->fg.isSubquery = 0; + assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 ); + if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){ + pNew->fg.isNestedFrom = 1; + } + }else{ + pNew->u4.zDatabase = pOld->u4.zDatabase; + pOld->u4.zDatabase = 0; } if( pOld->fg.isTabFunc ){ pNew->u1.pFuncArg = pOld->u1.pFuncArg; @@ -180809,8 +181759,7 @@ static YYACTIONTYPE yy_reduce( pOld->fg.isTabFunc = 0; pNew->fg.isTabFunc = 1; } - pOld->zName = pOld->zDatabase = 0; - pOld->pSelect = 0; + pOld->zName = 0; } sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy563); }else{ @@ -180821,127 +181770,127 @@ static YYACTIONTYPE yy_reduce( } } break; - case 117: /* dbnm ::= */ - case 132: /* indexed_opt ::= */ yytestcase(yyruleno==132); + case 116: /* dbnm ::= */ + case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 119: /* fullname ::= nm */ + case 118: /* fullname ::= nm */ { yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); } yymsp[0].minor.yy563 = yylhsminor.yy563; break; - case 120: /* fullname ::= nm DOT nm */ + case 119: /* fullname ::= nm DOT nm */ { yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); } yymsp[-2].minor.yy563 = yylhsminor.yy563; break; - case 121: /* xfullname ::= nm */ + case 120: /* xfullname ::= nm */ {yymsp[0].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 122: /* xfullname ::= nm DOT nm */ + case 121: /* xfullname ::= nm DOT nm */ {yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 123: /* xfullname ::= nm DOT nm AS nm */ + case 122: /* xfullname ::= nm DOT nm AS nm */ { yymsp[-4].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ if( yymsp[-4].minor.yy563 ) yymsp[-4].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 124: /* xfullname ::= nm AS nm */ + case 123: /* xfullname ::= nm AS nm */ { yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ if( yymsp[-2].minor.yy563 ) yymsp[-2].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 125: /* joinop ::= COMMA|JOIN */ + case 124: /* joinop ::= COMMA|JOIN */ { yymsp[0].minor.yy502 = JT_INNER; } break; - case 126: /* joinop ::= JOIN_KW JOIN */ + case 125: /* joinop ::= JOIN_KW JOIN */ {yymsp[-1].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 127: /* joinop ::= JOIN_KW nm JOIN */ + case 126: /* joinop ::= JOIN_KW nm JOIN */ {yymsp[-2].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 128: /* joinop ::= JOIN_KW nm nm JOIN */ + case 127: /* joinop ::= JOIN_KW nm nm JOIN */ {yymsp[-3].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 129: /* on_using ::= ON expr */ + case 128: /* on_using ::= ON expr */ {yymsp[-1].minor.yy421.pOn = yymsp[0].minor.yy590; yymsp[-1].minor.yy421.pUsing = 0;} break; - case 130: /* on_using ::= USING LP idlist RP */ + case 129: /* on_using ::= USING LP idlist RP */ {yymsp[-3].minor.yy421.pOn = 0; yymsp[-3].minor.yy421.pUsing = yymsp[-1].minor.yy204;} break; - case 131: /* on_using ::= */ + case 130: /* on_using ::= */ {yymsp[1].minor.yy421.pOn = 0; yymsp[1].minor.yy421.pUsing = 0;} break; - case 133: /* indexed_by ::= INDEXED BY nm */ + case 132: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 134: /* indexed_by ::= NOT INDEXED */ + case 133: /* indexed_by ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 136: /* orderby_opt ::= ORDER BY sortlist */ - case 146: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==146); + case 135: /* orderby_opt ::= ORDER BY sortlist */ + case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145); {yymsp[-2].minor.yy402 = yymsp[0].minor.yy402;} break; - case 137: /* sortlist ::= sortlist COMMA expr sortorder nulls */ + case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590); sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); } break; - case 138: /* sortlist ::= expr sortorder nulls */ + case 137: /* sortlist ::= expr sortorder nulls */ { yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy590); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); } break; - case 139: /* sortorder ::= ASC */ + case 138: /* sortorder ::= ASC */ {yymsp[0].minor.yy502 = SQLITE_SO_ASC;} break; - case 140: /* sortorder ::= DESC */ + case 139: /* sortorder ::= DESC */ {yymsp[0].minor.yy502 = SQLITE_SO_DESC;} break; - case 141: /* sortorder ::= */ - case 144: /* nulls ::= */ yytestcase(yyruleno==144); + case 140: /* sortorder ::= */ + case 143: /* nulls ::= */ yytestcase(yyruleno==143); {yymsp[1].minor.yy502 = SQLITE_SO_UNDEFINED;} break; - case 142: /* nulls ::= NULLS FIRST */ + case 141: /* nulls ::= NULLS FIRST */ {yymsp[-1].minor.yy502 = SQLITE_SO_ASC;} break; - case 143: /* nulls ::= NULLS LAST */ + case 142: /* nulls ::= NULLS LAST */ {yymsp[-1].minor.yy502 = SQLITE_SO_DESC;} break; - case 147: /* having_opt ::= */ - case 149: /* limit_opt ::= */ yytestcase(yyruleno==149); - case 154: /* where_opt ::= */ yytestcase(yyruleno==154); - case 156: /* where_opt_ret ::= */ yytestcase(yyruleno==156); - case 233: /* case_else ::= */ yytestcase(yyruleno==233); - case 234: /* case_operand ::= */ yytestcase(yyruleno==234); - case 253: /* vinto ::= */ yytestcase(yyruleno==253); + case 146: /* having_opt ::= */ + case 148: /* limit_opt ::= */ yytestcase(yyruleno==148); + case 153: /* where_opt ::= */ yytestcase(yyruleno==153); + case 155: /* where_opt_ret ::= */ yytestcase(yyruleno==155); + case 232: /* case_else ::= */ yytestcase(yyruleno==232); + case 233: /* case_operand ::= */ yytestcase(yyruleno==233); + case 252: /* vinto ::= */ yytestcase(yyruleno==252); {yymsp[1].minor.yy590 = 0;} break; - case 148: /* having_opt ::= HAVING expr */ - case 155: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==155); - case 157: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==157); - case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232); - case 252: /* vinto ::= INTO expr */ yytestcase(yyruleno==252); + case 147: /* having_opt ::= HAVING expr */ + case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154); + case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156); + case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231); + case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251); {yymsp[-1].minor.yy590 = yymsp[0].minor.yy590;} break; - case 150: /* limit_opt ::= LIMIT expr */ + case 149: /* limit_opt ::= LIMIT expr */ {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,0);} break; - case 151: /* limit_opt ::= LIMIT expr OFFSET expr */ + case 150: /* limit_opt ::= LIMIT expr OFFSET expr */ {yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 152: /* limit_opt ::= LIMIT expr COMMA expr */ + case 151: /* limit_opt ::= LIMIT expr COMMA expr */ {yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,yymsp[-2].minor.yy590);} break; - case 153: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ + case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret orderby_opt limit_opt */ { sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy563, &yymsp[-3].minor.yy0); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT @@ -180954,13 +181903,13 @@ static YYACTIONTYPE yy_reduce( sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy563,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[0].minor.yy590); } break; - case 158: /* where_opt_ret ::= RETURNING selcollist */ + case 157: /* where_opt_ret ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-1].minor.yy590 = 0;} break; - case 159: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ + case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-3].minor.yy590 = yymsp[-2].minor.yy590;} break; - case 160: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ + case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret orderby_opt limit_opt */ { sqlite3SrcListIndexedBy(pParse, yymsp[-7].minor.yy563, &yymsp[-6].minor.yy0); if( yymsp[-3].minor.yy563 ){ @@ -180986,79 +181935,79 @@ static YYACTIONTYPE yy_reduce( sqlite3Update(pParse,yymsp[-7].minor.yy563,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590,yymsp[-8].minor.yy502,yymsp[-1].minor.yy402,yymsp[0].minor.yy590,0); } break; - case 161: /* setlist ::= setlist COMMA nm EQ expr */ + case 160: /* setlist ::= setlist COMMA nm EQ expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[0].minor.yy590); sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, 1); } break; - case 162: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { yymsp[-6].minor.yy402 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy402, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); } break; - case 163: /* setlist ::= nm EQ expr */ + case 162: /* setlist ::= nm EQ expr */ { yylhsminor.yy402 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy590); sqlite3ExprListSetName(pParse, yylhsminor.yy402, &yymsp[-2].minor.yy0, 1); } yymsp[-2].minor.yy402 = yylhsminor.yy402; break; - case 164: /* setlist ::= LP idlist RP EQ expr */ + case 163: /* setlist ::= LP idlist RP EQ expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); } break; - case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { sqlite3Insert(pParse, yymsp[-3].minor.yy563, yymsp[-1].minor.yy637, yymsp[-2].minor.yy204, yymsp[-5].minor.yy502, yymsp[0].minor.yy403); } break; - case 166: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ { sqlite3Insert(pParse, yymsp[-4].minor.yy563, 0, yymsp[-3].minor.yy204, yymsp[-6].minor.yy502, 0); } break; - case 167: /* upsert ::= */ + case 166: /* upsert ::= */ { yymsp[1].minor.yy403 = 0; } break; - case 168: /* upsert ::= RETURNING selcollist */ + case 167: /* upsert ::= RETURNING selcollist */ { yymsp[-1].minor.yy403 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy402); } break; - case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ { yymsp[-11].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy402,yymsp[-6].minor.yy590,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,yymsp[0].minor.yy403);} break; - case 170: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ { yymsp[-8].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy402,yymsp[-3].minor.yy590,0,0,yymsp[0].minor.yy403); } break; - case 171: /* upsert ::= ON CONFLICT DO NOTHING returning */ + case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */ { yymsp[-4].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } break; - case 172: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ { yymsp[-7].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,0);} break; - case 173: /* returning ::= RETURNING selcollist */ + case 172: /* returning ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy402);} break; - case 176: /* idlist_opt ::= */ + case 175: /* idlist_opt ::= */ {yymsp[1].minor.yy204 = 0;} break; - case 177: /* idlist_opt ::= LP idlist RP */ + case 176: /* idlist_opt ::= LP idlist RP */ {yymsp[-2].minor.yy204 = yymsp[-1].minor.yy204;} break; - case 178: /* idlist ::= idlist COMMA nm */ + case 177: /* idlist ::= idlist COMMA nm */ {yymsp[-2].minor.yy204 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy204,&yymsp[0].minor.yy0);} break; - case 179: /* idlist ::= nm */ + case 178: /* idlist ::= nm */ {yymsp[0].minor.yy204 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 180: /* expr ::= LP expr RP */ + case 179: /* expr ::= LP expr RP */ {yymsp[-2].minor.yy590 = yymsp[-1].minor.yy590;} break; - case 181: /* expr ::= ID|INDEXED|JOIN_KW */ + case 180: /* expr ::= ID|INDEXED|JOIN_KW */ {yymsp[0].minor.yy590=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 182: /* expr ::= nm DOT nm */ + case 181: /* expr ::= nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); @@ -181066,7 +182015,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy590 = yylhsminor.yy590; break; - case 183: /* expr ::= nm DOT nm DOT nm */ + case 182: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); @@ -181079,18 +182028,18 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 184: /* term ::= NULL|FLOAT|BLOB */ - case 185: /* term ::= STRING */ yytestcase(yyruleno==185); + case 183: /* term ::= NULL|FLOAT|BLOB */ + case 184: /* term ::= STRING */ yytestcase(yyruleno==184); {yymsp[0].minor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 186: /* term ::= INTEGER */ + case 185: /* term ::= INTEGER */ { yylhsminor.yy590 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); if( yylhsminor.yy590 ) yylhsminor.yy590->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); } yymsp[0].minor.yy590 = yylhsminor.yy590; break; - case 187: /* expr ::= VARIABLE */ + case 186: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; @@ -181112,44 +182061,44 @@ static YYACTIONTYPE yy_reduce( } } break; - case 188: /* expr ::= expr COLLATE ID|STRING */ + case 187: /* expr ::= expr COLLATE ID|STRING */ { yymsp[-2].minor.yy590 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy590, &yymsp[0].minor.yy0, 1); } break; - case 189: /* expr ::= CAST LP expr AS typetoken RP */ + case 188: /* expr ::= CAST LP expr AS typetoken RP */ { yymsp[-5].minor.yy590 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy590, yymsp[-3].minor.yy590, 0); } break; - case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy502); } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy402, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy502); sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-1].minor.yy402); } yymsp[-7].minor.yy590 = yylhsminor.yy590; break; - case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } yymsp[-3].minor.yy590 = yylhsminor.yy590; break; - case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy402, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy502); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); } yymsp[-5].minor.yy590 = yylhsminor.yy590; break; - case 194: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy402, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy502); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); @@ -181157,20 +182106,20 @@ static YYACTIONTYPE yy_reduce( } yymsp[-8].minor.yy590 = yylhsminor.yy590; break; - case 195: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); } yymsp[-4].minor.yy590 = yylhsminor.yy590; break; - case 196: /* term ::= CTIME_KW */ + case 195: /* term ::= CTIME_KW */ { yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } yymsp[0].minor.yy590 = yylhsminor.yy590; break; - case 197: /* expr ::= LP nexprlist COMMA expr RP */ + case 196: /* expr ::= LP nexprlist COMMA expr RP */ { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590); yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -181184,22 +182133,22 @@ static YYACTIONTYPE yy_reduce( } } break; - case 198: /* expr ::= expr AND expr */ + case 197: /* expr ::= expr AND expr */ {yymsp[-2].minor.yy590=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 199: /* expr ::= expr OR expr */ - case 200: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==200); - case 201: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==201); - case 202: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==202); - case 203: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==203); - case 204: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==204); - case 205: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==205); + case 198: /* expr ::= expr OR expr */ + case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199); + case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200); + case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201); + case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202); + case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203); + case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204); {yymsp[-2].minor.yy590=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} break; - case 206: /* likeop ::= NOT LIKE_KW|MATCH */ + case 205: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 207: /* expr ::= expr likeop expr */ + case 206: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; @@ -181211,7 +182160,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-2].minor.yy590 ) yymsp[-2].minor.yy590->flags |= EP_InfixFunc; } break; - case 208: /* expr ::= expr likeop expr ESCAPE expr */ + case 207: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; @@ -181224,41 +182173,41 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-4].minor.yy590 ) yymsp[-4].minor.yy590->flags |= EP_InfixFunc; } break; - case 209: /* expr ::= expr ISNULL|NOTNULL */ + case 208: /* expr ::= expr ISNULL|NOTNULL */ {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy590,0);} break; - case 210: /* expr ::= expr NOT NULL */ + case 209: /* expr ::= expr NOT NULL */ {yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy590,0);} break; - case 211: /* expr ::= expr IS expr */ + case 210: /* expr ::= expr IS expr */ { yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-2].minor.yy590, TK_ISNULL); } break; - case 212: /* expr ::= expr IS NOT expr */ + case 211: /* expr ::= expr IS NOT expr */ { yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-3].minor.yy590, TK_NOTNULL); } break; - case 213: /* expr ::= expr IS NOT DISTINCT FROM expr */ + case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ { yymsp[-5].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-5].minor.yy590, TK_ISNULL); } break; - case 214: /* expr ::= expr IS DISTINCT FROM expr */ + case 213: /* expr ::= expr IS DISTINCT FROM expr */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy590,yymsp[0].minor.yy590); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-4].minor.yy590, TK_NOTNULL); } break; - case 215: /* expr ::= NOT expr */ - case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216); + case 214: /* expr ::= NOT expr */ + case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215); {yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy590, 0);/*A-overwrites-B*/} break; - case 217: /* expr ::= PLUS|MINUS expr */ + case 216: /* expr ::= PLUS|MINUS expr */ { Expr *p = yymsp[0].minor.yy590; u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS); @@ -181273,7 +182222,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 218: /* expr ::= expr PTR expr */ + case 217: /* expr ::= expr PTR expr */ { ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy590); pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy590); @@ -181281,11 +182230,11 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy590 = yylhsminor.yy590; break; - case 219: /* between_op ::= BETWEEN */ - case 222: /* in_op ::= IN */ yytestcase(yyruleno==222); + case 218: /* between_op ::= BETWEEN */ + case 221: /* in_op ::= IN */ yytestcase(yyruleno==221); {yymsp[0].minor.yy502 = 0;} break; - case 221: /* expr ::= expr between_op expr AND expr */ + case 220: /* expr ::= expr between_op expr AND expr */ { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590); @@ -181298,7 +182247,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 224: /* expr ::= expr in_op LP exprlist RP */ + case 223: /* expr ::= expr in_op LP exprlist RP */ { if( yymsp[-1].minor.yy402==0 ){ /* Expressions of the form @@ -181344,20 +182293,20 @@ static YYACTIONTYPE yy_reduce( } } break; - case 225: /* expr ::= LP select RP */ + case 224: /* expr ::= LP select RP */ { yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy590, yymsp[-1].minor.yy637); } break; - case 226: /* expr ::= expr in_op LP select RP */ + case 225: /* expr ::= expr in_op LP select RP */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, yymsp[-1].minor.yy637); if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 227: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); @@ -181367,14 +182316,14 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); } break; - case 228: /* expr ::= EXISTS LP select RP */ + case 227: /* expr ::= EXISTS LP select RP */ { Expr *p; p = yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy637); } break; - case 229: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 228: /* expr ::= CASE case_operand case_exprlist case_else END */ { yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy590, 0); if( yymsp[-4].minor.yy590 ){ @@ -181386,29 +182335,29 @@ static YYACTIONTYPE yy_reduce( } } break; - case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[0].minor.yy590); } break; - case 231: /* case_exprlist ::= WHEN expr THEN expr */ + case 230: /* case_exprlist ::= WHEN expr THEN expr */ { yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy402, yymsp[0].minor.yy590); } break; - case 236: /* nexprlist ::= nexprlist COMMA expr */ + case 235: /* nexprlist ::= nexprlist COMMA expr */ {yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[0].minor.yy590);} break; - case 237: /* nexprlist ::= expr */ + case 236: /* nexprlist ::= expr */ {yymsp[0].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy590); /*A-overwrites-Y*/} break; - case 239: /* paren_exprlist ::= LP exprlist RP */ - case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244); + case 238: /* paren_exprlist ::= LP exprlist RP */ + case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243); {yymsp[-2].minor.yy402 = yymsp[-1].minor.yy402;} break; - case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy402, yymsp[-10].minor.yy502, @@ -181418,48 +182367,48 @@ static YYACTIONTYPE yy_reduce( } } break; - case 241: /* uniqueflag ::= UNIQUE */ - case 283: /* raisetype ::= ABORT */ yytestcase(yyruleno==283); + case 240: /* uniqueflag ::= UNIQUE */ + case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); {yymsp[0].minor.yy502 = OE_Abort;} break; - case 242: /* uniqueflag ::= */ + case 241: /* uniqueflag ::= */ {yymsp[1].minor.yy502 = OE_None;} break; - case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */ { yymsp[-4].minor.yy402 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); } break; - case 246: /* eidlist ::= nm collate sortorder */ + case 245: /* eidlist ::= nm collate sortorder */ { yymsp[-2].minor.yy402 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); /*A-overwrites-Y*/ } break; - case 249: /* cmd ::= DROP INDEX ifexists fullname */ + case 248: /* cmd ::= DROP INDEX ifexists fullname */ {sqlite3DropIndex(pParse, yymsp[0].minor.yy563, yymsp[-1].minor.yy502);} break; - case 250: /* cmd ::= VACUUM vinto */ + case 249: /* cmd ::= VACUUM vinto */ {sqlite3Vacuum(pParse,0,yymsp[0].minor.yy590);} break; - case 251: /* cmd ::= VACUUM nm vinto */ + case 250: /* cmd ::= VACUUM nm vinto */ {sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy590);} break; - case 254: /* cmd ::= PRAGMA nm dbnm */ + case 253: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 255: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 256: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 257: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 258: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 261: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 260: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; @@ -181467,50 +182416,50 @@ static YYACTIONTYPE yy_reduce( sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy319, &all); } break; - case 262: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 263: /* trigger_time ::= BEFORE|AFTER */ + case 262: /* trigger_time ::= BEFORE|AFTER */ { yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 264: /* trigger_time ::= INSTEAD OF */ + case 263: /* trigger_time ::= INSTEAD OF */ { yymsp[-1].minor.yy502 = TK_INSTEAD;} break; - case 265: /* trigger_time ::= */ + case 264: /* trigger_time ::= */ { yymsp[1].minor.yy502 = TK_BEFORE; } break; - case 266: /* trigger_event ::= DELETE|INSERT */ - case 267: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==267); + case 265: /* trigger_event ::= DELETE|INSERT */ + case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266); {yymsp[0].minor.yy28.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy28.b = 0;} break; - case 268: /* trigger_event ::= UPDATE OF idlist */ + case 267: /* trigger_event ::= UPDATE OF idlist */ {yymsp[-2].minor.yy28.a = TK_UPDATE; yymsp[-2].minor.yy28.b = yymsp[0].minor.yy204;} break; - case 269: /* when_clause ::= */ - case 288: /* key_opt ::= */ yytestcase(yyruleno==288); + case 268: /* when_clause ::= */ + case 287: /* key_opt ::= */ yytestcase(yyruleno==287); { yymsp[1].minor.yy590 = 0; } break; - case 270: /* when_clause ::= WHEN expr */ - case 289: /* key_opt ::= KEY expr */ yytestcase(yyruleno==289); + case 269: /* when_clause ::= WHEN expr */ + case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); { yymsp[-1].minor.yy590 = yymsp[0].minor.yy590; } break; - case 271: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { assert( yymsp[-2].minor.yy319!=0 ); yymsp[-2].minor.yy319->pLast->pNext = yymsp[-1].minor.yy319; yymsp[-2].minor.yy319->pLast = yymsp[-1].minor.yy319; } break; - case 272: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ { assert( yymsp[-1].minor.yy319!=0 ); yymsp[-1].minor.yy319->pLast = yymsp[-1].minor.yy319; } break; - case 273: /* trnm ::= nm DOT nm */ + case 272: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -181518,39 +182467,39 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 274: /* tridxby ::= INDEXED BY nm */ + case 273: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* tridxby ::= NOT INDEXED */ + case 274: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 276: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ {yylhsminor.yy319 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy563, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590, yymsp[-7].minor.yy502, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy342);} yymsp[-8].minor.yy319 = yylhsminor.yy319; break; - case 277: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { yylhsminor.yy319 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy204,yymsp[-2].minor.yy637,yymsp[-6].minor.yy502,yymsp[-1].minor.yy403,yymsp[-7].minor.yy342,yymsp[0].minor.yy342);/*yylhsminor.yy319-overwrites-yymsp[-6].minor.yy502*/ } yymsp[-7].minor.yy319 = yylhsminor.yy319; break; - case 278: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ {yylhsminor.yy319 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy590, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy342);} yymsp[-5].minor.yy319 = yylhsminor.yy319; break; - case 279: /* trigger_cmd ::= scanpt select scanpt */ + case 278: /* trigger_cmd ::= scanpt select scanpt */ {yylhsminor.yy319 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy637, yymsp[-2].minor.yy342, yymsp[0].minor.yy342); /*yylhsminor.yy319-overwrites-yymsp[-1].minor.yy637*/} yymsp[-2].minor.yy319 = yylhsminor.yy319; break; - case 280: /* expr ::= RAISE LP IGNORE RP */ + case 279: /* expr ::= RAISE LP IGNORE RP */ { yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( yymsp[-3].minor.yy590 ){ @@ -181558,7 +182507,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 281: /* expr ::= RAISE LP raisetype COMMA expr RP */ + case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */ { yymsp[-5].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy590, 0); if( yymsp[-5].minor.yy590 ) { @@ -181566,117 +182515,117 @@ static YYACTIONTYPE yy_reduce( } } break; - case 282: /* raisetype ::= ROLLBACK */ + case 281: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy502 = OE_Rollback;} break; - case 284: /* raisetype ::= FAIL */ + case 283: /* raisetype ::= FAIL */ {yymsp[0].minor.yy502 = OE_Fail;} break; - case 285: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy563,yymsp[-1].minor.yy502); } break; - case 286: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy590, yymsp[-1].minor.yy590, yymsp[0].minor.yy590); } break; - case 287: /* cmd ::= DETACH database_kw_opt expr */ + case 286: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy590); } break; - case 290: /* cmd ::= REINDEX */ + case 289: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 291: /* cmd ::= REINDEX nm dbnm */ + case 290: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 292: /* cmd ::= ANALYZE */ + case 291: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 293: /* cmd ::= ANALYZE nm dbnm */ + case 292: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 294: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy563,&yymsp[0].minor.yy0); } break; - case 295: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 296: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy563, &yymsp[0].minor.yy0); } break; - case 297: /* add_column_fullname ::= fullname */ + case 296: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy563); } break; - case 298: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy563, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 299: /* cmd ::= create_vtab */ + case 298: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 300: /* cmd ::= create_vtab LP vtabarglist RP */ + case 299: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 301: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy502); } break; - case 302: /* vtabarg ::= */ + case 301: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 303: /* vtabargtoken ::= ANY */ - case 304: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==304); - case 305: /* lp ::= LP */ yytestcase(yyruleno==305); + case 302: /* vtabargtoken ::= ANY */ + case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); + case 304: /* lp ::= LP */ yytestcase(yyruleno==304); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 306: /* with ::= WITH wqlist */ - case 307: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==307); + case 305: /* with ::= WITH wqlist */ + case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); { sqlite3WithPush(pParse, yymsp[0].minor.yy125, 1); } break; - case 308: /* wqas ::= AS */ + case 307: /* wqas ::= AS */ {yymsp[0].minor.yy444 = M10d_Any;} break; - case 309: /* wqas ::= AS MATERIALIZED */ + case 308: /* wqas ::= AS MATERIALIZED */ {yymsp[-1].minor.yy444 = M10d_Yes;} break; - case 310: /* wqas ::= AS NOT MATERIALIZED */ + case 309: /* wqas ::= AS NOT MATERIALIZED */ {yymsp[-2].minor.yy444 = M10d_No;} break; - case 311: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ + case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ { yymsp[-5].minor.yy361 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy402, yymsp[-1].minor.yy637, yymsp[-3].minor.yy444); /*A-overwrites-X*/ } break; - case 312: /* withnm ::= nm */ + case 311: /* withnm ::= nm */ {pParse->bHasWith = 1;} break; - case 313: /* wqlist ::= wqitem */ + case 312: /* wqlist ::= wqitem */ { yymsp[0].minor.yy125 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy361); /*A-overwrites-X*/ } break; - case 314: /* wqlist ::= wqlist COMMA wqitem */ + case 313: /* wqlist ::= wqlist COMMA wqitem */ { yymsp[-2].minor.yy125 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy125, yymsp[0].minor.yy361); } break; - case 315: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { assert( yymsp[0].minor.yy483!=0 ); sqlite3WindowChain(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy483); @@ -181685,7 +182634,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy483 = yylhsminor.yy483; break; - case 316: /* windowdefn ::= nm AS LP window RP */ + case 315: /* windowdefn ::= nm AS LP window RP */ { if( ALWAYS(yymsp[-1].minor.yy483) ){ yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); @@ -181694,83 +182643,83 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy483 = yylhsminor.yy483; break; - case 317: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { yymsp[-4].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, 0); } break; - case 318: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, &yymsp[-5].minor.yy0); } yymsp[-5].minor.yy483 = yylhsminor.yy483; break; - case 319: /* window ::= ORDER BY sortlist frame_opt */ + case 318: /* window ::= ORDER BY sortlist frame_opt */ { yymsp[-3].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, 0); } break; - case 320: /* window ::= nm ORDER BY sortlist frame_opt */ + case 319: /* window ::= nm ORDER BY sortlist frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy483 = yylhsminor.yy483; break; - case 321: /* window ::= nm frame_opt */ + case 320: /* window ::= nm frame_opt */ { yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, 0, &yymsp[-1].minor.yy0); } yymsp[-1].minor.yy483 = yylhsminor.yy483; break; - case 322: /* frame_opt ::= */ + case 321: /* frame_opt ::= */ { yymsp[1].minor.yy483 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 323: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy502, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy444); } yymsp[-2].minor.yy483 = yylhsminor.yy483; break; - case 324: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy502, yymsp[-3].minor.yy205.eType, yymsp[-3].minor.yy205.pExpr, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, yymsp[0].minor.yy444); } yymsp[-5].minor.yy483 = yylhsminor.yy483; break; - case 326: /* frame_bound_s ::= frame_bound */ - case 328: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==328); + case 325: /* frame_bound_s ::= frame_bound */ + case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327); {yylhsminor.yy205 = yymsp[0].minor.yy205;} yymsp[0].minor.yy205 = yylhsminor.yy205; break; - case 327: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 329: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==329); - case 331: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==331); + case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328); + case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330); {yylhsminor.yy205.eType = yymsp[-1].major; yylhsminor.yy205.pExpr = 0;} yymsp[-1].minor.yy205 = yylhsminor.yy205; break; - case 330: /* frame_bound ::= expr PRECEDING|FOLLOWING */ + case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */ {yylhsminor.yy205.eType = yymsp[0].major; yylhsminor.yy205.pExpr = yymsp[-1].minor.yy590;} yymsp[-1].minor.yy205 = yylhsminor.yy205; break; - case 332: /* frame_exclude_opt ::= */ + case 331: /* frame_exclude_opt ::= */ {yymsp[1].minor.yy444 = 0;} break; - case 333: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ + case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ {yymsp[-1].minor.yy444 = yymsp[0].minor.yy444;} break; - case 334: /* frame_exclude ::= NO OTHERS */ - case 335: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==335); + case 333: /* frame_exclude ::= NO OTHERS */ + case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334); {yymsp[-1].minor.yy444 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 336: /* frame_exclude ::= GROUP|TIES */ + case 335: /* frame_exclude ::= GROUP|TIES */ {yymsp[0].minor.yy444 = yymsp[0].major; /*A-overwrites-X*/} break; - case 337: /* window_clause ::= WINDOW windowdefn_list */ + case 336: /* window_clause ::= WINDOW windowdefn_list */ { yymsp[-1].minor.yy483 = yymsp[0].minor.yy483; } break; - case 338: /* filter_over ::= filter_clause over_clause */ + case 337: /* filter_over ::= filter_clause over_clause */ { if( yymsp[0].minor.yy483 ){ yymsp[0].minor.yy483->pFilter = yymsp[-1].minor.yy590; @@ -181781,13 +182730,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[-1].minor.yy483 = yylhsminor.yy483; break; - case 339: /* filter_over ::= over_clause */ + case 338: /* filter_over ::= over_clause */ { yylhsminor.yy483 = yymsp[0].minor.yy483; } yymsp[0].minor.yy483 = yylhsminor.yy483; break; - case 340: /* filter_over ::= filter_clause */ + case 339: /* filter_over ::= filter_clause */ { yylhsminor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yylhsminor.yy483 ){ @@ -181799,13 +182748,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy483 = yylhsminor.yy483; break; - case 341: /* over_clause ::= OVER LP window RP */ + case 340: /* over_clause ::= OVER LP window RP */ { yymsp[-3].minor.yy483 = yymsp[-1].minor.yy483; assert( yymsp[-3].minor.yy483!=0 ); } break; - case 342: /* over_clause ::= OVER nm */ + case 341: /* over_clause ::= OVER nm */ { yymsp[-1].minor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yymsp[-1].minor.yy483 ){ @@ -181813,10 +182762,10 @@ static YYACTIONTYPE yy_reduce( } } break; - case 343: /* filter_clause ::= FILTER LP WHERE expr RP */ + case 342: /* filter_clause ::= FILTER LP WHERE expr RP */ { yymsp[-4].minor.yy590 = yymsp[-1].minor.yy590; } break; - case 344: /* term ::= QNUMBER */ + case 343: /* term ::= QNUMBER */ { yylhsminor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); sqlite3DequoteNumber(pParse, yylhsminor.yy590); @@ -181824,71 +182773,71 @@ static YYACTIONTYPE yy_reduce( yymsp[0].minor.yy590 = yylhsminor.yy590; break; default: - /* (345) input ::= cmdlist */ yytestcase(yyruleno==345); - /* (346) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==346); - /* (347) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=347); - /* (348) ecmd ::= SEMI */ yytestcase(yyruleno==348); - /* (349) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==349); - /* (350) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=350); - /* (351) trans_opt ::= */ yytestcase(yyruleno==351); - /* (352) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==352); - /* (353) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==353); - /* (354) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==354); - /* (355) savepoint_opt ::= */ yytestcase(yyruleno==355); - /* (356) cmd ::= create_table create_table_args */ yytestcase(yyruleno==356); - /* (357) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=357); - /* (358) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==358); - /* (359) columnlist ::= columnname carglist */ yytestcase(yyruleno==359); - /* (360) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==360); - /* (361) nm ::= STRING */ yytestcase(yyruleno==361); - /* (362) typetoken ::= typename */ yytestcase(yyruleno==362); - /* (363) typename ::= ID|STRING */ yytestcase(yyruleno==363); - /* (364) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); - /* (365) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=365); - /* (366) carglist ::= carglist ccons */ yytestcase(yyruleno==366); - /* (367) carglist ::= */ yytestcase(yyruleno==367); - /* (368) ccons ::= NULL onconf */ yytestcase(yyruleno==368); - /* (369) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==369); - /* (370) ccons ::= AS generated */ yytestcase(yyruleno==370); - /* (371) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==371); - /* (372) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==372); - /* (373) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=373); - /* (374) tconscomma ::= */ yytestcase(yyruleno==374); - /* (375) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=375); - /* (376) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=377); - /* (378) oneselect ::= values */ yytestcase(yyruleno==378); - /* (379) sclp ::= selcollist COMMA */ yytestcase(yyruleno==379); - /* (380) as ::= ID|STRING */ yytestcase(yyruleno==380); - /* (381) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=381); - /* (382) returning ::= */ yytestcase(yyruleno==382); - /* (383) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=383); - /* (384) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==384); - /* (385) case_operand ::= expr */ yytestcase(yyruleno==385); - /* (386) exprlist ::= nexprlist */ yytestcase(yyruleno==386); - /* (387) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=387); - /* (388) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=388); - /* (389) nmnum ::= ON */ yytestcase(yyruleno==389); - /* (390) nmnum ::= DELETE */ yytestcase(yyruleno==390); - /* (391) nmnum ::= DEFAULT */ yytestcase(yyruleno==391); - /* (392) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==392); - /* (393) foreach_clause ::= */ yytestcase(yyruleno==393); - /* (394) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==394); - /* (395) trnm ::= nm */ yytestcase(yyruleno==395); - /* (396) tridxby ::= */ yytestcase(yyruleno==396); - /* (397) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==397); - /* (398) database_kw_opt ::= */ yytestcase(yyruleno==398); - /* (399) kwcolumn_opt ::= */ yytestcase(yyruleno==399); - /* (400) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==400); - /* (401) vtabarglist ::= vtabarg */ yytestcase(yyruleno==401); - /* (402) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==402); - /* (403) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==403); - /* (404) anylist ::= */ yytestcase(yyruleno==404); - /* (405) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==405); - /* (406) anylist ::= anylist ANY */ yytestcase(yyruleno==406); - /* (407) with ::= */ yytestcase(yyruleno==407); - /* (408) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=408); - /* (409) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=409); + /* (344) input ::= cmdlist */ yytestcase(yyruleno==344); + /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345); + /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346); + /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347); + /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348); + /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349); + /* (350) trans_opt ::= */ yytestcase(yyruleno==350); + /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351); + /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352); + /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353); + /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354); + /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355); + /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356); + /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357); + /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358); + /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359); + /* (360) nm ::= STRING */ yytestcase(yyruleno==360); + /* (361) typetoken ::= typename */ yytestcase(yyruleno==361); + /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362); + /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363); + /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); + /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365); + /* (366) carglist ::= */ yytestcase(yyruleno==366); + /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367); + /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368); + /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369); + /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370); + /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371); + /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372); + /* (373) tconscomma ::= */ yytestcase(yyruleno==373); + /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374); + /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375); + /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) oneselect ::= values */ yytestcase(yyruleno==377); + /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378); + /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379); + /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380); + /* (381) returning ::= */ yytestcase(yyruleno==381); + /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382); + /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383); + /* (384) case_operand ::= expr */ yytestcase(yyruleno==384); + /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385); + /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386); + /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387); + /* (388) nmnum ::= ON */ yytestcase(yyruleno==388); + /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389); + /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390); + /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391); + /* (392) foreach_clause ::= */ yytestcase(yyruleno==392); + /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393); + /* (394) trnm ::= nm */ yytestcase(yyruleno==394); + /* (395) tridxby ::= */ yytestcase(yyruleno==395); + /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396); + /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397); + /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398); + /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399); + /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400); + /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401); + /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402); + /* (403) anylist ::= */ yytestcase(yyruleno==403); + /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404); + /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405); + /* (406) with ::= */ yytestcase(yyruleno==406); + /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407); + /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408); break; /********** End reduce actions ************************************************/ }; @@ -184156,32 +185105,6 @@ SQLITE_API char *sqlite3_temp_directory = 0; */ SQLITE_API char *sqlite3_data_directory = 0; -/* -** Determine whether or not high-precision (long double) floating point -** math works correctly on CPU currently running. -*/ -static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){ - if( sizeof(LONGDOUBLE_TYPE)<=8 ){ - /* If the size of "long double" is not more than 8, then - ** high-precision math is not possible. */ - return 0; - }else{ - /* Just because sizeof(long double)>8 does not mean that the underlying - ** hardware actually supports high-precision floating point. For example, - ** clearing the 0x100 bit in the floating-point control word on Intel - ** processors will make long double work like double, even though long - ** double takes up more space. The only way to determine if long double - ** actually works is to run an experiment. */ - LONGDOUBLE_TYPE a, b, c; - rc++; - a = 1.0+rc*0.1; - b = 1.0e+18+rc*25.0; - c = a+b; - return b!=c; - } -} - - /* ** Initialize SQLite. ** @@ -184376,13 +185299,6 @@ SQLITE_API int sqlite3_initialize(void){ rc = SQLITE_EXTRA_INIT(0); } #endif - - /* Experimentally determine if high-precision floating point is - ** available. */ -#ifndef SQLITE_OMIT_WSD - sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc); -#endif - return rc; } @@ -185453,10 +186369,6 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); -#if SQLITE_USER_AUTHENTICATION - sqlite3_free(db->auth.zAuthUser); - sqlite3_free(db->auth.zAuthPW); -#endif db->eOpenState = SQLITE_STATE_ERROR; @@ -185923,7 +186835,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS| + SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But @@ -186958,8 +187871,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ - }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){ - newLimit = 1; + }else if( newLimitaLimit[limitId] = newLimit; } @@ -187478,6 +188391,7 @@ static int openDatabase( if( ((1<<(flags&7)) & 0x46)==0 ){ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */ }else{ + if( zFilename==0 ) zFilename = ":memory:"; rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); } if( rc!=SQLITE_OK ){ @@ -188390,6 +189304,18 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N) + ** + ** Write the current optimization settings into *N. A zero bit means that + ** the optimization is on, and a 1 bit means that the optimization is off. + */ + case SQLITE_TESTCTRL_GETOPT: { + sqlite3 *db = va_arg(ap, sqlite3*); + int *pN = va_arg(ap, int*); + *pN = db->dbOptFlags; + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt); ** ** If parameter onoff is 1, subsequent calls to localtime() fail. @@ -188636,23 +189562,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; }; -#if !defined(SQLITE_OMIT_WSD) - /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X); - ** - ** X<0 Make no changes to the bUseLongDouble. Just report value. - ** X==0 Disable bUseLongDouble - ** X==1 Enable bUseLongDouble - ** X>=2 Set bUseLongDouble to its default value for this platform - */ - case SQLITE_TESTCTRL_USELONGDOUBLE: { - int b = va_arg(ap, int); - if( b>=2 ) b = hasHighPrecisionDouble(b); - if( b>=0 ) sqlite3Config.bUseLongDouble = b>0; - rc = sqlite3Config.bUseLongDouble!=0; - break; - } -#endif - #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** @@ -188960,7 +189869,11 @@ SQLITE_API int sqlite3_snapshot_get( if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ + Pager *pPager = sqlite3BtreePager(pBt); + i64 dummy = 0; + sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy); rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + sqlite3PagerSnapshotOpen(pPager, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } @@ -192779,10 +193692,15 @@ static int fts3PoslistPhraseMerge( if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); + /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN + ** entry, so this is actually end-of-doclist. */ + if( iCol1==0 ) return 0; } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); + /* As above, iCol2==0 indicates corruption. */ + if( iCol2==0 ) return 0; } while( 1 ){ @@ -195953,7 +196871,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - aTmp = sqlite3_malloc64(nTmp*2); + aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; @@ -196604,7 +197522,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ } #endif -#if !SQLITE_CORE +#if !defined(SQLITE_CORE) /* ** Initialize API pointer table, if required. */ @@ -199760,11 +200678,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( #ifdef SQLITE_TEST -#if defined(INCLUDE_SQLITE_TCL_H) -# include "sqlite_tcl.h" -#else -# include "tcl.h" -#endif +#include "tclsqlite.h" /* #include */ /* @@ -206991,6 +207905,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){ return 1; } + assert( pIter->nSnippet>=0 ); pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; @@ -211984,7 +212899,9 @@ static u32 jsonLookupStep( zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; - for(i=1; zPath[i] && zPath[i]!='"'; i++){} + for(i=1; zPath[i] && zPath[i]!='"'; i++){ + if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++; + } nKey = i-1; if( zPath[i] ){ i++; @@ -220896,7 +221813,7 @@ SQLITE_API int sqlite3_rtree_query_callback( ); } -#if !SQLITE_CORE +#ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -221487,7 +222404,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ return rc; } -#if !SQLITE_CORE +#ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -222745,6 +223662,27 @@ struct RbuFrame { u32 iWalFrame; }; +#ifndef UNUSED_PARAMETER +/* +** The following macros are used to suppress compiler warnings and to +** make it clear to human readers when a function parameter is deliberately +** left unused within the body of a function. This usually happens when +** a function is called via a function pointer. For example the +** implementation of an SQL aggregate step callback may not use the +** parameter indicating the number of arguments passed to the aggregate, +** if it knows that this is enforced elsewhere. +** +** When a function parameter is not used at all within the body of a function, +** it is generally named "NotUsed" or "NotUsed2" to make things even clearer. +** However, these macros may also be used to suppress warnings related to +** parameters that may or may not be used depending on compilation options. +** For example those parameters only used in assert() statements. In these +** cases the parameters are named as per the usual conventions. +*/ +#define UNUSED_PARAMETER(x) (void)(x) +#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y) +#endif + /* ** RBU handle. ** @@ -222796,7 +223734,7 @@ struct sqlite3rbu { int rc; /* Value returned by last rbu_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ int nStep; /* Rows processed for current object */ - int nProgress; /* Rows processed for all objects */ + sqlite3_int64 nProgress; /* Rows processed for all objects */ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ @@ -222913,7 +223851,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ v = (v<<6) + c; } z--; - *pLen -= z - zStart; + *pLen -= (int)(z - zStart); *pz = (char*)z; return v; } @@ -223098,6 +224036,7 @@ static void rbuFossilDeltaFunc( char *aOut; assert( argc==2 ); + UNUSED_PARAMETER(argc); nOrig = sqlite3_value_bytes(argv[0]); aOrig = (const char*)sqlite3_value_blob(argv[0]); @@ -224677,13 +225616,13 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ else if( c==')' ){ nParen--; if( nParen==0 ){ - int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; + int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan); pIter->aIdxCol[iIdxCol++].nSpan = nSpan; i++; break; } }else if( c==',' && nParen==1 ){ - int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; + int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan); pIter->aIdxCol[iIdxCol++].nSpan = nSpan; pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1]; }else if( c=='"' || c=='\'' || c=='`' ){ @@ -225373,6 +226312,8 @@ static void rbuFileSuffix3(const char *zBase, char *z){ for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } +#else + UNUSED_PARAMETER2(zBase,z); #endif } @@ -225957,7 +226898,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ "(%d, %Q), " "(%d, %Q), " "(%d, %d), " - "(%d, %d), " + "(%d, %lld), " "(%d, %lld), " "(%d, %lld), " "(%d, %lld), " @@ -226315,6 +227256,7 @@ static void rbuIndexCntFunc( sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain); assert( nVal==1 ); + UNUSED_PARAMETER(nVal); rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg, sqlite3_mprintf("SELECT count(*) FROM sqlite_schema " @@ -226590,7 +227532,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( ){ if( zTarget==0 ){ return rbuMisuseError(); } if( zState ){ - int n = strlen(zState); + size_t n = strlen(zState); if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){ return rbuMisuseError(); } @@ -226807,6 +227749,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ */ static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){ int rc = SQLITE_OK; + UNUSED_PARAMETER(pArg); #if defined(_WIN32_WCE) { LPWSTR zWideOld; @@ -227711,6 +228654,9 @@ static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ ** No-op. */ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ + UNUSED_PARAMETER(pVfs); + UNUSED_PARAMETER(a); + UNUSED_PARAMETER(b); return 0; } @@ -228109,6 +229055,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ pIdxInfo->orderByConsumed = 1; pIdxInfo->idxNum |= 0x08; } + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX; return SQLITE_OK; } @@ -228766,7 +229713,13 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } ** ** The data field of sqlite_dbpage table can be updated. The new ** value must be a BLOB which is the correct page size, otherwise the -** update fails. Rows may not be deleted or inserted. +** update fails. INSERT operations also work, and operate as if they +** where REPLACE. The size of the database can be extended by INSERT-ing +** new pages on the end. +** +** Rows may not be deleted. However, doing an INSERT to page number N +** with NULL page data causes the N-th page and all subsequent pages to be +** deleted and the database to be truncated. */ /* #include "sqliteInt.h" ** Requires access to internal data structures ** */ @@ -228789,6 +229742,8 @@ struct DbpageCursor { struct DbpageTable { sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* The database */ + int iDbTrunc; /* Database to truncate */ + Pgno pgnoTrunc; /* Size to truncate to */ }; /* Columns */ @@ -228797,7 +229752,6 @@ struct DbpageTable { #define DBPAGE_COLUMN_SCHEMA 2 - /* ** Connect to or create a dbpagevfs virtual table. */ @@ -229059,11 +230013,11 @@ static int dbpageUpdate( DbPage *pDbPage = 0; int rc = SQLITE_OK; char *zErr = 0; - const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; + int isInsert; (void)pRowid; if( pTab->db->flags & SQLITE_Defensive ){ @@ -229074,21 +230028,29 @@ static int dbpageUpdate( zErr = "cannot delete"; goto update_fail; } - pgno = sqlite3_value_int(argv[0]); - if( sqlite3_value_type(argv[0])==SQLITE_NULL - || (Pgno)sqlite3_value_int(argv[1])!=pgno - ){ - zErr = "cannot insert"; - goto update_fail; + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + pgno = (Pgno)sqlite3_value_int(argv[2]); + isInsert = 1; + }else{ + pgno = sqlite3_value_int(argv[0]); + if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ + zErr = "cannot insert"; + goto update_fail; + } + isInsert = 0; } - zSchema = (const char*)sqlite3_value_text(argv[4]); - iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1; - if( NEVER(iDb<0) ){ - zErr = "no such schema"; - goto update_fail; + if( sqlite3_value_type(argv[4])==SQLITE_NULL ){ + iDb = 0; + }else{ + const char *zSchema = (const char*)sqlite3_value_text(argv[4]); + iDb = sqlite3FindDbName(pTab->db, zSchema); + if( iDb<0 ){ + zErr = "no such schema"; + goto update_fail; + } } pBt = pTab->db->aDb[iDb].pBt; - if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){ + if( pgno<1 || NEVER(pBt==0) ){ zErr = "bad page number"; goto update_fail; } @@ -229096,18 +230058,25 @@ static int dbpageUpdate( if( sqlite3_value_type(argv[3])!=SQLITE_BLOB || sqlite3_value_bytes(argv[3])!=szPage ){ - zErr = "bad page value"; - goto update_fail; + if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){ + /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and + ** all subsequent pages to be deleted. */ + pTab->iDbTrunc = iDb; + pgno--; + pTab->pgnoTrunc = pgno; + }else{ + zErr = "bad page value"; + goto update_fail; + } } pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ const void *pData = sqlite3_value_blob(argv[3]); - assert( pData!=0 || pTab->db->mallocFailed ); - if( pData - && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK - ){ - memcpy(sqlite3PagerGetData(pDbPage), pData, szPage); + if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){ + unsigned char *aPage = sqlite3PagerGetData(pDbPage); + memcpy(aPage, pData, szPage); + pTab->pgnoTrunc = 0; } } sqlite3PagerUnref(pDbPage); @@ -229131,9 +230100,31 @@ static int dbpageBegin(sqlite3_vtab *pVtab){ Btree *pBt = db->aDb[i].pBt; if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0); } + pTab->pgnoTrunc = 0; return SQLITE_OK; } +/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT +*/ +static int dbpageSync(sqlite3_vtab *pVtab){ + DbpageTable *pTab = (DbpageTable *)pVtab; + if( pTab->pgnoTrunc>0 ){ + Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt; + Pager *pPager = sqlite3BtreePager(pBt); + sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc); + } + pTab->pgnoTrunc = 0; + return SQLITE_OK; +} + +/* Cancel any pending truncate. +*/ +static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){ + DbpageTable *pTab = (DbpageTable *)pVtab; + pTab->pgnoTrunc = 0; + (void)notUsed1; + return SQLITE_OK; +} /* ** Invoke this routine to register the "dbpage" virtual table module @@ -229155,14 +230146,14 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ dbpageRowid, /* xRowid - read data */ dbpageUpdate, /* xUpdate */ dbpageBegin, /* xBegin */ - 0, /* xSync */ + dbpageSync, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0, /* xRollbackTo */ + dbpageRollbackTo, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; @@ -229257,6 +230248,10 @@ struct SessionBuffer { ** input data. Input data may be supplied either as a single large buffer ** (e.g. sqlite3changeset_start()) or using a stream function (e.g. ** sqlite3changeset_start_strm()). +** +** bNoDiscard: +** If true, then the only time data is discarded is as a result of explicit +** sessionDiscardData() calls. Not within every sessionInputBuffer() call. */ struct SessionInput { int bNoDiscard; /* If true, do not discard in InputBuffer() */ @@ -230941,16 +231936,19 @@ static void sessionPreupdateOneChange( for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ - TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); - assert( trc==SQLITE_OK ); + /* This may fail if the column has a non-NULL default and was added + ** using ALTER TABLE ADD COLUMN after this record was created. */ + rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p); }else if( pTab->abPK[i] ){ TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); assert( trc==SQLITE_OK ); } - /* This may fail if SQLite value p contains a utf-16 string that must - ** be converted to utf-8 and an OOM error occurs while doing so. */ - rc = sessionSerializeValue(0, p, &nByte); + if( rc==SQLITE_OK ){ + /* This may fail if SQLite value p contains a utf-16 string that must + ** be converted to utf-8 and an OOM error occurs while doing so. */ + rc = sessionSerializeValue(0, p, &nByte); + } if( rc!=SQLITE_OK ) goto error_out; } if( pTab->bRowid ){ @@ -234331,15 +235329,21 @@ static int sessionChangesetApply( int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ int bPatchset; + u64 savedFlag = db->flags & SQLITE_FkNoAction; assert( xConflict!=0 ); + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ + db->flags |= ((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } + pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); - sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } @@ -234501,6 +235505,12 @@ static int sessionChangesetApply( sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_free((char*)sApply.constraints.aBuf); sqlite3_free((char*)sApply.rebase.aBuf); + + if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ + assert( db->flags & SQLITE_FkNoAction ); + db->flags &= ~((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } sqlite3_mutex_leave(sqlite3_db_mutex(db)); return rc; } @@ -234529,12 +235539,6 @@ SQLITE_API int sqlite3changeset_apply_v2( sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); - u64 savedFlag = db->flags & SQLITE_FkNoAction; - - if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ - db->flags |= ((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } if( rc==SQLITE_OK ){ rc = sessionChangesetApply( @@ -234542,11 +235546,6 @@ SQLITE_API int sqlite3changeset_apply_v2( ); } - if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ - assert( db->flags & SQLITE_FkNoAction ); - db->flags &= ~((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } return rc; } @@ -234867,6 +235866,9 @@ static int sessionChangesetExtendRecord( sessionAppendBlob(pOut, aRec, nRec, &rc); if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt); + if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){ + rc = sqlite3_errcode(pGrp->db); + } } for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){ int eType = sqlite3_column_type(pTab->pDfltStmt, ii); @@ -234883,6 +235885,7 @@ static int sessionChangesetExtendRecord( } if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + pOut->nBuf += 8; } break; } @@ -235022,6 +236025,8 @@ static int sessionOneChangeToHash( u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; + assert( nRec>0 ); + /* Ensure that only changesets, or only patchsets, but not a mixture ** of both, are being combined. It is an error to try to combine a ** changeset and a patchset. */ @@ -235099,6 +236104,7 @@ static int sessionChangesetToHash( int nRec; int rc = SQLITE_OK; + pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ rc = sessionOneChangeToHash(pGrp, pIter, bRebase); if( rc!=SQLITE_OK ) break; @@ -235731,7 +236737,27 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ /************** End of sqlite3session.c **************************************/ /************** Begin file fts5.c ********************************************/ - +/* +** This, the "fts5.c" source file, is a composite file that is itself +** assembled from the following files: +** +** fts5.h +** fts5Int.h +** fts5parse.h <--- Generated from fts5parse.y by Lemon +** fts5parse.c <--- Generated from fts5parse.y by Lemon +** fts5_aux.c +** fts5_buffer.c +** fts5_config.c +** fts5_expr.c +** fts5_hash.c +** fts5_index.c +** fts5_main.c +** fts5_storage.c +** fts5_tokenize.c +** fts5_unicode2.c +** fts5_varint.c +** fts5_vocab.c +*/ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) @@ -235741,6 +236767,12 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ # undef NDEBUG #endif +#ifdef HAVE_STDINT_H +/* #include */ +#endif +#ifdef HAVE_INTTYPES_H +/* #include */ +#endif /* ** 2014 May 31 ** @@ -235981,6 +237013,10 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** +** In all cases, matches are visited in (column ASC, offset ASC) order. +** i.e. all those in column 0, sorted by offset, followed by those in +** column 1, etc. +** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -236047,9 +237083,32 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. +** +** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) +** If parameter iCol is less than zero, or greater than or equal to the +** number of columns in the table, SQLITE_RANGE is returned. +** +** Otherwise, this function attempts to retrieve the locale associated +** with column iCol of the current row. Usually, there is no associated +** locale, and output parameters (*pzLocale) and (*pnLocale) are set +** to NULL and 0, respectively. However, if the fts5_locale() function +** was used to associate a locale with the value when it was inserted +** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated +** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) +** is set to the size in bytes of the buffer, not including the +** nul-terminator. +** +** If successful, SQLITE_OK is returned. Or, if an error occurs, an +** SQLite error code is returned. The final value of the output parameters +** is undefined in this case. +** +** xTokenize_v2: +** Tokenize text using the tokenizer belonging to the FTS5 table. This +** API is the same as the xTokenize() API, except that it allows a tokenizer +** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 4 */ void *(*xUserData)(Fts5Context*); @@ -236091,6 +237150,15 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); + + /* Below this point are iVersion>=4 only */ + int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xTokenize_v2)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); }; /* @@ -236111,7 +237179,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer object +** pointer provided by the application when the fts5_tokenizer_v2 object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -236135,7 +237203,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The second argument indicates the reason that FTS5 is requesting +** The third argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -236159,6 +237227,13 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** +** The sixth and seventh arguments passed to xTokenize() - pLocale and +** nLocale - are a pointer to a buffer containing the locale to use for +** tokenization (e.g. "en_US") and its size in bytes, respectively. The +** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in +** which case nLocale is always 0) to indicate that the tokenizer should +** use its default locale. +** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -236182,6 +237257,30 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** +** If the tokenizer is registered using an fts5_tokenizer_v2 object, +** then the xTokenize() method has two additional arguments - pLocale +** and nLocale. These specify the locale that the tokenizer should use +** for the current request. If pLocale and nLocale are both 0, then the +** tokenizer should use its default locale. Otherwise, pLocale points to +** an nLocale byte buffer containing the name of the locale to use as utf-8 +** text. pLocale is not nul-terminated. +** +** FTS5_TOKENIZER +** +** There is also an fts5_tokenizer object. This is an older, deprecated, +** version of fts5_tokenizer_v2. It is similar except that: +** +**
      +**
    • There is no "iVersion" field, and +**
    • The xTokenize() method does not take a locale argument. +**
    +** +** Legacy fts5_tokenizer tokenizers must be registered using the +** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). +** +** Tokenizer implementations registered using either API may be retrieved +** using both xFindTokenizer() and xFindTokenizer_v2(). +** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -236290,6 +237389,33 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; +struct fts5_tokenizer_v2 { + int iVersion; /* Currently always 2 */ + + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + const char *pLocale, int nLocale, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* +** New code should use the fts5_tokenizer_v2 type to define tokenizer +** implementations. The following type is included for legacy applications +** that still use it. +*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -236309,6 +237435,7 @@ struct fts5_tokenizer { ); }; + /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -236328,7 +237455,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 2 */ + int iVersion; /* Currently always set to 3 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -236355,6 +237482,25 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); + + /* APIs below this point are only available if iVersion>=3 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void *pUserData, + fts5_tokenizer_v2 *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void **ppUserData, + fts5_tokenizer_v2 **ppTokenizer + ); }; /* @@ -236428,6 +237574,22 @@ typedef sqlite3_uint64 u64; # define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) # define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) +/* The uptr type is an unsigned integer large enough to hold a pointer +*/ +#if defined(HAVE_STDINT_H) + typedef uintptr_t uptr; +#elif SQLITE_PTRSIZE==4 + typedef u32 uptr; +#else + typedef u64 uptr; +#endif + +#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC +# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) +#else +# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) +#endif + #endif /* Truncate very long tokens to this many bytes. Hard limit is @@ -236515,10 +237677,13 @@ typedef struct Fts5TokenizerConfig Fts5TokenizerConfig; struct Fts5TokenizerConfig { Fts5Tokenizer *pTok; - fts5_tokenizer *pTokApi; + fts5_tokenizer_v2 *pApi2; + fts5_tokenizer *pApi1; const char **azArg; int nArg; int ePattern; /* FTS_PATTERN_XXX constant */ + const char *pLocale; /* Current locale to use */ + int nLocale; /* Size of pLocale in bytes */ }; /* @@ -236559,6 +237724,8 @@ struct Fts5TokenizerConfig { ** ** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex); ** +** bLocale: +** Set to true if locale=1 was specified when the table was created. */ struct Fts5Config { sqlite3 *db; /* Database handle */ @@ -236572,15 +237739,18 @@ struct Fts5Config { int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ int eContent; /* An FTS5_CONTENT value */ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */ + int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */ char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ int bTokendata; /* "tokendata=" option value (dflt==0) */ + int bLocale; /* "locale=" option value (dflt==0) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5TokenizerConfig t; int bLock; /* True when table is preparing statement */ + /* Values loaded from the %_config table */ int iVersion; /* fts5 file format 'version' */ int iCookie; /* Incremented when %_config is modified */ @@ -236608,9 +237778,10 @@ struct Fts5Config { #define FTS5_CURRENT_VERSION 4 #define FTS5_CURRENT_VERSION_SECUREDELETE 5 -#define FTS5_CONTENT_NORMAL 0 -#define FTS5_CONTENT_NONE 1 -#define FTS5_CONTENT_EXTERNAL 2 +#define FTS5_CONTENT_NORMAL 0 +#define FTS5_CONTENT_NONE 1 +#define FTS5_CONTENT_EXTERNAL 2 +#define FTS5_CONTENT_UNINDEXED 3 #define FTS5_DETAIL_FULL 0 #define FTS5_DETAIL_NONE 1 @@ -236645,6 +237816,8 @@ static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, i static int sqlite3Fts5ConfigParseRank(const char*, char**, char**); +static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...); + /* ** End of interface to code in fts5_config.c. **************************************************************************/ @@ -236689,7 +237862,7 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); static void sqlite3Fts5Put32(u8*, int); static int sqlite3Fts5Get32(const u8*); -#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) +#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF) #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; @@ -236980,6 +238153,14 @@ static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); static int sqlite3Fts5FlushToDisk(Fts5Table*); +static void sqlite3Fts5ClearLocale(Fts5Config *pConfig); +static void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc); + +static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal); +static int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal, + const char **ppText, int *pnText, const char **ppLoc, int *pnLoc +); + /* ** End of interface to code in fts5.c. **************************************************************************/ @@ -237059,8 +238240,8 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); static int sqlite3Fts5DropAll(Fts5Config*); static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); -static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int); +static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); @@ -237085,6 +238266,9 @@ static int sqlite3Fts5StorageOptimize(Fts5Storage *p); static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); static int sqlite3Fts5StorageReset(Fts5Storage *p); +static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*); +static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel); + /* ** End of interface to code in fts5_storage.c. **************************************************************************/ @@ -239015,6 +240199,7 @@ static int fts5HighlightCb( return rc; } + /* ** Implementation of highlight() function. */ @@ -239045,12 +240230,19 @@ static void fts5HighlightFunction( sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); rc = SQLITE_OK; }else if( ctx.zIn ){ + const char *pLoc = 0; /* Locale of column iCol */ + int nLoc = 0; /* Size of pLoc in bytes */ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } if( rc==SQLITE_OK ){ - rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc); + } + if( rc==SQLITE_OK ){ + rc = pApi->xTokenize_v2( + pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb + ); } if( ctx.bOpen ){ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); @@ -239247,6 +240439,8 @@ static void fts5SnippetFunction( memset(&sFinder, 0, sizeof(Fts5SFinder)); for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc); if( rc!=SQLITE_OK ) break; - rc = pApi->xTokenize(pFts, - sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb + rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc); + if( rc!=SQLITE_OK ) break; + rc = pApi->xTokenize_v2(pFts, + sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb ); if( rc!=SQLITE_OK ) break; rc = pApi->xColumnSize(pFts, i, &nDocsize); @@ -239313,6 +240509,9 @@ static void fts5SnippetFunction( rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); } if( ctx.zIn ){ + const char *pLoc = 0; /* Locale of column iBestCol */ + int nLoc = 0; /* Bytes in pLoc */ + if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); } @@ -239331,7 +240530,12 @@ static void fts5SnippetFunction( } if( rc==SQLITE_OK ){ - rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc); + } + if( rc==SQLITE_OK ){ + rc = pApi->xTokenize_v2( + pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb + ); } if( ctx.bOpen ){ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); @@ -239515,6 +240719,53 @@ static void fts5Bm25Function( } } +/* +** Implementation of fts5_get_locale() function. +*/ +static void fts5GetLocaleFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + int iCol = 0; + int eType = 0; + int rc = SQLITE_OK; + const char *zLocale = 0; + int nLocale = 0; + + /* xColumnLocale() must be available */ + assert( pApi->iVersion>=4 ); + + if( nVal!=1 ){ + const char *z = "wrong number of arguments to function fts5_get_locale()"; + sqlite3_result_error(pCtx, z, -1); + return; + } + + eType = sqlite3_value_numeric_type(apVal[0]); + if( eType!=SQLITE_INTEGER ){ + const char *z = "non-integer argument passed to function fts5_get_locale()"; + sqlite3_result_error(pCtx, z, -1); + return; + } + + iCol = sqlite3_value_int(apVal[0]); + if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){ + sqlite3_result_error_code(pCtx, SQLITE_RANGE); + return; + } + + rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale); + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + return; + } + + sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT); +} + static int sqlite3Fts5AuxInit(fts5_api *pApi){ struct Builtin { const char *zFunc; /* Function name (nul-terminated) */ @@ -239522,9 +240773,10 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ fts5_extension_function xFunc;/* Callback function */ void (*xDestroy)(void*); /* Destructor function */ } aBuiltin [] = { - { "snippet", 0, fts5SnippetFunction, 0 }, - { "highlight", 0, fts5HighlightFunction, 0 }, - { "bm25", 0, fts5Bm25Function, 0 }, + { "snippet", 0, fts5SnippetFunction, 0 }, + { "highlight", 0, fts5HighlightFunction, 0 }, + { "bm25", 0, fts5Bm25Function, 0 }, + { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 }, }; int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ @@ -240196,6 +241448,7 @@ static int fts5ConfigParseSpecial( ){ int rc = SQLITE_OK; int nCmd = (int)strlen(zCmd); + if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){ const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES; const char *p; @@ -240315,6 +241568,16 @@ static int fts5ConfigParseSpecial( return rc; } + if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){ + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ + *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive"); + rc = SQLITE_ERROR; + }else{ + pConfig->bContentlessUnindexed = (zArg[0]=='1'); + } + return rc; + } + if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){ if( pConfig->zContentRowid ){ *pzErr = sqlite3_mprintf("multiple content_rowid=... directives"); @@ -240335,6 +241598,16 @@ static int fts5ConfigParseSpecial( return rc; } + if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){ + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ + *pzErr = sqlite3_mprintf("malformed locale=... directive"); + rc = SQLITE_ERROR; + }else{ + pConfig->bLocale = (zArg[0]=='1'); + } + return rc; + } + if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ const Fts5Enum aDetail[] = { { "none", FTS5_DETAIL_NONE }, @@ -240422,7 +241695,8 @@ static int fts5ConfigParseColumn( Fts5Config *p, char *zCol, char *zArg, - char **pzErr + char **pzErr, + int *pbUnindexed ){ int rc = SQLITE_OK; if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) @@ -240433,6 +241707,7 @@ static int fts5ConfigParseColumn( }else if( zArg ){ if( 0==sqlite3_stricmp(zArg, "unindexed") ){ p->abUnindexed[p->nCol] = 1; + *pbUnindexed = 1; }else{ *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg); rc = SQLITE_ERROR; @@ -240453,11 +241728,26 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){ sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid); if( p->eContent!=FTS5_CONTENT_NONE ){ + assert( p->eContent==FTS5_CONTENT_EXTERNAL + || p->eContent==FTS5_CONTENT_NORMAL + || p->eContent==FTS5_CONTENT_UNINDEXED + ); for(i=0; inCol; i++){ if( p->eContent==FTS5_CONTENT_EXTERNAL ){ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]); - }else{ + }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i); + }else{ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL"); + } + } + } + if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){ + for(i=0; inCol; i++){ + if( p->abUnindexed[i]==0 ){ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i); + }else{ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL"); } } } @@ -240491,6 +241781,7 @@ static int sqlite3Fts5ConfigParse( Fts5Config *pRet; /* New object to return */ int i; sqlite3_int64 nByte; + int bUnindexed = 0; /* True if there are one or more UNINDEXED */ *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; @@ -240550,7 +241841,7 @@ static int sqlite3Fts5ConfigParse( pzErr ); }else{ - rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); + rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed); zOne = 0; } } @@ -240582,6 +241873,19 @@ static int sqlite3Fts5ConfigParse( rc = SQLITE_ERROR; } + /* We only allow contentless_unindexed=1 if the table is actually a + ** contentless one. + */ + if( rc==SQLITE_OK + && pRet->bContentlessUnindexed + && pRet->eContent!=FTS5_CONTENT_NONE + ){ + *pzErr = sqlite3_mprintf( + "contentless_unindexed=1 requires a contentless table" + ); + rc = SQLITE_ERROR; + } + /* If no zContent option was specified, fill in the default values. */ if( rc==SQLITE_OK && pRet->zContent==0 ){ const char *zTail = 0; @@ -240590,6 +241894,9 @@ static int sqlite3Fts5ConfigParse( ); if( pRet->eContent==FTS5_CONTENT_NORMAL ){ zTail = "content"; + }else if( bUnindexed && pRet->bContentlessUnindexed ){ + pRet->eContent = FTS5_CONTENT_UNINDEXED; + zTail = "content"; }else if( pRet->bColumnsize ){ zTail = "docsize"; } @@ -240624,7 +241931,11 @@ static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ if( pConfig ){ int i; if( pConfig->t.pTok ){ - pConfig->t.pTokApi->xDelete(pConfig->t.pTok); + if( pConfig->t.pApi1 ){ + pConfig->t.pApi1->xDelete(pConfig->t.pTok); + }else{ + pConfig->t.pApi2->xDelete(pConfig->t.pTok); + } } sqlite3_free((char*)pConfig->t.azArg); sqlite3_free(pConfig->zDb); @@ -240707,9 +242018,15 @@ static int sqlite3Fts5Tokenize( rc = sqlite3Fts5LoadTokenizer(pConfig); } if( rc==SQLITE_OK ){ - rc = pConfig->t.pTokApi->xTokenize( - pConfig->t.pTok, pCtx, flags, pText, nText, xToken - ); + if( pConfig->t.pApi1 ){ + rc = pConfig->t.pApi1->xTokenize( + pConfig->t.pTok, pCtx, flags, pText, nText, xToken + ); + }else{ + rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags, + pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken + ); + } } } return rc; @@ -240966,13 +242283,10 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){ rc = SQLITE_ERROR; - if( pConfig->pzErrmsg ){ - assert( 0==*pConfig->pzErrmsg ); - *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format " - "(found %d, expected %d or %d) - run 'rebuild'", - iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE - ); - } + sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format " + "(found %d, expected %d or %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE + ); }else{ pConfig->iVersion = iVersion; } @@ -240983,6 +242297,29 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ return rc; } +/* +** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer +** containing the error message created using printf() style formatting +** string zFmt and its trailing arguments. +*/ +static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ + va_list ap; /* ... printf arguments */ + char *zMsg = 0; + + va_start(ap, zFmt); + zMsg = sqlite3_vmprintf(zFmt, ap); + if( pConfig->pzErrmsg ){ + assert( *pConfig->pzErrmsg==0 ); + *pConfig->pzErrmsg = zMsg; + }else{ + sqlite3_free(zMsg); + } + + va_end(ap); +} + + + /* ** 2014 May 31 ** @@ -241039,7 +242376,7 @@ struct Fts5Expr { /* ** eType: -** Expression node type. Always one of: +** Expression node type. Usually one of: ** ** FTS5_AND (nChild, apChild valid) ** FTS5_OR (nChild, apChild valid) @@ -241047,6 +242384,10 @@ struct Fts5Expr { ** FTS5_STRING (pNear valid) ** FTS5_TERM (pNear valid) ** +** An expression node with eType==0 may also exist. It always matches zero +** rows. This is created when a phrase containing no tokens is parsed. +** e.g. "". +** ** iHeight: ** Distance from this node to furthest leaf. This is always 0 for nodes ** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one @@ -241267,11 +242608,12 @@ static int sqlite3Fts5ExprNew( }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); sqlite3Fts5ParserFree(pEngine, fts5ParseFree); + assert( sParse.pExpr || sParse.rc!=SQLITE_OK ); assert_expr_depth_ok(sParse.rc, sParse.pExpr); /* If the LHS of the MATCH expression was a user column, apply the ** implicit column-filter. */ - if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ + if( sParse.rc==SQLITE_OK && iColnCol ){ int n = sizeof(Fts5Colset); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); if( pColset ){ @@ -241288,15 +242630,7 @@ static int sqlite3Fts5ExprNew( sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); }else{ - if( !sParse.pExpr ){ - const int nByte = sizeof(Fts5ExprNode); - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); - if( pNew->pRoot ){ - pNew->pRoot->bEof = 1; - } - }else{ - pNew->pRoot = sParse.pExpr; - } + pNew->pRoot = sParse.pExpr; pNew->pIndex = 0; pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; @@ -242114,7 +243448,7 @@ static int fts5ExprNodeTest_STRING( } }else{ Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; - if( pIter->iRowid==iLast || pIter->bEof ) continue; + if( pIter->iRowid==iLast ) continue; bMatch = 0; if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ return rc; @@ -242636,9 +243970,6 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( Fts5ExprNearset *pRet = 0; if( pParse->rc==SQLITE_OK ){ - if( pPhrase==0 ){ - return pNear; - } if( pNear==0 ){ sqlite3_int64 nByte; nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); @@ -242860,6 +244191,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( }else if( sCtx.pPhrase->nTerm ){ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } + assert( pParse->apPhrase!=0 ); pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; } @@ -243247,6 +244579,9 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ } } +/* +** Add pSub as a child of p. +*/ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ int ii = p->nChild; if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ @@ -243391,19 +244726,23 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( "fts5: %s queries are not supported (detail!=full)", pNear->nPhrase==1 ? "phrase": "NEAR" ); - sqlite3_free(pRet); + sqlite3Fts5ParseNodeFree(pRet); pRet = 0; + pNear = 0; + assert( pLeft==0 && pRight==0 ); } } }else{ + assert( pNear==0 ); fts5ExprAddChildren(pRet, pLeft); fts5ExprAddChildren(pRet, pRight); + pLeft = pRight = 0; if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){ sqlite3Fts5ParseError(pParse, "fts5 expression tree is too large (maximum depth %d)", SQLITE_FTS5_MAX_EXPR_DEPTH ); - sqlite3_free(pRet); + sqlite3Fts5ParseNodeFree(pRet); pRet = 0; } } @@ -243441,6 +244780,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( assert( pRight->eType==FTS5_STRING || pRight->eType==FTS5_TERM || pRight->eType==FTS5_EOF + || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd) ); if( pLeft->eType==FTS5_AND ){ @@ -243454,6 +244794,8 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( ); if( pRight->eType==FTS5_EOF ){ + assert( pParse->apPhrase!=0 ); + assert( pParse->nPhrase>0 ); assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); sqlite3Fts5ParseNodeFree(pRight); pRet = pLeft; @@ -244086,6 +245428,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ pNode->iRowid = iRowid; pNode->bEof = 0; switch( pNode->eType ){ + case 0: case FTS5_TERM: case FTS5_STRING: return (pNode->pNear->apPhrase[0]->poslist.n>0); @@ -245669,11 +247012,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); - sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; + int szData = (sizeof(Fts5Data) + 7) & ~7; + sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING; pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; - aOut = pRet->p = (u8*)&pRet[1]; + aOut = pRet->p = (u8*)pRet + szData; }else{ rc = SQLITE_NOMEM; } @@ -245696,6 +247040,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ } assert( (pRet==0)==(p->rc!=SQLITE_OK) ); + assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) ); return pRet; } @@ -247021,7 +248366,7 @@ static void fts5SegIterNext_None( if( iOffiEndofDoclist ){ /* Next entry is on the current page */ - i64 iDelta; + u64 iDelta; iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); pIter->iLeafOffset = iOff; pIter->iRowid += iDelta; @@ -249725,6 +251070,11 @@ static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){ nBest = nPercent; } } + + /* If pLvl is already the input level to an ongoing merge, look no + ** further for a merge candidate. The caller should be allowed to + ** continue merging from pLvl first. */ + if( pLvl->nMerge ) break; } } return iRet; @@ -253649,7 +254999,7 @@ static int fts5structConnectMethod( /* ** We must have a single struct=? constraint that will be passed through -** into the xFilter method. If there is no valid stmt=? constraint, +** into the xFilter method. If there is no valid struct=? constraint, ** then return an SQLITE_CONSTRAINT error. */ static int fts5structBestIndexMethod( @@ -253991,8 +255341,17 @@ struct Fts5Global { Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */ Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */ Fts5Cursor *pCsr; /* First in list of all open cursors */ + u32 aLocaleHdr[4]; }; +/* +** Size of header on fts5_locale() values. And macro to access a buffer +** containing a copy of the header from an Fts5Config pointer. +*/ +#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr )) +#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr)) + + /* ** Each auxiliary function registered with the FTS5 module is represented ** by an object of the following type. All such objects are stored as part @@ -254011,11 +255370,28 @@ struct Fts5Auxiliary { ** Each tokenizer module registered with the FTS5 module is represented ** by an object of the following type. All such objects are stored as part ** of the Fts5Global.pTok list. +** +** bV2Native: +** True if the tokenizer was registered using xCreateTokenizer_v2(), false +** for xCreateTokenizer(). If this variable is true, then x2 is populated +** with the routines as supplied by the caller and x1 contains synthesized +** wrapper routines. In this case the user-data pointer passed to +** x1.xCreate should be a pointer to the Fts5TokenizerModule structure, +** not a copy of pUserData. +** +** Of course, if bV2Native is false, then x1 contains the real routines and +** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule +** object should be passed to x2.xCreate. +** +** The synthesized wrapper routines are necessary for xFindTokenizer(_v2) +** calls. */ struct Fts5TokenizerModule { char *zName; /* Name of tokenizer */ void *pUserData; /* User pointer passed to xCreate() */ - fts5_tokenizer x; /* Tokenizer functions */ + int bV2Native; /* True if v2 native tokenizer */ + fts5_tokenizer x1; /* Tokenizer functions */ + fts5_tokenizer_v2 x2; /* V2 tokenizer functions */ void (*xDestroy)(void*); /* Destructor function */ Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; @@ -254103,7 +255479,7 @@ struct Fts5Cursor { Fts5Auxiliary *pAux; /* Currently executing extension function */ Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ - /* Cache used by auxiliary functions xInst() and xInstCount() */ + /* Cache used by auxiliary API functions xInst() and xInstCount() */ Fts5PoslistReader *aInstIter; /* One for each phrase */ int nInstAlloc; /* Size of aInst[] array (entries / 3) */ int nInstCount; /* Number of phrase instances */ @@ -254214,10 +255590,16 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){ #endif /* -** Return true if pTab is a contentless table. +** Return true if pTab is a contentless table. If parameter bIncludeUnindexed +** is true, this includes contentless tables that store UNINDEXED columns +** only. */ -static int fts5IsContentless(Fts5FullTable *pTab){ - return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE; +static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){ + int eContent = pTab->p.pConfig->eContent; + return ( + eContent==FTS5_CONTENT_NONE + || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED) + ); } /* @@ -254312,8 +255694,7 @@ static int fts5InitVtab( /* Load the initial configuration */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); - sqlite3Fts5IndexRollback(pTab->p.pIndex); + rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1); } if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ @@ -254509,13 +255890,14 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ if( p->usable==0 || iCol<0 ){ /* As there exists an unusable MATCH constraint this is an ** unusable plan. Return SQLITE_CONSTRAINT. */ + idxStr[iIdxStr] = 0; return SQLITE_CONSTRAINT; }else{ if( iCol==nCol+1 ){ if( bSeenRank ) continue; idxStr[iIdxStr++] = 'r'; bSeenRank = 1; - }else if( iCol>=0 ){ + }else{ nSeenMatch++; idxStr[iIdxStr++] = 'M'; sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); @@ -254901,7 +256283,7 @@ static int fts5PrepareStatement( rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, &pRet, 0); if( rc!=SQLITE_OK ){ - *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); + sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db)); } sqlite3_free(zSql); } @@ -255125,6 +256507,145 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ return iDefault; } +/* +** Set the error message on the virtual table passed as the first argument. +*/ +static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + sqlite3_free(p->p.base.zErrMsg); + p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale +** specified by pLocale/nLocale. The buffer indicated by pLocale must remain +** valid until after the final call to sqlite3Fts5Tokenize() that will use +** the locale. +*/ +static void sqlite3Fts5SetLocale( + Fts5Config *pConfig, + const char *zLocale, + int nLocale +){ + Fts5TokenizerConfig *pT = &pConfig->t; + pT->pLocale = zLocale; + pT->nLocale = nLocale; +} + +/* +** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale(). +*/ +static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){ + sqlite3Fts5SetLocale(pConfig, 0, 0); +} + +/* +** Return true if the value passed as the only argument is an +** fts5_locale() value. +*/ +static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){ + int ret = 0; + if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ + /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case. + ** If the blob was created using zeroblob(), then sqlite3_value_blob() + ** may call malloc(). If this malloc() fails, then the values returned + ** by both value_blob() and value_bytes() will be 0. If value_bytes() were + ** called first, then the NULL pointer returned by value_blob() might + ** be dereferenced. */ + const u8 *pBlob = sqlite3_value_blob(pVal); + int nBlob = sqlite3_value_bytes(pVal); + if( nBlob>FTS5_LOCALE_HDR_SIZE + && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE) + ){ + ret = 1; + } + } + return ret; +} + +/* +** Value pVal is guaranteed to be an fts5_locale() value, according to +** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale +** from the value and returns them separately. +** +** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set +** to point to buffers containing the text and locale, as utf-8, +** respectively. In this case output parameters (*pnText) and (*pnLoc) are +** set to the sizes in bytes of these two buffers. +** +** Or, if an error occurs, then an SQLite error code is returned. The final +** value of the four output parameters is undefined in this case. +*/ +static int sqlite3Fts5DecodeLocaleValue( + sqlite3_value *pVal, + const char **ppText, + int *pnText, + const char **ppLoc, + int *pnLoc +){ + const char *p = sqlite3_value_blob(pVal); + int n = sqlite3_value_bytes(pVal); + int nLoc = 0; + + assert( sqlite3_value_type(pVal)==SQLITE_BLOB ); + assert( n>FTS5_LOCALE_HDR_SIZE ); + + for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){ + if( nLoc==(n-1) ){ + return SQLITE_MISMATCH; + } + } + *ppLoc = &p[FTS5_LOCALE_HDR_SIZE]; + *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE; + + *ppText = &p[nLoc+1]; + *pnText = n - nLoc - 1; + return SQLITE_OK; +} + +/* +** Argument pVal is the text of a full-text search expression. It may or +** may not have been wrapped by fts5_locale(). This function extracts +** the text of the expression, and sets output variable (*pzText) to +** point to a nul-terminated buffer containing the expression. +** +** If pVal was an fts5_locale() value, then sqlite3Fts5SetLocale() is called +** to set the tokenizer to use the specified locale. +** +** If output variable (*pbFreeAndReset) is set to true, then the caller +** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer +** locale, and (b) call sqlite3_free() to free (*pzText). +*/ +static int fts5ExtractExprText( + Fts5Config *pConfig, /* Fts5 configuration */ + sqlite3_value *pVal, /* Value to extract expression text from */ + char **pzText, /* OUT: nul-terminated buffer of text */ + int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */ +){ + int rc = SQLITE_OK; + + if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + const char *pText = 0; + int nText = 0; + const char *pLoc = 0; + int nLoc = 0; + rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); + *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText); + if( rc==SQLITE_OK ){ + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + } + *pbFreeAndReset = 1; + }else{ + *pzText = (char*)sqlite3_value_text(pVal); + *pbFreeAndReset = 0; + } + + return rc; +} + + /* ** This is the xFilter interface for the virtual table. See ** the virtual table xFilter method documentation for additional @@ -255159,13 +256680,7 @@ static int fts5FilterMethod( int iIdxStr = 0; Fts5Expr *pExpr = 0; - if( pConfig->bLock ){ - pTab->p.base.zErrMsg = sqlite3_mprintf( - "recursively defined fts5 content table" - ); - return SQLITE_ERROR; - } - + assert( pConfig->bLock==0 ); if( pCsr->ePlan ){ fts5FreeCursorComponents(pCsr); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); @@ -255189,8 +256704,14 @@ static int fts5FilterMethod( pRank = apVal[i]; break; case 'M': { - const char *zText = (const char*)sqlite3_value_text(apVal[i]); + char *zText = 0; + int bFreeAndReset = 0; + int bInternal = 0; + + rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset); + if( rc!=SQLITE_OK ) goto filter_out; if( zText==0 ) zText = ""; + iCol = 0; do{ iCol = iCol*10 + (idxStr[iIdxStr]-'0'); @@ -255202,7 +256723,7 @@ static int fts5FilterMethod( ** indicates that the MATCH expression is not a full text query, ** but a request for an internal parameter. */ rc = fts5SpecialMatch(pTab, pCsr, &zText[1]); - goto filter_out; + bInternal = 1; }else{ char **pzErr = &pTab->p.base.zErrMsg; rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); @@ -255210,9 +256731,15 @@ static int fts5FilterMethod( rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); pExpr = 0; } - if( rc!=SQLITE_OK ) goto filter_out; } + if( bFreeAndReset ){ + sqlite3_free(zText); + sqlite3Fts5ClearLocale(pConfig); + } + + if( bInternal || rc!=SQLITE_OK ) goto filter_out; + break; } case 'L': @@ -255300,9 +256827,7 @@ static int fts5FilterMethod( } } }else if( pConfig->zContent==0 ){ - *pConfig->pzErrmsg = sqlite3_mprintf( - "%s: table does not support scanning", pConfig->zName - ); + fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName); rc = SQLITE_ERROR; }else{ /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup @@ -255377,6 +256902,7 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ return SQLITE_OK; } + /* ** If the cursor requires seeking (bSeekRequired flag is set), seek it. ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. @@ -255413,8 +256939,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK ){ rc = FTS5_CORRUPT; + fts5SetVtabError((Fts5FullTable*)pTab, + "fts5: missing row %lld from content table %s", + fts5CursorRowid(pCsr), + pTab->pConfig->zContent + ); }else if( pTab->pConfig->pzErrmsg ){ - *pTab->pConfig->pzErrmsg = sqlite3_mprintf( + fts5SetVtabError((Fts5FullTable*)pTab, "%s", sqlite3_errmsg(pTab->pConfig->db) ); } @@ -255423,14 +256954,6 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ return rc; } -static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ - va_list ap; /* ... printf arguments */ - va_start(ap, zFormat); - assert( p->p.base.zErrMsg==0 ); - p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); - va_end(ap); -} - /* ** This function is called to handle an FTS INSERT command. In other words, ** an INSERT statement of the form: @@ -255468,7 +256991,7 @@ static int fts5SpecialInsert( } bLoadConfig = 1; }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ - if( pConfig->eContent==FTS5_CONTENT_NONE ){ + if( fts5IsContentless(pTab, 1) ){ fts5SetVtabError(pTab, "'rebuild' may not be used with a contentless fts5 table" ); @@ -255524,7 +257047,7 @@ static int fts5SpecialDelete( int eType1 = sqlite3_value_type(apVal[1]); if( eType1==SQLITE_INTEGER ){ sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0); } return rc; } @@ -255537,7 +257060,7 @@ static void fts5StorageInsert( ){ int rc = *pRc; if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid); @@ -255545,6 +257068,67 @@ static void fts5StorageInsert( *pRc = rc; } +/* +** +** This function is called when the user attempts an UPDATE on a contentless +** table. Parameter bRowidModified is true if the UPDATE statement modifies +** the rowid value. Parameter apVal[] contains the new values for each user +** defined column of the fts5 table. pConfig is the configuration object of the +** table being updated (guaranteed to be contentless). The contentless_delete=1 +** and contentless_unindexed=1 options may or may not be set. +** +** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite +** error code if it cannot. In this case an error message is also loaded into +** pConfig. Output parameter (*pbContent) is set to true if the caller should +** update the %_content table only - not the FTS index or any other shadow +** table. This occurs when an UPDATE modifies only UNINDEXED columns of the +** table. +** +** An UPDATE may proceed if: +** +** * The only columns modified are UNINDEXED columns, or +** +** * The contentless_delete=1 option was specified and all of the indexed +** columns (not a subset) have been modified. +*/ +static int fts5ContentlessUpdate( + Fts5Config *pConfig, + sqlite3_value **apVal, + int bRowidModified, + int *pbContent +){ + int ii; + int bSeenIndex = 0; /* Have seen modified indexed column */ + int bSeenIndexNC = 0; /* Have seen unmodified indexed column */ + int rc = SQLITE_OK; + + for(ii=0; iinCol; ii++){ + if( pConfig->abUnindexed[ii]==0 ){ + if( sqlite3_value_nochange(apVal[ii]) ){ + bSeenIndexNC++; + }else{ + bSeenIndex++; + } + } + } + + if( bSeenIndex==0 && bRowidModified==0 ){ + *pbContent = 1; + }else{ + if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){ + rc = SQLITE_ERROR; + sqlite3Fts5ConfigErrmsg(pConfig, + (pConfig->bContentlessDelete ? + "%s a subset of columns on fts5 contentless-delete table: %s" : + "%s contentless fts5 table: %s") + , "cannot UPDATE", pConfig->zName + ); + } + } + + return rc; +} + /* ** This function is the implementation of the xUpdate callback used by ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be @@ -255631,41 +257215,46 @@ static int fts5UpdateMethod( assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); assert( nArg!=1 || eType0==SQLITE_INTEGER ); - /* Filter out attempts to run UPDATE or DELETE on contentless tables. - ** This is not suported. Except - they are both supported if the CREATE - ** VIRTUAL TABLE statement contained "contentless_delete=1". */ - if( eType0==SQLITE_INTEGER - && pConfig->eContent==FTS5_CONTENT_NONE - && pConfig->bContentlessDelete==0 - ){ - pTab->p.base.zErrMsg = sqlite3_mprintf( - "cannot %s contentless fts5 table: %s", - (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName - ); - rc = SQLITE_ERROR; - } - /* DELETE */ - else if( nArg==1 ){ - i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); - bUpdateOrDelete = 1; + if( nArg==1 ){ + /* It is only possible to DELETE from a contentless table if the + ** contentless_delete=1 flag is set. */ + if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){ + fts5SetVtabError(pTab, + "cannot DELETE from contentless fts5 table: %s", pConfig->zName + ); + rc = SQLITE_ERROR; + }else{ + i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); + bUpdateOrDelete = 1; + } } /* INSERT or UPDATE */ else{ int eType1 = sqlite3_value_numeric_type(apVal[1]); - if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ - rc = SQLITE_MISMATCH; + /* It is an error to write an fts5_locale() value to a table without + ** the locale=1 option. */ + if( pConfig->bLocale==0 ){ + int ii; + for(ii=0; iinCol; ii++){ + sqlite3_value *pVal = apVal[ii+2]; + if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + fts5SetVtabError(pTab, "fts5_locale() requires locale=1"); + rc = SQLITE_MISMATCH; + goto update_out; + } + } } - else if( eType0!=SQLITE_INTEGER ){ + if( eType0!=SQLITE_INTEGER ){ /* An INSERT statement. If the conflict-mode is REPLACE, first remove ** the current entry (if any). */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); bUpdateOrDelete = 1; } fts5StorageInsert(&rc, pTab, apVal, pRowid); @@ -255673,30 +257262,57 @@ static int fts5UpdateMethod( /* UPDATE */ else{ + Fts5Storage *pStorage = pTab->pStorage; i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ - if( eType1==SQLITE_INTEGER && iOld!=iNew ){ + int bContent = 0; /* Content only update */ + + /* If this is a contentless table (including contentless_unindexed=1 + ** tables), check if the UPDATE may proceed. */ + if( fts5IsContentless(pTab, 1) ){ + rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent); + if( rc!=SQLITE_OK ) goto update_out; + } + + if( eType1!=SQLITE_INTEGER ){ + rc = SQLITE_MISMATCH; + }else if( iOld!=iNew ){ + assert( bContent==0 ); if( eConflict==SQLITE_REPLACE ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); }else{ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); + rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid); } if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); + rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0); } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid); + } + } + }else if( bContent ){ + /* This occurs when an UPDATE on a contentless table affects *only* + ** UNINDEXED columns. This is a no-op for contentless_unindexed=0 + ** tables, or a write to the %_content table only for =1 tables. */ + assert( fts5IsContentless(pTab, 1) ); + rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid); } }else{ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1); fts5StorageInsert(&rc, pTab, apVal, pRowid); } bUpdateOrDelete = 1; + sqlite3Fts5StorageReleaseDeleteRow(pStorage); } + } } @@ -255713,6 +257329,7 @@ static int fts5UpdateMethod( } } + update_out: sqlite3Fts5IndexCloseReader(pTab->p.pIndex); pTab->p.pConfig->pzErrmsg = 0; return rc; @@ -255735,9 +257352,11 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ ** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ - fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); - fts5NewTransaction((Fts5FullTable*)pVtab); - return SQLITE_OK; + int rc = fts5NewTransaction((Fts5FullTable*)pVtab); + if( rc==SQLITE_OK ){ + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); + } + return rc; } /* @@ -255791,17 +257410,40 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); } -static int fts5ApiTokenize( +/* +** Implementation of xTokenize_v2() API. +*/ +static int fts5ApiTokenize_v2( Fts5Context *pCtx, const char *pText, int nText, + const char *pLoc, int nLoc, void *pUserData, int (*xToken)(void*, int, const char*, int, int, int) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - return sqlite3Fts5Tokenize( - pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken + int rc = SQLITE_OK; + + sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc); + rc = sqlite3Fts5Tokenize(pTab->pConfig, + FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken ); + sqlite3Fts5SetLocale(pTab->pConfig, 0, 0); + + return rc; +} + +/* +** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0 +** passed as the locale. +*/ +static int fts5ApiTokenize( + Fts5Context *pCtx, + const char *pText, int nText, + void *pUserData, + int (*xToken)(void*, int, const char*, int, int, int) +){ + return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken); } static int fts5ApiPhraseCount(Fts5Context *pCtx){ @@ -255814,6 +257456,49 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); } +/* +** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This +** function extracts the text value of column iCol of the current row. +** Additionally, if there is an associated locale, it invokes +** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller +** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point +** after this function returns. +** +** If successful, (*ppText) is set to point to a buffer containing the text +** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that +** buffer in bytes. It is not guaranteed to be nul-terminated. If an error +** occurs, an SQLite error code is returned. The final values of the two +** output parameters are undefined in this case. +*/ +static int fts5TextFromStmt( + Fts5Config *pConfig, + sqlite3_stmt *pStmt, + int iCol, + const char **ppText, + int *pnText +){ + sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1); + const char *pLoc = 0; + int nLoc = 0; + int rc = SQLITE_OK; + + if( pConfig->bLocale + && pConfig->eContent==FTS5_CONTENT_EXTERNAL + && sqlite3Fts5IsLocaleValue(pConfig, pVal) + ){ + rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc); + }else{ + *ppText = (const char*)sqlite3_value_text(pVal); + *pnText = sqlite3_value_bytes(pVal); + if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol); + nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol); + } + } + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + return rc; +} + static int fts5ApiColumnText( Fts5Context *pCtx, int iCol, @@ -255823,28 +257508,35 @@ static int fts5ApiColumnText( int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); if( iCol<0 || iCol>=pTab->pConfig->nCol ){ rc = SQLITE_RANGE; - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) - || pCsr->ePlan==FTS5_PLAN_SPECIAL - ){ + }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){ *pz = 0; *pn = 0; }else{ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ - *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); - *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn); + sqlite3Fts5ClearLocale(pTab->pConfig); } } return rc; } +/* +** This is called by various API functions - xInst, xPhraseFirst, +** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase +** of the current row. This function works for both detail=full tables (in +** which case the position-list was read from the fts index) or for other +** detail= modes if the row content is available. +*/ static int fts5CsrPoslist( - Fts5Cursor *pCsr, - int iPhrase, - const u8 **pa, - int *pn + Fts5Cursor *pCsr, /* Fts5 cursor object */ + int iPhrase, /* Phrase to find position list for */ + const u8 **pa, /* OUT: Pointer to position list buffer */ + int *pn /* OUT: Size of (*pa) in bytes */ ){ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; int rc = SQLITE_OK; @@ -255852,20 +257544,32 @@ static int fts5CsrPoslist( if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ rc = SQLITE_RANGE; + }else if( pConfig->eDetail!=FTS5_DETAIL_FULL + && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1) + ){ + *pa = 0; + *pn = 0; + return SQLITE_OK; }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ Fts5PoslistPopulator *aPopulator; int i; + aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); if( aPopulator==0 ) rc = SQLITE_NOMEM; + if( rc==SQLITE_OK ){ + rc = fts5SeekCursor(pCsr, 0); + } for(i=0; inCol && rc==SQLITE_OK; i++){ - int n; const char *z; - rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); + const char *z = 0; + int n = 0; + rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprPopulatePoslists( pConfig, pCsr->pExpr, aPopulator, i, z, n ); } + sqlite3Fts5ClearLocale(pConfig); } sqlite3_free(aPopulator); @@ -255890,7 +257594,6 @@ static int fts5CsrPoslist( *pn = 0; } - return rc; } @@ -255959,7 +257662,8 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); - if( aInst[1]<0 || aInst[1]>=nCol ){ + assert( aInst[1]>=0 ); + if( aInst[1]>=nCol ){ rc = FTS5_CORRUPT; break; } @@ -256037,7 +257741,7 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ if( pConfig->bColumnsize ){ i64 iRowid = fts5CursorRowid(pCsr); rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize); - }else if( pConfig->zContent==0 ){ + }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ int i; for(i=0; inCol; i++){ if( pConfig->abUnindexed[i]==0 ){ @@ -256046,17 +257750,19 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ } }else{ int i; + rc = fts5SeekCursor(pCsr, 0); for(i=0; rc==SQLITE_OK && inCol; i++){ if( pConfig->abUnindexed[i]==0 ){ - const char *z; int n; - void *p = (void*)(&pCsr->aColumnSize[i]); + const char *z = 0; + int n = 0; pCsr->aColumnSize[i] = 0; - rc = fts5ApiColumnText(pCtx, i, &z, &n); + rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5Tokenize( - pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX, + z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb ); } + sqlite3Fts5ClearLocale(pConfig); } } } @@ -256136,11 +257842,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ } static void fts5ApiPhraseNext( - Fts5Context *pUnused, + Fts5Context *pCtx, Fts5PhraseIter *pIter, int *piCol, int *piOff ){ - UNUSED_PARAM(pUnused); if( pIter->a>=pIter->b ){ *piCol = -1; *piOff = -1; @@ -256148,8 +257853,12 @@ static void fts5ApiPhraseNext( int iVal; pIter->a += fts5GetVarint32(pIter->a, iVal); if( iVal==1 ){ + /* Avoid returning a (*piCol) value that is too large for the table, + ** even if the position-list is corrupt. The caller might not be + ** expecting it. */ + int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol; pIter->a += fts5GetVarint32(pIter->a, iVal); - *piCol = iVal; + *piCol = (iVal>=nCol ? nCol-1 : iVal); *piOff = 0; pIter->a += fts5GetVarint32(pIter->a, iVal); } @@ -256299,8 +258008,48 @@ static int fts5ApiQueryPhrase(Fts5Context*, int, void*, int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) ); +/* +** The xColumnLocale() API. +*/ +static int fts5ApiColumnLocale( + Fts5Context *pCtx, + int iCol, + const char **pzLocale, + int *pnLocale +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + *pzLocale = 0; + *pnLocale = 0; + + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); + if( iCol<0 || iCol>=pConfig->nCol ){ + rc = SQLITE_RANGE; + }else if( + pConfig->abUnindexed[iCol]==0 + && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1) + && pConfig->bLocale + ){ + rc = fts5SeekCursor(pCsr, 0); + if( rc==SQLITE_OK ){ + const char *zDummy = 0; + int nDummy = 0; + rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy); + if( rc==SQLITE_OK ){ + *pzLocale = pConfig->t.pLocale; + *pnLocale = pConfig->t.nLocale; + } + sqlite3Fts5ClearLocale(pConfig); + } + } + + return rc; +} + static const Fts5ExtensionApi sFts5Api = { - 3, /* iVersion */ + 4, /* iVersion */ fts5ApiUserData, fts5ApiColumnCount, fts5ApiRowCount, @@ -256321,7 +258070,9 @@ static const Fts5ExtensionApi sFts5Api = { fts5ApiPhraseFirstColumn, fts5ApiPhraseNextColumn, fts5ApiQueryToken, - fts5ApiInstToken + fts5ApiInstToken, + fts5ApiColumnLocale, + fts5ApiTokenize_v2 }; /* @@ -256372,6 +258123,7 @@ static void fts5ApiInvoke( sqlite3_value **argv ){ assert( pCsr->pAux==0 ); + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); pCsr->pAux = pAux; pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv); pCsr->pAux = 0; @@ -256385,6 +258137,21 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){ return pCsr; } +/* +** Parameter zFmt is a printf() style formatting string. This function +** formats it using the trailing arguments and returns the result as +** an error message to the context passed as the first argument. +*/ +static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){ + char *zErr = 0; + va_list ap; + va_start(ap, zFmt); + zErr = sqlite3_vmprintf(zFmt, ap); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + va_end(ap); +} + static void fts5ApiCallback( sqlite3_context *context, int argc, @@ -256400,12 +258167,13 @@ static void fts5ApiCallback( iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); - if( pCsr==0 || pCsr->ePlan==0 ){ - char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); + if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){ + fts5ResultError(context, "no such cursor: %lld", iCsrId); }else{ + sqlite3_vtab *pTab = pCsr->base.pVtab; fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); + sqlite3_free(pTab->zErrMsg); + pTab->zErrMsg = 0; } } @@ -256523,8 +258291,8 @@ static int fts5ColumnMethod( ** auxiliary function. */ sqlite3_result_int64(pCtx, pCsr->iCsrId); }else if( iCol==pConfig->nCol+1 ){ - /* The value of the "rank" column. */ + if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ fts5PoslistBlob(pCtx, pCsr); }else if( @@ -256535,20 +258303,32 @@ static int fts5ColumnMethod( fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } - }else if( !fts5IsContentless(pTab) ){ - pConfig->pzErrmsg = &pTab->p.base.zErrMsg; - rc = fts5SeekCursor(pCsr, 1); - if( rc==SQLITE_OK ){ - sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); + }else{ + if( !sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){ + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; + rc = fts5SeekCursor(pCsr, 1); + if( rc==SQLITE_OK ){ + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); + if( pConfig->bLocale + && pConfig->eContent==FTS5_CONTENT_EXTERNAL + && sqlite3Fts5IsLocaleValue(pConfig, pVal) + ){ + const char *z = 0; + int n = 0; + rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n); + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT); + } + sqlite3Fts5ClearLocale(pConfig); + }else{ + sqlite3_result_value(pCtx, pVal); + } + } + + pConfig->pzErrmsg = 0; } - pConfig->pzErrmsg = 0; - }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){ - char *zErr = sqlite3_mprintf("cannot UPDATE a subset of " - "columns on fts5 contentless-delete table: %s", pConfig->zName - ); - sqlite3_result_error(pCtx, zErr, -1); - sqlite3_free(zErr); } + return rc; } @@ -256688,47 +258468,210 @@ static int fts5CreateAux( } /* -** Register a new tokenizer. This is the implementation of the -** fts5_api.xCreateTokenizer() method. +** This function is used by xCreateTokenizer_v2() and xCreateTokenizer(). +** It allocates and partially populates a new Fts5TokenizerModule object. +** The new object is already linked into the Fts5Global context before +** returning. +** +** If successful, SQLITE_OK is returned and a pointer to the new +** Fts5TokenizerModule object returned via output parameter (*ppNew). All +** that is required is for the caller to fill in the methods in +** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native +** as appropriate. +** +** If an error occurs, an SQLite error code is returned and the final value +** of (*ppNew) undefined. */ -static int fts5CreateTokenizer( - fts5_api *pApi, /* Global context (one per db handle) */ +static int fts5NewTokenizerModule( + Fts5Global *pGlobal, /* Global context (one per db handle) */ const char *zName, /* Name of new function */ void *pUserData, /* User data for aux. function */ - fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ - void(*xDestroy)(void*) /* Destructor for pUserData */ + void(*xDestroy)(void*), /* Destructor for pUserData */ + Fts5TokenizerModule **ppNew ){ - Fts5Global *pGlobal = (Fts5Global*)pApi; - Fts5TokenizerModule *pNew; - sqlite3_int64 nName; /* Size of zName and its \0 terminator */ - sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc = SQLITE_OK; + Fts5TokenizerModule *pNew; + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; - pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); + *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte); if( pNew ){ - memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; - pNew->x = *pTokenizer; pNew->xDestroy = xDestroy; pNew->pNext = pGlobal->pTok; pGlobal->pTok = pNew; if( pNew->pNext==0 ){ pGlobal->pDfltTok = pNew; } + } + + return rc; +} + +/* +** An instance of this type is used as the Fts5Tokenizer object for +** wrapper tokenizers - those that provide access to a v1 tokenizer via +** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer +** via the fts5_tokenizer API. +*/ +typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer; +struct Fts5VtoVTokenizer { + int bV2Native; /* True if v2 native tokenizer */ + fts5_tokenizer x1; /* Tokenizer functions */ + fts5_tokenizer_v2 x2; /* V2 tokenizer functions */ + Fts5Tokenizer *pReal; +}; + +/* +** Create a wrapper tokenizer. The context argument pCtx points to the +** Fts5TokenizerModule object. +*/ +static int fts5VtoVCreate( + void *pCtx, + const char **azArg, + int nArg, + Fts5Tokenizer **ppOut +){ + Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx; + Fts5VtoVTokenizer *pNew = 0; + int rc = SQLITE_OK; + + pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew)); + if( rc==SQLITE_OK ){ + pNew->x1 = pMod->x1; + pNew->x2 = pMod->x2; + pNew->bV2Native = pMod->bV2Native; + if( pMod->bV2Native ){ + rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); + }else{ + rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); + } + if( rc!=SQLITE_OK ){ + sqlite3_free(pNew); + pNew = 0; + } + } + + *ppOut = (Fts5Tokenizer*)pNew; + return rc; +} + +/* +** Delete an Fts5VtoVTokenizer wrapper tokenizer. +*/ +static void fts5VtoVDelete(Fts5Tokenizer *pTok){ + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; + if( p ){ + if( p->bV2Native ){ + p->x2.xDelete(p->pReal); + }else{ + p->x1.xDelete(p->pReal); + } + sqlite3_free(p); + } +} + + +/* +** xTokenizer method for a wrapper tokenizer that offers the v1 interface +** (no support for locales). +*/ +static int fts5V1toV2Tokenize( + Fts5Tokenizer *pTok, + void *pCtx, int flags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int, int, int) +){ + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; + assert( p->bV2Native ); + return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken); +} + +/* +** xTokenizer method for a wrapper tokenizer that offers the v2 interface +** (with locale support). +*/ +static int fts5V2toV1Tokenize( + Fts5Tokenizer *pTok, + void *pCtx, int flags, + const char *pText, int nText, + const char *pLocale, int nLocale, + int (*xToken)(void*, int, const char*, int, int, int) +){ + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; + assert( p->bV2Native==0 ); + UNUSED_PARAM2(pLocale,nLocale); + return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken); +} + +/* +** Register a new tokenizer. This is the implementation of the +** fts5_api.xCreateTokenizer_v2() method. +*/ +static int fts5CreateTokenizer_v2( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5Global *pGlobal = (Fts5Global*)pApi; + int rc = SQLITE_OK; + + if( pTokenizer->iVersion>2 ){ + rc = SQLITE_ERROR; }else{ - rc = SQLITE_NOMEM; + Fts5TokenizerModule *pNew = 0; + rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew); + if( pNew ){ + pNew->x2 = *pTokenizer; + pNew->bV2Native = 1; + pNew->x1.xCreate = fts5VtoVCreate; + pNew->x1.xTokenize = fts5V1toV2Tokenize; + pNew->x1.xDelete = fts5VtoVDelete; + } } return rc; } +/* +** The fts5_api.xCreateTokenizer() method. +*/ +static int fts5CreateTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5TokenizerModule *pNew = 0; + int rc = SQLITE_OK; + + rc = fts5NewTokenizerModule( + (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew + ); + if( pNew ){ + pNew->x1 = *pTokenizer; + pNew->x2.xCreate = fts5VtoVCreate; + pNew->x2.xTokenize = fts5V2toV1Tokenize; + pNew->x2.xDelete = fts5VtoVDelete; + } + return rc; +} + +/* +** Search the global context passed as the first argument for a tokenizer +** module named zName. If found, return a pointer to the Fts5TokenizerModule +** object. Otherwise, return NULL. +*/ static Fts5TokenizerModule *fts5LocateTokenizer( - Fts5Global *pGlobal, - const char *zName + Fts5Global *pGlobal, /* Global (one per db handle) object */ + const char *zName /* Name of tokenizer module to find */ ){ Fts5TokenizerModule *pMod = 0; @@ -256743,6 +258686,36 @@ static Fts5TokenizerModule *fts5LocateTokenizer( return pMod; } +/* +** Find a tokenizer. This is the implementation of the +** fts5_api.xFindTokenizer_v2() method. +*/ +static int fts5FindTokenizer_v2( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of tokenizer */ + void **ppUserData, + fts5_tokenizer_v2 **ppTokenizer /* Populate this object */ +){ + int rc = SQLITE_OK; + Fts5TokenizerModule *pMod; + + pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); + if( pMod ){ + if( pMod->bV2Native ){ + *ppUserData = pMod->pUserData; + }else{ + *ppUserData = (void*)pMod; + } + *ppTokenizer = &pMod->x2; + }else{ + *ppTokenizer = 0; + *ppUserData = 0; + rc = SQLITE_ERROR; + } + + return rc; +} + /* ** Find a tokenizer. This is the implementation of the ** fts5_api.xFindTokenizer() method. @@ -256758,66 +258731,75 @@ static int fts5FindTokenizer( pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); if( pMod ){ - *pTokenizer = pMod->x; - *ppUserData = pMod->pUserData; + if( pMod->bV2Native==0 ){ + *ppUserData = pMod->pUserData; + }else{ + *ppUserData = (void*)pMod; + } + *pTokenizer = pMod->x1; }else{ - memset(pTokenizer, 0, sizeof(fts5_tokenizer)); + memset(pTokenizer, 0, sizeof(*pTokenizer)); + *ppUserData = 0; rc = SQLITE_ERROR; } return rc; } -int fts5GetTokenizer( - Fts5Global *pGlobal, - const char **azArg, - int nArg, - Fts5Config *pConfig, - char **pzErr -){ - Fts5TokenizerModule *pMod; +/* +** Attempt to instantiate the tokenizer. +*/ +static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){ + const char **azArg = pConfig->t.azArg; + const int nArg = pConfig->t.nArg; + Fts5TokenizerModule *pMod = 0; int rc = SQLITE_OK; - pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); + pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]); if( pMod==0 ){ assert( nArg>0 ); rc = SQLITE_ERROR; - if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); + sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]); }else{ - rc = pMod->x.xCreate( - pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0; + if( pMod->bV2Native ){ + xCreate = pMod->x2.xCreate; + pConfig->t.pApi2 = &pMod->x2; + }else{ + pConfig->t.pApi1 = &pMod->x1; + xCreate = pMod->x1.xCreate; + } + + rc = xCreate(pMod->pUserData, + (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok ); - pConfig->t.pTokApi = &pMod->x; + if( rc!=SQLITE_OK ){ - if( pzErr && rc!=SQLITE_NOMEM ){ - *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + if( rc!=SQLITE_NOMEM ){ + sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor"); } - }else{ + }else if( pMod->bV2Native==0 ){ pConfig->t.ePattern = sqlite3Fts5TokenizerPattern( - pMod->x.xCreate, pConfig->t.pTok + pMod->x1.xCreate, pConfig->t.pTok ); } } if( rc!=SQLITE_OK ){ - pConfig->t.pTokApi = 0; + pConfig->t.pApi1 = 0; + pConfig->t.pApi2 = 0; pConfig->t.pTok = 0; } return rc; } + /* -** Attempt to instantiate the tokenizer. +** xDestroy callback passed to sqlite3_create_module(). This is invoked +** when the db handle is being closed. Free memory associated with +** tokenizers and aux functions registered with this db handle. */ -static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){ - return fts5GetTokenizer( - pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg, - pConfig, pConfig->pzErrmsg - ); -} - - static void fts5ModuleDestroy(void *pCtx){ Fts5TokenizerModule *pTok, *pNextTok; Fts5Auxiliary *pAux, *pNextAux; @@ -256838,6 +258820,10 @@ static void fts5ModuleDestroy(void *pCtx){ sqlite3_free(pGlobal); } +/* +** Implementation of the fts5() function used by clients to obtain the +** API pointer. +*/ static void fts5Fts5Func( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ @@ -256861,7 +258847,68 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc", -1, SQLITE_TRANSIENT); +} + +/* +** Implementation of fts5_locale(LOCALE, TEXT) function. +** +** If parameter LOCALE is NULL, or a zero-length string, then a copy of +** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as +** text, and the value returned is a blob consisting of: +** +** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER). +** * The LOCALE, as utf-8 text, followed by +** * 0x00, followed by +** * The TEXT, as utf-8 text. +** +** There is no final nul-terminator following the TEXT value. +*/ +static void fts5LocaleFunc( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apArg /* Function arguments */ +){ + const char *zLocale = 0; + int nLocale = 0; + const char *zText = 0; + int nText = 0; + + assert( nArg==2 ); + UNUSED_PARAM(nArg); + + zLocale = (const char*)sqlite3_value_text(apArg[0]); + nLocale = sqlite3_value_bytes(apArg[0]); + + zText = (const char*)sqlite3_value_text(apArg[1]); + nText = sqlite3_value_bytes(apArg[1]); + + if( zLocale==0 || zLocale[0]=='\0' ){ + sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT); + }else{ + Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx); + u8 *pBlob = 0; + u8 *pCsr = 0; + int nBlob = 0; + + nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText; + pBlob = (u8*)sqlite3_malloc(nBlob); + if( pBlob==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + + pCsr = pBlob; + memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE); + pCsr += FTS5_LOCALE_HDR_SIZE; + memcpy(pCsr, zLocale, nLocale); + pCsr += nLocale; + (*pCsr++) = 0x00; + if( zText ) memcpy(pCsr, zText, nText); + assert( &pCsr[nText]==&pBlob[nBlob] ); + + sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free); + } } /* @@ -256956,10 +259003,22 @@ static int fts5Init(sqlite3 *db){ void *p = (void*)pGlobal; memset(pGlobal, 0, sizeof(Fts5Global)); pGlobal->db = db; - pGlobal->api.iVersion = 2; + pGlobal->api.iVersion = 3; pGlobal->api.xCreateFunction = fts5CreateAux; pGlobal->api.xCreateTokenizer = fts5CreateTokenizer; pGlobal->api.xFindTokenizer = fts5FindTokenizer; + pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2; + pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2; + + /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector. + ** The constants below were generated randomly. */ + sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr); + pGlobal->aLocaleHdr[0] ^= 0xF924976D; + pGlobal->aLocaleHdr[1] ^= 0x16596E13; + pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA; + pGlobal->aLocaleHdr[3] ^= 0x9B03A67F; + assert( sizeof(pGlobal->aLocaleHdr)==16 ); + rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); @@ -256978,6 +259037,13 @@ static int fts5Init(sqlite3 *db){ p, fts5SourceIdFunc, 0, 0 ); } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5_locale", 2, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE, + p, fts5LocaleFunc, 0, 0 + ); + } } /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file @@ -257052,13 +259118,40 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){ /* #include "fts5Int.h" */ +/* +** pSavedRow: +** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it +** does a by-rowid lookup to retrieve a single row from the %_content +** table or equivalent external-content table/view. +** +** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original +** values for a row being UPDATEd. In that case, the SQL statement is +** not reset and pSavedRow is set to point at it. This is so that the +** insert operation that follows the delete may access the original +** row values for any new values for which sqlite3_value_nochange() returns +** true. i.e. if the user executes: +** +** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1); +** ... +** UPDATE fts SET a=?, b=? WHERE rowid=?; +** +** then the value passed to the xUpdate() method of this table as the +** new.c value is an sqlite3_value_nochange() value. So in this case it +** must be read from the saved row stored in Fts5Storage.pSavedRow. +** +** This is necessary - using sqlite3_value_nochange() instead of just having +** SQLite pass the original value back via xUpdate() - so as not to discard +** any locale information associated with such values. +** +*/ struct Fts5Storage { Fts5Config *pConfig; Fts5Index *pIndex; int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */ i64 nTotalRow; /* Total number of rows in FTS table */ i64 *aTotalSize; /* Total sizes of each column */ - sqlite3_stmt *aStmt[11]; + sqlite3_stmt *pSavedRow; + sqlite3_stmt *aStmt[12]; }; @@ -257072,14 +259165,15 @@ struct Fts5Storage { # error "FTS5_STMT_LOOKUP mismatch" #endif -#define FTS5_STMT_INSERT_CONTENT 3 -#define FTS5_STMT_REPLACE_CONTENT 4 -#define FTS5_STMT_DELETE_CONTENT 5 -#define FTS5_STMT_REPLACE_DOCSIZE 6 -#define FTS5_STMT_DELETE_DOCSIZE 7 -#define FTS5_STMT_LOOKUP_DOCSIZE 8 -#define FTS5_STMT_REPLACE_CONFIG 9 -#define FTS5_STMT_SCAN 10 +#define FTS5_STMT_LOOKUP2 3 +#define FTS5_STMT_INSERT_CONTENT 4 +#define FTS5_STMT_REPLACE_CONTENT 5 +#define FTS5_STMT_DELETE_CONTENT 6 +#define FTS5_STMT_REPLACE_DOCSIZE 7 +#define FTS5_STMT_DELETE_DOCSIZE 8 +#define FTS5_STMT_LOOKUP_DOCSIZE 9 +#define FTS5_STMT_REPLACE_CONFIG 10 +#define FTS5_STMT_SCAN 11 /* ** Prepare the two insert statements - Fts5Storage.pInsertContent and @@ -257109,6 +259203,7 @@ static int fts5StorageGetStmt( "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC", "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC", "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */ + "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */ "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */ @@ -257124,6 +259219,8 @@ static int fts5StorageGetStmt( Fts5Config *pC = p->pConfig; char *zSql = 0; + assert( ArraySize(azStmt)==ArraySize(p->aStmt) ); + switch( eStmt ){ case FTS5_STMT_SCAN: zSql = sqlite3_mprintf(azStmt[eStmt], @@ -257140,6 +259237,7 @@ static int fts5StorageGetStmt( break; case FTS5_STMT_LOOKUP: + case FTS5_STMT_LOOKUP2: zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, pC->zContent, pC->zContentRowid ); @@ -257147,20 +259245,35 @@ static int fts5StorageGetStmt( case FTS5_STMT_INSERT_CONTENT: case FTS5_STMT_REPLACE_CONTENT: { - int nCol = pC->nCol + 1; - char *zBind; + char *zBind = 0; int i; - zBind = sqlite3_malloc64(1 + nCol*2); - if( zBind ){ - for(i=0; ieContent==FTS5_CONTENT_NORMAL + || pC->eContent==FTS5_CONTENT_UNINDEXED + ); + + /* Add bindings for the "c*" columns - those that store the actual + ** table content. If eContent==NORMAL, then there is one binding + ** for each column. Or, if eContent==UNINDEXED, then there are only + ** bindings for the UNINDEXED columns. */ + for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){ + if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){ + zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1); + } + } + + /* Add bindings for any "l*" columns. Only non-UNINDEXED columns + ** require these. */ + if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){ + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pC->abUnindexed[i]==0 ){ + zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2); + } } - zBind[i*2-1] = '\0'; - zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind); - sqlite3_free(zBind); } + + zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind); + sqlite3_free(zBind); break; } @@ -257186,7 +259299,7 @@ static int fts5StorageGetStmt( rc = SQLITE_NOMEM; }else{ int f = SQLITE_PREPARE_PERSISTENT; - if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; + if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB; p->pConfig->bLock++; rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); p->pConfig->bLock--; @@ -257346,9 +259459,11 @@ static int sqlite3Fts5StorageOpen( p->pIndex = pIndex; if( bCreate ){ - if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL + || pConfig->eContent==FTS5_CONTENT_UNINDEXED + ){ int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10); + char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20); if( zDefn==0 ){ rc = SQLITE_NOMEM; }else{ @@ -257357,8 +259472,20 @@ static int sqlite3Fts5StorageOpen( sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); iOff = (int)strlen(zDefn); for(i=0; inCol; i++){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); - iOff += (int)strlen(&zDefn[iOff]); + if( pConfig->eContent==FTS5_CONTENT_NORMAL + || pConfig->abUnindexed[i] + ){ + sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); + iOff += (int)strlen(&zDefn[iOff]); + } + } + if( pConfig->bLocale ){ + for(i=0; inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i); + iOff += (int)strlen(&zDefn[iOff]); + } + } } rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); } @@ -257435,15 +259562,49 @@ static int fts5StorageInsertCallback( return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); } +/* +** This function is used as part of an UPDATE statement that modifies the +** rowid of a row. In that case, this function is called first to set +** Fts5Storage.pSavedRow to point to a statement that may be used to +** access the original values of the row being deleted - iDel. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** It is not considered an error if row iDel does not exist. In this case +** pSavedRow is not set and SQLITE_OK returned. +*/ +static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){ + int rc = SQLITE_OK; + sqlite3_stmt *pSeek = 0; + + assert( p->pSavedRow==0 ); + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pSeek, 1, iDel); + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + rc = sqlite3_reset(pSeek); + }else{ + p->pSavedRow = pSeek; + } + } + + return rc; +} + /* ** If a row with rowid iDel is present in the %_content table, add the ** delete-markers to the FTS index necessary to delete it. Do not actually ** remove the %_content row at this time though. +** +** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left +** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access +** the original values of the row being deleted. This is used by UPDATE +** statements. */ static int fts5StorageDeleteFromIndex( Fts5Storage *p, i64 iDel, - sqlite3_value **apVal + sqlite3_value **apVal, + int bSaveRow /* True to set pSavedRow */ ){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ @@ -257452,12 +259613,21 @@ static int fts5StorageDeleteFromIndex( int iCol; Fts5InsertCtx ctx; + assert( bSaveRow==0 || apVal==0 ); + assert( bSaveRow==0 || bSaveRow==1 ); + assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 ); + if( apVal==0 ){ - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_int64(pSeek, 1, iDel); - if( sqlite3_step(pSeek)!=SQLITE_ROW ){ - return sqlite3_reset(pSeek); + if( p->pSavedRow && bSaveRow ){ + pSeek = p->pSavedRow; + p->pSavedRow = 0; + }else{ + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pSeek, 1, iDel); + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + return sqlite3_reset(pSeek); + } } } @@ -257465,26 +259635,42 @@ static int fts5StorageDeleteFromIndex( ctx.iCol = -1; for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ - const char *zText; - int nText; + sqlite3_value *pVal = 0; + const char *pText = 0; + int nText = 0; + const char *pLoc = 0; + int nLoc = 0; + assert( pSeek==0 || apVal==0 ); assert( pSeek!=0 || apVal!=0 ); if( pSeek ){ - zText = (const char*)sqlite3_column_text(pSeek, iCol); - nText = sqlite3_column_bytes(pSeek, iCol); - }else if( ALWAYS(apVal) ){ - zText = (const char*)sqlite3_value_text(apVal[iCol-1]); - nText = sqlite3_value_bytes(apVal[iCol-1]); + pVal = sqlite3_column_value(pSeek, iCol); }else{ - continue; + pVal = apVal[iCol-1]; } - ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, - zText, nText, (void*)&ctx, fts5StorageInsertCallback - ); - p->aTotalSize[iCol-1] -= (i64)ctx.szCol; - if( p->aTotalSize[iCol-1]<0 ){ - rc = FTS5_CORRUPT; + + if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); + }else{ + pText = (const char*)sqlite3_value_text(pVal); + nText = sqlite3_value_bytes(pVal); + if( pConfig->bLocale && pSeek ){ + pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol); + nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol); + } + } + + if( rc==SQLITE_OK ){ + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + ctx.szCol = 0; + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + pText, nText, (void*)&ctx, fts5StorageInsertCallback + ); + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){ + rc = FTS5_CORRUPT; + } + sqlite3Fts5ClearLocale(pConfig); } } } @@ -257494,11 +259680,29 @@ static int fts5StorageDeleteFromIndex( p->nTotalRow--; } - rc2 = sqlite3_reset(pSeek); - if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK && bSaveRow ){ + assert( p->pSavedRow==0 ); + p->pSavedRow = pSeek; + }else{ + rc2 = sqlite3_reset(pSeek); + if( rc==SQLITE_OK ) rc = rc2; + } return rc; } +/* +** Reset any saved statement pSavedRow. Zero pSavedRow as well. This +** should be called by the xUpdate() method of the fts5 table before +** returning from any operation that may have set Fts5Storage.pSavedRow. +*/ +static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){ + assert( pStorage->pSavedRow==0 + || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2] + ); + sqlite3_reset(pStorage->pSavedRow); + pStorage->pSavedRow = 0; +} + /* ** This function is called to process a DELETE on a contentless_delete=1 ** table. It adds the tombstone required to delete the entry with rowid @@ -257511,7 +259715,9 @@ static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){ int rc = SQLITE_OK; assert( p->pConfig->bContentlessDelete ); - assert( p->pConfig->eContent==FTS5_CONTENT_NONE ); + assert( p->pConfig->eContent==FTS5_CONTENT_NONE + || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED + ); /* Look up the origin of the document in the %_docsize table. Store ** this in stack variable iOrigin. */ @@ -257555,12 +259761,12 @@ static int fts5StorageInsertDocsize( rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin); sqlite3_bind_int64(pReplace, 3, iOrigin); } - if( rc==SQLITE_OK ){ - sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); - sqlite3_step(pReplace); - rc = sqlite3_reset(pReplace); - sqlite3_bind_null(pReplace, 2); - } + } + if( rc==SQLITE_OK ){ + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 2); } } return rc; @@ -257614,7 +259820,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){ /* ** Remove a row from the FTS table. */ -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ +static int sqlite3Fts5StorageDelete( + Fts5Storage *p, /* Storage object */ + i64 iDel, /* Rowid to delete from table */ + sqlite3_value **apVal, /* Optional - values to remove from index */ + int bSaveRow /* If true, set pSavedRow for deleted row */ +){ Fts5Config *pConfig = p->pConfig; int rc; sqlite3_stmt *pDel = 0; @@ -257630,8 +259841,14 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap if( rc==SQLITE_OK ){ if( p->pConfig->bContentlessDelete ){ rc = fts5StorageContentlessDelete(p, iDel); + if( rc==SQLITE_OK + && bSaveRow + && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED + ){ + rc = sqlite3Fts5StorageFindDeleteRow(p, iDel); + } }else{ - rc = fts5StorageDeleteFromIndex(p, iDel, apVal); + rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow); } } @@ -257646,7 +259863,9 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap } /* Delete the %_content record */ - if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL + || pConfig->eContent==FTS5_CONTENT_UNINDEXED + ){ if( rc==SQLITE_OK ){ rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0); } @@ -257678,8 +259897,13 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ ); if( rc==SQLITE_OK && pConfig->bColumnsize ){ rc = fts5ExecPrintf(pConfig->db, 0, - "DELETE FROM %Q.'%q_docsize';", - pConfig->zDb, pConfig->zName + "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName + ); + } + + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName ); } @@ -257720,14 +259944,36 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1); - int nText = sqlite3_column_bytes(pScan, ctx.iCol+1); - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - zText, nText, - (void*)&ctx, - fts5StorageInsertCallback - ); + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ + int nLoc = 0; /* Size of pLoc in bytes */ + const char *pLoc = 0; /* Pointer to buffer containing text value */ + + sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1); + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL + && sqlite3Fts5IsLocaleValue(pConfig, pVal) + ){ + rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); + }else{ + pText = (const char*)sqlite3_value_text(pVal); + nText = sqlite3_value_bytes(pVal); + if( pConfig->bLocale ){ + int iCol = ctx.iCol + 1 + pConfig->nCol; + pLoc = (const char*)sqlite3_column_text(pScan, iCol); + nLoc = sqlite3_column_bytes(pScan, iCol); + } + } + + if( rc==SQLITE_OK ){ + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + pText, nText, + (void*)&ctx, + fts5StorageInsertCallback + ); + sqlite3Fts5ClearLocale(pConfig); + } } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; @@ -257793,6 +260039,7 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ */ static int sqlite3Fts5StorageContentInsert( Fts5Storage *p, + int bReplace, /* True to use REPLACE instead of INSERT */ sqlite3_value **apVal, i64 *piRowid ){ @@ -257800,7 +260047,9 @@ static int sqlite3Fts5StorageContentInsert( int rc = SQLITE_OK; /* Insert the new row into the %_content table. */ - if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL + && pConfig->eContent!=FTS5_CONTENT_UNINDEXED + ){ if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ *piRowid = sqlite3_value_int64(apVal[1]); }else{ @@ -257809,9 +260058,52 @@ static int sqlite3Fts5StorageContentInsert( }else{ sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ int i; /* Counter variable */ - rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); - for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ - rc = sqlite3_bind_value(pInsert, i, apVal[i]); + + assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT ); + assert( bReplace==0 || bReplace==1 ); + rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0); + if( pInsert ) sqlite3_clear_bindings(pInsert); + + /* Bind the rowid value */ + sqlite3_bind_value(pInsert, 1, apVal[1]); + + /* Loop through values for user-defined columns. i=2 is the leftmost + ** user-defined column. As is column 1 of pSavedRow. */ + for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ + int bUnindexed = pConfig->abUnindexed[i-2]; + if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){ + sqlite3_value *pVal = apVal[i]; + + if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ + /* This is an UPDATE statement, and user-defined column (i-2) was not + ** modified. Retrieve the value from Fts5Storage.pSavedRow. */ + pVal = sqlite3_column_value(p->pSavedRow, i-1); + if( pConfig->bLocale && bUnindexed==0 ){ + sqlite3_bind_value(pInsert, pConfig->nCol + i, + sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1) + ); + } + }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + const char *pText = 0; + const char *pLoc = 0; + int nText = 0; + int nLoc = 0; + assert( pConfig->bLocale ); + + rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); + if( rc==SQLITE_OK ){ + sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT); + if( bUnindexed==0 ){ + int iLoc = pConfig->nCol + i; + sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT); + } + } + + continue; + } + + rc = sqlite3_bind_value(pInsert, i, pVal); + } } if( rc==SQLITE_OK ){ sqlite3_step(pInsert); @@ -257846,14 +260138,38 @@ static int sqlite3Fts5StorageIndexInsert( for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]); - int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]); - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - zText, nText, - (void*)&ctx, - fts5StorageInsertCallback - ); + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ + int nLoc = 0; /* Size of pText in bytes */ + const char *pLoc = 0; /* Pointer to buffer containing text value */ + + sqlite3_value *pVal = apVal[ctx.iCol+2]; + if( p->pSavedRow && sqlite3_value_nochange(pVal) ){ + pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1); + if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){ + int iCol = ctx.iCol + 1 + pConfig->nCol; + pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol); + nLoc = sqlite3_column_bytes(p->pSavedRow, iCol); + } + }else{ + pVal = apVal[ctx.iCol+2]; + } + + if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); + }else{ + pText = (const char*)sqlite3_value_text(pVal); + nText = sqlite3_value_bytes(pVal); + } + + if( rc==SQLITE_OK ){ + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, + fts5StorageInsertCallback + ); + sqlite3Fts5ClearLocale(pConfig); + } } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; @@ -258017,29 +260333,61 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } for(i=0; rc==SQLITE_OK && inCol; i++){ - if( pConfig->abUnindexed[i] ) continue; - ctx.iCol = i; - ctx.szCol = 0; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); - } - if( rc==SQLITE_OK ){ - const char *zText = (const char*)sqlite3_column_text(pScan, i+1); - int nText = sqlite3_column_bytes(pScan, i+1); - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - zText, nText, - (void*)&ctx, - fts5StorageIntegrityCallback - ); - } - if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ - rc = FTS5_CORRUPT; - } - aTotalSize[i] += ctx.szCol; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + if( pConfig->abUnindexed[i]==0 ){ + const char *pText = 0; + int nText = 0; + const char *pLoc = 0; + int nLoc = 0; + sqlite3_value *pVal = sqlite3_column_value(pScan, i+1); + + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL + && sqlite3Fts5IsLocaleValue(pConfig, pVal) + ){ + rc = sqlite3Fts5DecodeLocaleValue( + pVal, &pText, &nText, &pLoc, &nLoc + ); + }else{ + if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){ + int iCol = i + 1 + pConfig->nCol; + pLoc = (const char*)sqlite3_column_text(pScan, iCol); + nLoc = sqlite3_column_bytes(pScan, iCol); + } + pText = (const char*)sqlite3_value_text(pVal); + nText = sqlite3_value_bytes(pVal); + } + + ctx.iCol = i; + ctx.szCol = 0; + + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + + if( rc==SQLITE_OK ){ + sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + pText, nText, + (void*)&ctx, + fts5StorageIntegrityCallback + ); + sqlite3Fts5ClearLocale(pConfig); + } + + /* If this is not a columnsize=0 database, check that the number + ** of tokens in the value matches the aColSize[] value read from + ** the %_docsize table. */ + if( rc==SQLITE_OK + && pConfig->bColumnsize + && ctx.szCol!=aColSize[i] + ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } } } sqlite3Fts5TermsetFree(ctx.pTermset); @@ -258465,7 +260813,7 @@ static const unsigned char sqlite3Utf8Trans1[] = { c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ - while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + while( zInpTokenizer ){ - p->tokenizer.xDelete(p->pTokenizer); + p->tokenizer_v2.xDelete(p->pTokenizer); } sqlite3_free(p); } @@ -258853,6 +261199,7 @@ static int fts5PorterCreate( PorterTokenizer *pRet; void *pUserdata = 0; const char *zBase = "unicode61"; + fts5_tokenizer_v2 *pV2 = 0; if( nArg>0 ){ zBase = azArg[0]; @@ -258861,14 +261208,15 @@ static int fts5PorterCreate( pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); if( pRet ){ memset(pRet, 0, sizeof(PorterTokenizer)); - rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer); + rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); }else{ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ int nArg2 = (nArg>0 ? nArg-1 : 0); - const char **azArg2 = (nArg2 ? &azArg[1] : 0); - rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer); + const char **az2 = (nArg2 ? &azArg[1] : 0); + memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2)); + rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer); } if( rc!=SQLITE_OK ){ @@ -259519,6 +261867,7 @@ static int fts5PorterTokenize( void *pCtx, int flags, const char *pText, int nText, + const char *pLoc, int nLoc, int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) ){ PorterTokenizer *p = (PorterTokenizer*)pTokenizer; @@ -259526,8 +261875,8 @@ static int fts5PorterTokenize( sCtx.xToken = xToken; sCtx.pCtx = pCtx; sCtx.aBuf = p->aBuf; - return p->tokenizer.xTokenize( - p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb + return p->tokenizer_v2.xTokenize( + p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb ); } @@ -259557,40 +261906,46 @@ static int fts5TriCreate( Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; - TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + TrigramTokenizer *pNew = 0; UNUSED_PARAM(pUnused); - if( pNew==0 ){ - rc = SQLITE_NOMEM; + if( nArg%2 ){ + rc = SQLITE_ERROR; }else{ int i; - pNew->bFold = 1; - pNew->iFoldParam = 0; - for(i=0; rc==SQLITE_OK && ibFold = 1; + pNew->iFoldParam = 0; + + for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); + } + }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ + if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ + rc = SQLITE_ERROR; + }else{ + pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; + } }else{ - pNew->bFold = (zArg[0]=='0'); - } - }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ - if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ rc = SQLITE_ERROR; - }else{ - pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; } - }else{ - rc = SQLITE_ERROR; } - } - if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ - rc = SQLITE_ERROR; - } + if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ + rc = SQLITE_ERROR; + } - if( rc!=SQLITE_OK ){ - fts5TriDelete((Fts5Tokenizer*)pNew); - pNew = 0; + if( rc!=SQLITE_OK ){ + fts5TriDelete((Fts5Tokenizer*)pNew); + pNew = 0; + } } } *ppOut = (Fts5Tokenizer*)pNew; @@ -259614,7 +261969,7 @@ static int fts5TriTokenize( int ii; const unsigned char *zIn = (const unsigned char*)pText; const unsigned char *zEof = &zIn[nText]; - u32 iCode; + u32 iCode = 0; int aStart[3]; /* Input offset of each character in aBuf[] */ UNUSED_PARAM(unusedFlags); @@ -259623,8 +261978,8 @@ static int fts5TriTokenize( for(ii=0; ii<3; ii++){ do { aStart[ii] = zIn - (const unsigned char*)pText; + if( zIn>=zEof ) return SQLITE_OK; READ_UTF8(zIn, zEof, iCode); - if( iCode==0 ) return SQLITE_OK; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); WRITE_UTF8(zOut, iCode); @@ -259645,8 +262000,11 @@ static int fts5TriTokenize( /* Read characters from the input up until the first non-diacritic */ do { iNext = zIn - (const unsigned char*)pText; + if( zIn>=zEof ){ + iCode = 0; + break; + } READ_UTF8(zIn, zEof, iCode); - if( iCode==0 ) break; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); @@ -259715,7 +262073,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ } aBuiltin[] = { { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, - { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, }; @@ -259730,7 +262087,20 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ 0 ); } - + if( rc==SQLITE_OK ){ + fts5_tokenizer_v2 sPorter = { + 2, + fts5PorterCreate, + fts5PorterDelete, + fts5PorterTokenize + }; + rc = pApi->xCreateTokenizer_v2(pApi, + "porter", + (void*)pApi, + &sPorter, + 0 + ); + } return rc; } @@ -260100,6 +262470,9 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ default: return 1; } break; + + default: + return 1; } return 0; } @@ -261668,7 +264041,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ } - +/* Here ends the fts5.c composite file. */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ @@ -268901,6 +271274,7 @@ SQLITE_PRIVATE int sqlite3HctTreeForeach( /* #include */ /* #include */ +/* #include */ #define HCT_DEFAULT_PAGESIZE 4096 @@ -269403,16 +271777,36 @@ static void hctFilePagemapZeroValue(HctFile *pFile, u32 iSlot){ } } +/* +** Open a file descriptor for read/write access on the filename formed by +** concatenating arguments zFile and zPost (e.g. "test.db" and "-pagemap"). +** Return the file descriptor if successful. +*/ static int hctFileOpen(int *pRc, const char *zFile, const char *zPost){ - int fd = 0; + int fd = -1; if( *pRc==SQLITE_OK ){ char *zPath = sqlite3_mprintf("%s%s", zFile, zPost); if( zPath==0 ){ *pRc = SQLITE_NOMEM_BKPT; }else{ - fd = open(zPath, O_CREAT|O_RDWR, 0644); - if( fd<0 ){ - *pRc = SQLITE_CANTOPEN_BKPT; + while( fd<0 ){ + fd = open(zPath, O_CREAT|O_RDWR, 0644); + if( fd<0 ){ + *pRc = SQLITE_CANTOPEN_BKPT; + break; + } + if( fd<3 ){ + /* Do not use any file-descriptor with values 0, 1 or 2. Using + ** these means that stray calls to printf() etc. may corrupt the + ** database. */ + close(fd); + fd = open("/dev/null", O_RDONLY, 0644); + if( fd<0 ){ + *pRc = SQLITE_CANTOPEN_BKPT; + break; + } + fd = -1; + } } sqlite3_free(zPath); } @@ -269672,7 +272066,8 @@ static void hctFileOpenDataFiles( if( rc!=SQLITE_OK ){ for(ii=1; iinFdDb; ii++){ - close(p->aFdDb[ii]); + if( p->aFdDb[ii]>0 ) close(p->aFdDb[ii]); + p->aFdDb[ii] = -1; } p->nFdDb = 1; } @@ -270149,11 +272544,16 @@ static int hctFileServerFind(HctFile *pFile, const char *zFile){ if( pServer==0 ){ int fd = hctFileOpen(&rc, zFile, ""); if( rc==SQLITE_OK ){ + assert( fd>0 ); hctFileLock(&rc, fd, zFile); pServer = (HctFileServer*)sqlite3HctMalloc(&rc, sizeof(*pServer)); if( pServer==0 ){ - if( fd ) close(fd); + close(fd); }else{ + int ii; + for(ii=0; iiaFdDb[ii] = -1; + } fstat(fd, &sStat); pServer->st_dev = (i64)sStat.st_dev; pServer->st_ino = (i64)sStat.st_ino; @@ -270297,7 +272697,9 @@ SQLITE_PRIVATE void sqlite3HctFileClose(HctFile *pFile){ } /* Close the data files and the mapping file. */ - for(i=0; inFdDb; i++){ close(pDel->aFdDb[i]); } + for(i=0; inFdDb; i++){ + if( pDel->aFdDb[i]>0 ) close(pDel->aFdDb[i]); + } if( pDel->fdMap ) close(pDel->fdMap); if( pDel->xJrnlDel ){ @@ -271455,6 +273857,7 @@ SQLITE_PRIVATE int sqlite3HctFileVtabInit(sqlite3 *db){ } SQLITE_PRIVATE int sqlite3HctIoerr(int rc){ + sqlite3_log(rc, "sqlite3HctIoerr() - rc=%d errno=%d\n", rc, (int)errno); assert( 0 ); abort(); return rc; @@ -283255,4 +285658,5 @@ SQLITE_API void sqlite3_hct_journal_hashentry( /************** End of hct_journalhash.c *************************************/ /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +#endif /* SQLITE_AMALGAMATION */ /************************** End of sqlite3.c ******************************/ diff --git a/libstuff/sqlite3.h b/libstuff/sqlite3.h index 4fbc9e6cd..12fe5fda2 100644 --- a/libstuff/sqlite3.h +++ b/libstuff/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.47.0" -#define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-11-04 14:53:59 0c7b45cfde33ed7f3a9b8ddbe249093968bd2eef32a58074b6642a1f52b8426f" +#define SQLITE_VERSION "3.48.0" +#define SQLITE_VERSION_NUMBER 3048000 +#define SQLITE_SOURCE_ID "2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -652,6 +652,13 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. +** +** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read +** from the database file in amounts that are not a multiple of the +** page size and that do not begin at a page boundary. Without this +** property, SQLite is careful to only do full-page reads and write +** on aligned pages, with the one exception that it will do a sub-page +** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -668,6 +675,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 +#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -814,6 +822,7 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] +**
  • [SQLITE_IOCAP_SUBPAGE_READ] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1091,6 +1100,11 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
  • [[SQLITE_FCNTL_NULL_IO]] +** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor +** or file handle for the [sqlite3_file] object such that it will no longer +** read or write to the database file. +** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1244,6 +1258,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 +#define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2622,10 +2637,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE +** and that if the number of rows modified by the most recent INSERT, UPDATE, ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. +** For the purposes of this interface, a CREATE TABLE AS SELECT statement +** does not count as an INSERT, UPDATE or DELETE statement and hence the rows +** added to the new table by the CREATE TABLE AS SELECT statement are not +** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -4222,13 +4241,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the -** first zero terminator. ^If nByte is positive, then it is the -** number of bytes read from zSql. ^If nByte is zero, then no prepared +** first zero terminator. ^If nByte is positive, then it is the maximum +** number of bytes read from zSql. When nByte is positive, zSql is read +** up to the first zero terminator or until the nByte bytes have been read, +** whichever comes first. ^If nByte is zero, then no prepared ** statement is generated. ** If the caller knows that the supplied string is nul-terminated, then ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. +** Note that nByte measure the length of the input in bytes, not +** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5599,7 +5622,7 @@ SQLITE_API int sqlite3_create_window_function( ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this +** All SQL functions that invoke [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. @@ -5615,6 +5638,15 @@ SQLITE_API int sqlite3_create_window_function( ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. +** +** [[SQLITE_SELFORDER1]]
    SQLITE_SELFORDER1
    +** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate +** that internally orders the values provided to the first argument. The +** ordered-set aggregate SQL notation with a single ORDER BY term can be +** used to invoke this function. If the ordered-set aggregate notation is +** used on a function that lacks this flag, then an error is raised. Note +** that the ordered-set aggregate syntax is only available if SQLite is +** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option. **
    ** */ @@ -5623,6 +5655,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 +#define SQLITE_SELFORDER1 0x002000000 /* ** CAPI3REF: Deprecated Functions @@ -5820,7 +5853,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** -** Every [application-defined SQL function] that invoke this interface +** Every [application-defined SQL function] that invokes this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() @@ -7427,9 +7460,11 @@ struct sqlite3_module { ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a -** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - -** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite -** assumes that the strategy may visit at most one row. +** mask of SQLITE_INDEX_SCAN_* flags. One such flag is +** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] +** output to show the idxNum has hex instead of as decimal. Another flag is +** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will +** return at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -7493,7 +7528,9 @@ struct sqlite3_index_info { ** [sqlite3_index_info].idxFlags field to some combination of ** these bits. */ -#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ +#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */ +#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */ + /* in EXPLAIN QUERY PLAN */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes @@ -8330,6 +8367,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_GETOPT 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8349,7 +8387,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 +#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ #define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 #define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ @@ -9326,6 +9364,16 @@ typedef struct sqlite3_backup sqlite3_backup; ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. +** +** Alternatives To Using The Backup API +** +** Other techniques for safely creating a consistent backup of an SQLite +** database include: +** +**
      +**
    • The [VACUUM INTO] command. +**
    • The [sqlite3_rsync] utility program. +**
    */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ @@ -10525,6 +10573,14 @@ typedef struct sqlite3_snapshot { ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** +** If a read-transaction is opened by this function, then it is guaranteed +** that the returned snapshot object may not be invalidated by a database +** writer or checkpointer until after the read-transaction is closed. This +** is not guaranteed if a read-transaction is already open when this +** function is called. In that case, any subsequent write or checkpoint +** operation on the database may invalidate the returned snapshot handle, +** even while the read-transaction remains open. +** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined @@ -10964,7 +11020,7 @@ SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -#endif /* SQLITE3_H */ +/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ /******** Begin file sqlite3rtree.h *********/ /* @@ -13185,6 +13241,10 @@ struct Fts5PhraseIter { ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** +** In all cases, matches are visited in (column ASC, offset ASC) order. +** i.e. all those in column 0, sorted by offset, followed by those in +** column 1, etc. +** ** xPhraseNext() ** See xPhraseFirst above. ** @@ -13251,9 +13311,32 @@ struct Fts5PhraseIter { ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. +** +** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) +** If parameter iCol is less than zero, or greater than or equal to the +** number of columns in the table, SQLITE_RANGE is returned. +** +** Otherwise, this function attempts to retrieve the locale associated +** with column iCol of the current row. Usually, there is no associated +** locale, and output parameters (*pzLocale) and (*pnLocale) are set +** to NULL and 0, respectively. However, if the fts5_locale() function +** was used to associate a locale with the value when it was inserted +** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated +** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) +** is set to the size in bytes of the buffer, not including the +** nul-terminator. +** +** If successful, SQLITE_OK is returned. Or, if an error occurs, an +** SQLite error code is returned. The final value of the output parameters +** is undefined in this case. +** +** xTokenize_v2: +** Tokenize text using the tokenizer belonging to the FTS5 table. This +** API is the same as the xTokenize() API, except that it allows a tokenizer +** locale to be specified. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 4 */ void *(*xUserData)(Fts5Context*); @@ -13295,6 +13378,15 @@ struct Fts5ExtensionApi { const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); + + /* Below this point are iVersion>=4 only */ + int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xTokenize_v2)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); }; /* @@ -13315,7 +13407,7 @@ struct Fts5ExtensionApi { ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer object +** pointer provided by the application when the fts5_tokenizer_v2 object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the @@ -13339,7 +13431,7 @@ struct Fts5ExtensionApi { ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** -** The second argument indicates the reason that FTS5 is requesting +** The third argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** @@ -13363,6 +13455,13 @@ struct Fts5ExtensionApi { ** on a columnsize=0 database. ** ** +** The sixth and seventh arguments passed to xTokenize() - pLocale and +** nLocale - are a pointer to a buffer containing the locale to use for +** tokenization (e.g. "en_US") and its size in bytes, respectively. The +** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in +** which case nLocale is always 0) to indicate that the tokenizer should +** use its default locale. +** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth @@ -13386,6 +13485,30 @@ struct Fts5ExtensionApi { ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** +** If the tokenizer is registered using an fts5_tokenizer_v2 object, +** then the xTokenize() method has two additional arguments - pLocale +** and nLocale. These specify the locale that the tokenizer should use +** for the current request. If pLocale and nLocale are both 0, then the +** tokenizer should use its default locale. Otherwise, pLocale points to +** an nLocale byte buffer containing the name of the locale to use as utf-8 +** text. pLocale is not nul-terminated. +** +** FTS5_TOKENIZER +** +** There is also an fts5_tokenizer object. This is an older, deprecated, +** version of fts5_tokenizer_v2. It is similar except that: +** +**
      +**
    • There is no "iVersion" field, and +**
    • The xTokenize() method does not take a locale argument. +**
    +** +** Legacy fts5_tokenizer tokenizers must be registered using the +** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2(). +** +** Tokenizer implementations registered using either API may be retrieved +** using both xFindTokenizer() and xFindTokenizer_v2(). +** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a @@ -13494,6 +13617,33 @@ struct Fts5ExtensionApi { ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; +struct fts5_tokenizer_v2 { + int iVersion; /* Currently always 2 */ + + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + const char *pLocale, int nLocale, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* +** New code should use the fts5_tokenizer_v2 type to define tokenizer +** implementations. The following type is included for legacy applications +** that still use it. +*/ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); @@ -13513,6 +13663,7 @@ struct fts5_tokenizer { ); }; + /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 @@ -13532,7 +13683,7 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 2 */ + int iVersion; /* Currently always set to 3 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( @@ -13559,6 +13710,25 @@ struct fts5_api { fts5_extension_function xFunction, void (*xDestroy)(void*) ); + + /* APIs below this point are only available if iVersion>=3 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void *pUserData, + fts5_tokenizer_v2 *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer_v2)( + fts5_api *pApi, + const char *zName, + void **ppUserData, + fts5_tokenizer_v2 **ppTokenizer + ); }; /* @@ -13572,3 +13742,4 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif /* SQLITE3_H */ From 8684d822918bdb6c829c943dda8ca8f175239e14 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 13:19:04 -0800 Subject: [PATCH 03/11] Fix slow shutdown --- BedrockServer.cpp | 3 +++ libstuff/SSignal.cpp | 7 +++++++ libstuff/SSynchronizedQueue.h | 1 + libstuff/libstuff.h | 2 ++ test/lib/BedrockTester.h | 8 ++++---- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index 8fbd245a9..547393954 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -1224,6 +1224,9 @@ BedrockServer::BedrockServer(const SData& args_) { _version = VERSION; + // This allows the signal thread to notify us when a signal is received to interrupt the current poll loop. + SSIGNAL_NOTIFY_INTERRUPT = &_notifyDone; + // Enable the requested plugins, and update our version string if required. list pluginNameList = SParseList(args["-plugins"]); SINFO("Loading plugins: " << args["-plugins"]); diff --git a/libstuff/SSignal.cpp b/libstuff/SSignal.cpp index e6c246f7d..c391e9f68 100644 --- a/libstuff/SSignal.cpp +++ b/libstuff/SSignal.cpp @@ -1,4 +1,5 @@ #include "libstuff.h" +#include "SSynchronizedQueue.h" #include #include #include @@ -17,6 +18,8 @@ void SSetSignalHandlerDieFunc(function&& func) { constexpr auto sigStackSize{1024*64}; char __SIGSTACK[sigStackSize]; +void* SSIGNAL_NOTIFY_INTERRUPT; + // The function to call in our thread that handles signals. void _SSignal_signalHandlerThreadFunc(); @@ -153,6 +156,10 @@ void _SSignal_signalHandlerThreadFunc() { } int signum = siginfo.si_signo; + if (SSIGNAL_NOTIFY_INTERRUPT) { + static_cast*>(SSIGNAL_NOTIFY_INTERRUPT)->push(true); + } + if (result > 0) { // Do the same handling for these functions here as any other thread. if (signum == SIGSEGV || signum == SIGABRT || signum == SIGFPE || signum == SIGILL || signum == SIGBUS) { diff --git a/libstuff/SSynchronizedQueue.h b/libstuff/SSynchronizedQueue.h index 06951ce21..71bfd9b5d 100644 --- a/libstuff/SSynchronizedQueue.h +++ b/libstuff/SSynchronizedQueue.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/libstuff/libstuff.h b/libstuff/libstuff.h index 140880c95..976ed0ad8 100644 --- a/libstuff/libstuff.h +++ b/libstuff/libstuff.h @@ -31,6 +31,8 @@ using namespace std; // Global indicating whether we're running the server on dev or production. extern atomic GLOBAL_IS_LIVE; +extern void* SSIGNAL_NOTIFY_INTERRUPT; + // Initialize libstuff on every thread before calling any of its functions void SInitialize(string threadName = "", const char* processName = 0); diff --git a/test/lib/BedrockTester.h b/test/lib/BedrockTester.h index 6e694b795..9fb31f111 100644 --- a/test/lib/BedrockTester.h +++ b/test/lib/BedrockTester.h @@ -36,7 +36,7 @@ class BedrockTester { atomic* alternateCounter = nullptr); // Destructor. - ~BedrockTester(); + virtual ~BedrockTester(); // Start the server. If `wait` is specified, wait until the server is fully up with the command port open and // accepting requests. Otherwise, returns as soon as the control port is open and can return `Status`. @@ -65,17 +65,17 @@ class BedrockTester { // Takes a list of requests, and returns a corresponding list of responses. // Uses `connections` parallel connections to the server to send the requests. // If `control` is set, sends the message to the control port. - vector executeWaitMultipleData(vector requests, int connections = 10, bool control = false, bool returnOnDisconnect = false, int* errorCode = nullptr); + virtual vector executeWaitMultipleData(vector requests, int connections = 10, bool control = false, bool returnOnDisconnect = false, int* errorCode = nullptr); // Sends a single request, returning the response content. // If the response method line doesn't begin with the expected result, throws. // Convenience wrapper around executeWaitMultipleData. - string executeWaitVerifyContent(SData request, const string& expectedResult = "200 OK", bool control = false, uint64_t retryTimeoutUS = 0); + virtual string executeWaitVerifyContent(SData request, const string& expectedResult = "200 OK", bool control = false, uint64_t retryTimeoutUS = 0); // Sends a single request, returning the response content as a STable. // If the response method line doesn't begin with the expected result, throws. // Convenience wrapper around executeWaitMultipleData. - STable executeWaitVerifyContentTable(SData request, const string& expectedResult = "200 OK"); + virtual STable executeWaitVerifyContentTable(SData request, const string& expectedResult = "200 OK"); // Read from the DB file, without going through the bedrock server. Two interfaces are provided to maintain // compatibility with the `SQLite` class. From be93a5ed78fa45109fe74bf792c72f89418eb211 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 14:49:38 -0800 Subject: [PATCH 04/11] Fixed shutdown by breaking startup --- BedrockServer.cpp | 20 ++++++++++++++++---- BedrockServer.h | 4 ++-- libstuff/SSignal.cpp | 10 ++++++---- main.cpp | 4 ++++ test/lib/BedrockTester.cpp | 6 +++++- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index 547393954..121d7c629 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -2,7 +2,9 @@ #include "BedrockServer.h" #include +#include #include +#include #include #include #include @@ -217,7 +219,7 @@ void BedrockServer::sync() _syncNode->beginShutdown(); // This will cause us to skip the next `poll` iteration which avoids a 1 second wait. - _notifyDone.push(true); + _notifyDoneSync.push(true); } // The fd_map contains a list of all file descriptors (eg, sockets, Unix pipes) that poll will wait on for @@ -225,7 +227,7 @@ void BedrockServer::sync() fd_map fdm; // Pre-process any sockets the sync node is managing (i.e., communication with peer nodes). - _notifyDone.prePoll(fdm); + _notifyDoneSync.prePoll(fdm); _syncNode->prePoll(fdm); // Add our command queues to our fd_map. @@ -236,6 +238,12 @@ void BedrockServer::sync() { AutoTimerTime pollTime(pollTimer); S_poll(fdm, max(nextActivity, now) - now); + + bool terminated = SCheckSignal(SIGTERM); + if (terminated) { + cout << "sync thread poll interrupted at " << SCURRENT_TIMESTAMP_MS() << " with SIGTERM set." << endl; + _notifyDone.push(true); + } } // And set our next timeout for 1 second from now. @@ -251,7 +259,7 @@ void BedrockServer::sync() AutoTimerTime postPollTime(postPollTimer); _syncNode->postPoll(fdm, nextActivity); _syncNodeQueuedCommands.postPoll(fdm); - _notifyDone.postPoll(fdm); + _notifyDoneSync.postPoll(fdm); } // Ok, let the sync node to it's updating for as many iterations as it requires. We'll update the replication @@ -350,6 +358,9 @@ void BedrockServer::sync() committingCommand = true; _syncNode->startCommit(SQLiteNode::QUORUM); _lastQuorumCommandTime = STimeNow(); + + // This interrupts the next poll loop immediately. This prevents a 1-second wait when running as a single server. + _notifyDoneSync.push(true); SDEBUG("Finished sending distributed transaction for db upgrade."); // As it's a quorum commit, we'll need to read from peers. Let's start the next loop iteration. @@ -1225,7 +1236,7 @@ BedrockServer::BedrockServer(const SData& args_) _version = VERSION; // This allows the signal thread to notify us when a signal is received to interrupt the current poll loop. - SSIGNAL_NOTIFY_INTERRUPT = &_notifyDone; + SSIGNAL_NOTIFY_INTERRUPT = &_notifyDoneSync; // Enable the requested plugins, and update our version string if required. list pluginNameList = SParseList(args["-plugins"]); @@ -1955,6 +1966,7 @@ bool BedrockServer::_upgradeDB(SQLite& db) { void BedrockServer::_beginShutdown(const string& reason, bool detach) { if (_shutdownState.load() == RUNNING) { + cout << "Beginning shutdown due to signal at: " << SCURRENT_TIMESTAMP_MS() << endl; _detach = detach; // Begin a graceful shutdown; close our port SINFO("Beginning graceful shutdown due to '" << reason << "', closing command port on '" << args["-serverHost"] << "'."); diff --git a/BedrockServer.h b/BedrockServer.h index 13ff40ba6..4a6175d27 100644 --- a/BedrockServer.h +++ b/BedrockServer.h @@ -467,9 +467,9 @@ class BedrockServer : public SQLiteServer { // We call this method whenever a node changes state void notifyStateChangeToPlugins(SQLite& db, SQLiteNodeState newState) override; - // This is just here to allow `poll` in main.cpp to get interrupted when the server shuts down. - // to wait up to a full second for them. + // These are just here to allow `poll` in main.cpp to get interrupted when the server shuts down. SSynchronizedQueue _notifyDone; + SSynchronizedQueue _notifyDoneSync; atomic _maxSocketThreads{3'000}; atomic _dbPoolSize{25'000}; diff --git a/libstuff/SSignal.cpp b/libstuff/SSignal.cpp index c391e9f68..cebb1a4ac 100644 --- a/libstuff/SSignal.cpp +++ b/libstuff/SSignal.cpp @@ -9,6 +9,7 @@ #include #include +#include thread_local function SSignalHandlerDieFunc; void SSetSignalHandlerDieFunc(function&& func) { SSignalHandlerDieFunc = move(func); @@ -156,10 +157,6 @@ void _SSignal_signalHandlerThreadFunc() { } int signum = siginfo.si_signo; - if (SSIGNAL_NOTIFY_INTERRUPT) { - static_cast*>(SSIGNAL_NOTIFY_INTERRUPT)->push(true); - } - if (result > 0) { // Do the same handling for these functions here as any other thread. if (signum == SIGSEGV || signum == SIGABRT || signum == SIGFPE || signum == SIGILL || signum == SIGBUS) { @@ -170,6 +167,11 @@ void _SSignal_signalHandlerThreadFunc() { _SSignal_pendingSignalBitMask.fetch_or(1 << signum); } } + + if (SSIGNAL_NOTIFY_INTERRUPT) { + cout << "Signal notification at: " << SCURRENT_TIMESTAMP_MS() << endl; + static_cast*>(SSIGNAL_NOTIFY_INTERRUPT)->push(true); + } } } diff --git a/main.cpp b/main.cpp index f14683522..dc0eecf86 100644 --- a/main.cpp +++ b/main.cpp @@ -367,6 +367,10 @@ int main(int argc, char* argv[]) { const uint64_t now = STimeNow(); auto timeBeforePoll = chrono::steady_clock::now(); S_poll(fdm, max(nextActivity, now) - now); + bool terminated = SCheckSignal(SIGTERM); + if (terminated) { + cout << "main thread poll interrupted at " << SCURRENT_TIMESTAMP_MS() << " with SIGTERM set." << endl; + } nextActivity = STimeNow() + STIME_US_PER_S; // 1s max period auto timeAfterPoll = chrono::steady_clock::now(); server.postPoll(fdm, nextActivity); diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index d4524b516..d1609303a 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -238,6 +238,7 @@ string BedrockTester::startServer(bool wait) { cout << endl; exit(1); } else { + cout << "Begin startup at: " << SCURRENT_TIMESTAMP_MS() << endl; // We'll kill this later. _serverPID = childPID; @@ -270,10 +271,11 @@ string BedrockTester::startServer(bool wait) { SData status("Status"); auto result = executeWaitMultipleData({status}, 1, !wait); if (result[0].methodLine == "200 OK") { + cout << "End startup at: " << SCURRENT_TIMESTAMP_MS() << endl; return result[0].content; } // This will happen if the server's not up yet. We'll just try again. - usleep(100000); // 0.1 seconds. + usleep(50'000); // 0.05 seconds. continue; } } @@ -282,9 +284,11 @@ string BedrockTester::startServer(bool wait) { void BedrockTester::stopServer(int signal) { if (_serverPID) { + cout << "Begin shutdown at: " << SCURRENT_TIMESTAMP_MS() << endl; kill(_serverPID, signal); int status; waitpid(_serverPID, &status, 0); + cout << "End shutdown at: " << SCURRENT_TIMESTAMP_MS() << endl; _serverPID = 0; } } From 1aa4def0077200dec725170fc83e08a5157b037a Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 15:08:12 -0800 Subject: [PATCH 05/11] Both startup and shutdown are fast --- BedrockServer.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index 121d7c629..96843aef4 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -23,6 +23,8 @@ setBedrockServer::_blacklistedParallelCommands; shared_timed_mutex BedrockServer::_blacklistedParallelCommandMutex; thread_local atomic BedrockServer::_nodeStateSnapshot = SQLiteNodeState::UNKNOWN; +bool __NOTIFY = false; + void BedrockServer::syncWrapper() { // Initialize the thread. @@ -237,7 +239,14 @@ void BedrockServer::sync() const uint64_t now = STimeNow(); { AutoTimerTime pollTime(pollTimer); + if (__NOTIFY) { + cout << "Starting poll at: " << SCURRENT_TIMESTAMP_MS() << endl; + } S_poll(fdm, max(nextActivity, now) - now); + if (__NOTIFY) { + cout << "Stopping poll at: " << SCURRENT_TIMESTAMP_MS() << endl; + __NOTIFY = false; + } bool terminated = SCheckSignal(SIGTERM); if (terminated) { @@ -361,6 +370,8 @@ void BedrockServer::sync() // This interrupts the next poll loop immediately. This prevents a 1-second wait when running as a single server. _notifyDoneSync.push(true); + cout << "Interrupting next sync loop at startup at: " << SCURRENT_TIMESTAMP_MS() << endl; + __NOTIFY = true; SDEBUG("Finished sending distributed transaction for db upgrade."); // As it's a quorum commit, we'll need to read from peers. Let's start the next loop iteration. @@ -389,6 +400,8 @@ void BedrockServer::sync() _upgradeInProgress = false; _upgradeCompleted = true; SINFO("UpgradeDB succeeded, done."); + cout << "Upgrade complete at " << SCURRENT_TIMESTAMP_MS() << endl; + _notifyDone.push(true); } else { SINFO("UpgradeDB failed, trying again."); } From 2afa422d57f6fc67a7628598d2c07a3956cb5fbc Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 15:29:51 -0800 Subject: [PATCH 06/11] Remove some debug logging --- BedrockServer.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index 96843aef4..15d2477e5 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -23,8 +23,6 @@ setBedrockServer::_blacklistedParallelCommands; shared_timed_mutex BedrockServer::_blacklistedParallelCommandMutex; thread_local atomic BedrockServer::_nodeStateSnapshot = SQLiteNodeState::UNKNOWN; -bool __NOTIFY = false; - void BedrockServer::syncWrapper() { // Initialize the thread. @@ -239,18 +237,9 @@ void BedrockServer::sync() const uint64_t now = STimeNow(); { AutoTimerTime pollTime(pollTimer); - if (__NOTIFY) { - cout << "Starting poll at: " << SCURRENT_TIMESTAMP_MS() << endl; - } S_poll(fdm, max(nextActivity, now) - now); - if (__NOTIFY) { - cout << "Stopping poll at: " << SCURRENT_TIMESTAMP_MS() << endl; - __NOTIFY = false; - } - bool terminated = SCheckSignal(SIGTERM); if (terminated) { - cout << "sync thread poll interrupted at " << SCURRENT_TIMESTAMP_MS() << " with SIGTERM set." << endl; _notifyDone.push(true); } } @@ -370,8 +359,6 @@ void BedrockServer::sync() // This interrupts the next poll loop immediately. This prevents a 1-second wait when running as a single server. _notifyDoneSync.push(true); - cout << "Interrupting next sync loop at startup at: " << SCURRENT_TIMESTAMP_MS() << endl; - __NOTIFY = true; SDEBUG("Finished sending distributed transaction for db upgrade."); // As it's a quorum commit, we'll need to read from peers. Let's start the next loop iteration. @@ -400,7 +387,6 @@ void BedrockServer::sync() _upgradeInProgress = false; _upgradeCompleted = true; SINFO("UpgradeDB succeeded, done."); - cout << "Upgrade complete at " << SCURRENT_TIMESTAMP_MS() << endl; _notifyDone.push(true); } else { SINFO("UpgradeDB failed, trying again."); @@ -1979,7 +1965,6 @@ bool BedrockServer::_upgradeDB(SQLite& db) { void BedrockServer::_beginShutdown(const string& reason, bool detach) { if (_shutdownState.load() == RUNNING) { - cout << "Beginning shutdown due to signal at: " << SCURRENT_TIMESTAMP_MS() << endl; _detach = detach; // Begin a graceful shutdown; close our port SINFO("Beginning graceful shutdown due to '" << reason << "', closing command port on '" << args["-serverHost"] << "'."); From a6557a96157b55796db41cc78afbba5dde2fd7b2 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 15:33:16 -0800 Subject: [PATCH 07/11] Remove more debug lines --- BedrockServer.cpp | 4 +--- libstuff/SSignal.cpp | 1 - main.cpp | 4 ---- test/lib/BedrockTester.cpp | 4 ---- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index 15d2477e5..f7958613f 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -238,8 +237,7 @@ void BedrockServer::sync() { AutoTimerTime pollTime(pollTimer); S_poll(fdm, max(nextActivity, now) - now); - bool terminated = SCheckSignal(SIGTERM); - if (terminated) { + if (SCheckSignal(SIGTERM)) { _notifyDone.push(true); } } diff --git a/libstuff/SSignal.cpp b/libstuff/SSignal.cpp index cebb1a4ac..158536d7d 100644 --- a/libstuff/SSignal.cpp +++ b/libstuff/SSignal.cpp @@ -169,7 +169,6 @@ void _SSignal_signalHandlerThreadFunc() { } if (SSIGNAL_NOTIFY_INTERRUPT) { - cout << "Signal notification at: " << SCURRENT_TIMESTAMP_MS() << endl; static_cast*>(SSIGNAL_NOTIFY_INTERRUPT)->push(true); } } diff --git a/main.cpp b/main.cpp index dc0eecf86..f14683522 100644 --- a/main.cpp +++ b/main.cpp @@ -367,10 +367,6 @@ int main(int argc, char* argv[]) { const uint64_t now = STimeNow(); auto timeBeforePoll = chrono::steady_clock::now(); S_poll(fdm, max(nextActivity, now) - now); - bool terminated = SCheckSignal(SIGTERM); - if (terminated) { - cout << "main thread poll interrupted at " << SCURRENT_TIMESTAMP_MS() << " with SIGTERM set." << endl; - } nextActivity = STimeNow() + STIME_US_PER_S; // 1s max period auto timeAfterPoll = chrono::steady_clock::now(); server.postPoll(fdm, nextActivity); diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index d1609303a..421930386 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -238,7 +238,6 @@ string BedrockTester::startServer(bool wait) { cout << endl; exit(1); } else { - cout << "Begin startup at: " << SCURRENT_TIMESTAMP_MS() << endl; // We'll kill this later. _serverPID = childPID; @@ -271,7 +270,6 @@ string BedrockTester::startServer(bool wait) { SData status("Status"); auto result = executeWaitMultipleData({status}, 1, !wait); if (result[0].methodLine == "200 OK") { - cout << "End startup at: " << SCURRENT_TIMESTAMP_MS() << endl; return result[0].content; } // This will happen if the server's not up yet. We'll just try again. @@ -284,11 +282,9 @@ string BedrockTester::startServer(bool wait) { void BedrockTester::stopServer(int signal) { if (_serverPID) { - cout << "Begin shutdown at: " << SCURRENT_TIMESTAMP_MS() << endl; kill(_serverPID, signal); int status; waitpid(_serverPID, &status, 0); - cout << "End shutdown at: " << SCURRENT_TIMESTAMP_MS() << endl; _serverPID = 0; } } From 3ba3ce0061081afca2c8362d23ddf8f5ed41a023 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 19 Nov 2024 19:28:02 -0800 Subject: [PATCH 08/11] Use explicit namespace to avoid calling derived methods --- test/lib/BedrockTester.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index 421930386..d30542694 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -293,7 +293,7 @@ string BedrockTester::executeWaitVerifyContent(SData request, const string& expe uint64_t start = STimeNow(); vector results; do { - results = executeWaitMultipleData({request}, 1, control); + results = BedrockTester::executeWaitMultipleData({request}, 1, control); if (results.size() > 0 && SStartsWith(results[0].methodLine, expectedResult)) { // good, got the result we wanted @@ -608,7 +608,7 @@ bool BedrockTester::waitForStatusTerm(const string& term, const string& testValu uint64_t start = STimeNow(); while (STimeNow() < start + timeoutUS) { try { - string result = SParseJSONObject(executeWaitVerifyContent(SData("Status"), "200", true))[term]; + string result = SParseJSONObject(BedrockTester::executeWaitVerifyContent(SData("Status"), "200", true))[term]; // if the value matches, return, otherwise wait if (result == testValue) { From 638da12905d350e6f4ed4721cdfca93912733475 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Wed, 20 Nov 2024 07:40:41 -0800 Subject: [PATCH 09/11] Ignore clang tidy file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 367c42837..fa2fd8f26 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ libstuff/libstuff.d libstuff/libstuff.h.gch .idea .clangd +.clang-tidy .nfs* .cache compile_commands.json From b40c3958884746371b24df7246a8864f7d3a2c3f Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Wed, 20 Nov 2024 07:51:19 -0800 Subject: [PATCH 10/11] Revert HC-tree changes to merge test changes --- Makefile | 2 +- libstuff/sqlite3.c | 27808 ++++------------------------------- libstuff/sqlite3.h | 67 +- test/lib/BedrockTester.cpp | 2 +- 4 files changed, 2679 insertions(+), 25200 deletions(-) diff --git a/Makefile b/Makefile index a1737b23d..71a34084a 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ $(INTERMEDIATEDIR)/%.d $(INTERMEDIATEDIR)/%.o: %.cpp mbedtls/library/libmbedcryp # SQLITE_MAX_MMAP_SIZE is set to 16TB. $(INTERMEDIATEDIR)/%.o: %.c @mkdir -p $(dir $@) - $(CC) -g $(BEDROCK_OPTIM_COMPILE_FLAG) -fPIC $(AMALGAMATION_FLAGS) -o $@ -c $< + $(CC) $(BEDROCK_OPTIM_COMPILE_FLAG) -fPIC $(AMALGAMATION_FLAGS) -o $@ -c $< # Bring in the dependency files. This will cause them to be created if necessary. This is skipped if we're cleaning, as # they'll just get deleted anyway. diff --git a/libstuff/sqlite3.c b/libstuff/sqlite3.c index 64b8eca84..462558ad3 100644 --- a/libstuff/sqlite3.c +++ b/libstuff/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.48.0. By combining all the individual C code files into this +** version 3.47.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,11 +18,8 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** ed829bf2b069a48c644ae5706399dad7486e with changes in files: -** -** +** 35aa893d4537d0b3605084a1f2f5529794e8. */ -#ifndef SQLITE_AMALGAMATION #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE @@ -82,17 +79,6 @@ # define SQLITE_TCLAPI #endif -#define SQLITE_ENABLE_HCT 1 -#ifdef SQLITE_ENABLE_HCT -# define SQLITE_OMIT_SHARED_CACHE 1 -# define SQLITE_ENABLE_PREUPDATE_HOOK 1 -#endif - -#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS -# define SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS 1 -#endif -#define SQLITE_SHARED_MAPPING 1 - /* ** Include the header file used to customize the compiler options for MSVC. ** This should be done first so that it can successfully prevent spurious @@ -477,9 +463,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.48.0" -#define SQLITE_VERSION_NUMBER 3048000 -#define SQLITE_SOURCE_ID "2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc" +#define SQLITE_VERSION "3.47.0" +#define SQLITE_VERSION_NUMBER 3047000 +#define SQLITE_SOURCE_ID "2024-11-13 14:42:32 35aa893d4537d0b3605084a1f2f5529794e82af59b8893053815d3fcb4719a27" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -983,13 +969,6 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. -** -** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read -** from the database file in amounts that are not a multiple of the -** page size and that do not begin at a page boundary. Without this -** property, SQLite is careful to only do full-page reads and write -** on aligned pages, with the one exception that it will do a sub-page -** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -1006,7 +985,6 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 -#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -1153,7 +1131,6 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] -**
  • [SQLITE_IOCAP_SUBPAGE_READ] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1431,11 +1408,6 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** -**
  • [[SQLITE_FCNTL_NULL_IO]] -** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor -** or file handle for the [sqlite3_file] object such that it will no longer -** read or write to the database file. -** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1589,7 +1561,6 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 -#define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2968,14 +2939,10 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE, +** and that if the number of rows modified by the most recent INSERT, UPDATE ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. -** For the purposes of this interface, a CREATE TABLE AS SELECT statement -** does not count as an INSERT, UPDATE or DELETE statement and hence the rows -** added to the new table by the CREATE TABLE AS SELECT statement are not -** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -4572,17 +4539,13 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the -** first zero terminator. ^If nByte is positive, then it is the maximum -** number of bytes read from zSql. When nByte is positive, zSql is read -** up to the first zero terminator or until the nByte bytes have been read, -** whichever comes first. ^If nByte is zero, then no prepared +** first zero terminator. ^If nByte is positive, then it is the +** number of bytes read from zSql. ^If nByte is zero, then no prepared ** statement is generated. ** If the caller knows that the supplied string is nul-terminated, then ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. -** Note that nByte measure the length of the input in bytes, not -** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5953,7 +5916,7 @@ SQLITE_API int sqlite3_create_window_function( ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). -** All SQL functions that invoke [sqlite3_value_subtype()] should have this +** SQL functions that invokes [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. @@ -8718,9 +8681,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ -#define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 -#define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_USELONGDOUBLE 34 +#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -9695,16 +9657,6 @@ typedef struct sqlite3_backup sqlite3_backup; ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. -** -** Alternatives To Using The Backup API -** -** Other techniques for safely creating a consistent backup of an SQLite -** database include: -** -**
      -**
    • The [VACUUM INTO] command. -**
    • The [sqlite3_rsync] utility program. -**
    */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ @@ -10904,14 +10856,6 @@ typedef struct sqlite3_snapshot { ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** -** If a read-transaction is opened by this function, then it is guaranteed -** that the returned snapshot object may not be invalidated by a database -** writer or checkpointer until after the read-transaction is closed. This -** is not guaranteed if a read-transaction is already open when this -** function is called. In that case, any subsequent write or checkpoint -** operation on the database may invalidate the returned snapshot handle, -** even while the read-transaction remains open. -** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined @@ -11334,9 +11278,6 @@ SQLITE_API int sqlite3_commit_status( # undef double #endif -SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset); -SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); - #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 @@ -11351,7 +11292,7 @@ SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); #if 0 } /* End of the 'extern "C"' block */ #endif -/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ +#endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ /* @@ -13730,6 +13671,7 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting +** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -14073,7 +14015,6 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ -#endif /* SQLITE3_H */ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -14119,7 +14060,6 @@ struct fts5_api { #ifndef SQLITE_MAX_LENGTH # define SQLITE_MAX_LENGTH 1000000000 #endif -#define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */ /* ** This is the maximum number of @@ -14474,7 +14414,7 @@ struct fts5_api { ** which case memory allocation statistics are disabled by default. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) -# define SQLITE_DEFAULT_MEMSTATUS 0 +# define SQLITE_DEFAULT_MEMSTATUS 1 #endif /* @@ -14887,122 +14827,122 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_GE 59 #define TK_ESCAPE 60 #define TK_COLUMNKW 61 -#define TK_CONCURRENT 62 -#define TK_DO 63 -#define TK_FOR 64 -#define TK_IGNORE 65 -#define TK_INITIALLY 66 -#define TK_INSTEAD 67 -#define TK_NO 68 -#define TK_KEY 69 -#define TK_OF 70 -#define TK_OFFSET 71 -#define TK_PRAGMA 72 -#define TK_RAISE 73 -#define TK_RECURSIVE 74 -#define TK_REPLACE 75 -#define TK_RESTRICT 76 -#define TK_ROW 77 -#define TK_ROWS 78 -#define TK_TRIGGER 79 -#define TK_VACUUM 80 -#define TK_VIEW 81 -#define TK_VIRTUAL 82 -#define TK_WITH 83 -#define TK_NULLS 84 -#define TK_FIRST 85 -#define TK_LAST 86 -#define TK_CURRENT 87 -#define TK_FOLLOWING 88 -#define TK_PARTITION 89 -#define TK_PRECEDING 90 -#define TK_RANGE 91 -#define TK_UNBOUNDED 92 -#define TK_EXCLUDE 93 -#define TK_GROUPS 94 -#define TK_OTHERS 95 -#define TK_TIES 96 -#define TK_GENERATED 97 -#define TK_ALWAYS 98 -#define TK_MATERIALIZED 99 -#define TK_REINDEX 100 -#define TK_RENAME 101 -#define TK_CTIME_KW 102 -#define TK_ANY 103 -#define TK_BITAND 104 -#define TK_BITOR 105 -#define TK_LSHIFT 106 -#define TK_RSHIFT 107 -#define TK_PLUS 108 -#define TK_MINUS 109 -#define TK_STAR 110 -#define TK_SLASH 111 -#define TK_REM 112 -#define TK_CONCAT 113 -#define TK_PTR 114 -#define TK_COLLATE 115 -#define TK_BITNOT 116 -#define TK_ON 117 -#define TK_INDEXED 118 -#define TK_STRING 119 -#define TK_JOIN_KW 120 -#define TK_CONSTRAINT 121 -#define TK_DEFAULT 122 -#define TK_NULL 123 -#define TK_PRIMARY 124 -#define TK_UNIQUE 125 -#define TK_CHECK 126 -#define TK_REFERENCES 127 -#define TK_AUTOINCR 128 -#define TK_INSERT 129 -#define TK_DELETE 130 -#define TK_UPDATE 131 -#define TK_SET 132 -#define TK_DEFERRABLE 133 -#define TK_FOREIGN 134 -#define TK_DROP 135 -#define TK_UNION 136 -#define TK_ALL 137 -#define TK_EXCEPT 138 -#define TK_INTERSECT 139 -#define TK_SELECT 140 -#define TK_VALUES 141 -#define TK_DISTINCT 142 -#define TK_DOT 143 -#define TK_FROM 144 -#define TK_JOIN 145 -#define TK_USING 146 -#define TK_ORDER 147 -#define TK_GROUP 148 -#define TK_HAVING 149 -#define TK_LIMIT 150 -#define TK_WHERE 151 -#define TK_RETURNING 152 -#define TK_INTO 153 -#define TK_NOTHING 154 -#define TK_FLOAT 155 -#define TK_BLOB 156 -#define TK_INTEGER 157 -#define TK_VARIABLE 158 -#define TK_CASE 159 -#define TK_WHEN 160 -#define TK_THEN 161 -#define TK_ELSE 162 -#define TK_INDEX 163 -#define TK_ALTER 164 -#define TK_ADD 165 -#define TK_WINDOW 166 -#define TK_OVER 167 -#define TK_FILTER 168 -#define TK_COLUMN 169 -#define TK_AGG_FUNCTION 170 -#define TK_AGG_COLUMN 171 -#define TK_TRUEFALSE 172 -#define TK_FUNCTION 173 -#define TK_UPLUS 174 -#define TK_UMINUS 175 -#define TK_TRUTH 176 -#define TK_REGISTER 177 +#define TK_DO 62 +#define TK_FOR 63 +#define TK_IGNORE 64 +#define TK_INITIALLY 65 +#define TK_INSTEAD 66 +#define TK_NO 67 +#define TK_KEY 68 +#define TK_OF 69 +#define TK_OFFSET 70 +#define TK_PRAGMA 71 +#define TK_RAISE 72 +#define TK_RECURSIVE 73 +#define TK_REPLACE 74 +#define TK_RESTRICT 75 +#define TK_ROW 76 +#define TK_ROWS 77 +#define TK_TRIGGER 78 +#define TK_VACUUM 79 +#define TK_VIEW 80 +#define TK_VIRTUAL 81 +#define TK_WITH 82 +#define TK_NULLS 83 +#define TK_FIRST 84 +#define TK_LAST 85 +#define TK_CURRENT 86 +#define TK_FOLLOWING 87 +#define TK_PARTITION 88 +#define TK_PRECEDING 89 +#define TK_RANGE 90 +#define TK_UNBOUNDED 91 +#define TK_EXCLUDE 92 +#define TK_GROUPS 93 +#define TK_OTHERS 94 +#define TK_TIES 95 +#define TK_GENERATED 96 +#define TK_ALWAYS 97 +#define TK_MATERIALIZED 98 +#define TK_REINDEX 99 +#define TK_RENAME 100 +#define TK_CTIME_KW 101 +#define TK_ANY 102 +#define TK_BITAND 103 +#define TK_BITOR 104 +#define TK_LSHIFT 105 +#define TK_RSHIFT 106 +#define TK_PLUS 107 +#define TK_MINUS 108 +#define TK_STAR 109 +#define TK_SLASH 110 +#define TK_REM 111 +#define TK_CONCAT 112 +#define TK_PTR 113 +#define TK_COLLATE 114 +#define TK_BITNOT 115 +#define TK_ON 116 +#define TK_INDEXED 117 +#define TK_STRING 118 +#define TK_JOIN_KW 119 +#define TK_CONSTRAINT 120 +#define TK_DEFAULT 121 +#define TK_NULL 122 +#define TK_PRIMARY 123 +#define TK_UNIQUE 124 +#define TK_CHECK 125 +#define TK_REFERENCES 126 +#define TK_AUTOINCR 127 +#define TK_INSERT 128 +#define TK_DELETE 129 +#define TK_UPDATE 130 +#define TK_SET 131 +#define TK_DEFERRABLE 132 +#define TK_FOREIGN 133 +#define TK_DROP 134 +#define TK_UNION 135 +#define TK_ALL 136 +#define TK_EXCEPT 137 +#define TK_INTERSECT 138 +#define TK_SELECT 139 +#define TK_VALUES 140 +#define TK_DISTINCT 141 +#define TK_DOT 142 +#define TK_FROM 143 +#define TK_JOIN 144 +#define TK_USING 145 +#define TK_ORDER 146 +#define TK_GROUP 147 +#define TK_HAVING 148 +#define TK_LIMIT 149 +#define TK_WHERE 150 +#define TK_RETURNING 151 +#define TK_INTO 152 +#define TK_NOTHING 153 +#define TK_FLOAT 154 +#define TK_BLOB 155 +#define TK_INTEGER 156 +#define TK_VARIABLE 157 +#define TK_CASE 158 +#define TK_WHEN 159 +#define TK_THEN 160 +#define TK_ELSE 161 +#define TK_INDEX 162 +#define TK_ALTER 163 +#define TK_ADD 164 +#define TK_WINDOW 165 +#define TK_OVER 166 +#define TK_FILTER 167 +#define TK_COLUMN 168 +#define TK_AGG_FUNCTION 169 +#define TK_AGG_COLUMN 170 +#define TK_TRUEFALSE 171 +#define TK_FUNCTION 172 +#define TK_UPLUS 173 +#define TK_UMINUS 174 +#define TK_TRUTH 175 +#define TK_REGISTER 176 +#define TK_CONCURRENT 177 #define TK_VECTOR 178 #define TK_SELECT_COLUMN 179 #define TK_IF_NULL_ROW 180 @@ -15020,7 +14960,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #include #include #include -#include /* ** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY. @@ -15043,6 +14982,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define float sqlite_int64 # define fabs(X) ((X)<0?-(X):(X)) # define sqlite3IsOverflow(X) 0 +# define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif @@ -15217,6 +15157,9 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define INT8_TYPE signed char # endif #endif +#ifndef LONGDOUBLE_TYPE +# define LONGDOUBLE_TYPE long double +#endif typedef sqlite_int64 i64; /* 8-byte signed integer */ typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ @@ -16388,6 +16331,8 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); #endif +SQLITE_PRIVATE void sqlite3PagerSetCommitTime(Pager *pPager, u64 *aCommitTime); + #endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ @@ -16429,9 +16374,6 @@ SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); #define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ -typedef struct BtCursorMethods BtCursorMethods; -typedef struct BtreeMethods BtreeMethods; - /* ** Forward declarations of structure */ @@ -16639,9 +16581,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursor( ); SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(Btree*,BtCursor*); -#endif SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -16820,21 +16759,6 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif -#define BTREE_DIR_NONE 0 -#define BTREE_DIR_FORWARD 1 -#define BTREE_DIR_REVERSE 2 - -#ifdef SQLITE_ENABLE_HCT -SQLITE_PRIVATE void sqlite3BtreeCursorDir(BtCursor*, int eDir); -SQLITE_PRIVATE int sqlite3HctVtabInit(sqlite3*); -SQLITE_PRIVATE int sqlite3BtreeSchemaLoaded(Btree *pBt); -#else -# define sqlite3BtreeCursorDir(a,b) -# define sqlite3BtreeSchemaLoaded(x) SQLITE_OK -#endif - -SQLITE_PRIVATE int sqlite3BtreePragma(Btree *pBtree, char **aFnctl); -SQLITE_PRIVATE int sqlite3BtreeIdxDelete(BtCursor*, UnpackedRecord*); #endif /* SQLITE_BTREE_H */ @@ -17130,23 +17054,23 @@ typedef struct VdbeOpList VdbeOpList; #define OP_SetCookie 100 #define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 103 /* synopsis: root=P2 iDb=P3 */ -#define OP_BitAnd 104 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 105 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 106 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 108 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 109 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 110 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 111 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 112 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 113 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 107 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 108 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 109 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 110 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 111 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 112 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenDup 114 -#define OP_OpenAutoindex 115 /* synopsis: nColumn=P2 */ -#define OP_BitNot 116 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_BitNot 115 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */ #define OP_OpenEphemeral 117 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 118 -#define OP_String8 119 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_String8 118 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_SorterOpen 119 #define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ #define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */ #define OP_Close 122 @@ -17181,8 +17105,8 @@ typedef struct VdbeOpList VdbeOpList; #define OP_DropTable 151 #define OP_DropIndex 152 #define OP_DropTrigger 153 -#define OP_IntegrityCk 154 -#define OP_Real 155 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_Real 154 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_IntegrityCk 155 #define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */ #define OP_Param 157 #define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */ @@ -17243,14 +17167,14 @@ typedef struct VdbeOpList VdbeOpList; /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ /* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\ -/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x00,\ +/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x26, 0x26, 0x40, 0x40, 0x12, 0x40, 0x00, 0x10,\ +/* 112 */ 0x26, 0x00, 0x40, 0x12, 0x40, 0x40, 0x10, 0x00,\ /* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\ /* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\ /* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x10, 0x06, 0x10, 0x00, 0x04,\ +/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04,\ /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ /* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ @@ -17511,171 +17435,67 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr); #endif + +#define COMMIT_TIME_START 0 +#define COMMIT_TIME_BEFORE_HALT 1 +#define COMMIT_TIME_BEFORE_VDBECOMMIT 2 + +#define COMMIT_TIME_BEFORE_PHASEONE 3 +#define COMMIT_TIME_START_FIXUNLOCKED 4 +#define COMMIT_TIME_START_RELOCATE1 5 +#define COMMIT_TIME_START_RELOCATE2 6 + +#define COMMIT_TIME_OTHERWRITERS 7 +#define COMMIT_TIME_RELOCATE1COUNT 8 +#define COMMIT_TIME_RELOCATE2COUNT 9 + +#define COMMIT_TIME_RELOCATE2_READUS 10 +#define COMMIT_TIME_RELOCATE2_READCOUNT 11 +#define COMMIT_TIME_RELOCATE2_ALLOCATEUS 12 +#define COMMIT_TIME_RELOCATE2_RELOCATEUS 13 + +#define COMMIT_TIME_AFTER_FIXUNLOCKED 14 + +#define COMMIT_TIME_BEFORE_WALFRAMES 15 +#define COMMIT_TIME_AFTER_CHANGECOUNTER 16 +#define COMMIT_TIME_AFTER_RESTARTLOG 17 +#define COMMIT_TIME_AFTER_WRITEHDR 18 + +#define COMMIT_TIME_OSWRITE 19 + +#define COMMIT_TIME_AFTER_WRITEFRAMES 20 + +#define COMMIT_TIME_NFRAME 21 +#define COMMIT_TIME_HASHMAPUS 22 + +#define COMMIT_TIME_BEFORE_WALINDEX 23 +#define COMMIT_TIME_AFTER_WALINDEX 24 +#define COMMIT_TIME_AFTER_WALINDEXHDR 25 + +#define COMMIT_TIME_WALFRAMESFLAGS 26 + +#define COMMIT_TIME_AFTER_WALFRAMES 27 + +#define COMMIT_TIME_BEFORE_PHASETWO 28 +#define COMMIT_TIME_AFTER_PHASETWO 29 + +#define COMMIT_TIME_AFTER_VDBECOMMIT 30 +#define COMMIT_TIME_AFTER_HALT 31 +#define COMMIT_TIME_FINISH 32 + +#define COMMIT_TIME_N 33 + +/* #define COMMIT_TIME_TIMEOUT (2*1000*1000) */ +#define COMMIT_TIME_TIMEOUT (10*1000) /* 10ms threshold */ + +SQLITE_PRIVATE void sqlite3CommitTimeLog(u64*); +SQLITE_PRIVATE u64 sqlite3STimeNow(); +SQLITE_PRIVATE void sqlite3CommitTimeSet(u64*, int); + #endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ -/************** Include btreeModules.h in the middle of sqliteInt.h **********/ -/************** Begin file btreeModules.h ************************************/ -SQLITE_PRIVATE int sqlite3HctBtreeCursor(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); -SQLITE_PRIVATE sqlite3_uint64 sqlite3HctBtreeSeekCount(Btree*); -SQLITE_PRIVATE Pgno sqlite3HctBtreeLastPage(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeClose(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeSetCacheSize(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeSetSpillSize(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeSetMmapLimit(Btree*, sqlite3_int64); -SQLITE_PRIVATE int sqlite3HctBtreeSetPagerFlags(Btree*, unsigned); -SQLITE_PRIVATE int sqlite3HctBtreeSetPageSize(Btree*, int, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeGetPageSize(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeGetReserveNoMutex(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeGetRequestedReserve(Btree*); -SQLITE_PRIVATE Pgno sqlite3HctBtreeMaxPageCount(Btree*, Pgno); -SQLITE_PRIVATE int sqlite3HctBtreeSecureDelete(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeSetAutoVacuum(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeGetAutoVacuum(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeNewDb(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeBeginTrans(Btree*, int, int*); -SQLITE_PRIVATE int sqlite3HctBtreeIncrVacuum(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseOne(Btree*, const char*); -SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseTwo(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeCommit(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeTripAllCursors(Btree*, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeRollback(Btree*, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeBeginStmt(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeSavepoint(Btree*, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeCreateTable(Btree*, Pgno*, int); -SQLITE_PRIVATE int sqlite3HctBtreeClearTable(Btree*, int, i64*); -SQLITE_PRIVATE int sqlite3HctBtreeDropTable(Btree*, int, int*); -SQLITE_PRIVATE void sqlite3HctBtreeGetMeta(Btree*, int, u32*); -SQLITE_PRIVATE int sqlite3HctBtreeUpdateMeta(Btree*, int, u32); -SQLITE_PRIVATE int sqlite3HctBtreePragma(Btree*, char**); -SQLITE_PRIVATE Pager *sqlite3HctBtreePager(Btree*); -SQLITE_PRIVATE const char *sqlite3HctBtreeGetFilename(Btree*); -SQLITE_PRIVATE const char *sqlite3HctBtreeGetJournalname(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeTxnState(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeIsInBackup(Btree*); -SQLITE_PRIVATE void *sqlite3HctBtreeSchema(Btree*, int, void(*)(void *)); -SQLITE_PRIVATE int sqlite3HctBtreeSchemaLocked(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeIsReadonly(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeSetVersion(Btree*, int); -SQLITE_PRIVATE int sqlite3HctBtreeIntegrityCheck(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); -SQLITE_PRIVATE int sqlite3HctBtreeCheckpoint(Btree*, int, int *, int *); -SQLITE_PRIVATE int sqlite3HctBtreeExclusiveLock(Btree*); -SQLITE_PRIVATE int sqlite3HctBtreeNext(BtCursor*, int); -SQLITE_PRIVATE int sqlite3HctBtreeCursorHasMoved(BtCursor*); -SQLITE_PRIVATE void sqlite3HctBtreeClearCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreeCursorRestore(BtCursor*, int*); -SQLITE_PRIVATE void sqlite3HctBtreeCursorHintFlags(BtCursor*, unsigned); -SQLITE_PRIVATE int sqlite3HctBtreeCloseCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValid(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValidNN(BtCursor*); -SQLITE_PRIVATE i64 sqlite3HctBtreeIntegerKey(BtCursor*); -SQLITE_PRIVATE void sqlite3HctBtreeCursorPin(BtCursor*); -SQLITE_PRIVATE void sqlite3HctBtreeCursorUnpin(BtCursor*); -SQLITE_PRIVATE u32 sqlite3HctBtreePayloadSize(BtCursor*); -SQLITE_PRIVATE sqlite3_int64 sqlite3HctBtreeMaxRecordSize(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreePayload(BtCursor*, u32, u32, void*); -SQLITE_PRIVATE int sqlite3HctBtreePayloadChecked(BtCursor*, u32, u32, void *); -SQLITE_PRIVATE const void *sqlite3HctBtreePayloadFetch(BtCursor*, u32*); -SQLITE_PRIVATE int sqlite3HctBtreeFirst(BtCursor*, int*); -SQLITE_PRIVATE int sqlite3HctBtreeLast(BtCursor*, int*); -SQLITE_PRIVATE int sqlite3HctBtreeTableMoveto(BtCursor*, i64, int, int*); -SQLITE_PRIVATE int sqlite3HctBtreeIndexMoveto(BtCursor*, UnpackedRecord*, int*); -SQLITE_PRIVATE void sqlite3HctBtreeCursorDir(BtCursor*, int); -SQLITE_PRIVATE int sqlite3HctBtreeEof(BtCursor*); -SQLITE_PRIVATE i64 sqlite3HctBtreeRowCountEst(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreePrevious(BtCursor*, int); -SQLITE_PRIVATE int sqlite3HctBtreeInsert(BtCursor*, const BtreePayload*, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeDelete(BtCursor*, u8); -SQLITE_PRIVATE int sqlite3HctBtreeIdxDelete(BtCursor*, UnpackedRecord*); -SQLITE_PRIVATE int sqlite3HctBtreePutData(BtCursor*, u32, u32, void*); -SQLITE_PRIVATE void sqlite3HctBtreeIncrblobCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreeCursorHasHint(BtCursor*, unsigned int); -SQLITE_PRIVATE int sqlite3HctBtreeTransferRow(BtCursor*, BtCursor*, i64); -SQLITE_PRIVATE int sqlite3HctBtreeClearTableOfCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3HctBtreeCount(sqlite3*, BtCursor*, i64*); -SQLITE_PRIVATE int sqlite3StockBtreeCursor(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); -SQLITE_PRIVATE sqlite3_uint64 sqlite3StockBtreeSeekCount(Btree*); -SQLITE_PRIVATE Pgno sqlite3StockBtreeLastPage(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeClose(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeSetCacheSize(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeSetSpillSize(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeSetMmapLimit(Btree*, sqlite3_int64); -SQLITE_PRIVATE int sqlite3StockBtreeSetPagerFlags(Btree*, unsigned); -SQLITE_PRIVATE int sqlite3StockBtreeSetPageSize(Btree*, int, int, int); -SQLITE_PRIVATE int sqlite3StockBtreeGetPageSize(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeGetReserveNoMutex(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeGetRequestedReserve(Btree*); -SQLITE_PRIVATE Pgno sqlite3StockBtreeMaxPageCount(Btree*, Pgno); -SQLITE_PRIVATE int sqlite3StockBtreeSecureDelete(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeSetAutoVacuum(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeGetAutoVacuum(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeNewDb(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeBeginTrans(Btree*, int, int*); -SQLITE_PRIVATE int sqlite3StockBtreeIncrVacuum(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeCommitPhaseOne(Btree*, const char*); -SQLITE_PRIVATE int sqlite3StockBtreeCommitPhaseTwo(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeCommit(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeTripAllCursors(Btree*, int, int); -SQLITE_PRIVATE int sqlite3StockBtreeRollback(Btree*, int, int); -SQLITE_PRIVATE int sqlite3StockBtreeBeginStmt(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeSavepoint(Btree*, int, int); -SQLITE_PRIVATE int sqlite3StockBtreeCreateTable(Btree*, Pgno*, int); -SQLITE_PRIVATE int sqlite3StockBtreeClearTable(Btree*, int, i64*); -SQLITE_PRIVATE int sqlite3StockBtreeDropTable(Btree*, int, int*); -SQLITE_PRIVATE void sqlite3StockBtreeGetMeta(Btree*, int, u32*); -SQLITE_PRIVATE int sqlite3StockBtreeUpdateMeta(Btree*, int, u32); -SQLITE_PRIVATE int sqlite3StockBtreePragma(Btree*, char**); -SQLITE_PRIVATE Pager *sqlite3StockBtreePager(Btree*); -SQLITE_PRIVATE const char *sqlite3StockBtreeGetFilename(Btree*); -SQLITE_PRIVATE const char *sqlite3StockBtreeGetJournalname(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeTxnState(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeIsInBackup(Btree*); -SQLITE_PRIVATE void *sqlite3StockBtreeSchema(Btree*, int, void(*)(void *)); -SQLITE_PRIVATE int sqlite3StockBtreeSchemaLocked(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeIsReadonly(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeSetVersion(Btree*, int); -SQLITE_PRIVATE int sqlite3StockBtreeIntegrityCheck(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); -SQLITE_PRIVATE int sqlite3StockBtreeCheckpoint(Btree*, int, int *, int *); -SQLITE_PRIVATE int sqlite3StockBtreeExclusiveLock(Btree*); -SQLITE_PRIVATE int sqlite3StockBtreeNext(BtCursor*, int); -SQLITE_PRIVATE int sqlite3StockBtreeCursorHasMoved(BtCursor*); -SQLITE_PRIVATE void sqlite3StockBtreeClearCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreeCursorRestore(BtCursor*, int*); -SQLITE_PRIVATE void sqlite3StockBtreeCursorHintFlags(BtCursor*, unsigned); -SQLITE_PRIVATE int sqlite3StockBtreeCloseCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValid(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValidNN(BtCursor*); -SQLITE_PRIVATE i64 sqlite3StockBtreeIntegerKey(BtCursor*); -SQLITE_PRIVATE void sqlite3StockBtreeCursorPin(BtCursor*); -SQLITE_PRIVATE void sqlite3StockBtreeCursorUnpin(BtCursor*); -SQLITE_PRIVATE u32 sqlite3StockBtreePayloadSize(BtCursor*); -SQLITE_PRIVATE sqlite3_int64 sqlite3StockBtreeMaxRecordSize(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreePayload(BtCursor*, u32, u32, void*); -SQLITE_PRIVATE int sqlite3StockBtreePayloadChecked(BtCursor*, u32, u32, void *); -SQLITE_PRIVATE const void *sqlite3StockBtreePayloadFetch(BtCursor*, u32*); -SQLITE_PRIVATE int sqlite3StockBtreeFirst(BtCursor*, int*); -SQLITE_PRIVATE int sqlite3StockBtreeLast(BtCursor*, int*); -SQLITE_PRIVATE int sqlite3StockBtreeTableMoveto(BtCursor*, i64, int, int*); -SQLITE_PRIVATE int sqlite3StockBtreeIndexMoveto(BtCursor*, UnpackedRecord*, int*); -SQLITE_PRIVATE void sqlite3StockBtreeCursorDir(BtCursor*, int); -SQLITE_PRIVATE int sqlite3StockBtreeEof(BtCursor*); -SQLITE_PRIVATE i64 sqlite3StockBtreeRowCountEst(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreePrevious(BtCursor*, int); -SQLITE_PRIVATE int sqlite3StockBtreeInsert(BtCursor*, const BtreePayload*, int, int); -SQLITE_PRIVATE int sqlite3StockBtreeDelete(BtCursor*, u8); -SQLITE_PRIVATE int sqlite3StockBtreeIdxDelete(BtCursor*, UnpackedRecord*); -SQLITE_PRIVATE int sqlite3StockBtreePutData(BtCursor*, u32, u32, void*); -SQLITE_PRIVATE void sqlite3StockBtreeIncrblobCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreeCursorHasHint(BtCursor*, unsigned int); -SQLITE_PRIVATE int sqlite3StockBtreeTransferRow(BtCursor*, BtCursor*, i64); -SQLITE_PRIVATE int sqlite3StockBtreeClearTableOfCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3StockBtreeCount(sqlite3*, BtCursor*, i64*); -SQLITE_PRIVATE BtCursor *sqlite3StockBtreeFakeValidCursor(void); - - -/************** End of btreeModules.h ****************************************/ -/************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ /* @@ -18155,11 +17975,47 @@ struct FuncDefHash { }; #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) +#if defined(SQLITE_USER_AUTHENTICATION) +# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \ + See ext/userauth/user-auth.txt for details." +#endif +#ifdef SQLITE_USER_AUTHENTICATION +/* +** Information held in the "sqlite3" database connection object and used +** to manage user authentication. +*/ +typedef struct sqlite3_userauth sqlite3_userauth; +struct sqlite3_userauth { + u8 authLevel; /* Current authentication level */ + int nAuthPW; /* Size of the zAuthPW in bytes */ + char *zAuthPW; /* Password used to authenticate */ + char *zAuthUser; /* User name used to authenticate */ +}; + +/* Allowed values for sqlite3_userauth.authLevel */ +#define UAUTH_Unknown 0 /* Authentication not yet checked */ +#define UAUTH_Fail 1 /* User authentication failed */ +#define UAUTH_User 2 /* Authenticated as a normal user */ +#define UAUTH_Admin 3 /* Authenticated as an administrator */ + +/* Functions used only by user authorization logic */ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); +SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); +SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); +SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); + +#endif /* SQLITE_USER_AUTHENTICATION */ + /* ** typedef for the authorization callback function. */ -typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, - const char*); +#ifdef SQLITE_USER_AUTHENTICATION + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*, const char*); +#else + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); +#endif #ifndef SQLITE_OMIT_DEPRECATED /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing @@ -18322,6 +18178,9 @@ struct sqlite3 { void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif +#ifdef SQLITE_USER_AUTHENTICATION + sqlite3_userauth auth; /* User authentication information */ +#endif #ifndef SQLITE_OMIT_CONCURRENT /* Return values for sqlite3_commit_status() requests: ** SQLITE_COMMIT_CONFLICT_DB, CONFLICT_FRAME and CONFLICT_PGNO. @@ -18329,16 +18188,56 @@ struct sqlite3 { u32 aCommit[5]; #endif - /* Used as part of testing hctree commits */ - void (*xMtCommit)(void*, int); - void *pMtCommitCtx; + u64 *aPrepareTime; + u64 *aSchemaTime; +}; + +#define PREPARE_TIME_START 0 +#define PREPARE_TIME_BEGINPARSE 1 +#define PREPARE_TIME_BEGINPRAGMA 2 + +#define PREPARE_TIME_BEGINAUTHCHECK 3 +#define PREPARE_TIME_ENDAUTHCHECK 4 +#define PREPARE_TIME_BEGINLOADSCHEMA 5 +#define PREPARE_TIME_ENDLOADSCHEMA 6 + + +#define PREPARE_TIME_BEGINCACHESIZE 7 +#define PREPARE_TIME_BEGINSETCACHESIZE 8 +#define PREPARE_TIME_ENDSETCACHESIZE 9 +#define PREPARE_TIME_ENDCACHESIZE 10 +#define PREPARE_TIME_ENDPRAGMA 11 +#define PREPARE_TIME_ENDPARSE 12 +#define PREPARE_TIME_FINISH 13 + +#define PREPARE_TIME_N 14 - /* The sqlite3_hct_journal_validation_hook() callback */ - void *pValidateArg; - int (*xValidate)(void*, i64, const char*, const void*, int, i64); - int bHctMigrate; -}; + +#define SCHEMA_TIME_START 0 +#define SCHEMA_TIME_AFTER_CREATE_1 1 +#define SCHEMA_TIME_AFTER_OPEN_TRANS 2 +#define SCHEMA_TIME_AFTER_GET_META 3 +#define SCHEMA_TIME_AFTER_FIX_ENCODING 4 +#define SCHEMA_TIME_AFTER_SETCACHESIZE 5 +#define SCHEMA_TIME_BEGIN_EXEC 6 +#define SCHEMA_TIME_BEFORE_STEP 7 +#define SCHEMA_TIME_BEFORE_PREPARE 8 +#define SCHEMA_TIME_BEFORE_FINALIZE 9 +#define SCHEMA_TIME_BEGIN_ANALYZE_LOAD 10 +#define SCHEMA_TIME_END_ANALYZE_LOAD 11 +#define SCHEMA_TIME_FINISH 12 + +#define SCHEMA_TIME_N 13 +#define SCHEMA_TIME_TIMEOUT (2 * 1000 * 1000) + + + +#define sqlite3PrepareTimeSet(x,y) sqlite3CommitTimeSet(x,y) +SQLITE_PRIVATE void sqlite3PrepareTimeLog(const char *zSql, int nSql, u64 *aPrepareTime); +SQLITE_PRIVATE void sqlite3SchemaTimeLog(u64 *aSchemaTime); + +#define PREPARE_TIME_TIMEOUT (2 * 1000 * 1000) /* 2 second timeout */ /* @@ -19191,7 +19090,6 @@ struct FKey { struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ - u16 nUniqField; u16 nKeyField; /* Number of key columns in the index */ u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ @@ -19646,7 +19544,7 @@ struct Expr { #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ -#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */ + /* 0x80000000 // Available */ /* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. @@ -20202,7 +20100,7 @@ struct Select { ** row of result as the key in table pDest->iSDParm. ** Apply the affinity pDest->affSdst before storing ** results. if pDest->iSDParm2 is positive, then it is -** a register holding a Bloom filter for the IN operator +** a regsiter holding a Bloom filter for the IN operator ** that should be populated in addition to the ** pDest->iSDParm table. This SRT is used to ** implement "IN (SELECT ...)". @@ -20801,6 +20699,7 @@ struct Sqlite3Config { u8 bUseCis; /* Use covering indices for full-scans */ u8 bSmallMalloc; /* Avoid large memory allocations if true */ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ + u8 bUseLongDouble; /* Make use of long double */ #ifdef SQLITE_DEBUG u8 bJsonSelfcheck; /* Double-check JSON parsing */ #endif @@ -21175,6 +21074,15 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_ENABLE_FTS3 1 #endif +/* +** The ctype.h header is needed for non-ASCII systems. It is also +** needed by FTS3 when FTS3 is included in the amalgamation. +*/ +#if !defined(SQLITE_ASCII) || \ + (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION)) +# include +#endif + /* ** The following macros mimic the standard library functions toupper(), ** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The @@ -21798,7 +21706,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 -SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar); +SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); #endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); @@ -22381,11 +22289,6 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void); # define IS_STMT_SCANSTATUS(db) 0 #endif -#ifdef SQLITE_ENABLE_HCT -SQLITE_PRIVATE int sqlite3IsHct(Btree*); -SQLITE_PRIVATE int sqlite3HctSchemaOp(Btree*, const char*); -#endif - #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ @@ -23261,6 +23164,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif +#ifdef SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif @@ -23537,6 +23443,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ 0, /* bSmallMalloc */ 1, /* bExtraSchemaChecks */ + sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */ #ifdef SQLITE_DEBUG 0, /* bJsonSelfcheck */ #endif @@ -24230,6 +24137,7 @@ struct Vdbe { int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif + u64 *aCommitTime; }; /* @@ -24256,11 +24164,9 @@ struct PreUpdate { int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ - Mem oldipk; /* Memory cell holding "old" IPK value */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ - sqlite3_value **apDflt; /* Array of default values, if required */ }; /* @@ -29706,29 +29612,16 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. -** -** Because these routines raise false-positive alerts in TSAN, disable -** them (make them always return 1) when compiling with TSAN. */ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ -# if defined(__has_feature) -# if __has_feature(thread_sanitizer) - p = 0; -# endif -# endif assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ -# if defined(__has_feature) -# if __has_feature(thread_sanitizer) - p = 0; -# endif -# endif assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } -#endif /* NDEBUG */ +#endif #endif /* !defined(SQLITE_MUTEX_OMIT) */ @@ -33085,7 +32978,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ + char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -35143,7 +35036,7 @@ static const unsigned char sqlite3Utf8Trans1[] = { c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ - while( zIn=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2; + if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2; n++; } return (int)(z-(unsigned char const *)zIn) @@ -36117,8 +36008,6 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ - double rr[2]; - u64 s2; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -36230,41 +36119,68 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en e++; } - rr[0] = (double)s; - s2 = (u64)rr[0]; -#if defined(_MSC_VER) && _MSC_VER<1700 - if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } + if( e==0 ){ + *pResult = s; + }else if( sqlite3Config.bUseLongDouble ){ + LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s; + if( e>0 ){ + while( e>=100 ){ e-=100; r *= 1.0e+100L; } + while( e>=10 ){ e-=10; r *= 1.0e+10L; } + while( e>=1 ){ e-=1; r *= 1.0e+01L; } + }else{ + while( e<=-100 ){ e+=100; r *= 1.0e-100L; } + while( e<=-10 ){ e+=10; r *= 1.0e-10L; } + while( e<=-1 ){ e+=1; r *= 1.0e-01L; } + } + assert( r>=0.0 ); + if( r>+1.7976931348623157081452742373e+308L ){ +#ifdef INFINITY + *pResult = +INFINITY; +#else + *pResult = 1.0e308*10.0; #endif - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); - if( e>0 ){ - while( e>=100 ){ - e -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( e>=10 ){ - e -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( e>=1 ){ - e -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); + }else{ + *pResult = (double)r; } }else{ - while( e<=-100 ){ - e += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( e<=-10 ){ - e += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( e<=-1 ){ - e += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); + double rr[2]; + u64 s2; + rr[0] = (double)s; + s2 = (u64)rr[0]; +#if defined(_MSC_VER) && _MSC_VER<1700 + if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } +#endif + rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); + if( e>0 ){ + while( e>=100 ){ + e -= 100; + dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); + } + while( e>=10 ){ + e -= 10; + dekkerMul2(rr, 1.0e+10, 0.0); + } + while( e>=1 ){ + e -= 1; + dekkerMul2(rr, 1.0e+01, 0.0); + } + }else{ + while( e<=-100 ){ + e += 100; + dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); + } + while( e<=-10 ){ + e += 10; + dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); + } + while( e<=-1 ){ + e += 1; + dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); + } } + *pResult = rr[0]+rr[1]; + if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; if( sign<0 ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); @@ -36585,10 +36501,9 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou int i; u64 v; int e, exp = 0; - double rr[2]; - p->isSpecial = 0; p->z = p->zBuf; + assert( mxRound>0 ); /* Convert negative numbers to positive. Deal with Infinity, 0.0, and @@ -36616,45 +36531,62 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou /* Multiply r by powers of ten until it lands somewhere in between ** 1.0e+19 and 1.0e+17. - ** - ** Use Dekker-style double-double computation to increase the - ** precision. - ** - ** The error terms on constants like 1.0e+100 computed using the - ** decimal extension, for example as follows: - ** - ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); */ - rr[0] = r; - rr[1] = 0.0; - if( rr[0]>9.223372036854774784e+18 ){ - while( rr[0]>9.223372036854774784e+118 ){ - exp += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( rr[0]>9.223372036854774784e+28 ){ - exp += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( rr[0]>9.223372036854774784e+18 ){ - exp += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); + if( sqlite3Config.bUseLongDouble ){ + LONGDOUBLE_TYPE rr = r; + if( rr>=1.0e+19 ){ + while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; } + while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; } + while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; } + }else{ + while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; } + while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; } + while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; } } + v = (u64)rr; }else{ - while( rr[0]<9.223372036854774784e-83 ){ - exp -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( rr[0]<9.223372036854774784e+07 ){ - exp -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( rr[0]<9.22337203685477478e+17 ){ - exp -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); + /* If high-precision floating point is not available using "long double", + ** then use Dekker-style double-double computation to increase the + ** precision. + ** + ** The error terms on constants like 1.0e+100 computed using the + ** decimal extension, for example as follows: + ** + ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); + */ + double rr[2]; + rr[0] = r; + rr[1] = 0.0; + if( rr[0]>9.223372036854774784e+18 ){ + while( rr[0]>9.223372036854774784e+118 ){ + exp += 100; + dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); + } + while( rr[0]>9.223372036854774784e+28 ){ + exp += 10; + dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); + } + while( rr[0]>9.223372036854774784e+18 ){ + exp += 1; + dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); + } + }else{ + while( rr[0]<9.223372036854774784e-83 ){ + exp -= 100; + dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); + } + while( rr[0]<9.223372036854774784e+07 ){ + exp -= 10; + dekkerMul2(rr, 1.0e+10, 0.0); + } + while( rr[0]<9.22337203685477478e+17 ){ + exp -= 1; + dekkerMul2(rr, 1.0e+01, 0.0); + } } + v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; } - v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; + /* Extract significant digits. */ i = sizeof(p->zBuf)-1; @@ -37425,6 +37357,104 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam return 0; } +/* +** High-resolution hardware timer used for debugging and testing only. +*/ +#if defined(VDBE_PROFILE) \ + || defined(SQLITE_PERFORMANCE_TRACE) \ + || defined(SQLITE_ENABLE_STMT_SCANSTATUS) +/************** Include hwtime.h in the middle of util.c *********************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 and x86_64 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on Pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if !defined(__STRICT_ANSI__) && \ + (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + /* + ** asm() is needed for hardware timing support. Without asm(), + ** disable the sqlite3Hwtime() routine. + ** + ** sqlite3Hwtime() is only used for some obscure debugging + ** and analysis configurations, not in any deliverable, so this + ** should not be a great loss. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in util.c ***********************/ +#endif + /************** End of util.c ************************************************/ /************** Begin file hash.c ********************************************/ /* @@ -37815,23 +37845,23 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 100 */ "SetCookie" OpHelp(""), /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 103 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 104 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 105 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 106 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 108 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 109 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 110 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 111 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 112 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 113 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 107 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 108 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 109 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 110 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 111 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 112 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), /* 114 */ "OpenDup" OpHelp(""), - /* 115 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 116 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 115 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"), /* 117 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 118 */ "SorterOpen" OpHelp(""), - /* 119 */ "String8" OpHelp("r[P2]='P4'"), + /* 118 */ "String8" OpHelp("r[P2]='P4'"), + /* 119 */ "SorterOpen" OpHelp(""), /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), /* 122 */ "Close" OpHelp(""), @@ -37866,8 +37896,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 151 */ "DropTable" OpHelp(""), /* 152 */ "DropIndex" OpHelp(""), /* 153 */ "DropTrigger" OpHelp(""), - /* 154 */ "IntegrityCk" OpHelp(""), - /* 155 */ "Real" OpHelp("r[P2]=P4"), + /* 154 */ "Real" OpHelp("r[P2]=P4"), + /* 155 */ "IntegrityCk" OpHelp(""), /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), /* 157 */ "Param" OpHelp(""), /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), @@ -39116,7 +39146,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ # endif #else /* !SQLITE_WASI */ # ifndef HAVE_FCHMOD -# define HAVE_FCHMOD 1 +# define HAVE_FCHMOD # endif #endif /* SQLITE_WASI */ @@ -41386,33 +41416,54 @@ static int robust_flock(int fd, int op){ ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ -#ifdef SQLITE_DEBUG + int rc = SQLITE_OK; + int reserved = 0; unixFile *pFile = (unixFile*)id; -#else - UNUSED_PARAMETER(id); -#endif SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); - assert( pFile->eFileLock<=SHARED_LOCK ); - /* The flock VFS only ever takes exclusive locks (see function flockLock). - ** Therefore, if this connection is holding any lock at all, no other - ** connection may be holding a RESERVED lock. So set *pResOut to 0 - ** in this case. - ** - ** Or, this connection may be holding no lock. In that case, set *pResOut to - ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the - ** db in order to roll the hot journal back. If there is another connection - ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to - ** the user. With other VFS, we try to avoid this, in order to allow a reader - ** to proceed while a writer is preparing its transaction. But that won't - ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is - ** not a problem in this case. */ - *pResOut = 0; + /* Check if a thread in this process holds such a lock */ + if( pFile->eFileLock>SHARED_LOCK ){ + reserved = 1; + } - return SQLITE_OK; + /* Otherwise see if some other process holds it. */ + if( !reserved ){ + /* attempt to get the lock */ + int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); + if( !lrc ){ + /* got the lock, unlock it */ + lrc = robust_flock(pFile->h, LOCK_UN); + if ( lrc ) { + int tErrno = errno; + /* unlock failed with an error */ + lrc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, tErrno); + rc = lrc; + } + } else { + int tErrno = errno; + reserved = 1; + /* someone else might have it reserved */ + lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if( IS_LOCK_ERROR(lrc) ){ + storeLastErrno(pFile, tErrno); + rc = lrc; + } + } + } + OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); + +#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS + if( (rc & 0xff) == SQLITE_IOERR ){ + rc = SQLITE_OK; + reserved=1; + } +#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ + *pResOut = reserved; + return rc; } /* @@ -42909,11 +42960,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ - case SQLITE_FCNTL_NULL_IO: { - osClose(pFile->h); - pFile->h = -1; - return SQLITE_OK; - } case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -43018,7 +43064,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ -#ifndef SQLITE_OMIT_WAL case SQLITE_FCNTL_EXTERNAL_READER: { #if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) return unixFcntlExternalReader((unixFile*)id, (int*)pArg); @@ -43027,7 +43072,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; #endif } -#endif } return SQLITE_NOTFOUND; } @@ -43060,7 +43104,6 @@ static void setDeviceCharacteristics(unixFile *pFd){ if( pFd->ctrlFlags & UNIXFILE_PSOW ){ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; } - pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ; pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } @@ -43111,7 +43154,7 @@ static void setDeviceCharacteristics(unixFile *pFile){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ - (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) | + ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; @@ -43119,7 +43162,7 @@ static void setDeviceCharacteristics(unixFile *pFile){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ - (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) | + ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; @@ -50954,11 +50997,6 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; } #endif - case SQLITE_FCNTL_NULL_IO: { - (void)osCloseHandle(pFile->h); - pFile->h = NULL; - return SQLITE_OK; - } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); @@ -51020,7 +51058,7 @@ static int winSectorSize(sqlite3_file *id){ */ static int winDeviceCharacteristics(sqlite3_file *id){ winFile *p = (winFile*)id; - return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ | + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } @@ -56982,7 +57020,13 @@ static void pcache1Unpin( assert( PAGE_IS_PINNED(pPage) ); if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ + /* If pcache1.separateCache is set, temporarily set the isBulkLocal flag + ** so that pcache1RemoveFromHash() moves the page buffer to the pFree + ** list instead of sqlite3_free()ing it. */ + u16 isBulkLocal = pPage->isBulkLocal; + pPage->isBulkLocal = (u16)pcache1.separateCache; pcache1RemoveFromHash(pPage, 1); + pPage->isBulkLocal = isBulkLocal; }else{ /* Add the page to the PGroup LRU list. */ PgHdr1 **ppFirst = &pGroup->lru.pLruNext; @@ -57884,17 +57928,14 @@ SQLITE_PRIVATE int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); /* sqlite3_wal_info() data */ SQLITE_PRIVATE int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); +SQLITE_PRIVATE void sqlite3WalSetCommitTime(Wal *pWal, u64 *aCommitTime); + #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ -#ifdef SQLITE_ENABLE_HCT -# define IS_HCT(pPager) (pPager->pVfs==0) -#else -# define IS_HCT(pPager) 0 -#endif /******************* NOTES ON THE DESIGN OF THE PAGER ************************ ** @@ -58576,6 +58617,7 @@ struct Pager { Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif + u64 *aCommitTime; }; /* @@ -58670,28 +58712,20 @@ static const unsigned char aJournalMagic[] = { ** Return true if page pgno can be read directly from the database file ** by the b-tree layer. This is the case if: ** -** (1) the database file is open -** (2) the VFS for the database is able to do unaligned sub-page reads -** (3) there are no dirty pages in the cache, and -** (4) the desired page is not currently in the wal file. +** * the database file is open, +** * there are no dirty pages in the cache, and +** * the desired page is not currently in the wal file. */ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ - assert( pPager!=0 ); - assert( pPager->fd!=0 ); - if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */ - if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */ + if( pPager->fd->pMethods==0 ) return 0; + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return iRead==0; /* Condition (4) */ + return iRead==0; } #endif - assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); - if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) - & SQLITE_IOCAP_SUBPAGE_READ)==0 ){ - return 0; /* Case (2) */ - } return 1; } #endif @@ -60931,6 +60965,7 @@ static int pager_playback(Pager *pPager, int isHot){ static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ int rc = SQLITE_OK; /* Return code */ + u64 t1 = 0; #ifndef SQLITE_OMIT_WAL u32 iFrame = 0; /* Frame of WAL containing pgno */ @@ -60942,6 +60977,9 @@ static int readDbPage(PgHdr *pPg){ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); if( rc ) return rc; } + if( pPager->aCommitTime ){ + t1 = sqlite3STimeNow(); + } if( iFrame ){ rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData); }else @@ -60953,6 +60991,10 @@ static int readDbPage(PgHdr *pPg){ rc = SQLITE_OK; } } + if( pPager->aCommitTime ){ + pPager->aCommitTime[COMMIT_TIME_RELOCATE2_READUS] += (sqlite3STimeNow() - t1); + pPager->aCommitTime[COMMIT_TIME_RELOCATE2_READCOUNT]++; + } if( pPg->pgno==1 ){ if( rc ){ @@ -61144,6 +61186,7 @@ static int pagerWalFrames( pPager->aStat[PAGER_STAT_WRITE] += nList; if( pList->pgno==1 ) pager_write_changecounter(pList); + sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_AFTER_CHANGECOUNTER); rc = sqlite3WalFrames(pPager->pWal, pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags ); @@ -64384,7 +64427,6 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){ */ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager, PgHdr *pPage1, u32 *aConflict){ int rc = pPager->errCode; - if( IS_HCT(pPager) ) return SQLITE_OK; assert( assert_pager_state(pPager) ); if( rc==SQLITE_OK ){ assert( pPager->eState==PAGER_WRITER_CACHEMOD @@ -64535,7 +64577,9 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( } assert( rc==SQLITE_OK ); if( ALWAYS(pList) ){ + sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_BEFORE_WALFRAMES); rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); + sqlite3CommitTimeSet(pPager->aCommitTime, COMMIT_TIME_AFTER_WALFRAMES); } sqlite3PagerUnref(pPageOne); if( rc==SQLITE_OK ){ @@ -64709,6 +64753,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( return rc; } +SQLITE_PRIVATE void sqlite3PagerSetCommitTime(Pager *pPager, u64 *aCommitTime){ + pPager->aCommitTime = aCommitTime; + sqlite3WalSetCommitTime(pPager->pWal, aCommitTime); +} /* ** When this function is called, the database file has been completely @@ -65133,10 +65181,6 @@ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ ** not yet been opened. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ -#ifdef SQLITE_ENABLE_HCT - static sqlite3_file s = {0}; - if( pPager->pVfs==0 ) return &s; -#endif return pPager->fd; } @@ -65492,7 +65536,6 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){ ** is unmodified. */ SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ - if( IS_HCT(pPager) ) return 0; assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0; if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0; @@ -65918,7 +65961,7 @@ SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ ** 28: Checksum-2 (second part of checksum for first 24 bytes of header). ** ** Immediately following the wal-header are zero or more frames. Each -** frame consists of a 24-byte frame-header followed by bytes +** frame consists of a 24-byte frame-header followed by a bytes ** of page data. The frame-header is six big-endian 32-bit unsigned ** integer values, as follows: ** @@ -66678,13 +66721,13 @@ struct Wal { #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ - int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */ #endif int bClosing; /* Set to true at start of sqlite3WalClose() */ int bWal2; /* bWal2 flag passed to WalOpen() */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3 *db; #endif + u64 *aCommitTime; }; /* @@ -66939,7 +66982,14 @@ static int walIndexPage( ){ SEH_INJECT_FAULT; if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){ - return walIndexPageRealloc(pWal, iPage, ppPage); + int rc; + u64 t1; + if( pWal->aCommitTime ) t1 = sqlite3STimeNow(); + rc = walIndexPageRealloc(pWal, iPage, ppPage); + if( pWal->aCommitTime ){ + pWal->aCommitTime[COMMIT_TIME_HASHMAPUS] += sqlite3STimeNow() - t1; + } + return rc; } return SQLITE_OK; } @@ -68921,7 +68971,7 @@ static int walHandleException(Wal *pWal){ /* ** Assert that the Wal.lockMask mask, which indicates the locks held -** by the connection, is consistent with the Wal.readLock, Wal.writeLock +** by the connenction, is consistent with the Wal.readLock, Wal.writeLock ** and Wal.ckptLock variables. To be used as: ** ** assert( walAssertLockmask(pWal) ); @@ -69640,7 +69690,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ u32 mxFrame; /* Wal frame to lock to */ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT - && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0) + && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0) #endif ){ /* The WAL has been completely backfilled (or it is empty). @@ -70922,6 +70972,7 @@ static int walWriteToLog( sqlite3_int64 iOffset /* Start writing at this offset */ ){ int rc; + u64 t; if( iOffsetiSyncPoint && iOffset+iAmt>=p->iSyncPoint ){ int iFirstAmt = (int)(p->iSyncPoint - iOffset); rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset); @@ -70933,7 +70984,13 @@ static int walWriteToLog( rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } + if( p->pWal->aCommitTime ){ + t = sqlite3STimeNow(); + } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); + if( p->pWal->aCommitTime ){ + p->pWal->aCommitTime[COMMIT_TIME_OSWRITE] += (sqlite3STimeNow() - t); + } return rc; } @@ -71048,6 +71105,9 @@ static int walFrames( WalIndexHdr *pLive; /* Pointer to shared header */ int iApp; int bWal2 = isWalMode2(pWal); + int nFrame = 0; + + int logFlags = 0; assert( pList ); assert( pWal->writeLock ); @@ -71069,6 +71129,8 @@ static int walFrames( return rc; } + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_RESTARTLOG); + /* If this is the first frame written into the log, write the WAL ** header to the start of the WAL file. See comments at the top of ** this source file for a description of the WAL header format. @@ -71084,6 +71146,7 @@ static int walFrames( } #endif + logFlags |= (iFrame==0 ? 0x01 : 0x00); if( iFrame==0 ){ u32 iCkpt = 0; u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ @@ -71137,6 +71200,7 @@ static int walFrames( if( (int)pWal->szPage!=szPage ){ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */ } + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WRITEHDR); /* Setup information needed to write frames into the WAL */ w.pWal = pWal; @@ -71148,6 +71212,7 @@ static int walFrames( szFrame = szPage + WAL_FRAME_HDRSIZE; /* Write all frames into the log file exactly once */ + logFlags |= (iFirst==0 ? 0x00 : 0x02); for(p=pList; p; p=p->pDirty){ int nDbSize; /* 0 normally. Positive == commit flag */ @@ -71186,8 +71251,10 @@ static int walFrames( p->flags |= PGHDR_WAL_APPEND; } + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WRITEFRAMES); /* Recalculate checksums within the wal file if required. */ + logFlags |= (pWal->iReCksum==0 ? 0x00 : 0x04); if( isCommit && pWal->iReCksum ){ rc = walRewriteChecksums(pWal, iFrame); if( rc ) return rc; @@ -71207,6 +71274,7 @@ static int walFrames( ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ + logFlags |= (WAL_SYNC_FLAGS(sync_flags)==0 ? 0x00 : 0x08); if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ @@ -71241,6 +71309,8 @@ static int walFrames( pWal->truncateOnCommit = 0; } + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_BEFORE_WALINDEX); + /* Append data to the wal-index. It is not necessary to lock the ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index ** guarantees that there are no other writers, and no data that may @@ -71251,6 +71321,7 @@ static int walFrames( if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iApp, iFrame, p->pgno); + nFrame++; } assert( pLast!=0 || nExtra==0 ); while( rc==SQLITE_OK && nExtra>0 ){ @@ -71258,6 +71329,9 @@ static int walFrames( nExtra--; rc = walIndexAppend(pWal, iApp, iFrame, pLast->pgno); } + if( pWal->aCommitTime ) pWal->aCommitTime[COMMIT_TIME_NFRAME] = nFrame; + + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WALINDEX); if( rc==SQLITE_OK ){ /* Update the private copy of the header. */ @@ -71286,6 +71360,11 @@ static int walFrames( } } + sqlite3CommitTimeSet(pWal->aCommitTime, COMMIT_TIME_AFTER_WALINDEXHDR); + if( pWal->aCommitTime ){ + pWal->aCommitTime[COMMIT_TIME_WALFRAMESFLAGS] = logFlags; + } + WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok")); return rc; } @@ -71594,20 +71673,7 @@ SQLITE_PRIVATE void sqlite3WalSnapshotOpen( Wal *pWal, sqlite3_snapshot *pSnapshot ){ - if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){ - /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In - ** this case set the bGetSnapshot flag so that if the call to - ** sqlite3_snapshot_get() is about to read transaction on this wal - ** file, it does not take read-lock 0 if the wal file has been completely - ** checkpointed. Taking read-lock 0 would work, but then it would be - ** possible for a subsequent writer to destroy the snapshot even while - ** this connection is holding its read-transaction open. This is contrary - ** to user expectations, so we avoid it by not taking read-lock 0. */ - pWal->bGetSnapshot = 1; - }else{ - pWal->pSnapshot = (WalIndexHdr*)pSnapshot; - pWal->bGetSnapshot = 0; - } + pWal->pSnapshot = (WalIndexHdr*)pSnapshot; } /* @@ -71710,6 +71776,12 @@ SQLITE_PRIVATE int sqlite3WalJournalMode(Wal *pWal){ return (isWalMode2(pWal) ? PAGER_JOURNALMODE_WAL2 : PAGER_JOURNALMODE_WAL); } +SQLITE_PRIVATE void sqlite3WalSetCommitTime(Wal *pWal, u64 *aCommitTime){ + if( pWal ){ + pWal->aCommitTime = aCommitTime; + } +} + #endif /* #ifndef SQLITE_OMIT_WAL */ /************** End of wal.c *************************************************/ @@ -72082,7 +72154,6 @@ struct BtLock { ** they often do so without holding sqlite3.mutex. */ struct Btree { - const BtreeMethods *pMethods; sqlite3 *db; /* The database connection holding this btree */ BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ @@ -72206,6 +72277,8 @@ struct BtShared { BtreePtrmap *pMap; #endif int nPreformatSize; /* Size of last cell written by TransferRow() */ + + u64 *aCommitTime; }; /* @@ -72272,7 +72345,6 @@ struct CellInfo { ** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { - const BtCursorMethods *pMethods; u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ @@ -72802,93 +72874,6 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ ** Including a description of file format and an overview of operation. */ /* #include "btreeInt.h" */ -/************** Include btreeDefine.h in the middle of btree.c ***************/ -/************** Begin file btreeDefine.h *************************************/ -#define sqlite3BtreeNext sqlite3StockBtreeNext -#define sqlite3BtreeCursorHasMoved sqlite3StockBtreeCursorHasMoved -#define sqlite3BtreeClearCursor sqlite3StockBtreeClearCursor -#define sqlite3BtreeCursorRestore sqlite3StockBtreeCursorRestore -#define sqlite3BtreeCursorHintFlags sqlite3StockBtreeCursorHintFlags -#define sqlite3BtreeCloseCursor sqlite3StockBtreeCloseCursor -#define sqlite3BtreeCursorIsValid sqlite3StockBtreeCursorIsValid -#define sqlite3BtreeCursorIsValidNN sqlite3StockBtreeCursorIsValidNN -#define sqlite3BtreeIntegerKey sqlite3StockBtreeIntegerKey -#define sqlite3BtreeCursorPin sqlite3StockBtreeCursorPin -#define sqlite3BtreeCursorUnpin sqlite3StockBtreeCursorUnpin -#define sqlite3BtreePayloadSize sqlite3StockBtreePayloadSize -#define sqlite3BtreeMaxRecordSize sqlite3StockBtreeMaxRecordSize -#define sqlite3BtreePayload sqlite3StockBtreePayload -#define sqlite3BtreePayloadChecked sqlite3StockBtreePayloadChecked -#define sqlite3BtreePayloadFetch sqlite3StockBtreePayloadFetch -#define sqlite3BtreeFirst sqlite3StockBtreeFirst -#define sqlite3BtreeLast sqlite3StockBtreeLast -#define sqlite3BtreeTableMoveto sqlite3StockBtreeTableMoveto -#define sqlite3BtreeIndexMoveto sqlite3StockBtreeIndexMoveto -#define sqlite3BtreeCursorDir sqlite3StockBtreeCursorDir -#define sqlite3BtreeEof sqlite3StockBtreeEof -#define sqlite3BtreeRowCountEst sqlite3StockBtreeRowCountEst -#define sqlite3BtreePrevious sqlite3StockBtreePrevious -#define sqlite3BtreeInsert sqlite3StockBtreeInsert -#define sqlite3BtreeDelete sqlite3StockBtreeDelete -#define sqlite3BtreeIdxDelete sqlite3StockBtreeIdxDelete -#define sqlite3BtreePutData sqlite3StockBtreePutData -#define sqlite3BtreeIncrblobCursor sqlite3StockBtreeIncrblobCursor -#define sqlite3BtreeCursorHasHint sqlite3StockBtreeCursorHasHint -#define sqlite3BtreeTransferRow sqlite3StockBtreeTransferRow -#define sqlite3BtreeClearTableOfCursor sqlite3StockBtreeClearTableOfCursor -#define sqlite3BtreeCount sqlite3StockBtreeCount -#define sqlite3BtreeCursor sqlite3StockBtreeCursor -#define sqlite3BtreeSeekCount sqlite3StockBtreeSeekCount -#define sqlite3BtreeLastPage sqlite3StockBtreeLastPage -#define sqlite3BtreeClose sqlite3StockBtreeClose -#define sqlite3BtreeSetCacheSize sqlite3StockBtreeSetCacheSize -#define sqlite3BtreeSetSpillSize sqlite3StockBtreeSetSpillSize -#define sqlite3BtreeSetMmapLimit sqlite3StockBtreeSetMmapLimit -#define sqlite3BtreeSetPagerFlags sqlite3StockBtreeSetPagerFlags -#define sqlite3BtreeSetPageSize sqlite3StockBtreeSetPageSize -#define sqlite3BtreeGetPageSize sqlite3StockBtreeGetPageSize -#define sqlite3BtreeGetReserveNoMutex sqlite3StockBtreeGetReserveNoMutex -#define sqlite3BtreeGetRequestedReserve sqlite3StockBtreeGetRequestedReserve -#define sqlite3BtreeMaxPageCount sqlite3StockBtreeMaxPageCount -#define sqlite3BtreeSecureDelete sqlite3StockBtreeSecureDelete -#define sqlite3BtreeSetAutoVacuum sqlite3StockBtreeSetAutoVacuum -#define sqlite3BtreeGetAutoVacuum sqlite3StockBtreeGetAutoVacuum -#define sqlite3BtreeNewDb sqlite3StockBtreeNewDb -#define sqlite3BtreeBeginTrans sqlite3StockBtreeBeginTrans -#define sqlite3BtreeIncrVacuum sqlite3StockBtreeIncrVacuum -#define sqlite3BtreeCommitPhaseOne sqlite3StockBtreeCommitPhaseOne -#define sqlite3BtreeCommitPhaseTwo sqlite3StockBtreeCommitPhaseTwo -#define sqlite3BtreeCommit sqlite3StockBtreeCommit -#define sqlite3BtreeTripAllCursors sqlite3StockBtreeTripAllCursors -#define sqlite3BtreeRollback sqlite3StockBtreeRollback -#define sqlite3BtreeBeginStmt sqlite3StockBtreeBeginStmt -#define sqlite3BtreeSavepoint sqlite3StockBtreeSavepoint -#define sqlite3BtreeCreateTable sqlite3StockBtreeCreateTable -#define sqlite3BtreeClearTable sqlite3StockBtreeClearTable -#define sqlite3BtreeDropTable sqlite3StockBtreeDropTable -#define sqlite3BtreeGetMeta sqlite3StockBtreeGetMeta -#define sqlite3BtreeUpdateMeta sqlite3StockBtreeUpdateMeta -#define sqlite3BtreePragma sqlite3StockBtreePragma -#define sqlite3BtreePager sqlite3StockBtreePager -#define sqlite3BtreeGetFilename sqlite3StockBtreeGetFilename -#define sqlite3BtreeGetJournalname sqlite3StockBtreeGetJournalname -#define sqlite3BtreeTxnState sqlite3StockBtreeTxnState -#define sqlite3BtreeIsInBackup sqlite3StockBtreeIsInBackup -#define sqlite3BtreeSchema sqlite3StockBtreeSchema -#define sqlite3BtreeSchemaLocked sqlite3StockBtreeSchemaLocked -#define sqlite3BtreeIsReadonly sqlite3StockBtreeIsReadonly -#define sqlite3BtreeSetVersion sqlite3StockBtreeSetVersion -#define sqlite3BtreeIntegrityCheck sqlite3StockBtreeIntegrityCheck -#define sqlite3BtreeCheckpoint sqlite3StockBtreeCheckpoint -#define sqlite3BtreeExclusiveLock sqlite3StockBtreeExclusiveLock -#define sqlite3BtreeFakeValidCursor sqlite3StockBtreeFakeValidCursor -#define sqlite3BtreeCursorSize sqlite3StockBtreeCursorSize -#define sqlite3BtreeCursorZero sqlite3StockBtreeCursorZero -#define sqlite3BtreeOpen sqlite3StockBtreeOpen - - -/************** End of btreeDefine.h *****************************************/ -/************** Continuing where we left off in btree.c **********************/ /* ** The header string that appears at the beginning of every @@ -74045,16 +74030,11 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ -#ifdef SQLITE_ENABLE_HCT - assert( EIGHT_BYTE_ALIGNMENT(pCur) ); - return (CURSOR_VALID!=pCur->eState); -#else assert( EIGHT_BYTE_ALIGNMENT(pCur) || pCur==sqlite3BtreeFakeValidCursor() ); assert( offsetof(BtCursor, eState)==0 ); assert( sizeof(pCur->eState)==1 ); return CURSOR_VALID != *(u8*)pCur; -#endif } /* @@ -76108,7 +76088,9 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); + sqlite3PrepareTimeSet(p->db->aPrepareTime, PREPARE_TIME_BEGINSETCACHESIZE); sqlite3PagerSetCachesize(pBt->pPager, mxPage); + sqlite3PrepareTimeSet(p->db->aPrepareTime, PREPARE_TIME_ENDSETCACHESIZE); sqlite3BtreeLeave(p); return SQLITE_OK; } @@ -77435,27 +77417,60 @@ static int btreeRelocateRange( if( pEntry->eType==PTRMAP_FREEPAGE ){ Pgno dummy; + u64 t1; + if( pBt->aCommitTime ) t1 = sqlite3STimeNow(); rc = allocateBtreePage(pBt, &pFree, &dummy, iPg, BTALLOC_EXACT); + if( pBt->aCommitTime ){ + pBt->aCommitTime[COMMIT_TIME_RELOCATE2_ALLOCATEUS] += (sqlite3STimeNow() - t1); + } if( pFree ){ assert( sqlite3PagerPageRefcount(pFree->pDbPage)==1 ); sqlite3PcacheDrop(pFree->pDbPage); } assert( rc!=SQLITE_OK || dummy==iPg ); }else if( pnCurrent ){ + u64 t1; btreeGetPage(pBt, iPg, &pPg, 0); assert( sqlite3PagerIswriteable(pPg->pDbPage) ); assert( sqlite3PagerPageRefcount(pPg->pDbPage)==1 ); iNew = ++(*pnCurrent); if( iNew==PENDING_BYTE_PAGE(pBt) ) iNew = ++(*pnCurrent); + if( pBt->aCommitTime ) t1 = sqlite3STimeNow(); rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent, iNew, 1); + if( pBt->aCommitTime ){ + pBt->aCommitTime[COMMIT_TIME_RELOCATE2_RELOCATEUS] += (sqlite3STimeNow() - t1); + } releasePageNotNull(pPg); - }else{ - rc = allocateBtreePage(pBt, &pFree, &iNew, iFirst-1, BTALLOC_LE); + }else if( pEntry->eType!=0 ){ + u64 t1; + if( pBt->aCommitTime ) t1 = sqlite3STimeNow(); + + /* Allocate a new page from the free-list to move page iPg to. + ** Except - if the page allocated is within the range being relocated + ** (i.e. pgno>=iFirst), then discard it and allocate another. */ + do { + rc = allocateBtreePage(pBt, &pFree, &iNew, 0, 0); + if( iNew>=iFirst ){ + assert( sqlite3PagerPageRefcount(pFree->pDbPage)==1 ); + assert( iNew>iPg ); + sqlite3PcacheDrop(pFree->pDbPage); + pMap->aPtr[iNew - pMap->iFirst].eType = 0; + pFree = 0; + } + }while( pFree==0 ); + + if( pBt->aCommitTime ){ + pBt->aCommitTime[COMMIT_TIME_RELOCATE2_ALLOCATEUS] += (sqlite3STimeNow() - t1); + } assert( rc!=SQLITE_OK || iNewaCommitTime ) t1 = sqlite3STimeNow(); rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent,iNew,1); + if( pBt->aCommitTime ){ + pBt->aCommitTime[COMMIT_TIME_RELOCATE2_RELOCATEUS] += (sqlite3STimeNow() - t1); + } releasePage(pPg); } } @@ -77485,6 +77500,8 @@ static int btreeFixUnlocked(Btree *p){ Pgno nPage = btreePagecount(pBt); u32 nFree = get4byte(&p1[36]); + sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_START_FIXUNLOCKED); + assert( pBt->pMap ); rc = sqlite3PagerUpgradeSnapshot(pPager, pPage1->pDbPage); assert( p1==pPage1->aData ); @@ -77531,6 +77548,7 @@ static int btreeFixUnlocked(Btree *p){ nCurrent = MAX(nPage, nHPage); pBt->nPage = nCurrent; + sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_START_RELOCATE1); rc = btreeRelocateRange(pBt, pMap->iFirst, iLast, &nCurrent); /* There are now no collisions with the snapshot at the head of the @@ -77547,7 +77565,17 @@ static int btreeFixUnlocked(Btree *p){ nFin--; } nFin = MAX(nFin, nHPage); + if( p->pBt->aCommitTime ){ + p->pBt->aCommitTime[COMMIT_TIME_OTHERWRITERS] = (1+nHPage-pMap->iFirst); + p->pBt->aCommitTime[COMMIT_TIME_RELOCATE1COUNT] = (1+iLast-pMap->iFirst); + p->pBt->aCommitTime[COMMIT_TIME_RELOCATE2COUNT] = (nCurrent - nFin); + } + sqlite3CommitTimeSet( + p->pBt->aCommitTime, COMMIT_TIME_START_RELOCATE2 + ); + sqlite3PagerSetCommitTime(pBt->pPager, pBt->aCommitTime); rc = btreeRelocateRange(pBt, nFin+1, nCurrent, 0); + sqlite3PagerSetCommitTime(pBt->pPager, 0); } put4byte(&p1[28], nFin); @@ -77612,9 +77640,12 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ #endif if( rc==SQLITE_OK && ISCONCURRENT && p->db->eConcurrent==CONCURRENT_OPEN ){ rc = btreeFixUnlocked(p); + sqlite3CommitTimeSet(p->pBt->aCommitTime, COMMIT_TIME_AFTER_FIXUNLOCKED); } if( rc==SQLITE_OK ){ + sqlite3PagerSetCommitTime(pBt->pPager, p->pBt->aCommitTime); rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); + sqlite3PagerSetCommitTime(pBt->pPager, 0); } #ifndef SQLITE_OMIT_CONCURRENT if( rc==SQLITE_OK ){ @@ -77719,7 +77750,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ BtShared *pBt = p->pBt; assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); + sqlite3PagerSetCommitTime(pBt->pPager, p->pBt->aCommitTime); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); + sqlite3PagerSetCommitTime(pBt->pPager, 0); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; @@ -78102,25 +78135,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ return ROUND8(sizeof(BtCursor)); } -#ifdef SQLITE_DEBUG -/* -** Return true if and only if the Btree object will be automatically -** closed with the BtCursor closes. This is used within assert() statements -** only. -*/ -SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor( - Btree *pBtree, /* the btree object */ - BtCursor *pCur /* Corresponding cursor */ -){ - BtShared *pBt = pBtree->pBt; - if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0; - if( pBt->pCursor!=pCur ) return 0; - if( pCur->pNext!=0 ) return 0; - if( pCur->pBtree!=pBtree ) return 0; - return 1; -} -#endif - /* ** Initialize memory that will be converted into a BtCursor object. ** @@ -85014,97 +85028,6 @@ SQLITE_API int sqlite3_commit_status( return rc; } -/************** Include btreeUndef.h in the middle of btree.c ****************/ -/************** Begin file btreeUndef.h **************************************/ -#undef sqlite3BtreeNext -#undef sqlite3BtreeCursorHasMoved -#undef sqlite3BtreeClearCursor -#undef sqlite3BtreeCursorRestore -#undef sqlite3BtreeCursorHintFlags -#undef sqlite3BtreeCloseCursor -#undef sqlite3BtreeCursorIsValid -#undef sqlite3BtreeCursorIsValidNN -#undef sqlite3BtreeIntegerKey -#undef sqlite3BtreeCursorPin -#undef sqlite3BtreeCursorUnpin -#undef sqlite3BtreePayloadSize -#undef sqlite3BtreeMaxRecordSize -#undef sqlite3BtreePayload -#undef sqlite3BtreePayloadChecked -#undef sqlite3BtreePayloadFetch -#undef sqlite3BtreeFirst -#undef sqlite3BtreeLast -#undef sqlite3BtreeTableMoveto -#undef sqlite3BtreeIndexMoveto -#undef sqlite3BtreeCursorDir -#undef sqlite3BtreeEof -#undef sqlite3BtreeRowCountEst -#undef sqlite3BtreePrevious -#undef sqlite3BtreeInsert -#undef sqlite3BtreeDelete -#undef sqlite3BtreeIdxDelete -#undef sqlite3BtreePutData -#undef sqlite3BtreeIncrblobCursor -#undef sqlite3BtreeCursorHasHint -#undef sqlite3BtreeTransferRow -#undef sqlite3BtreeClearTableOfCursor -#undef sqlite3BtreeCount -#undef sqlite3BtreeCursor -#undef sqlite3BtreeSeekCount -#undef sqlite3BtreeLastPage -#undef sqlite3BtreeClose -#undef sqlite3BtreeSetCacheSize -#undef sqlite3BtreeSetSpillSize -#undef sqlite3BtreeSetMmapLimit -#undef sqlite3BtreeSetPagerFlags -#undef sqlite3BtreeSetPageSize -#undef sqlite3BtreeGetPageSize -#undef sqlite3BtreeGetReserveNoMutex -#undef sqlite3BtreeGetRequestedReserve -#undef sqlite3BtreeMaxPageCount -#undef sqlite3BtreeSecureDelete -#undef sqlite3BtreeSetAutoVacuum -#undef sqlite3BtreeGetAutoVacuum -#undef sqlite3BtreeNewDb -#undef sqlite3BtreeBeginTrans -#undef sqlite3BtreeIncrVacuum -#undef sqlite3BtreeCommitPhaseOne -#undef sqlite3BtreeCommitPhaseTwo -#undef sqlite3BtreeCommit -#undef sqlite3BtreeTripAllCursors -#undef sqlite3BtreeRollback -#undef sqlite3BtreeBeginStmt -#undef sqlite3BtreeSavepoint -#undef sqlite3BtreeCreateTable -#undef sqlite3BtreeClearTable -#undef sqlite3BtreeDropTable -#undef sqlite3BtreeGetMeta -#undef sqlite3BtreeUpdateMeta -#undef sqlite3BtreePragma -#undef sqlite3BtreePager -#undef sqlite3BtreeGetFilename -#undef sqlite3BtreeGetJournalname -#undef sqlite3BtreeTxnState -#undef sqlite3BtreeIsInBackup -#undef sqlite3BtreeSchema -#undef sqlite3BtreeSchemaLocked -#undef sqlite3BtreeIsReadonly -#undef sqlite3BtreeSetVersion -#undef sqlite3BtreeIntegrityCheck -#undef sqlite3BtreeCheckpoint -#undef sqlite3BtreeExclusiveLock -#undef sqlite3BtreeFakeValidCursor -#undef sqlite3BtreeCursorSize -#undef sqlite3BtreeCursorZero -#undef sqlite3BtreeOpen -#ifndef SQLITE_DEBUG -# define sqlite3BtreeSeekCount(X) 0 -#endif - - -/************** End of btreeUndef.h ******************************************/ -/************** Continuing where we left off in btree.c **********************/ - /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -85876,681 +85799,6 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ #endif /* SQLITE_OMIT_VACUUM */ /************** End of backup.c **********************************************/ -/************** Begin file btwrapper.c ***************************************/ -/* -** 2022 November 10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ - -/* #include "sqliteInt.h" */ - -#ifndef SQLITE_AMALGAMATION -struct BtCursor { - const BtCursorMethods *pMethods; -}; - -struct Btree { - const BtreeMethods *pMethods; -}; -#endif - -SQLITE_PRIVATE int sqlite3HctBtreeCursorSize(void); -SQLITE_PRIVATE int sqlite3HctBtreeOpen(sqlite3_vfs*, const char*, sqlite3*, Btree**, int, int); -SQLITE_PRIVATE int sqlite3HctBtreeSchemaLoaded(Btree*); - -SQLITE_PRIVATE int sqlite3StockBtreeCursorSize(void); -SQLITE_PRIVATE int sqlite3StockBtreeOpen(sqlite3_vfs*, const char*, sqlite3*, Btree**,int,int); - -SQLITE_PRIVATE int sqlite3StockBtreePragma(Btree *p, char **a){ - return SQLITE_NOTFOUND; -} -SQLITE_PRIVATE void sqlite3StockBtreeCursorDir(BtCursor *p, int a){ - /* no-op */ -} - - -SQLITE_PRIVATE int sqlite3StockBtreeIdxDelete(BtCursor *p, UnpackedRecord *pRec){ - int rc = SQLITE_OK; - int res = 0; - - rc = sqlite3BtreeIndexMoveto(p, pRec, &res); - if( rc==SQLITE_OK && res==0 ){ - rc = sqlite3BtreeDelete(p, BTREE_AUXDELETE); - } - - return rc; -} - -#ifndef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3StockBtreeCursorIsValid(BtCursor *pCursor){ - return 1; -} -SQLITE_PRIVATE sqlite3_uint64 sqlite3StockBtreeSeekCount(Btree *p){ - return 0; -} -#endif - -/* BEGIN_HCT_MKBTREEWRAPPER_TCL_CODE */ -/****************************************************************** -** GENERATED CODE - DO NOT EDIT! -** -** Code generated by tool/hct_mkbtreewrapper.tcl -*/ -struct BtCursorMethods { - int(*xBtreeNext)(BtCursor*, int); - int(*xBtreeCursorHasMoved)(BtCursor*); - void(*xBtreeClearCursor)(BtCursor*); - int(*xBtreeCursorRestore)(BtCursor*, int*); - void(*xBtreeCursorHintFlags)(BtCursor*, unsigned); - int(*xBtreeCloseCursor)(BtCursor*); - int(*xBtreeCursorIsValid)(BtCursor*); - int(*xBtreeCursorIsValidNN)(BtCursor*); - i64(*xBtreeIntegerKey)(BtCursor*); - void(*xBtreeCursorPin)(BtCursor*); - void(*xBtreeCursorUnpin)(BtCursor*); - u32(*xBtreePayloadSize)(BtCursor*); - sqlite3_int64(*xBtreeMaxRecordSize)(BtCursor*); - int(*xBtreePayload)(BtCursor*, u32, u32, void*); - int(*xBtreePayloadChecked)(BtCursor*, u32, u32, void *); - const void *(*xBtreePayloadFetch)(BtCursor*, u32*); - int(*xBtreeFirst)(BtCursor*, int*); - int(*xBtreeLast)(BtCursor*, int*); - int(*xBtreeTableMoveto)(BtCursor*, i64, int, int*); - int(*xBtreeIndexMoveto)(BtCursor*, UnpackedRecord*, int*); - void(*xBtreeCursorDir)(BtCursor*, int); - int(*xBtreeEof)(BtCursor*); - i64(*xBtreeRowCountEst)(BtCursor*); - int(*xBtreePrevious)(BtCursor*, int); - int(*xBtreeInsert)(BtCursor*, const BtreePayload*, int, int); - int(*xBtreeDelete)(BtCursor*, u8); - int(*xBtreeIdxDelete)(BtCursor*, UnpackedRecord*); - int(*xBtreePutData)(BtCursor*, u32, u32, void*); - void(*xBtreeIncrblobCursor)(BtCursor*); - int(*xBtreeCursorHasHint)(BtCursor*, unsigned int); - int(*xBtreeTransferRow)(BtCursor*, BtCursor*, i64); - int(*xBtreeClearTableOfCursor)(BtCursor*); - int(*xBtreeCount)(sqlite3*, BtCursor*, i64*); -}; -struct BtreeMethods { - BtCursorMethods const *pCsrMethods; - int(*xBtreeCursor)(Btree*, Pgno, int, struct KeyInfo*, BtCursor*); - sqlite3_uint64(*xBtreeSeekCount)(Btree*); - Pgno(*xBtreeLastPage)(Btree*); - int(*xBtreeClose)(Btree*); - int(*xBtreeSetCacheSize)(Btree*, int); - int(*xBtreeSetSpillSize)(Btree*, int); - int(*xBtreeSetMmapLimit)(Btree*, sqlite3_int64); - int(*xBtreeSetPagerFlags)(Btree*, unsigned); - int(*xBtreeSetPageSize)(Btree*, int, int, int); - int(*xBtreeGetPageSize)(Btree*); - int(*xBtreeGetReserveNoMutex)(Btree*); - int(*xBtreeGetRequestedReserve)(Btree*); - Pgno(*xBtreeMaxPageCount)(Btree*, Pgno); - int(*xBtreeSecureDelete)(Btree*, int); - int(*xBtreeSetAutoVacuum)(Btree*, int); - int(*xBtreeGetAutoVacuum)(Btree*); - int(*xBtreeNewDb)(Btree*); - int(*xBtreeBeginTrans)(Btree*, int, int*); - int(*xBtreeIncrVacuum)(Btree*); - int(*xBtreeCommitPhaseOne)(Btree*, const char*); - int(*xBtreeCommitPhaseTwo)(Btree*, int); - int(*xBtreeCommit)(Btree*); - int(*xBtreeTripAllCursors)(Btree*, int, int); - int(*xBtreeRollback)(Btree*, int, int); - int(*xBtreeBeginStmt)(Btree*, int); - int(*xBtreeSavepoint)(Btree*, int, int); - int(*xBtreeCreateTable)(Btree*, Pgno*, int); - int(*xBtreeClearTable)(Btree*, int, i64*); - int(*xBtreeDropTable)(Btree*, int, int*); - void(*xBtreeGetMeta)(Btree*, int, u32*); - int(*xBtreeUpdateMeta)(Btree*, int, u32); - int(*xBtreePragma)(Btree*, char**); - Pager *(*xBtreePager)(Btree*); - const char *(*xBtreeGetFilename)(Btree*); - const char *(*xBtreeGetJournalname)(Btree*); - int(*xBtreeTxnState)(Btree*); - int(*xBtreeIsInBackup)(Btree*); - void *(*xBtreeSchema)(Btree*, int, void(*)(void *)); - int(*xBtreeSchemaLocked)(Btree*); - int(*xBtreeIsReadonly)(Btree*); - int(*xBtreeSetVersion)(Btree*, int); - int(*xBtreeIntegrityCheck)(sqlite3*, Btree*, Pgno*, Mem*, int, int, int*, char**); - int(*xBtreeCheckpoint)(Btree*, int, int *, int *); - int(*xBtreeExclusiveLock)(Btree*); -}; -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *p, int a){ - return p->pMethods->xBtreeNext(p, a); -} -SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *p){ - p->pMethods->xBtreeClearCursor(p); -} -SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *p, int *a){ - return p->pMethods->xBtreeCursorRestore(p, a); -} -SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *p, unsigned a){ - p->pMethods->xBtreeCursorHintFlags(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *p){ - return p->pMethods->xBtreeCursorIsValid(p); -} -SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *p){ - return p->pMethods->xBtreeCursorIsValidNN(p); -} -SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *p){ - return p->pMethods->xBtreeIntegerKey(p); -} -SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *p){ - p->pMethods->xBtreeCursorPin(p); -} -SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *p){ - p->pMethods->xBtreeCursorUnpin(p); -} -SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *p){ - return p->pMethods->xBtreePayloadSize(p); -} -SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *p){ - return p->pMethods->xBtreeMaxRecordSize(p); -} -SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *p, u32 a, u32 b, void *c){ - return p->pMethods->xBtreePayload(p, a, b, c); -} -SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *p, u32 a, u32 b, void *c){ - return p->pMethods->xBtreePayloadChecked(p, a, b, c); -} -const void * sqlite3BtreePayloadFetch(BtCursor *p, u32 *a){ - return p->pMethods->xBtreePayloadFetch(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *p, int *a){ - return p->pMethods->xBtreeFirst(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *p, int *a){ - return p->pMethods->xBtreeLast(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeTableMoveto(BtCursor *p, i64 a, int b, int *c){ - return p->pMethods->xBtreeTableMoveto(p, a, b, c); -} -SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(BtCursor *p, UnpackedRecord *a, int *b){ - return p->pMethods->xBtreeIndexMoveto(p, a, b); -} -SQLITE_PRIVATE void sqlite3BtreeCursorDir(BtCursor *p, int a){ - p->pMethods->xBtreeCursorDir(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *p){ - return p->pMethods->xBtreeEof(p); -} -SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *p){ - return p->pMethods->xBtreeRowCountEst(p); -} -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *p, int a){ - return p->pMethods->xBtreePrevious(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor *p, const BtreePayload *a, int b, int c){ - return p->pMethods->xBtreeInsert(p, a, b, c); -} -SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *p, u8 a){ - return p->pMethods->xBtreeDelete(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeIdxDelete(BtCursor *p, UnpackedRecord *a){ - return p->pMethods->xBtreeIdxDelete(p, a); -} -SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *p, u32 a, u32 b, void *c){ - return p->pMethods->xBtreePutData(p, a, b, c); -} -SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *p){ - p->pMethods->xBtreeIncrblobCursor(p); -} -SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *p, unsigned int a){ - return p->pMethods->xBtreeCursorHasHint(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *p, BtCursor *a, i64 b){ - return p->pMethods->xBtreeTransferRow(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *p){ - return p->pMethods->xBtreeClearTableOfCursor(p); -} -SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *a, BtCursor *p, i64 *b){ - return p->pMethods->xBtreeCount(a, p, b); -} -SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){ - return p->pMethods->xBtreeLastPage(p); -} -SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ - return p->pMethods->xBtreeClose(p); -} -SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int a){ - return p->pMethods->xBtreeSetCacheSize(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int a){ - return p->pMethods->xBtreeSetSpillSize(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 a){ - return p->pMethods->xBtreeSetMmapLimit(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree *p, unsigned a){ - return p->pMethods->xBtreeSetPagerFlags(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int a, int b, int c){ - return p->pMethods->xBtreeSetPageSize(p, a, b, c); -} -SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ - return p->pMethods->xBtreeGetPageSize(p); -} -SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ - return p->pMethods->xBtreeGetReserveNoMutex(p); -} -SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){ - return p->pMethods->xBtreeGetRequestedReserve(p); -} -SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno a){ - return p->pMethods->xBtreeMaxPageCount(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int a){ - if( p==0 ) return 0; - return p->pMethods->xBtreeSecureDelete(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int a){ - return p->pMethods->xBtreeSetAutoVacuum(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ - return p->pMethods->xBtreeGetAutoVacuum(p); -} -SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ - return p->pMethods->xBtreeNewDb(p); -} -SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int a, int *b){ - return p->pMethods->xBtreeBeginTrans(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ - return p->pMethods->xBtreeIncrVacuum(p); -} -SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *a){ - return p->pMethods->xBtreeCommitPhaseOne(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int a){ - return p->pMethods->xBtreeCommitPhaseTwo(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ - return p->pMethods->xBtreeCommit(p); -} -SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *p, int a, int b){ - if( p==0 ) return 0; - return p->pMethods->xBtreeTripAllCursors(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int a, int b){ - return p->pMethods->xBtreeRollback(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int a){ - return p->pMethods->xBtreeBeginStmt(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int a, int b){ - if( p==0 ) return 0; - return p->pMethods->xBtreeSavepoint(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *a, int b){ - return p->pMethods->xBtreeCreateTable(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int a, i64 *b){ - return p->pMethods->xBtreeClearTable(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int a, int *b){ - return p->pMethods->xBtreeDropTable(p, a, b); -} -SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int a, u32 *b){ - p->pMethods->xBtreeGetMeta(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int a, u32 b){ - return p->pMethods->xBtreeUpdateMeta(p, a, b); -} -SQLITE_PRIVATE int sqlite3BtreePragma(Btree *p, char* *a){ - return p->pMethods->xBtreePragma(p, a); -} -Pager * sqlite3BtreePager(Btree *p){ - return p->pMethods->xBtreePager(p); -} -const char * sqlite3BtreeGetFilename(Btree *p){ - return p->pMethods->xBtreeGetFilename(p); -} -const char * sqlite3BtreeGetJournalname(Btree *p){ - return p->pMethods->xBtreeGetJournalname(p); -} -SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){ - if( p==0 ) return 0; - return p->pMethods->xBtreeTxnState(p); -} -SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ - return p->pMethods->xBtreeIsInBackup(p); -} -void * sqlite3BtreeSchema(Btree *p, int a, void (*xFree)(void *)){ - return p->pMethods->xBtreeSchema(p, a, xFree); -} -SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ - return p->pMethods->xBtreeSchemaLocked(p); -} -SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ - return p->pMethods->xBtreeIsReadonly(p); -} -SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *p, int a){ - return p->pMethods->xBtreeSetVersion(p, a); -} -SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(sqlite3 *a, Btree *p, Pgno *b, Mem *c, int d, int e, int *f, char* *g){ - return p->pMethods->xBtreeIntegrityCheck(a, p, b, c, d, e, f, g); -} -SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int a, int *b, int *c){ - if( p==0 ) return 0; - return p->pMethods->xBtreeCheckpoint(p, a, b, c); -} -SQLITE_PRIVATE int sqlite3BtreeExclusiveLock(Btree *p){ - return p->pMethods->xBtreeExclusiveLock(p); -} -static const BtCursorMethods hct_btcursor_methods = { - .xBtreeNext = sqlite3HctBtreeNext, - .xBtreeCursorHasMoved = sqlite3HctBtreeCursorHasMoved, - .xBtreeClearCursor = sqlite3HctBtreeClearCursor, - .xBtreeCursorRestore = sqlite3HctBtreeCursorRestore, - .xBtreeCursorHintFlags = sqlite3HctBtreeCursorHintFlags, - .xBtreeCloseCursor = sqlite3HctBtreeCloseCursor, - .xBtreeCursorIsValid = sqlite3HctBtreeCursorIsValid, - .xBtreeCursorIsValidNN = sqlite3HctBtreeCursorIsValidNN, - .xBtreeIntegerKey = sqlite3HctBtreeIntegerKey, - .xBtreeCursorPin = sqlite3HctBtreeCursorPin, - .xBtreeCursorUnpin = sqlite3HctBtreeCursorUnpin, - .xBtreePayloadSize = sqlite3HctBtreePayloadSize, - .xBtreeMaxRecordSize = sqlite3HctBtreeMaxRecordSize, - .xBtreePayload = sqlite3HctBtreePayload, - .xBtreePayloadChecked = sqlite3HctBtreePayloadChecked, - .xBtreePayloadFetch = sqlite3HctBtreePayloadFetch, - .xBtreeFirst = sqlite3HctBtreeFirst, - .xBtreeLast = sqlite3HctBtreeLast, - .xBtreeTableMoveto = sqlite3HctBtreeTableMoveto, - .xBtreeIndexMoveto = sqlite3HctBtreeIndexMoveto, - .xBtreeCursorDir = sqlite3HctBtreeCursorDir, - .xBtreeEof = sqlite3HctBtreeEof, - .xBtreeRowCountEst = sqlite3HctBtreeRowCountEst, - .xBtreePrevious = sqlite3HctBtreePrevious, - .xBtreeInsert = sqlite3HctBtreeInsert, - .xBtreeDelete = sqlite3HctBtreeDelete, - .xBtreeIdxDelete = sqlite3HctBtreeIdxDelete, - .xBtreePutData = sqlite3HctBtreePutData, - .xBtreeIncrblobCursor = sqlite3HctBtreeIncrblobCursor, - .xBtreeCursorHasHint = sqlite3HctBtreeCursorHasHint, - .xBtreeTransferRow = sqlite3HctBtreeTransferRow, - .xBtreeClearTableOfCursor = sqlite3HctBtreeClearTableOfCursor, - .xBtreeCount = sqlite3HctBtreeCount, -}; -static const BtreeMethods hct_btree_methods = { - .pCsrMethods = &hct_btcursor_methods, - .xBtreeCursor = sqlite3HctBtreeCursor, - .xBtreeSeekCount = sqlite3HctBtreeSeekCount, - .xBtreeLastPage = sqlite3HctBtreeLastPage, - .xBtreeClose = sqlite3HctBtreeClose, - .xBtreeSetCacheSize = sqlite3HctBtreeSetCacheSize, - .xBtreeSetSpillSize = sqlite3HctBtreeSetSpillSize, - .xBtreeSetMmapLimit = sqlite3HctBtreeSetMmapLimit, - .xBtreeSetPagerFlags = sqlite3HctBtreeSetPagerFlags, - .xBtreeSetPageSize = sqlite3HctBtreeSetPageSize, - .xBtreeGetPageSize = sqlite3HctBtreeGetPageSize, - .xBtreeGetReserveNoMutex = sqlite3HctBtreeGetReserveNoMutex, - .xBtreeGetRequestedReserve = sqlite3HctBtreeGetRequestedReserve, - .xBtreeMaxPageCount = sqlite3HctBtreeMaxPageCount, - .xBtreeSecureDelete = sqlite3HctBtreeSecureDelete, - .xBtreeSetAutoVacuum = sqlite3HctBtreeSetAutoVacuum, - .xBtreeGetAutoVacuum = sqlite3HctBtreeGetAutoVacuum, - .xBtreeNewDb = sqlite3HctBtreeNewDb, - .xBtreeBeginTrans = sqlite3HctBtreeBeginTrans, - .xBtreeIncrVacuum = sqlite3HctBtreeIncrVacuum, - .xBtreeCommitPhaseOne = sqlite3HctBtreeCommitPhaseOne, - .xBtreeCommitPhaseTwo = sqlite3HctBtreeCommitPhaseTwo, - .xBtreeCommit = sqlite3HctBtreeCommit, - .xBtreeTripAllCursors = sqlite3HctBtreeTripAllCursors, - .xBtreeRollback = sqlite3HctBtreeRollback, - .xBtreeBeginStmt = sqlite3HctBtreeBeginStmt, - .xBtreeSavepoint = sqlite3HctBtreeSavepoint, - .xBtreeCreateTable = sqlite3HctBtreeCreateTable, - .xBtreeClearTable = sqlite3HctBtreeClearTable, - .xBtreeDropTable = sqlite3HctBtreeDropTable, - .xBtreeGetMeta = sqlite3HctBtreeGetMeta, - .xBtreeUpdateMeta = sqlite3HctBtreeUpdateMeta, - .xBtreePragma = sqlite3HctBtreePragma, - .xBtreePager = sqlite3HctBtreePager, - .xBtreeGetFilename = sqlite3HctBtreeGetFilename, - .xBtreeGetJournalname = sqlite3HctBtreeGetJournalname, - .xBtreeTxnState = sqlite3HctBtreeTxnState, - .xBtreeIsInBackup = sqlite3HctBtreeIsInBackup, - .xBtreeSchema = sqlite3HctBtreeSchema, - .xBtreeSchemaLocked = sqlite3HctBtreeSchemaLocked, - .xBtreeIsReadonly = sqlite3HctBtreeIsReadonly, - .xBtreeSetVersion = sqlite3HctBtreeSetVersion, - .xBtreeIntegrityCheck = sqlite3HctBtreeIntegrityCheck, - .xBtreeCheckpoint = sqlite3HctBtreeCheckpoint, - .xBtreeExclusiveLock = sqlite3HctBtreeExclusiveLock, -}; - -static const BtCursorMethods stock_btcursor_methods = { - .xBtreeNext = sqlite3StockBtreeNext, - .xBtreeCursorHasMoved = sqlite3StockBtreeCursorHasMoved, - .xBtreeClearCursor = sqlite3StockBtreeClearCursor, - .xBtreeCursorRestore = sqlite3StockBtreeCursorRestore, - .xBtreeCursorHintFlags = sqlite3StockBtreeCursorHintFlags, - .xBtreeCloseCursor = sqlite3StockBtreeCloseCursor, - .xBtreeCursorIsValid = sqlite3StockBtreeCursorIsValid, - .xBtreeCursorIsValidNN = sqlite3StockBtreeCursorIsValidNN, - .xBtreeIntegerKey = sqlite3StockBtreeIntegerKey, - .xBtreeCursorPin = sqlite3StockBtreeCursorPin, - .xBtreeCursorUnpin = sqlite3StockBtreeCursorUnpin, - .xBtreePayloadSize = sqlite3StockBtreePayloadSize, - .xBtreeMaxRecordSize = sqlite3StockBtreeMaxRecordSize, - .xBtreePayload = sqlite3StockBtreePayload, - .xBtreePayloadChecked = sqlite3StockBtreePayloadChecked, - .xBtreePayloadFetch = sqlite3StockBtreePayloadFetch, - .xBtreeFirst = sqlite3StockBtreeFirst, - .xBtreeLast = sqlite3StockBtreeLast, - .xBtreeTableMoveto = sqlite3StockBtreeTableMoveto, - .xBtreeIndexMoveto = sqlite3StockBtreeIndexMoveto, - .xBtreeCursorDir = sqlite3StockBtreeCursorDir, - .xBtreeEof = sqlite3StockBtreeEof, - .xBtreeRowCountEst = sqlite3StockBtreeRowCountEst, - .xBtreePrevious = sqlite3StockBtreePrevious, - .xBtreeInsert = sqlite3StockBtreeInsert, - .xBtreeDelete = sqlite3StockBtreeDelete, - .xBtreeIdxDelete = sqlite3StockBtreeIdxDelete, - .xBtreePutData = sqlite3StockBtreePutData, - .xBtreeIncrblobCursor = sqlite3StockBtreeIncrblobCursor, - .xBtreeCursorHasHint = sqlite3StockBtreeCursorHasHint, - .xBtreeTransferRow = sqlite3StockBtreeTransferRow, - .xBtreeClearTableOfCursor = sqlite3StockBtreeClearTableOfCursor, - .xBtreeCount = sqlite3StockBtreeCount, -}; -static const BtreeMethods stock_btree_methods = { - .pCsrMethods = &stock_btcursor_methods, - .xBtreeCursor = sqlite3StockBtreeCursor, - .xBtreeSeekCount = sqlite3StockBtreeSeekCount, - .xBtreeLastPage = sqlite3StockBtreeLastPage, - .xBtreeClose = sqlite3StockBtreeClose, - .xBtreeSetCacheSize = sqlite3StockBtreeSetCacheSize, - .xBtreeSetSpillSize = sqlite3StockBtreeSetSpillSize, - .xBtreeSetMmapLimit = sqlite3StockBtreeSetMmapLimit, - .xBtreeSetPagerFlags = sqlite3StockBtreeSetPagerFlags, - .xBtreeSetPageSize = sqlite3StockBtreeSetPageSize, - .xBtreeGetPageSize = sqlite3StockBtreeGetPageSize, - .xBtreeGetReserveNoMutex = sqlite3StockBtreeGetReserveNoMutex, - .xBtreeGetRequestedReserve = sqlite3StockBtreeGetRequestedReserve, - .xBtreeMaxPageCount = sqlite3StockBtreeMaxPageCount, - .xBtreeSecureDelete = sqlite3StockBtreeSecureDelete, - .xBtreeSetAutoVacuum = sqlite3StockBtreeSetAutoVacuum, - .xBtreeGetAutoVacuum = sqlite3StockBtreeGetAutoVacuum, - .xBtreeNewDb = sqlite3StockBtreeNewDb, - .xBtreeBeginTrans = sqlite3StockBtreeBeginTrans, - .xBtreeIncrVacuum = sqlite3StockBtreeIncrVacuum, - .xBtreeCommitPhaseOne = sqlite3StockBtreeCommitPhaseOne, - .xBtreeCommitPhaseTwo = sqlite3StockBtreeCommitPhaseTwo, - .xBtreeCommit = sqlite3StockBtreeCommit, - .xBtreeTripAllCursors = sqlite3StockBtreeTripAllCursors, - .xBtreeRollback = sqlite3StockBtreeRollback, - .xBtreeBeginStmt = sqlite3StockBtreeBeginStmt, - .xBtreeSavepoint = sqlite3StockBtreeSavepoint, - .xBtreeCreateTable = sqlite3StockBtreeCreateTable, - .xBtreeClearTable = sqlite3StockBtreeClearTable, - .xBtreeDropTable = sqlite3StockBtreeDropTable, - .xBtreeGetMeta = sqlite3StockBtreeGetMeta, - .xBtreeUpdateMeta = sqlite3StockBtreeUpdateMeta, - .xBtreePragma = sqlite3StockBtreePragma, - .xBtreePager = sqlite3StockBtreePager, - .xBtreeGetFilename = sqlite3StockBtreeGetFilename, - .xBtreeGetJournalname = sqlite3StockBtreeGetJournalname, - .xBtreeTxnState = sqlite3StockBtreeTxnState, - .xBtreeIsInBackup = sqlite3StockBtreeIsInBackup, - .xBtreeSchema = sqlite3StockBtreeSchema, - .xBtreeSchemaLocked = sqlite3StockBtreeSchemaLocked, - .xBtreeIsReadonly = sqlite3StockBtreeIsReadonly, - .xBtreeSetVersion = sqlite3StockBtreeSetVersion, - .xBtreeIntegrityCheck = sqlite3StockBtreeIntegrityCheck, - .xBtreeCheckpoint = sqlite3StockBtreeCheckpoint, - .xBtreeExclusiveLock = sqlite3StockBtreeExclusiveLock, -}; - -/* -** END OF GENERATED CODE -******************************************************************/ -/* END_HCT_MKBTREEWRAPPER_TCL_CODE */ - -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *p){ - return p->pMethods->xBtreeSeekCount(p); -} -#endif - -SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ - static BtCursor csr = {0}; - return &csr; -} - -SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ - return MAX( - sqlite3HctBtreeCursorSize(), - sqlite3StockBtreeCursorSize() - ); -} - -SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ - memset(p, 0, sqlite3BtreeCursorSize()); -} - -SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ - if( pCur->pMethods==0 ) return 0; - return pCur->pMethods->xBtreeCursorHasMoved(pCur); -} - -SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ - if( pCur->pMethods==0 ) return 0; - return pCur->pMethods->xBtreeCloseCursor(pCur); -} - -SQLITE_PRIVATE int sqlite3BtreeCursor( - Btree *p, /* The btree */ - Pgno iTable, /* Root page of table to open */ - int wrFlag, /* 1 to write. 0 read-only */ - struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ - BtCursor *pCur /* Write new cursor here */ -){ - int rc = p->pMethods->xBtreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); - pCur->pMethods = p->pMethods->pCsrMethods; - return rc; -} - -static int btWrapperUseHct( - sqlite3_vfs *pVfs, - const char *zFilename, - int *pbUseHct -){ - int rc = SQLITE_OK; - char *zFull = 0; - char *zPagemap = 0; - int bUseHct = 0; - - if( zFilename && zFilename[0] ){ - int nAlloc = pVfs->mxPathname+2; - int bExists = 0; - - zFull = (char*)sqlite3_malloc(nAlloc); - if( zFull==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - memset(zFull, 0, nAlloc); - rc = pVfs->xFullPathname(pVfs, zFilename, pVfs->mxPathname, zFull); - } - - if( rc==SQLITE_OK ){ - rc = pVfs->xAccess(pVfs, zFull, SQLITE_ACCESS_EXISTS, &bExists); - } - if( rc==SQLITE_OK ){ - zPagemap = sqlite3_mprintf("%s-pagemap", zFull); - if( zPagemap==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else if( bExists ){ - rc = pVfs->xAccess(pVfs, zPagemap, SQLITE_ACCESS_EXISTS, &bUseHct); - }else{ - sqlite3OsDelete(pVfs, zPagemap, 0); - bUseHct = sqlite3_uri_boolean(zFilename, "hctree", 0); - } - } - } - - sqlite3_free(zFull); - sqlite3_free(zPagemap); - *pbUseHct = bUseHct; - return rc; -} - -SQLITE_PRIVATE int sqlite3BtreeOpen( - sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ - const char *zFilename, /* Name of the file containing the BTree database */ - sqlite3 *db, /* Associated database handle */ - Btree **ppBtree, /* Pointer to new Btree object written here */ - int flags, /* Options */ - int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ -){ - Btree *pBtree = 0; - int rc = SQLITE_OK; - int bUseHct = 0; - - rc = btWrapperUseHct(pVfs, zFilename, &bUseHct); - if( rc==SQLITE_OK ){ - if( bUseHct ){ - rc = sqlite3HctBtreeOpen(pVfs, zFilename, db, &pBtree, flags, vfsFlags); - if( rc==SQLITE_OK ) pBtree->pMethods = &hct_btree_methods; - }else{ - rc = sqlite3StockBtreeOpen(pVfs, zFilename, db, &pBtree, flags, vfsFlags); - if( rc==SQLITE_OK ) pBtree->pMethods = &stock_btree_methods; - } - } - *ppBtree = pBtree; - return rc; -} - -SQLITE_PRIVATE int sqlite3IsHct(Btree *pBt){ - return (pBt && pBt->pMethods==&hct_btree_methods); -} - -SQLITE_PRIVATE int sqlite3BtreeSchemaLoaded(Btree *pBt){ - int rc = SQLITE_OK; - if( sqlite3IsHct(pBt) ){ - rc = sqlite3HctBtreeSchemaLoaded(pBt); - } - return rc; -} - - - -/************** End of btwrapper.c *******************************************/ /************** Begin file vdbemem.c *****************************************/ /* ** 2004 May 26 @@ -88088,8 +87336,7 @@ static int valueFromFunction( goto value_from_function_out; } for(i=0; ipParse, pList->a[i].pExpr, aff, - &apVal[i]); + rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]); if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out; } } @@ -88625,6 +87872,8 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ +/* #include "btreeInt.h" */ + /* Forward references */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef); static void vdbeFreeOpArray(sqlite3 *, Op *, int); @@ -91610,13 +90859,18 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ + sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_PHASEONE); for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ + pBt->pBt->aCommitTime = p->aCommitTime; rc = sqlite3BtreeCommitPhaseOne(pBt, 0); + pBt->pBt->aCommitTime = 0; } } + sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_PHASETWO); + /* Do the commit only if all databases successfully complete phase 1. ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an ** IO error while deleting or truncating a journal file. It is unlikely, @@ -91625,9 +90879,13 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ + pBt->pBt->aCommitTime = p->aCommitTime; rc = sqlite3BtreeCommitPhaseTwo(pBt, 0); + pBt->pBt->aCommitTime = 0; } } + + sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_AFTER_PHASETWO); if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } @@ -92024,7 +91282,9 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ + sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_BEFORE_VDBECOMMIT); rc = vdbeCommit(db, p); + sqlite3CommitTimeSet(p->aCommitTime, COMMIT_TIME_AFTER_VDBECOMMIT); } if( (rc & 0xFF)==SQLITE_BUSY && p->readOnly ){ sqlite3VdbeLeave(p); @@ -93143,7 +92403,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem ** We must use separate SQLITE_NOINLINE functions here, since otherwise ** optimizer code movement causes gcov to become very confused. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) static int SQLITE_NOINLINE doubleLt(double a, double b){ return ar ); + testcase( x==r ); + return (xr); }else{ i64 y; if( r<-9223372036854775808.0 ) return +1; @@ -94049,6 +93316,91 @@ SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr) } #endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */ +/* #include */ +SQLITE_PRIVATE void sqlite3CommitTimeLog(u64 *aCommit){ + u64 i1 = aCommit[COMMIT_TIME_START]; + assert( COMMIT_TIME_START==0 && COMMIT_TIME_FINISH==COMMIT_TIME_N-1 ); + if( aCommit[COMMIT_TIME_FINISH]>(i1+COMMIT_TIME_TIMEOUT) ){ + char *zStr = 0; + int ii; + for(ii=1; ii(i1+PREPARE_TIME_TIMEOUT) ){ + int nByte = nSql; + char *zStr = 0; + int ii; + for(ii=1; ii(i1+SCHEMA_TIME_TIMEOUT) ){ + char *zStr = 0; + int ii; + for(ii=1; iinField; i++){ @@ -94168,13 +93519,6 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( } sqlite3DbNNFreeNN(db, preupdate.aNew); } - if( preupdate.apDflt ){ - int i; - for(i=0; inCol; i++){ - sqlite3ValueFree(preupdate.apDflt[i]); - } - sqlite3DbFree(db, preupdate.apDflt); - } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -95803,17 +95147,6 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ ** ** The error code stored in database p->db is overwritten with the return ** value in any case. -** -** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK, -** that means all of the the following will be true: -** -** p!=0 -** p->pVar!=0 -** i>0 -** i<=p->nVar -** -** An assert() is normally added after vdbeUnbind() to help static analyzers -** realize this. */ static int vdbeUnbind(Vdbe *p, unsigned int i){ Mem *pVar; @@ -95871,7 +95204,6 @@ static int bindText( rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ if( zData!=0 ){ pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); @@ -95921,7 +95253,6 @@ SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); sqlite3_mutex_leave(p->db->mutex); } @@ -95935,7 +95266,6 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); sqlite3_mutex_leave(p->db->mutex); } @@ -95946,7 +95276,6 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3_mutex_leave(p->db->mutex); } return rc; @@ -95962,7 +95291,6 @@ SQLITE_API int sqlite3_bind_pointer( Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); sqlite3_mutex_leave(p->db->mutex); }else if( xDestructor ){ @@ -96044,7 +95372,6 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #else @@ -96379,64 +95706,37 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_old_out; } - if( iIdx==p->pTab->iPKey ){ - *ppValue = pMem = &p->oldipk; - sqlite3VdbeMemSetInt64(pMem, p->iKey1); - }else{ - - /* If the old.* record has not yet been loaded into memory, do so now. */ - if( p->pUnpacked==0 ){ - u32 nRec; - u8 *aRec; + /* If the old.* record has not yet been loaded into memory, do so now. */ + if( p->pUnpacked==0 ){ + u32 nRec; + u8 *aRec; - assert( p->pCsr->eCurType==CURTYPE_BTREE ); - nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); - aRec = sqlite3DbMallocRaw(db, nRec); - if( !aRec ) goto preupdate_old_out; - rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); - if( rc==SQLITE_OK ){ - p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); - if( !p->pUnpacked ) rc = SQLITE_NOMEM; - } - if( rc!=SQLITE_OK ){ - sqlite3DbFree(db, aRec); - goto preupdate_old_out; - } - p->aRecord = aRec; + assert( p->pCsr->eCurType==CURTYPE_BTREE ); + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); + aRec = sqlite3DbMallocRaw(db, nRec); + if( !aRec ) goto preupdate_old_out; + rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); + if( rc==SQLITE_OK ){ + p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + if( !p->pUnpacked ) rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, aRec); + goto preupdate_old_out; } + p->aRecord = aRec; + } - pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; - if( iIdx>=p->pUnpacked->nField ){ - /* This occurs when the table has been extended using ALTER TABLE - ** ADD COLUMN. The value to return is the default value of the column. */ - Column *pCol = &p->pTab->aCol[iIdx]; - if( pCol->iDflt>0 ){ - if( p->apDflt==0 ){ - int nByte = sizeof(sqlite3_value*)*p->pTab->nCol; - p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); - if( p->apDflt==0 ) goto preupdate_old_out; - } - if( p->apDflt[iIdx]==0 ){ - sqlite3_value *pVal = 0; - Expr *pDflt; - assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) ); - pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; - rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal); - if( rc==SQLITE_OK && pVal==0 ){ - rc = SQLITE_CORRUPT_BKPT; - } - p->apDflt[iIdx] = pVal; - } - *ppValue = p->apDflt[iIdx]; - }else{ - *ppValue = (sqlite3_value *)columnNullValue(); - } - }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & (MEM_Int|MEM_IntReal) ){ - testcase( pMem->flags & MEM_Int ); - testcase( pMem->flags & MEM_IntReal ); - sqlite3VdbeMemRealify(pMem); - } + pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey1); + }else if( iIdx>=p->pUnpacked->nField ){ + *ppValue = (sqlite3_value *)columnNullValue(); + }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); + sqlite3VdbeMemRealify(pMem); } } @@ -96984,104 +96284,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ -/* -** High-resolution hardware timer used for debugging and testing only. -*/ -#if defined(VDBE_PROFILE) \ - || defined(SQLITE_PERFORMANCE_TRACE) \ - || defined(SQLITE_ENABLE_STMT_SCANSTATUS) -/************** Include hwtime.h in the middle of vdbe.c *********************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 and x86_64 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - -/* -** The following routine only works on Pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - /* - ** asm() is needed for hardware timing support. Without asm(), - ** disable the sqlite3Hwtime() routine. - ** - ** sqlite3Hwtime() is only used for some obscure debugging - ** and analysis configurations, not in any deliverable, so this - ** should not be a great loss. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in vdbe.c ***********************/ -#endif - /* ** Invoke this macro on memory cells just prior to changing the ** value of the cell. This macro verifies that shallow copies are @@ -100049,9 +99251,7 @@ case OP_Column: { /* ncycle */ pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); assert( pC->szRow<=pC->payloadSize ); -#if 0 assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ -#endif } pC->cacheStatus = p->cacheCtr; if( (aOffset[0] = pC->aRow[0])<0x80 ){ @@ -101018,6 +100218,11 @@ case OP_AutoCommit: { assert( p->bIsReader ); if( desiredAutoCommit!=db->autoCommit ){ + + u64 aCommit[COMMIT_TIME_N]; + memset(aCommit, 0, sizeof(aCommit)); + sqlite3CommitTimeSet(aCommit, COMMIT_TIME_START); + if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); @@ -101042,7 +100247,11 @@ case OP_AutoCommit: { }else{ db->autoCommit = (u8)desiredAutoCommit; } + sqlite3CommitTimeSet(aCommit, COMMIT_TIME_BEFORE_HALT); + p->aCommitTime = aCommit; hrc = sqlite3VdbeHalt(p); + p->aCommitTime = 0; + sqlite3CommitTimeSet(aCommit, COMMIT_TIME_AFTER_HALT); if( (hrc & 0xFF)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); @@ -101058,6 +100267,8 @@ case OP_AutoCommit: { }else{ rc = SQLITE_ERROR; } + sqlite3CommitTimeSet(aCommit, COMMIT_TIME_FINISH); + if( desiredAutoCommit ) sqlite3CommitTimeLog(aCommit); goto vdbe_return; }else{ sqlite3VdbeError(p, @@ -101282,11 +100493,6 @@ case OP_SetCookie: { *(u32*)&pDb->pSchema->schema_cookie = *(u32*)&pOp->p3 - pOp->p5; db->mDbFlags |= DBFLAG_SchemaChange; sqlite3FkClearTriggerCache(db, pOp->p1); -#ifdef SQLITE_ENABLE_HCT - if( sqlite3IsHct(pDb->pBt) ){ - rc = sqlite3HctSchemaOp(pDb->pBt, p->zSql); - } -#endif }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; @@ -101633,13 +100839,8 @@ case OP_OpenEphemeral: { /* ncycle */ } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); - assert( p->apCsr[pOp->p1]==pCx ); if( rc ){ - assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); sqlite3BtreeClose(pCx->ub.pBtx); - p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */ - }else{ - assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); } } } @@ -101937,9 +101138,6 @@ case OP_SeekGT: { /* jump0, in3, group, ncycle */ if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } - sqlite3BtreeCursorDir(pC->uc.pCursor, - (oc==OP_SeekGE || oc==OP_SeekGT) ? BTREE_DIR_FORWARD : BTREE_DIR_REVERSE - ); rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ @@ -101993,9 +101191,6 @@ case OP_SeekGT: { /* jump0, in3, group, ncycle */ } #endif r.eqSeen = 0; - sqlite3BtreeCursorDir(pC->uc.pCursor, - (oc==OP_SeekGE || oc==OP_SeekGT) ? BTREE_DIR_FORWARD : BTREE_DIR_REVERSE - ); rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -102417,9 +101612,6 @@ case OP_Found: { /* jump, in3, ncycle */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); - sqlite3BtreeCursorDir(pC->uc.pCursor, - pOp->opcode==OP_NoConflict ? BTREE_DIR_NONE : BTREE_DIR_FORWARD - ); r.nField = (u16)pOp->p4.i; if( r.nField>0 ){ /* Key values in an array of registers */ @@ -102570,7 +101762,6 @@ case OP_NotExists: /* jump, in3, ncycle */ pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); res = 0; - sqlite3BtreeCursorDir(pCrsr, 0); rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ @@ -103652,6 +102843,7 @@ case OP_SorterInsert: { /* in2 */ case OP_IdxDelete: { VdbeCursor *pC; BtCursor *pCrsr; + int res; UnpackedRecord r; assert( pOp->p3>0 ); @@ -103667,10 +102859,6 @@ case OP_IdxDelete: { r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; -#if 1 - rc = sqlite3BtreeIdxDelete(pCrsr, &r); - if( rc ) goto abort_due_to_error; -#else rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ @@ -103680,7 +102868,6 @@ case OP_IdxDelete: { rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); goto abort_due_to_error; } -#endif assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; @@ -106189,7 +105376,7 @@ case OP_ReleaseReg: { ** As with all opcodes, the meanings of the parameters for OP_Explain ** are subject to change from one release to the next. Applications ** should not attempt to interpret or use any of the information -** contained in the OP_Explain opcode. The information provided by this +** contined in the OP_Explain opcode. The information provided by this ** opcode is intended for testing and debugging use only. */ default: { /* This is really OP_Noop, OP_Explain */ @@ -111285,7 +110472,7 @@ static int lookupName( */ if( cntTab==0 || (cntTab==1 - && pMatch!=0 + && ALWAYS(pMatch!=0) && ALWAYS(pMatch->pSTab!=0) && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0 && (pTab->tabFlags & TF_Ephemeral)==0) @@ -111918,8 +111105,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* Resolve function names */ case TK_FUNCTION: { - ExprList *pList; /* The argument list */ - int n; /* Number of arguments */ + ExprList *pList = pExpr->x.pList; /* The argument list */ + int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ @@ -111932,8 +111119,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER ); - pList = pExpr->x.pList; - n = pList ? pList->nExpr : 0; zId = pExpr->u.zToken; pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ @@ -111982,24 +111167,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } } #endif - - /* If the function may call sqlite3_value_subtype(), then set the - ** EP_SubtArg flag on all of its argument expressions. This prevents - ** where.c from replacing the expression with a value read from an - ** index on the same expression, which will not have the correct - ** subtype. Also set the flag if the function expression itself is - ** an EP_SubtArg expression. In this case subtypes are required as - ** the function may return a value with a subtype back to its - ** caller using sqlite3_result_value(). */ - if( (pDef->funcFlags & SQLITE_SUBTYPE) - || ExprHasProperty(pExpr, EP_SubtArg) - ){ - int ii; - for(ii=0; iia[ii].pExpr, EP_SubtArg); - } - } - if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered @@ -117674,59 +116841,6 @@ static int exprCodeInlineFunction( return target; } -/* -** Expression Node callback for sqlite3ExprCanReturnSubtype(). -** -** Only a function call is able to return a subtype. So if the node -** is not a function call, return WRC_Prune immediately. -** -** A function call is able to return a subtype if it has the -** SQLITE_RESULT_SUBTYPE property. -** -** Assume that every function is able to pass-through a subtype from -** one of its argument (using sqlite3_result_value()). Most functions -** are not this way, but we don't have a mechanism to distinguish those -** that are from those that are not, so assume they all work this way. -** That means that if one of its arguments is another function and that -** other function is able to return a subtype, then this function is -** able to return a subtype. -*/ -static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ - int n; - FuncDef *pDef; - sqlite3 *db; - if( pExpr->op!=TK_FUNCTION ){ - return WRC_Prune; - } - assert( ExprUseXList(pExpr) ); - db = pWalker->pParse->db; - n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; - pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ - pWalker->eCode = 1; - return WRC_Prune; - } - return WRC_Continue; -} - -/* -** Return TRUE if expression pExpr is able to return a subtype. -** -** A TRUE return does not guarantee that a subtype will be returned. -** It only indicates that a subtype return is possible. False positives -** are acceptable as they only disable an optimization. False negatives, -** on the other hand, can lead to incorrect answers. -*/ -static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ - Walker w; - memset(&w, 0, sizeof(w)); - w.pParse = pParse; - w.xExprCallback = exprNodeCanReturnSubtype; - sqlite3WalkExpr(&w, pExpr); - return w.eCode; -} - - /* ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr. ** If it is, then resolve the expression by reading from the index and @@ -117759,17 +116873,6 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( continue; } - - /* Functions that might set a subtype should not be replaced by the - ** value taken from an expression index if they are themselves an - ** argument to another scalar function or aggregate. - ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */ - if( ExprHasProperty(pExpr, EP_SubtArg) - && sqlite3ExprCanReturnSubtype(pParse, pExpr) - ){ - continue; - } - v = pParse->pVdbe; assert( v!=0 ); if( p->bMaybeNullRow ){ @@ -124568,8 +123671,8 @@ static int loadStatTbl( char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ int nSample; /* Number of samples */ - i64 nByte; /* Bytes of space required */ - i64 i; /* Bytes of space required */ + int nByte; /* Bytes of space required */ + int i; /* Bytes of space required */ tRowcnt *pSpace; /* Available allocated memory space */ u8 *pPtr; /* Available memory as a u8 for easier manipulation */ @@ -125019,6 +124122,15 @@ static void attachFunc( sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } +#ifdef SQLITE_USER_AUTHENTICATION + if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ + u8 newAuth = 0; + rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); + if( newAuthauth.authLevel ){ + rc = SQLITE_AUTH_USER; + } + } +#endif if( rc ){ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ int iDb = db->nDb - 1; @@ -125516,7 +124628,11 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; - rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ char *z = sqlite3_mprintf("%s.%s", zTab, zCol); if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); @@ -125623,7 +124739,11 @@ SQLITE_PRIVATE int sqlite3AuthCheck( testcase( zArg3==0 ); testcase( pParse->zAuthContext==0 ); - rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; @@ -125856,6 +124976,17 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } sqlite3VdbeAddOp0(v, OP_Halt); +#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE) + if( pParse->nTableLock>0 && db->init.busy==0 ){ + sqlite3UserAuthInit(db); + if( db->auth.authLevelrc = SQLITE_AUTH_USER; + return; + } + } +#endif + /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a @@ -125984,6 +125115,16 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested--; } +#if SQLITE_USER_AUTHENTICATION +/* +** Return TRUE if zTable is the name of the system table that stores the +** list of users and their access credentials. +*/ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ + return sqlite3_stricmp(zTable, "sqlite_user")==0; +} +#endif + /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -126002,6 +125143,13 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); +#if SQLITE_USER_AUTHENTICATION + /* Only the admin user is allowed to know that the sqlite_user table + ** exists */ + if( db->auth.authLevelnDb; i++){ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; @@ -129660,6 +128808,9 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 +#if SQLITE_USER_AUTHENTICATION + && sqlite3UserAuthTable(pTab->zName)==0 +#endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -131289,7 +130440,6 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } if( pKey ){ - if( pIdx->onError ) pKey->nUniqField = pIdx->nKeyCol; assert( sqlite3KeyInfoIsWriteable(pKey) ); for(i=0; iazColl[i]; @@ -132056,7 +131206,6 @@ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char * ** is for a top-level SQL statement. */ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ - assert( IsVirtual(pTab) ); if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){ return 1; } @@ -135551,13 +134700,7 @@ static void signFunc( ** Implementation of fpdecode(x,y,z) function. ** ** x is a real number that is to be decoded. y is the precision. -** z is the maximum real precision. Return a string that shows the -** results of the sqlite3FpDecode() function. -** -** Used for testing and debugging only, specifically testing and debugging -** of the sqlite3FpDecode() function. This SQL function does not appear -** in production builds. This function is not an API and is subject to -** modification or removal in future versions of SQLite. +** z is the maximum real precision. */ static void fpdecodeFunc( sqlite3_context *context, @@ -135584,82 +134727,6 @@ static void fpdecodeFunc( } #endif /* SQLITE_DEBUG */ -#ifdef SQLITE_DEBUG -/* -** Implementation of parseuri(uri,flags) function. -** -** Required Arguments: -** "uri" The URI to parse. -** "flags" Bitmask of flags, as if to sqlite3_open_v2(). -** -** Additional arguments beyond the first two make calls to -** sqlite3_uri_key() for integers and sqlite3_uri_parameter for -** anything else. -** -** The result is a string showing the results of calling sqlite3ParseUri(). -** -** Used for testing and debugging only, specifically testing and debugging -** of the sqlite3ParseUri() function. This SQL function does not appear -** in production builds. This function is not an API and is subject to -** modification or removal in future versions of SQLite. -*/ -static void parseuriFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - sqlite3_str *pResult; - const char *zVfs; - const char *zUri; - unsigned int flgs; - int rc; - sqlite3_vfs *pVfs = 0; - char *zFile = 0; - char *zErr = 0; - - if( argc<2 ) return; - pVfs = sqlite3_vfs_find(0); - assert( pVfs ); - zVfs = pVfs->zName; - zUri = (const char*)sqlite3_value_text(argv[0]); - if( zUri==0 ) return; - flgs = (unsigned int)sqlite3_value_int(argv[1]); - rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr); - pResult = sqlite3_str_new(0); - if( pResult ){ - int i; - sqlite3_str_appendf(pResult, "rc=%d", rc); - sqlite3_str_appendf(pResult, ", flags=0x%x", flgs); - sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0); - sqlite3_str_appendf(pResult, ", err=%Q", zErr); - sqlite3_str_appendf(pResult, ", file=%Q", zFile); - if( zFile ){ - const char *z = zFile; - z += sqlite3Strlen30(z)+1; - while( z[0] ){ - sqlite3_str_appendf(pResult, ", %Q", z); - z += sqlite3Strlen30(z)+1; - } - for(i=2; ibHctMigrate ) bUseSeek = 0; sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); @@ -139643,11 +138710,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** the following conflict logic if it does not. */ VdbeNoopComment((v, "uniqueness check for ROWID")); sqlite3VdbeVerifyAbortable(v, onError); - if( db->bHctMigrate ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRowidOk); - }else{ - sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); - } + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ @@ -139863,13 +138926,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); - if( db->bHctMigrate ){ - addrConflictCk = sqlite3VdbeAddOp2(v, OP_Goto, 0, addrUniqueOk); - }else{ - addrConflictCk = - sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, - regIdx, pIdx->nKeyCol); VdbeCoverage(v); - } + addrConflictCk = + sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, + regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField); @@ -140802,6 +139861,7 @@ SQLITE_API int sqlite3_exec( int nCol = 0; char **azVals = 0; + sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_PREPARE); pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); @@ -140815,6 +139875,7 @@ SQLITE_API int sqlite3_exec( } callbackIsInit = 0; + sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_STEP); while( 1 ){ int i; rc = sqlite3_step(pStmt); @@ -140860,6 +139921,7 @@ SQLITE_API int sqlite3_exec( } } + sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_BEFORE_FINALIZE); if( rc!=SQLITE_ROW ){ rc = sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; @@ -143643,6 +142705,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPRAGMA); if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; @@ -143668,11 +142731,13 @@ SQLITE_PRIVATE void sqlite3Pragma( zRight = sqlite3NameFromToken(db, pValue); } + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINAUTHCHECK); assert( pId2 ); zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDAUTHCHECK); /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS ** connection. If it returns SQLITE_OK, then assume that the VFS @@ -143694,10 +142759,7 @@ SQLITE_PRIVATE void sqlite3Pragma( aFcntl[2] = zRight; aFcntl[3] = 0; db->busyHandler.nBusy = 0; - rc = sqlite3BtreePragma(pDb->pBt, aFcntl); - if( rc==SQLITE_NOTFOUND ){ - rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); - } + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); if( rc==SQLITE_OK ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT); @@ -143723,10 +142785,12 @@ SQLITE_PRIVATE void sqlite3Pragma( goto pragma_out; } + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINLOADSCHEMA); /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDLOADSCHEMA); /* Register the result column names for pragmas that return results */ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 @@ -144086,6 +143150,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_CACHE_SIZE: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINCACHESIZE); if( !zRight ){ returnSingleInt(v, pDb->pSchema->cache_size); }else{ @@ -144093,6 +143158,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDCACHESIZE); break; } @@ -144365,6 +143431,12 @@ SQLITE_PRIVATE void sqlite3Pragma( ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } +#if SQLITE_USER_AUTHENTICATION + if( db->auth.authLevel==UAUTH_User ){ + /* Do not allow non-admin users to modify the schema arbitrarily */ + mask &= ~(SQLITE_WriteSchema); + } +#endif if( sqlite3GetBoolean(zRight, 0) ){ if( (mask & SQLITE_WriteSchema)==0 @@ -144976,7 +144048,6 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Make sure sufficient number of registers have been allocated */ sqlite3TouchRegister(pParse, 8+cnt); - sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt); sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ @@ -145974,6 +145045,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pragma_out: sqlite3DbFree(db, zLeft); sqlite3DbFree(db, zRight); + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPRAGMA); } #ifndef SQLITE_OMIT_VIRTUALTABLE /***************************************************************************** @@ -146504,6 +145576,11 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); + u64 aSchemaTime[SCHEMA_TIME_N]; + memset(aSchemaTime, 0, sizeof(aSchemaTime)); + db->aSchemaTime = aSchemaTime; + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_START); + assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); @@ -146538,6 +145615,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl goto error_out; } + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_CREATE_1); + /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; @@ -146561,6 +145640,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl openedTransaction = 1; } + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_OPEN_TRANS); + /* Get the database meta information. ** ** Meta values are as follows: @@ -146586,6 +145667,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_GET_META); + /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same @@ -146601,7 +145684,14 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #else encoding = SQLITE_UTF8; #endif - sqlite3SetTextEncoding(db, encoding); + if( db->nVdbeActive>0 && encoding!=ENC(db) + && (db->mDbFlags & DBFLAG_Vacuum)==0 + ){ + rc = SQLITE_LOCKED; + goto initone_error_out; + }else{ + sqlite3SetTextEncoding(db, encoding); + } }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ @@ -146614,6 +145704,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl } pDb->pSchema->enc = ENC(db); + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_FIX_ENCODING); + if( pDb->pSchema->cache_size==0 ){ #ifndef SQLITE_OMIT_DEPRECATED size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]); @@ -146625,6 +145717,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_AFTER_SETCACHESIZE); + /* ** file_format==1 Version 3.0.0. ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN @@ -146665,6 +145759,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl xAuth = db->xAuth; db->xAuth = 0; #endif + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_BEGIN_EXEC); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; @@ -146672,11 +145767,13 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #endif if( rc==SQLITE_OK ) rc = initData.rc; sqlite3DbFree(db, zSql); + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_BEGIN_ANALYZE_LOAD); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_END_ANALYZE_LOAD); } assert( pDb == &(db->aDb[iDb]) ); if( db->mallocFailed ){ @@ -146710,6 +145807,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl sqlite3BtreeLeave(pDb->pBt); error_out: + db->aSchemaTime = 0; + sqlite3PrepareTimeSet(aSchemaTime, SCHEMA_TIME_FINISH); + sqlite3SchemaTimeLog(aSchemaTime); if( rc ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); @@ -146773,14 +145873,6 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ }else if( db->noSharedCache ){ db->mDbFlags |= DBFLAG_SchemaKnownOk; } -#ifdef SQLITE_ENABLE_HCT - { - int iDb; - for(iDb=0; rc==SQLITE_OK && iDbnDb; iDb++){ - rc = sqlite3BtreeSchemaLoaded(db->aDb[iDb].pBt); - } - } -#endif } return rc; } @@ -147078,14 +146170,18 @@ static int sqlite3Prepare( } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPARSE); sqlite3RunParser(&sParse, zSqlCopy); + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPARSE); sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); }else{ sParse.zTail = &zSql[nBytes]; } }else{ + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_BEGINPARSE); sqlite3RunParser(&sParse, zSql); + sqlite3PrepareTimeSet(db->aPrepareTime, PREPARE_TIME_ENDPARSE); } assert( 0==sParse.nQueryLoop ); @@ -147146,6 +146242,12 @@ static int sqlite3LockAndPrepare( ){ int rc; int cnt = 0; + u64 *aPrepareSave = db->aPrepareTime; + + u64 aPrepareTime[PREPARE_TIME_N]; + memset(aPrepareTime, 0, sizeof(aPrepareTime)); + sqlite3PrepareTimeSet(aPrepareTime, PREPARE_TIME_START); + db->aPrepareTime = aPrepareTime; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; @@ -147171,6 +146273,11 @@ static int sqlite3LockAndPrepare( db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || (*ppStmt)==0 ); + + db->aPrepareTime = aPrepareSave; + sqlite3PrepareTimeSet(aPrepareTime, PREPARE_TIME_FINISH); + sqlite3PrepareTimeLog(zSql, nBytes, aPrepareTime); + return rc; } @@ -147303,24 +146410,12 @@ static int sqlite3Prepare16( if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } - - /* Make sure nBytes is non-negative and correct. It should be the - ** number of bytes until the end of the input buffer or until the first - ** U+0000 character. If the input nBytes is odd, convert it into - ** an even number. If the input nBytes is negative, then the input - ** must be terminated by at least one U+0000 character */ if( nBytes>=0 ){ int sz; const char *z = (const char*)zSql; for(sz=0; szmutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ @@ -147334,7 +146429,7 @@ static int sqlite3Prepare16( ** the same number of characters into the UTF-16 string. */ int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); - *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed); + *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); } sqlite3DbFree(db, zSql8); rc = sqlite3ApiExit(db, rc); @@ -148919,7 +148014,6 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->enc = ENC(db); p->db = db; p->nRef = 1; - p->nUniqField = 0; memset(&p[1], 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); @@ -159824,15 +158918,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; /* IMP: R-15610-35227 */ } - if( sqlite3IsHct(db->aDb[iDb].pBt) ){ - if( pOut==0 ){ - /* Silent noop */ - return SQLITE_OK; - } - sqlite3SetString(pzErrMsg, db, "cannot VACUUM - hctree database"); - return SQLITE_ERROR; - } - saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ @@ -160948,7 +160033,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; - assert( IsOrdinaryTable(pNew) ); sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); pTab->nNVCol = pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); @@ -162013,17 +161097,9 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( const WhereInfo *pWInfo, /* WHERE clause */ const WhereLevel *pLevel /* Bloom filter on this level */ ); -SQLITE_PRIVATE void sqlite3WhereAddExplainText( - Parse *pParse, /* Parse context */ - int addr, - SrcList *pTabList, /* Table list this loop refers to */ - WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ -); #else # define sqlite3WhereExplainOneScan(u,v,w,x) 0 # define sqlite3WhereExplainBloomFilter(u,v,w) 0 -# define sqlite3WhereAddExplainText(u,v,w,x,y) #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -162225,38 +161301,38 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ } /* -** This function sets the P4 value of an existing OP_Explain opcode to -** text describing the loop in pLevel. If the OP_Explain opcode already has -** a P4 value, it is freed before it is overwritten. +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN +** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG +** was defined at compile-time. If it is not a no-op, a single OP_Explain +** opcode is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. */ -SQLITE_PRIVATE void sqlite3WhereAddExplainText( +SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ - int addr, /* Address of OP_Explain opcode */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ + int ret = 0; #if !defined(SQLITE_DEBUG) if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) #endif { - VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr); - SrcItem *pItem = &pTabList->a[pLevel->iFrom]; + Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ -#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) char *zMsg; /* Text to add to EQP output */ -#endif StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ - if( db->mallocFailed ) return; - pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) @@ -162280,7 +161356,7 @@ SQLITE_PRIVATE void sqlite3WhereAddExplainText( zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; - }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ + }else if( flags & WHERE_IDX_ONLY ){ zFmt = "COVERING INDEX %s"; }else{ zFmt = "INDEX %s"; @@ -162332,50 +161408,11 @@ SQLITE_PRIVATE void sqlite3WhereAddExplainText( sqlite3_str_append(&str, " (~1 row)", 9); } #endif -#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) zMsg = sqlite3StrAccumFinish(&str); sqlite3ExplainBreakpoint("",zMsg); -#endif - - assert( pOp->opcode==OP_Explain ); - assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 ); - sqlite3DbFree(db, pOp->p4.z); - pOp->p4type = P4_DYNAMIC; - pOp->p4.z = sqlite3StrAccumFinish(&str); - } -} - - -/* -** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG -** was defined at compile-time. If it is not a no-op, a single OP_Explain -** opcode is added to the output to describe the table scan strategy in pLevel. -** -** If an OP_Explain opcode is added to the VM, its address is returned. -** Otherwise, if no OP_Explain is coded, zero is returned. -*/ -SQLITE_PRIVATE int sqlite3WhereExplainOneScan( - Parse *pParse, /* Parse context */ - SrcList *pTabList, /* Table list this loop refers to */ - WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ -){ - int ret = 0; -#if !defined(SQLITE_DEBUG) - if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) -#endif - { - if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 - && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 - ){ - Vdbe *v = pParse->pVdbe; - int addr = sqlite3VdbeCurrentAddr(v); - ret = sqlite3VdbeAddOp3( - v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun - ); - sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags); - } + ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), + pParse->addrExplain, pLoop->rRun, + zMsg, P4_DYNAMIC); } return ret; } @@ -162474,10 +161511,9 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( } }else{ int addr; - VdbeOp *pOp; assert( pSrclist->a[pLvl->iFrom].fg.isSubquery ); addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub; - pOp = sqlite3VdbeGetOp(v, addr-1); + VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); @@ -165277,25 +164313,20 @@ static int isLikeOrGlob( z = (u8*)pRight->u.zToken; } if( z ){ - /* Count the number of prefix bytes prior to the first wildcard. - ** or U+fffd character. If the underlying database has a UTF16LE - ** encoding, then only consider ASCII characters. Note that the - ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in - ** this code, but the database engine itself might be processing - ** content using a different encoding. */ + + /* Count the number of prefix characters prior to the first wildcard. + ** If the underlying database has a UTF16LE encoding, then only consider + ** ASCII characters. Note that the encoding of z[] is UTF8 - we are + ** dealing with only UTF8 here in this code, but the database engine + ** itself might be processing content using a different encoding. */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; - if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){ + if( c==wc[3] && z[cnt]!=0 ){ cnt++; - }else if( c>=0x80 ){ - const u8 *z2 = z+cnt-1; - if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){ - cnt--; - break; - }else{ - cnt = (int)(z2-z); - } + }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){ + cnt--; + break; } } @@ -165307,7 +164338,7 @@ static int isLikeOrGlob( ** range search. The third is because the caller assumes that the pattern ** consists of at least one character after all escapes have been ** removed. */ - if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){ + if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ @@ -168599,11 +167630,9 @@ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ + sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; - sqlite3_vtab *pVtab; - assert( IsVirtual(pTab) ); - pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; whereTraceIndexInfoInputs(p, pTab); pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); @@ -169546,7 +168575,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** and Y has additional constraints that might speed the search that X lacks ** but the cost of running X is not more than the cost of running Y. ** -** In other words, return true if the cost relationship between X and Y +** In other words, return true if the cost relationwship between X and Y ** is inverted and needs to be adjusted. ** ** Case 1: @@ -173164,7 +172193,6 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( WhereTerm *pTerm, *pEnd; SrcItem *pItem; WhereLoop *pLoop; - Bitmask m1; pLoop = pWInfo->a[i].pWLoop; pItem = &pWInfo->pTabList->a[pLoop->iTab]; if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue; @@ -173191,10 +172219,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( } } if( pTerm omit unused FROM-clause term %c\n",pLoop->cId)); - m1 = MASKBIT(i)-1; - testcase( ((pWInfo->revMask>>1) & ~m1)!=0 ); - pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1); + WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId)); notReady &= ~pLoop->maskSelf; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ @@ -173265,6 +172290,58 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } +/* +** Expression Node callback for sqlite3ExprCanReturnSubtype(). +** +** Only a function call is able to return a subtype. So if the node +** is not a function call, return WRC_Prune immediately. +** +** A function call is able to return a subtype if it has the +** SQLITE_RESULT_SUBTYPE property. +** +** Assume that every function is able to pass-through a subtype from +** one of its argument (using sqlite3_result_value()). Most functions +** are not this way, but we don't have a mechanism to distinguish those +** that are from those that are not, so assume they all work this way. +** That means that if one of its arguments is another function and that +** other function is able to return a subtype, then this function is +** able to return a subtype. +*/ +static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ + int n; + FuncDef *pDef; + sqlite3 *db; + if( pExpr->op!=TK_FUNCTION ){ + return WRC_Prune; + } + assert( ExprUseXList(pExpr) ); + db = pWalker->pParse->db; + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ + pWalker->eCode = 1; + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Return TRUE if expression pExpr is able to return a subtype. +** +** A TRUE return does not guarantee that a subtype will be returned. +** It only indicates that a subtype return is possible. False positives +** are acceptable as they only disable an optimization. False negatives, +** on the other hand, can lead to incorrect answers. +*/ +static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ + Walker w; + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = exprNodeCanReturnSubtype; + sqlite3WalkExpr(&w, pExpr); + return w.eCode; +} + /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor @@ -173298,6 +172375,12 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( continue; } if( sqlite3ExprIsConstant(0,pExpr) ) continue; + if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){ + /* Functions that might set a subtype should not be replaced by the + ** value taken from an expression index since the index omits the + ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ + continue; + } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; @@ -174404,28 +173487,14 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); - }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ + }else{ + /* Unable to translate the table reference into an index + ** reference. Verify that this is harmless - that the + ** table being referenced really is open. + */ if( pLoop->wsFlags & WHERE_IDX_ONLY ){ - /* An error. pLoop is supposed to be a covering index loop, - ** and yet the VM code refers to a column of the table that - ** is not part of the index. */ sqlite3ErrorMsg(pParse, "internal query planner error"); pParse->rc = SQLITE_INTERNAL; - }else{ - /* The WHERE_EXPRIDX flag is set by the planner when it is likely - ** that pLoop is a covering index loop, but it is not possible - ** to be 100% sure. In this case, any OP_Explain opcode - ** corresponding to this loop describes the index as a "COVERING - ** INDEX". But, pOp proves that pLoop is not actually a covering - ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the - ** text that accompanies the OP_Explain opcode, if any. */ - pLoop->wsFlags &= ~WHERE_EXPRIDX; - sqlite3WhereAddExplainText(pParse, - pLevel->addrBody-1, - pTabList, - pLevel, - pWInfo->wctrlFlags - ); } } }else if( pOp->opcode==OP_Rowid ){ @@ -176133,7 +175202,6 @@ static void windowAggStep( int regArg; int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; - int addrIf = 0; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); @@ -176150,18 +175218,6 @@ static void windowAggStep( } regArg = reg; - if( pWin->pFilter ){ - int regTmp; - assert( ExprUseXList(pWin->pOwner) ); - assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); - assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); - addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); - VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, regTmp); - } - if( pMWin->regStartRowid==0 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) @@ -176181,13 +175237,25 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ - assert( pWin->pFilter==0 ); assert( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); }else if( pFunc->xSFunc!=noopStepFunc ){ + int addrIf = 0; + if( pWin->pFilter ){ + int regTmp; + assert( ExprUseXList(pWin->pOwner) ); + assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); + assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); + addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regTmp); + } + if( pWin->bExprArgs ){ int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; @@ -176218,9 +175286,8 @@ static void windowAggStep( if( pWin->bExprArgs ){ sqlite3ReleaseTempRange(pParse, regArg, nArg); } + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } - - if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } @@ -177880,122 +176947,122 @@ static void updateDeleteLimitError( #define TK_GE 59 #define TK_ESCAPE 60 #define TK_COLUMNKW 61 -#define TK_CONCURRENT 62 -#define TK_DO 63 -#define TK_FOR 64 -#define TK_IGNORE 65 -#define TK_INITIALLY 66 -#define TK_INSTEAD 67 -#define TK_NO 68 -#define TK_KEY 69 -#define TK_OF 70 -#define TK_OFFSET 71 -#define TK_PRAGMA 72 -#define TK_RAISE 73 -#define TK_RECURSIVE 74 -#define TK_REPLACE 75 -#define TK_RESTRICT 76 -#define TK_ROW 77 -#define TK_ROWS 78 -#define TK_TRIGGER 79 -#define TK_VACUUM 80 -#define TK_VIEW 81 -#define TK_VIRTUAL 82 -#define TK_WITH 83 -#define TK_NULLS 84 -#define TK_FIRST 85 -#define TK_LAST 86 -#define TK_CURRENT 87 -#define TK_FOLLOWING 88 -#define TK_PARTITION 89 -#define TK_PRECEDING 90 -#define TK_RANGE 91 -#define TK_UNBOUNDED 92 -#define TK_EXCLUDE 93 -#define TK_GROUPS 94 -#define TK_OTHERS 95 -#define TK_TIES 96 -#define TK_GENERATED 97 -#define TK_ALWAYS 98 -#define TK_MATERIALIZED 99 -#define TK_REINDEX 100 -#define TK_RENAME 101 -#define TK_CTIME_KW 102 -#define TK_ANY 103 -#define TK_BITAND 104 -#define TK_BITOR 105 -#define TK_LSHIFT 106 -#define TK_RSHIFT 107 -#define TK_PLUS 108 -#define TK_MINUS 109 -#define TK_STAR 110 -#define TK_SLASH 111 -#define TK_REM 112 -#define TK_CONCAT 113 -#define TK_PTR 114 -#define TK_COLLATE 115 -#define TK_BITNOT 116 -#define TK_ON 117 -#define TK_INDEXED 118 -#define TK_STRING 119 -#define TK_JOIN_KW 120 -#define TK_CONSTRAINT 121 -#define TK_DEFAULT 122 -#define TK_NULL 123 -#define TK_PRIMARY 124 -#define TK_UNIQUE 125 -#define TK_CHECK 126 -#define TK_REFERENCES 127 -#define TK_AUTOINCR 128 -#define TK_INSERT 129 -#define TK_DELETE 130 -#define TK_UPDATE 131 -#define TK_SET 132 -#define TK_DEFERRABLE 133 -#define TK_FOREIGN 134 -#define TK_DROP 135 -#define TK_UNION 136 -#define TK_ALL 137 -#define TK_EXCEPT 138 -#define TK_INTERSECT 139 -#define TK_SELECT 140 -#define TK_VALUES 141 -#define TK_DISTINCT 142 -#define TK_DOT 143 -#define TK_FROM 144 -#define TK_JOIN 145 -#define TK_USING 146 -#define TK_ORDER 147 -#define TK_GROUP 148 -#define TK_HAVING 149 -#define TK_LIMIT 150 -#define TK_WHERE 151 -#define TK_RETURNING 152 -#define TK_INTO 153 -#define TK_NOTHING 154 -#define TK_FLOAT 155 -#define TK_BLOB 156 -#define TK_INTEGER 157 -#define TK_VARIABLE 158 -#define TK_CASE 159 -#define TK_WHEN 160 -#define TK_THEN 161 -#define TK_ELSE 162 -#define TK_INDEX 163 -#define TK_ALTER 164 -#define TK_ADD 165 -#define TK_WINDOW 166 -#define TK_OVER 167 -#define TK_FILTER 168 -#define TK_COLUMN 169 -#define TK_AGG_FUNCTION 170 -#define TK_AGG_COLUMN 171 -#define TK_TRUEFALSE 172 -#define TK_FUNCTION 173 -#define TK_UPLUS 174 -#define TK_UMINUS 175 -#define TK_TRUTH 176 -#define TK_REGISTER 177 +#define TK_DO 62 +#define TK_FOR 63 +#define TK_IGNORE 64 +#define TK_INITIALLY 65 +#define TK_INSTEAD 66 +#define TK_NO 67 +#define TK_KEY 68 +#define TK_OF 69 +#define TK_OFFSET 70 +#define TK_PRAGMA 71 +#define TK_RAISE 72 +#define TK_RECURSIVE 73 +#define TK_REPLACE 74 +#define TK_RESTRICT 75 +#define TK_ROW 76 +#define TK_ROWS 77 +#define TK_TRIGGER 78 +#define TK_VACUUM 79 +#define TK_VIEW 80 +#define TK_VIRTUAL 81 +#define TK_WITH 82 +#define TK_NULLS 83 +#define TK_FIRST 84 +#define TK_LAST 85 +#define TK_CURRENT 86 +#define TK_FOLLOWING 87 +#define TK_PARTITION 88 +#define TK_PRECEDING 89 +#define TK_RANGE 90 +#define TK_UNBOUNDED 91 +#define TK_EXCLUDE 92 +#define TK_GROUPS 93 +#define TK_OTHERS 94 +#define TK_TIES 95 +#define TK_GENERATED 96 +#define TK_ALWAYS 97 +#define TK_MATERIALIZED 98 +#define TK_REINDEX 99 +#define TK_RENAME 100 +#define TK_CTIME_KW 101 +#define TK_ANY 102 +#define TK_BITAND 103 +#define TK_BITOR 104 +#define TK_LSHIFT 105 +#define TK_RSHIFT 106 +#define TK_PLUS 107 +#define TK_MINUS 108 +#define TK_STAR 109 +#define TK_SLASH 110 +#define TK_REM 111 +#define TK_CONCAT 112 +#define TK_PTR 113 +#define TK_COLLATE 114 +#define TK_BITNOT 115 +#define TK_ON 116 +#define TK_INDEXED 117 +#define TK_STRING 118 +#define TK_JOIN_KW 119 +#define TK_CONSTRAINT 120 +#define TK_DEFAULT 121 +#define TK_NULL 122 +#define TK_PRIMARY 123 +#define TK_UNIQUE 124 +#define TK_CHECK 125 +#define TK_REFERENCES 126 +#define TK_AUTOINCR 127 +#define TK_INSERT 128 +#define TK_DELETE 129 +#define TK_UPDATE 130 +#define TK_SET 131 +#define TK_DEFERRABLE 132 +#define TK_FOREIGN 133 +#define TK_DROP 134 +#define TK_UNION 135 +#define TK_ALL 136 +#define TK_EXCEPT 137 +#define TK_INTERSECT 138 +#define TK_SELECT 139 +#define TK_VALUES 140 +#define TK_DISTINCT 141 +#define TK_DOT 142 +#define TK_FROM 143 +#define TK_JOIN 144 +#define TK_USING 145 +#define TK_ORDER 146 +#define TK_GROUP 147 +#define TK_HAVING 148 +#define TK_LIMIT 149 +#define TK_WHERE 150 +#define TK_RETURNING 151 +#define TK_INTO 152 +#define TK_NOTHING 153 +#define TK_FLOAT 154 +#define TK_BLOB 155 +#define TK_INTEGER 156 +#define TK_VARIABLE 157 +#define TK_CASE 158 +#define TK_WHEN 159 +#define TK_THEN 160 +#define TK_ELSE 161 +#define TK_INDEX 162 +#define TK_ALTER 163 +#define TK_ADD 164 +#define TK_WINDOW 165 +#define TK_OVER 166 +#define TK_FILTER 167 +#define TK_COLUMN 168 +#define TK_AGG_FUNCTION 169 +#define TK_AGG_COLUMN 170 +#define TK_TRUEFALSE 171 +#define TK_FUNCTION 172 +#define TK_UPLUS 173 +#define TK_UMINUS 174 +#define TK_TRUTH 175 +#define TK_REGISTER 176 +#define TK_CONCURRENT 177 #define TK_VECTOR 178 #define TK_SELECT_COLUMN 179 #define TK_IF_NULL_ROW 180 @@ -178071,7 +177138,7 @@ static void updateDeleteLimitError( #define YYCODETYPE unsigned short int #define YYNOCODE 323 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 103 +#define YYWILDCARD 102 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; @@ -178208,454 +177275,450 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2212) +#define YY_ACTTAB_COUNT (2176) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 130, 127, 234, 130, 127, 234, 574, 574, 574, 580, - /* 10 */ 1294, 1259, 1, 1, 586, 2, 1263, 580, 502, 417, - /* 20 */ 585, 321, 1263, 155, 1546, 1297, 294, 321, 166, 155, - /* 30 */ 1345, 987, 51, 51, 1626, 987, 1345, 1337, 1337, 988, - /* 40 */ 82, 82, 1304, 988, 137, 138, 91, 534, 1232, 1232, + /* 0 */ 1332, 580, 1311, 580, 379, 580, 1285, 282, 282, 1626, + /* 10 */ 1332, 1259, 1, 1, 586, 2, 1263, 1304, 1283, 417, + /* 20 */ 577, 321, 566, 155, 81, 81, 51, 51, 51, 51, + /* 30 */ 1345, 987, 130, 127, 234, 1153, 1661, 1294, 1661, 988, + /* 40 */ 130, 127, 234, 436, 137, 138, 91, 534, 1232, 1232, /* 50 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 60 */ 214, 288, 288, 425, 362, 288, 288, 453, 453, 453, - /* 70 */ 441, 288, 288, 405, 577, 368, 566, 540, 577, 580, - /* 80 */ 566, 1208, 288, 288, 577, 285, 566, 973, 136, 136, - /* 90 */ 136, 136, 129, 245, 491, 577, 329, 566, 275, 245, - /* 100 */ 264, 231, 19, 19, 134, 134, 134, 134, 133, 133, - /* 110 */ 132, 132, 132, 131, 128, 455, 1296, 430, 1606, 586, - /* 120 */ 2, 1263, 460, 385, 417, 459, 321, 357, 155, 360, - /* 130 */ 1111, 459, 1586, 384, 1111, 1345, 134, 134, 134, 134, - /* 140 */ 133, 133, 132, 132, 132, 131, 128, 455, 518, 137, - /* 150 */ 138, 91, 524, 1232, 1232, 1067, 1070, 1057, 1057, 135, - /* 160 */ 135, 136, 136, 136, 136, 580, 438, 1208, 497, 182, - /* 170 */ 288, 288, 274, 291, 376, 521, 371, 520, 262, 130, - /* 180 */ 127, 234, 233, 577, 367, 566, 407, 1510, 51, 51, - /* 190 */ 1208, 1209, 1208, 1178, 298, 1178, 1285, 1572, 245, 133, - /* 200 */ 133, 132, 132, 132, 131, 128, 455, 973, 1283, 134, - /* 210 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 220 */ 455, 288, 288, 132, 132, 132, 131, 128, 455, 417, - /* 230 */ 459, 1023, 476, 350, 577, 112, 566, 157, 1228, 44, - /* 240 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 250 */ 128, 455, 483, 267, 137, 138, 91, 455, 1232, 1232, - /* 260 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 270 */ 1054, 1054, 1068, 1071, 1208, 1439, 1208, 1209, 1208, 257, - /* 280 */ 580, 139, 515, 512, 511, 348, 527, 527, 1588, 580, - /* 290 */ 383, 7, 510, 487, 1173, 257, 320, 571, 515, 512, - /* 300 */ 511, 417, 1581, 51, 51, 544, 7, 1173, 510, 1574, - /* 310 */ 1173, 381, 82, 82, 134, 134, 134, 134, 133, 133, - /* 320 */ 132, 132, 132, 131, 128, 455, 137, 138, 91, 1632, - /* 330 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, - /* 340 */ 136, 136, 417, 1173, 1173, 1058, 432, 94, 1228, 561, - /* 350 */ 948, 93, 320, 571, 551, 947, 1173, 1173, 535, 1173, - /* 360 */ 1173, 1153, 1661, 543, 1661, 303, 386, 137, 138, 91, - /* 370 */ 1343, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 380 */ 136, 136, 136, 1208, 1209, 1208, 134, 134, 134, 134, - /* 390 */ 133, 133, 132, 132, 132, 131, 128, 455, 973, 421, - /* 400 */ 288, 288, 580, 1586, 548, 288, 288, 466, 136, 136, - /* 410 */ 136, 136, 542, 577, 417, 566, 1153, 1662, 577, 1662, - /* 420 */ 566, 1023, 130, 127, 234, 81, 81, 134, 134, 134, - /* 430 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 137, - /* 440 */ 138, 91, 1151, 1232, 1232, 1067, 1070, 1057, 1057, 135, - /* 450 */ 135, 136, 136, 136, 136, 580, 134, 134, 134, 134, - /* 460 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 282, - /* 470 */ 282, 1208, 580, 261, 1208, 348, 471, 334, 82, 82, - /* 480 */ 1602, 1281, 577, 496, 566, 530, 485, 493, 391, 579, - /* 490 */ 564, 82, 82, 233, 464, 82, 82, 1151, 379, 134, - /* 500 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 510 */ 455, 485, 464, 463, 214, 561, 288, 288, 973, 417, - /* 520 */ 288, 288, 396, 364, 560, 288, 288, 410, 316, 577, - /* 530 */ 1208, 566, 561, 577, 1315, 566, 45, 436, 577, 417, - /* 540 */ 566, 443, 422, 516, 137, 138, 91, 219, 1232, 1232, - /* 550 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 560 */ 1208, 382, 296, 417, 137, 138, 91, 890, 1232, 1232, - /* 570 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, - /* 580 */ 1208, 1209, 1208, 1208, 1209, 1208, 464, 299, 137, 138, - /* 590 */ 91, 485, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, - /* 600 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133, - /* 610 */ 132, 132, 132, 131, 128, 455, 283, 427, 96, 1515, - /* 620 */ 1208, 580, 539, 1208, 134, 134, 134, 134, 133, 133, - /* 630 */ 132, 132, 132, 131, 128, 455, 197, 1515, 1517, 1208, - /* 640 */ 1209, 1208, 452, 451, 82, 82, 320, 571, 134, 134, - /* 650 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 660 */ 1208, 953, 289, 289, 229, 526, 975, 302, 417, 1208, - /* 670 */ 1209, 1208, 883, 198, 1285, 577, 1208, 566, 130, 127, - /* 680 */ 234, 450, 1335, 1335, 582, 46, 582, 331, 417, 1240, - /* 690 */ 227, 1240, 1191, 137, 138, 91, 1455, 1232, 1232, 1067, - /* 700 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 44, - /* 710 */ 232, 1515, 417, 137, 138, 91, 1045, 1232, 1232, 1067, - /* 720 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 1208, - /* 730 */ 1209, 1208, 1208, 1209, 1208, 377, 1599, 137, 138, 91, - /* 740 */ 390, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 750 */ 136, 136, 136, 134, 134, 134, 134, 133, 133, 132, - /* 760 */ 132, 132, 131, 128, 455, 533, 320, 571, 580, 1208, - /* 770 */ 1209, 1208, 580, 134, 134, 134, 134, 133, 133, 132, - /* 780 */ 132, 132, 131, 128, 455, 1208, 1209, 1208, 22, 22, - /* 790 */ 1208, 145, 145, 417, 536, 19, 19, 134, 134, 134, - /* 800 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 222, - /* 810 */ 435, 580, 974, 131, 128, 455, 580, 417, 137, 138, - /* 820 */ 91, 1028, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, - /* 830 */ 136, 136, 136, 136, 147, 147, 491, 417, 1208, 66, - /* 840 */ 66, 1129, 137, 138, 91, 554, 1232, 1232, 1067, 1070, - /* 850 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 578, 44, - /* 860 */ 940, 940, 137, 138, 91, 1556, 1232, 1232, 1067, 1070, - /* 870 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 134, 134, - /* 880 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, - /* 890 */ 1558, 182, 108, 537, 1663, 403, 580, 886, 465, 1208, - /* 900 */ 1209, 1208, 134, 134, 134, 134, 133, 133, 132, 132, - /* 910 */ 132, 131, 128, 455, 1439, 1454, 320, 571, 6, 19, - /* 920 */ 19, 538, 134, 134, 134, 134, 133, 133, 132, 132, - /* 930 */ 132, 131, 128, 455, 437, 115, 347, 452, 451, 580, - /* 940 */ 1208, 580, 417, 1372, 315, 1572, 1237, 1208, 1209, 1208, - /* 950 */ 111, 1239, 562, 40, 377, 1599, 1453, 1208, 461, 1238, - /* 960 */ 555, 555, 82, 82, 82, 82, 1572, 137, 138, 91, - /* 970 */ 5, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, - /* 980 */ 136, 136, 136, 340, 1240, 433, 1240, 288, 288, 1130, - /* 990 */ 1044, 1439, 209, 48, 580, 377, 1599, 475, 580, 317, - /* 1000 */ 577, 561, 566, 1173, 1131, 528, 886, 1033, 552, 552, - /* 1010 */ 563, 1032, 1349, 7, 50, 1572, 1173, 61, 61, 1173, - /* 1020 */ 1132, 82, 82, 392, 577, 388, 566, 134, 134, 134, - /* 1030 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 1554, - /* 1040 */ 288, 288, 926, 1032, 1032, 1034, 337, 580, 339, 1208, - /* 1050 */ 1209, 1208, 927, 577, 529, 566, 417, 1573, 449, 381, - /* 1060 */ 485, 215, 434, 47, 1208, 427, 1208, 1209, 1208, 427, - /* 1070 */ 67, 67, 1192, 1631, 580, 915, 417, 3, 1573, 502, - /* 1080 */ 381, 137, 138, 91, 119, 1232, 1232, 1067, 1070, 1057, - /* 1090 */ 1057, 135, 135, 136, 136, 136, 136, 82, 82, 580, - /* 1100 */ 491, 137, 138, 91, 1044, 1232, 1232, 1067, 1070, 1057, - /* 1110 */ 1057, 135, 135, 136, 136, 136, 136, 1439, 1332, 214, - /* 1120 */ 1311, 1033, 19, 19, 1545, 1032, 1314, 1573, 1332, 381, - /* 1130 */ 338, 227, 416, 324, 454, 212, 304, 306, 866, 213, - /* 1140 */ 125, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 1150 */ 131, 128, 455, 580, 307, 580, 307, 1032, 1032, 1034, - /* 1160 */ 580, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 1170 */ 131, 128, 455, 1208, 1209, 1208, 19, 19, 19, 19, - /* 1180 */ 477, 417, 536, 19, 19, 1439, 1192, 379, 498, 1228, - /* 1190 */ 1579, 442, 554, 206, 7, 1572, 1313, 523, 207, 474, - /* 1200 */ 305, 417, 10, 345, 267, 1109, 137, 126, 91, 502, - /* 1210 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, - /* 1220 */ 136, 136, 906, 580, 948, 550, 446, 138, 91, 947, - /* 1230 */ 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, - /* 1240 */ 136, 136, 1089, 49, 549, 878, 19, 19, 402, 1253, - /* 1250 */ 507, 402, 1152, 1184, 1509, 519, 447, 109, 160, 580, - /* 1260 */ 1580, 556, 557, 907, 7, 1211, 134, 134, 134, 134, - /* 1270 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 261, - /* 1280 */ 1502, 537, 21, 21, 141, 502, 134, 134, 134, 134, - /* 1290 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1228, - /* 1300 */ 1130, 53, 53, 580, 325, 1184, 417, 1573, 1575, 381, - /* 1310 */ 854, 855, 856, 375, 1578, 1131, 1577, 502, 7, 439, - /* 1320 */ 7, 68, 68, 374, 476, 350, 54, 54, 580, 1254, - /* 1330 */ 1344, 1132, 1254, 91, 6, 1232, 1232, 1067, 1070, 1057, - /* 1340 */ 1057, 135, 135, 136, 136, 136, 136, 456, 422, 580, - /* 1350 */ 557, 69, 69, 568, 580, 878, 580, 123, 572, 580, - /* 1360 */ 4, 580, 1340, 580, 367, 580, 1114, 1114, 499, 158, - /* 1370 */ 414, 413, 70, 70, 575, 1211, 328, 71, 71, 72, - /* 1380 */ 72, 479, 73, 73, 55, 55, 56, 56, 57, 57, - /* 1390 */ 532, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 1400 */ 131, 128, 455, 580, 300, 502, 580, 456, 580, 1286, - /* 1410 */ 423, 569, 580, 492, 580, 573, 423, 123, 572, 580, - /* 1420 */ 4, 44, 260, 259, 258, 481, 59, 59, 580, 60, - /* 1430 */ 60, 74, 74, 111, 575, 75, 75, 76, 76, 580, - /* 1440 */ 1044, 467, 20, 20, 468, 467, 121, 121, 9, 580, - /* 1450 */ 355, 77, 77, 469, 122, 415, 456, 581, 456, 580, - /* 1460 */ 221, 1032, 143, 143, 415, 297, 478, 1227, 580, 297, - /* 1470 */ 1157, 569, 144, 144, 424, 184, 482, 415, 320, 571, - /* 1480 */ 287, 231, 78, 78, 238, 546, 580, 415, 456, 580, - /* 1490 */ 545, 62, 62, 1032, 1032, 1034, 1035, 35, 123, 572, - /* 1500 */ 1044, 4, 580, 97, 218, 580, 121, 121, 242, 79, - /* 1510 */ 79, 580, 63, 63, 122, 575, 456, 581, 456, 108, - /* 1520 */ 319, 1032, 1192, 580, 489, 80, 80, 580, 64, 64, - /* 1530 */ 1248, 415, 456, 1370, 170, 170, 897, 580, 120, 580, - /* 1540 */ 117, 580, 123, 572, 580, 4, 171, 171, 538, 580, - /* 1550 */ 87, 87, 569, 1032, 1032, 1034, 1035, 35, 38, 575, - /* 1560 */ 65, 65, 83, 83, 146, 146, 546, 84, 84, 580, - /* 1570 */ 23, 547, 168, 168, 161, 1384, 16, 1148, 1383, 404, - /* 1580 */ 580, 1044, 1192, 580, 470, 580, 222, 121, 121, 580, - /* 1590 */ 293, 39, 148, 148, 580, 122, 569, 456, 581, 456, - /* 1600 */ 905, 904, 1032, 142, 142, 1561, 169, 169, 162, 162, - /* 1610 */ 546, 428, 152, 152, 346, 545, 111, 151, 151, 1025, - /* 1620 */ 484, 266, 266, 490, 323, 1044, 580, 244, 580, 341, - /* 1630 */ 580, 121, 121, 893, 1032, 1032, 1034, 1035, 35, 122, - /* 1640 */ 1096, 456, 581, 456, 580, 1534, 1032, 456, 580, 149, - /* 1650 */ 149, 150, 150, 86, 86, 912, 913, 123, 572, 486, - /* 1660 */ 4, 266, 351, 1192, 111, 990, 991, 88, 88, 1036, - /* 1670 */ 1533, 85, 85, 205, 575, 580, 494, 290, 1032, 1032, - /* 1680 */ 1034, 1035, 35, 1605, 1196, 458, 580, 508, 292, 263, - /* 1690 */ 946, 352, 125, 400, 400, 399, 277, 397, 52, 52, - /* 1700 */ 863, 1380, 365, 165, 111, 111, 456, 1192, 356, 58, - /* 1710 */ 58, 569, 1092, 239, 263, 327, 123, 572, 978, 4, - /* 1720 */ 266, 359, 943, 326, 125, 1108, 456, 1108, 1107, 876, - /* 1730 */ 1107, 159, 361, 575, 363, 1328, 90, 572, 1312, 4, - /* 1740 */ 1044, 370, 945, 893, 125, 380, 121, 121, 952, 1593, - /* 1750 */ 1096, 1393, 1438, 575, 122, 241, 456, 581, 456, 1366, - /* 1760 */ 1378, 1032, 567, 175, 1443, 503, 43, 1293, 1363, 1284, - /* 1770 */ 569, 1272, 1271, 1273, 1613, 280, 167, 312, 313, 1036, - /* 1780 */ 314, 401, 224, 240, 333, 1425, 12, 237, 336, 295, - /* 1790 */ 569, 343, 344, 1032, 1032, 1034, 1035, 35, 1620, 1044, - /* 1800 */ 349, 1430, 1429, 301, 408, 121, 121, 513, 488, 1311, - /* 1810 */ 373, 1506, 228, 122, 1505, 456, 581, 456, 418, 1044, - /* 1820 */ 1032, 1375, 1192, 320, 571, 121, 121, 1616, 570, 1376, - /* 1830 */ 1374, 395, 1248, 122, 186, 456, 581, 456, 210, 559, - /* 1840 */ 1032, 270, 1553, 211, 223, 1373, 1551, 462, 1245, 235, - /* 1850 */ 195, 426, 1032, 1032, 1034, 1035, 35, 92, 95, 558, - /* 1860 */ 96, 1511, 220, 140, 1420, 557, 332, 180, 13, 1426, - /* 1870 */ 188, 1413, 1032, 1032, 1034, 1035, 35, 335, 1196, 458, - /* 1880 */ 472, 1192, 292, 473, 190, 191, 192, 400, 400, 399, - /* 1890 */ 277, 397, 193, 506, 863, 247, 109, 1432, 406, 480, - /* 1900 */ 456, 1192, 1431, 14, 1434, 409, 199, 239, 102, 327, - /* 1910 */ 123, 572, 251, 4, 1500, 501, 495, 326, 1522, 203, - /* 1920 */ 354, 522, 281, 253, 504, 358, 254, 575, 1274, 255, - /* 1930 */ 440, 411, 1331, 1322, 104, 1330, 1329, 897, 1321, 229, - /* 1940 */ 444, 531, 445, 310, 311, 268, 269, 1630, 1598, 241, - /* 1950 */ 1629, 1301, 412, 372, 1300, 1299, 1628, 175, 1584, 1398, - /* 1960 */ 43, 378, 1583, 448, 569, 11, 1487, 389, 1397, 318, - /* 1970 */ 110, 116, 541, 42, 583, 1202, 276, 240, 278, 1354, - /* 1980 */ 279, 387, 584, 1269, 1264, 185, 1353, 216, 393, 394, - /* 1990 */ 419, 420, 172, 1044, 1538, 850, 1539, 156, 308, 121, - /* 2000 */ 121, 1537, 1536, 173, 174, 457, 89, 122, 225, 456, - /* 2010 */ 581, 456, 418, 226, 1032, 217, 236, 320, 571, 322, - /* 2020 */ 154, 1106, 1104, 330, 187, 176, 929, 189, 1227, 243, - /* 2030 */ 246, 342, 1120, 194, 177, 178, 429, 431, 196, 98, - /* 2040 */ 99, 462, 100, 101, 1123, 179, 1032, 1032, 1034, 1035, - /* 2050 */ 35, 248, 292, 249, 1119, 163, 24, 400, 400, 399, - /* 2060 */ 277, 397, 250, 353, 863, 1112, 266, 200, 500, 1242, - /* 2070 */ 252, 201, 15, 374, 865, 1192, 505, 239, 256, 327, - /* 2080 */ 202, 509, 103, 25, 895, 366, 26, 326, 514, 369, - /* 2090 */ 105, 908, 517, 309, 164, 106, 181, 1189, 525, 230, - /* 2100 */ 27, 1073, 107, 1159, 17, 204, 1158, 284, 286, 976, - /* 2110 */ 1175, 125, 1179, 265, 982, 28, 1177, 8, 1182, 241, - /* 2120 */ 1183, 29, 30, 31, 32, 1164, 41, 175, 208, 553, - /* 2130 */ 43, 111, 33, 113, 114, 1087, 1074, 1072, 1076, 34, - /* 2140 */ 1077, 565, 1128, 118, 271, 36, 18, 240, 1037, 877, - /* 2150 */ 124, 939, 37, 272, 273, 398, 576, 183, 153, 1621, - /* 2160 */ 1198, 1197, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 2170 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 2180 */ 1260, 1260, 418, 1260, 1260, 1260, 1260, 320, 571, 1260, - /* 2190 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 2200 */ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, - /* 2210 */ 1260, 462, + /* 60 */ 1208, 1546, 580, 38, 1285, 288, 288, 1606, 586, 2, + /* 70 */ 1263, 285, 1208, 973, 582, 321, 582, 155, 577, 502, + /* 80 */ 566, 214, 288, 288, 1345, 82, 82, 391, 136, 136, + /* 90 */ 136, 136, 129, 245, 416, 577, 39, 566, 1337, 1337, + /* 100 */ 264, 231, 283, 134, 134, 134, 134, 133, 133, 132, + /* 110 */ 132, 132, 131, 128, 455, 1151, 307, 1581, 307, 288, + /* 120 */ 288, 7, 561, 417, 1545, 459, 1586, 384, 1586, 548, + /* 130 */ 1208, 535, 577, 1572, 566, 134, 134, 134, 134, 133, + /* 140 */ 133, 132, 132, 132, 131, 128, 455, 245, 137, 138, + /* 150 */ 91, 455, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, + /* 160 */ 136, 136, 136, 136, 130, 127, 234, 233, 1208, 1209, + /* 170 */ 1208, 257, 953, 1297, 515, 512, 511, 182, 441, 459, + /* 180 */ 1208, 1209, 1208, 368, 510, 132, 132, 132, 131, 128, + /* 190 */ 455, 1178, 973, 1178, 134, 134, 134, 134, 133, 133, + /* 200 */ 132, 132, 132, 131, 128, 455, 362, 134, 134, 134, + /* 210 */ 134, 133, 133, 132, 132, 132, 131, 128, 455, 133, + /* 220 */ 133, 132, 132, 132, 131, 128, 455, 417, 452, 451, + /* 230 */ 44, 289, 289, 112, 485, 1023, 261, 1237, 1208, 1209, + /* 240 */ 1208, 111, 1239, 44, 577, 1574, 566, 381, 580, 329, + /* 250 */ 1238, 502, 137, 138, 91, 518, 1232, 1232, 1067, 1070, + /* 260 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 357, 465, + /* 270 */ 360, 19, 19, 438, 392, 1240, 388, 1240, 139, 274, + /* 280 */ 291, 376, 521, 371, 520, 262, 430, 320, 571, 348, + /* 290 */ 1296, 367, 1173, 1173, 527, 527, 1509, 1023, 417, 7, + /* 300 */ 320, 571, 487, 544, 422, 1173, 1173, 294, 1173, 1173, + /* 310 */ 296, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 320 */ 131, 128, 455, 137, 138, 91, 1632, 1232, 1232, 1067, + /* 330 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 417, + /* 340 */ 1510, 1455, 288, 288, 94, 257, 214, 93, 515, 512, + /* 350 */ 511, 348, 471, 334, 396, 577, 385, 566, 510, 410, + /* 360 */ 182, 543, 386, 502, 137, 138, 91, 417, 1232, 1232, + /* 370 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 380 */ 377, 1599, 134, 134, 134, 134, 133, 133, 132, 132, + /* 390 */ 132, 131, 128, 455, 91, 421, 1232, 1232, 1067, 1070, + /* 400 */ 1057, 1057, 135, 135, 136, 136, 136, 136, 425, 1602, + /* 410 */ 417, 1208, 130, 127, 234, 44, 579, 1208, 130, 127, + /* 420 */ 234, 476, 350, 134, 134, 134, 134, 133, 133, 132, + /* 430 */ 132, 132, 131, 128, 455, 137, 138, 91, 427, 1232, + /* 440 */ 1232, 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, + /* 450 */ 136, 134, 134, 134, 134, 133, 133, 132, 132, 132, + /* 460 */ 131, 128, 455, 580, 452, 451, 1439, 460, 1208, 580, + /* 470 */ 157, 1208, 320, 571, 562, 45, 554, 552, 552, 496, + /* 480 */ 528, 46, 7, 493, 197, 275, 82, 82, 1054, 1054, + /* 490 */ 1068, 1071, 61, 61, 134, 134, 134, 134, 133, 133, + /* 500 */ 132, 132, 132, 131, 128, 455, 468, 1208, 331, 288, + /* 510 */ 288, 1240, 580, 1240, 417, 288, 288, 415, 364, 1208, + /* 520 */ 1209, 1208, 577, 561, 566, 1208, 1209, 1208, 577, 529, + /* 530 */ 566, 382, 563, 580, 417, 51, 51, 432, 516, 137, + /* 540 */ 138, 91, 219, 1232, 1232, 1067, 1070, 1057, 1057, 135, + /* 550 */ 135, 136, 136, 136, 136, 379, 82, 82, 539, 137, + /* 560 */ 138, 91, 1058, 1232, 1232, 1067, 1070, 1057, 1057, 135, + /* 570 */ 135, 136, 136, 136, 136, 1173, 1208, 1209, 1208, 1208, + /* 580 */ 1209, 1208, 536, 108, 320, 571, 551, 580, 1173, 987, + /* 590 */ 580, 1173, 1575, 540, 446, 407, 1208, 988, 134, 134, + /* 600 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 610 */ 82, 82, 538, 82, 82, 1208, 1209, 1208, 134, 134, + /* 620 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 455, + /* 630 */ 288, 288, 550, 1153, 1662, 1588, 1662, 383, 417, 574, + /* 640 */ 574, 574, 890, 577, 542, 566, 578, 561, 940, 940, + /* 650 */ 561, 549, 131, 128, 455, 1208, 560, 238, 417, 443, + /* 660 */ 1184, 483, 883, 137, 138, 91, 303, 1232, 1232, 1067, + /* 670 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 108, + /* 680 */ 537, 464, 111, 137, 138, 91, 533, 1232, 1232, 1067, + /* 690 */ 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, 464, + /* 700 */ 463, 288, 288, 1248, 1208, 1209, 1208, 1439, 538, 22, + /* 710 */ 22, 427, 1184, 1151, 577, 1208, 566, 580, 232, 1343, + /* 720 */ 1572, 554, 134, 134, 134, 134, 133, 133, 132, 132, + /* 730 */ 132, 131, 128, 455, 580, 1281, 580, 229, 526, 96, + /* 740 */ 82, 82, 134, 134, 134, 134, 133, 133, 132, 132, + /* 750 */ 132, 131, 128, 455, 288, 288, 580, 19, 19, 19, + /* 760 */ 19, 6, 417, 1208, 1209, 1208, 1191, 577, 48, 566, + /* 770 */ 288, 288, 435, 464, 437, 320, 571, 316, 433, 145, + /* 780 */ 145, 212, 417, 577, 897, 566, 1045, 137, 138, 91, + /* 790 */ 975, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 800 */ 136, 136, 136, 580, 390, 580, 523, 137, 138, 91, + /* 810 */ 6, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 820 */ 136, 136, 136, 1208, 1209, 1208, 19, 19, 19, 19, + /* 830 */ 427, 469, 1573, 948, 381, 209, 555, 555, 947, 580, + /* 840 */ 475, 306, 415, 442, 530, 1556, 134, 134, 134, 134, + /* 850 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1558, + /* 860 */ 580, 1579, 82, 82, 580, 7, 134, 134, 134, 134, + /* 870 */ 133, 133, 132, 132, 132, 131, 128, 455, 1208, 288, + /* 880 */ 288, 19, 19, 19, 19, 491, 417, 19, 19, 492, + /* 890 */ 1028, 198, 577, 1111, 566, 461, 206, 1111, 207, 317, + /* 900 */ 213, 1208, 556, 1631, 580, 915, 417, 136, 136, 136, + /* 910 */ 136, 137, 138, 91, 40, 1232, 1232, 1067, 1070, 1057, + /* 920 */ 1057, 135, 135, 136, 136, 136, 136, 147, 147, 1515, + /* 930 */ 497, 137, 138, 91, 1228, 1232, 1232, 1067, 1070, 1057, + /* 940 */ 1057, 135, 135, 136, 136, 136, 136, 1515, 1517, 267, + /* 950 */ 340, 1130, 141, 1439, 134, 134, 134, 134, 133, 133, + /* 960 */ 132, 132, 132, 131, 128, 455, 1131, 1109, 1572, 536, + /* 970 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 980 */ 128, 455, 1132, 477, 1208, 298, 1208, 1209, 1208, 1208, + /* 990 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 1000 */ 128, 455, 5, 926, 580, 485, 345, 1208, 1044, 1208, + /* 1010 */ 1209, 1208, 337, 927, 339, 478, 50, 580, 125, 417, + /* 1020 */ 3, 1515, 1349, 1129, 434, 1033, 415, 66, 66, 1032, + /* 1030 */ 453, 453, 453, 290, 577, 866, 566, 414, 413, 417, + /* 1040 */ 67, 67, 1572, 1228, 137, 138, 91, 115, 1232, 1232, + /* 1050 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 1060 */ 580, 1032, 1032, 1034, 137, 138, 91, 537, 1232, 1232, + /* 1070 */ 1067, 1070, 1057, 1057, 135, 135, 136, 136, 136, 136, + /* 1080 */ 1573, 299, 381, 82, 82, 476, 350, 1228, 1554, 485, + /* 1090 */ 47, 1192, 1208, 1209, 1208, 474, 338, 1208, 1209, 1208, + /* 1100 */ 10, 564, 267, 134, 134, 134, 134, 133, 133, 132, + /* 1110 */ 132, 132, 131, 128, 455, 1208, 1209, 1208, 1572, 974, + /* 1120 */ 449, 507, 580, 134, 134, 134, 134, 133, 133, 132, + /* 1130 */ 132, 132, 131, 128, 455, 580, 288, 288, 1089, 557, + /* 1140 */ 580, 1114, 1114, 499, 580, 21, 21, 580, 485, 577, + /* 1150 */ 261, 566, 417, 1620, 1573, 1439, 381, 215, 82, 82, + /* 1160 */ 260, 259, 258, 82, 82, 302, 49, 53, 53, 1211, + /* 1170 */ 68, 68, 417, 1335, 1335, 1454, 1502, 137, 138, 91, + /* 1180 */ 119, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 1190 */ 136, 136, 136, 906, 324, 450, 1228, 137, 138, 91, + /* 1200 */ 454, 1232, 1232, 1067, 1070, 1057, 1057, 135, 135, 136, + /* 1210 */ 136, 136, 136, 1453, 377, 1599, 1663, 403, 422, 854, + /* 1220 */ 855, 856, 1286, 423, 304, 519, 498, 973, 1372, 315, + /* 1230 */ 1573, 580, 381, 907, 367, 502, 134, 134, 134, 134, + /* 1240 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 227, + /* 1250 */ 580, 491, 377, 1599, 54, 54, 134, 134, 134, 134, + /* 1260 */ 133, 133, 132, 132, 132, 131, 128, 455, 580, 1173, + /* 1270 */ 580, 69, 69, 70, 70, 580, 417, 214, 1211, 227, + /* 1280 */ 1344, 557, 1173, 325, 878, 1173, 573, 423, 1439, 439, + /* 1290 */ 405, 71, 71, 72, 72, 580, 417, 160, 73, 73, + /* 1300 */ 158, 137, 126, 91, 502, 1232, 1232, 1067, 1070, 1057, + /* 1310 */ 1057, 135, 135, 136, 136, 136, 136, 580, 55, 55, + /* 1320 */ 886, 233, 138, 91, 580, 1232, 1232, 1067, 1070, 1057, + /* 1330 */ 1057, 135, 135, 136, 136, 136, 136, 402, 1253, 491, + /* 1340 */ 56, 56, 1130, 424, 184, 456, 973, 57, 57, 1340, + /* 1350 */ 502, 347, 580, 466, 580, 123, 572, 1131, 4, 447, + /* 1360 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 1370 */ 128, 455, 575, 1132, 109, 59, 59, 60, 60, 580, + /* 1380 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, + /* 1390 */ 128, 455, 580, 878, 568, 355, 580, 222, 585, 580, + /* 1400 */ 1263, 580, 74, 74, 120, 321, 117, 155, 569, 402, + /* 1410 */ 1152, 161, 1044, 16, 1345, 75, 75, 1254, 44, 76, + /* 1420 */ 76, 482, 20, 20, 77, 77, 1580, 1578, 886, 1033, + /* 1430 */ 7, 7, 415, 1032, 1577, 489, 580, 1044, 7, 305, + /* 1440 */ 1227, 467, 948, 121, 121, 467, 580, 947, 297, 288, + /* 1450 */ 288, 122, 297, 456, 581, 456, 580, 319, 1032, 143, + /* 1460 */ 143, 456, 577, 166, 566, 1032, 1032, 1034, 415, 144, + /* 1470 */ 144, 123, 572, 242, 4, 320, 571, 245, 328, 78, + /* 1480 */ 78, 287, 231, 293, 481, 479, 456, 580, 575, 1254, + /* 1490 */ 1032, 1032, 1034, 1035, 35, 1192, 123, 572, 580, 4, + /* 1500 */ 97, 218, 9, 580, 1148, 580, 404, 580, 300, 459, + /* 1510 */ 62, 62, 580, 575, 23, 375, 580, 323, 580, 221, + /* 1520 */ 1192, 79, 79, 580, 569, 374, 63, 63, 80, 80, + /* 1530 */ 64, 64, 580, 490, 1384, 170, 170, 532, 546, 171, + /* 1540 */ 171, 87, 87, 545, 912, 913, 65, 65, 346, 569, + /* 1550 */ 111, 1383, 580, 1044, 428, 83, 83, 580, 222, 121, + /* 1560 */ 121, 470, 1025, 546, 266, 905, 904, 122, 547, 456, + /* 1570 */ 581, 456, 1561, 893, 1032, 146, 146, 456, 1044, 1096, + /* 1580 */ 84, 84, 990, 991, 121, 121, 524, 123, 572, 341, + /* 1590 */ 4, 244, 122, 1534, 456, 581, 456, 580, 484, 1032, + /* 1600 */ 266, 580, 456, 580, 575, 1036, 1032, 1032, 1034, 1035, + /* 1610 */ 35, 205, 123, 572, 580, 4, 1157, 1108, 580, 1108, + /* 1620 */ 168, 168, 1533, 494, 148, 148, 142, 142, 486, 575, + /* 1630 */ 266, 1032, 1032, 1034, 1035, 35, 1192, 169, 169, 292, + /* 1640 */ 569, 162, 162, 352, 400, 400, 399, 277, 397, 580, + /* 1650 */ 351, 863, 111, 1380, 546, 580, 508, 580, 263, 545, + /* 1660 */ 365, 1192, 111, 356, 239, 569, 327, 359, 580, 1044, + /* 1670 */ 361, 363, 152, 152, 326, 121, 121, 1328, 151, 151, + /* 1680 */ 149, 149, 893, 122, 1315, 456, 581, 456, 1096, 1314, + /* 1690 */ 1032, 150, 150, 1313, 1044, 580, 165, 1092, 111, 263, + /* 1700 */ 121, 121, 952, 1312, 978, 241, 266, 580, 122, 370, + /* 1710 */ 456, 581, 456, 175, 1036, 1032, 43, 380, 86, 86, + /* 1720 */ 1370, 1393, 1032, 1032, 1034, 1035, 35, 1605, 1196, 458, + /* 1730 */ 88, 88, 292, 240, 946, 1438, 125, 400, 400, 399, + /* 1740 */ 277, 397, 580, 943, 863, 125, 1366, 1032, 1032, 1034, + /* 1750 */ 1035, 35, 1192, 1593, 1107, 580, 1107, 239, 876, 327, + /* 1760 */ 159, 945, 1378, 125, 580, 85, 85, 326, 418, 567, + /* 1770 */ 503, 1443, 1293, 320, 571, 1284, 1272, 1192, 52, 52, + /* 1780 */ 1271, 1273, 1613, 280, 401, 167, 1363, 58, 58, 12, + /* 1790 */ 312, 313, 314, 1425, 224, 237, 295, 462, 241, 333, + /* 1800 */ 336, 343, 344, 301, 349, 488, 175, 1375, 456, 43, + /* 1810 */ 1430, 513, 1429, 228, 1376, 1311, 408, 210, 123, 572, + /* 1820 */ 373, 4, 1506, 1505, 1374, 1373, 240, 1616, 456, 570, + /* 1830 */ 211, 395, 1248, 270, 1553, 575, 1245, 223, 90, 572, + /* 1840 */ 1551, 4, 426, 186, 96, 1511, 220, 92, 235, 1426, + /* 1850 */ 95, 195, 140, 557, 332, 575, 13, 180, 1420, 188, + /* 1860 */ 1413, 418, 335, 472, 190, 191, 320, 571, 473, 192, + /* 1870 */ 193, 569, 506, 247, 109, 1434, 406, 199, 495, 1432, + /* 1880 */ 251, 102, 1431, 480, 409, 14, 501, 1522, 281, 354, + /* 1890 */ 462, 569, 1500, 203, 253, 522, 358, 254, 504, 1274, + /* 1900 */ 1044, 255, 1331, 411, 1330, 1329, 121, 121, 440, 104, + /* 1910 */ 1301, 412, 1322, 1630, 122, 1629, 456, 581, 456, 897, + /* 1920 */ 1044, 1032, 372, 1300, 1299, 1628, 121, 121, 1321, 229, + /* 1930 */ 1598, 444, 531, 310, 122, 445, 456, 581, 456, 311, + /* 1940 */ 559, 1032, 378, 268, 269, 448, 1398, 11, 1487, 389, + /* 1950 */ 116, 318, 110, 1032, 1032, 1034, 1035, 35, 1354, 387, + /* 1960 */ 558, 1353, 216, 1584, 1583, 541, 1397, 393, 42, 394, + /* 1970 */ 583, 1202, 276, 1032, 1032, 1034, 1035, 35, 1196, 458, + /* 1980 */ 278, 279, 292, 1192, 584, 1538, 172, 400, 400, 399, + /* 1990 */ 277, 397, 156, 1539, 863, 1269, 1264, 1537, 1536, 308, + /* 2000 */ 456, 225, 173, 1192, 226, 174, 850, 239, 457, 327, + /* 2010 */ 123, 572, 89, 4, 217, 322, 419, 326, 185, 420, + /* 2020 */ 154, 236, 1106, 1104, 330, 187, 176, 575, 1227, 189, + /* 2030 */ 929, 243, 342, 246, 1120, 194, 177, 178, 429, 98, + /* 2040 */ 99, 196, 100, 101, 179, 431, 1123, 248, 241, 1119, + /* 2050 */ 249, 163, 24, 250, 266, 353, 175, 1242, 1112, 43, + /* 2060 */ 500, 252, 200, 569, 201, 15, 374, 865, 505, 509, + /* 2070 */ 256, 895, 202, 103, 25, 26, 240, 366, 164, 514, + /* 2080 */ 369, 105, 309, 517, 1189, 908, 106, 525, 107, 1073, + /* 2090 */ 1159, 17, 1044, 1158, 27, 181, 230, 284, 121, 121, + /* 2100 */ 286, 204, 265, 976, 28, 125, 122, 982, 456, 581, + /* 2110 */ 456, 418, 29, 1032, 1175, 30, 320, 571, 31, 1179, + /* 2120 */ 8, 1177, 1182, 32, 1164, 41, 553, 33, 34, 208, + /* 2130 */ 111, 1087, 1074, 1072, 1076, 1128, 271, 113, 565, 114, + /* 2140 */ 462, 118, 1077, 36, 18, 1032, 1032, 1034, 1035, 35, + /* 2150 */ 1037, 877, 1183, 939, 124, 37, 398, 272, 153, 576, + /* 2160 */ 273, 183, 1621, 1198, 1197, 1260, 1260, 1260, 1260, 1260, + /* 2170 */ 1260, 1260, 1260, 1260, 1260, 1192, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 277, 278, 279, 277, 278, 279, 212, 213, 214, 195, - /* 10 */ 218, 187, 188, 189, 190, 191, 192, 195, 195, 19, - /* 20 */ 190, 197, 192, 199, 298, 218, 206, 197, 23, 199, - /* 30 */ 206, 31, 218, 219, 217, 31, 206, 237, 238, 39, - /* 40 */ 218, 219, 225, 39, 44, 45, 46, 206, 48, 49, + /* 0 */ 225, 195, 227, 195, 195, 195, 195, 241, 242, 217, + /* 10 */ 235, 187, 188, 189, 190, 191, 192, 225, 207, 19, + /* 20 */ 254, 197, 256, 199, 218, 219, 218, 219, 218, 219, + /* 30 */ 206, 31, 277, 278, 279, 22, 23, 218, 25, 39, + /* 40 */ 277, 278, 279, 234, 44, 45, 46, 206, 48, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 60 */ 195, 241, 242, 240, 16, 241, 242, 212, 213, 214, - /* 70 */ 19, 241, 242, 208, 254, 24, 256, 255, 254, 195, - /* 80 */ 256, 9, 241, 242, 254, 23, 256, 25, 56, 57, - /* 90 */ 58, 59, 60, 269, 195, 254, 195, 256, 26, 269, - /* 100 */ 259, 260, 218, 219, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 114, 115, 218, 233, 189, 190, - /* 120 */ 191, 192, 299, 221, 19, 301, 197, 79, 199, 81, - /* 130 */ 29, 301, 318, 319, 33, 206, 104, 105, 106, 107, - /* 140 */ 108, 109, 110, 111, 112, 113, 114, 115, 97, 44, - /* 150 */ 45, 46, 147, 48, 49, 50, 51, 52, 53, 54, - /* 160 */ 55, 56, 57, 58, 59, 195, 115, 9, 67, 195, - /* 170 */ 241, 242, 121, 122, 123, 124, 125, 126, 127, 277, - /* 180 */ 278, 279, 120, 254, 133, 256, 206, 286, 218, 219, - /* 190 */ 118, 119, 120, 88, 295, 90, 195, 195, 269, 108, - /* 200 */ 109, 110, 111, 112, 113, 114, 115, 145, 207, 104, - /* 210 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 220 */ 115, 241, 242, 110, 111, 112, 113, 114, 115, 19, - /* 230 */ 301, 75, 130, 131, 254, 25, 256, 25, 9, 83, - /* 240 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 250 */ 114, 115, 272, 24, 44, 45, 46, 115, 48, 49, - /* 260 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 270 */ 48, 49, 50, 51, 9, 195, 118, 119, 120, 121, - /* 280 */ 195, 71, 124, 125, 126, 129, 312, 313, 318, 195, - /* 290 */ 320, 317, 134, 195, 78, 121, 140, 141, 124, 125, - /* 300 */ 126, 19, 313, 218, 219, 89, 317, 91, 134, 307, - /* 310 */ 94, 309, 218, 219, 104, 105, 106, 107, 108, 109, - /* 320 */ 110, 111, 112, 113, 114, 115, 44, 45, 46, 232, - /* 330 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 340 */ 58, 59, 19, 78, 78, 123, 266, 24, 119, 255, - /* 350 */ 137, 69, 140, 141, 89, 142, 91, 91, 264, 94, - /* 360 */ 94, 22, 23, 147, 25, 206, 221, 44, 45, 46, - /* 370 */ 206, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 380 */ 57, 58, 59, 118, 119, 120, 104, 105, 106, 107, - /* 390 */ 108, 109, 110, 111, 112, 113, 114, 115, 25, 200, - /* 400 */ 241, 242, 195, 318, 319, 241, 242, 272, 56, 57, - /* 410 */ 58, 59, 147, 254, 19, 256, 22, 23, 254, 25, - /* 420 */ 256, 75, 277, 278, 279, 218, 219, 104, 105, 106, - /* 430 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 44, - /* 440 */ 45, 46, 103, 48, 49, 50, 51, 52, 53, 54, - /* 450 */ 55, 56, 57, 58, 59, 195, 104, 105, 106, 107, - /* 460 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 241, - /* 470 */ 242, 9, 195, 48, 9, 129, 130, 131, 218, 219, - /* 480 */ 195, 206, 254, 284, 256, 206, 195, 288, 281, 195, - /* 490 */ 206, 218, 219, 120, 195, 218, 219, 103, 195, 104, - /* 500 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 510 */ 115, 195, 213, 214, 195, 255, 241, 242, 145, 19, - /* 520 */ 241, 242, 203, 23, 264, 241, 242, 208, 255, 254, - /* 530 */ 9, 256, 255, 254, 228, 256, 74, 234, 254, 19, - /* 540 */ 256, 264, 117, 23, 44, 45, 46, 152, 48, 49, - /* 550 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 560 */ 9, 195, 271, 19, 44, 45, 46, 23, 48, 49, - /* 570 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - /* 580 */ 118, 119, 120, 118, 119, 120, 287, 271, 44, 45, - /* 590 */ 46, 195, 48, 49, 50, 51, 52, 53, 54, 55, - /* 600 */ 56, 57, 58, 59, 104, 105, 106, 107, 108, 109, - /* 610 */ 110, 111, 112, 113, 114, 115, 215, 195, 153, 195, - /* 620 */ 9, 195, 195, 9, 104, 105, 106, 107, 108, 109, - /* 630 */ 110, 111, 112, 113, 114, 115, 22, 213, 214, 118, - /* 640 */ 119, 120, 108, 109, 218, 219, 140, 141, 104, 105, - /* 650 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 660 */ 9, 110, 241, 242, 167, 168, 145, 271, 19, 118, - /* 670 */ 119, 120, 23, 22, 195, 254, 9, 256, 277, 278, - /* 680 */ 279, 255, 237, 238, 205, 74, 207, 265, 19, 155, - /* 690 */ 25, 157, 23, 44, 45, 46, 276, 48, 49, 50, - /* 700 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 83, - /* 710 */ 195, 287, 19, 44, 45, 46, 23, 48, 49, 50, - /* 720 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 118, - /* 730 */ 119, 120, 118, 119, 120, 315, 316, 44, 45, 46, - /* 740 */ 195, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 750 */ 57, 58, 59, 104, 105, 106, 107, 108, 109, 110, - /* 760 */ 111, 112, 113, 114, 115, 195, 140, 141, 195, 118, - /* 770 */ 119, 120, 195, 104, 105, 106, 107, 108, 109, 110, - /* 780 */ 111, 112, 113, 114, 115, 118, 119, 120, 218, 219, - /* 790 */ 9, 218, 219, 19, 19, 218, 219, 104, 105, 106, - /* 800 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 144, - /* 810 */ 233, 195, 145, 113, 114, 115, 195, 19, 44, 45, - /* 820 */ 46, 23, 48, 49, 50, 51, 52, 53, 54, 55, - /* 830 */ 56, 57, 58, 59, 218, 219, 195, 19, 9, 218, - /* 840 */ 219, 23, 44, 45, 46, 195, 48, 49, 50, 51, - /* 850 */ 52, 53, 54, 55, 56, 57, 58, 59, 136, 83, - /* 860 */ 138, 139, 44, 45, 46, 195, 48, 49, 50, 51, - /* 870 */ 52, 53, 54, 55, 56, 57, 58, 59, 104, 105, - /* 880 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - /* 890 */ 195, 195, 117, 118, 304, 305, 195, 9, 122, 118, - /* 900 */ 119, 120, 104, 105, 106, 107, 108, 109, 110, 111, - /* 910 */ 112, 113, 114, 115, 195, 276, 140, 141, 215, 218, - /* 920 */ 219, 146, 104, 105, 106, 107, 108, 109, 110, 111, - /* 930 */ 112, 113, 114, 115, 233, 161, 295, 108, 109, 195, - /* 940 */ 9, 195, 19, 262, 263, 195, 117, 118, 119, 120, - /* 950 */ 25, 122, 206, 22, 315, 316, 276, 9, 195, 130, - /* 960 */ 310, 311, 218, 219, 218, 219, 195, 44, 45, 46, - /* 970 */ 22, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 980 */ 57, 58, 59, 16, 155, 266, 157, 241, 242, 12, - /* 990 */ 102, 195, 289, 243, 195, 315, 316, 294, 195, 255, - /* 1000 */ 254, 255, 256, 78, 27, 206, 118, 119, 312, 313, - /* 1010 */ 264, 123, 242, 317, 243, 195, 91, 218, 219, 94, - /* 1020 */ 43, 218, 219, 251, 254, 253, 256, 104, 105, 106, - /* 1030 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 195, - /* 1040 */ 241, 242, 65, 155, 156, 157, 79, 195, 81, 118, - /* 1050 */ 119, 120, 75, 254, 255, 256, 19, 307, 255, 309, - /* 1060 */ 195, 24, 266, 243, 9, 195, 118, 119, 120, 195, - /* 1070 */ 218, 219, 184, 23, 195, 25, 19, 22, 307, 195, - /* 1080 */ 309, 44, 45, 46, 161, 48, 49, 50, 51, 52, - /* 1090 */ 53, 54, 55, 56, 57, 58, 59, 218, 219, 195, - /* 1100 */ 195, 44, 45, 46, 102, 48, 49, 50, 51, 52, - /* 1110 */ 53, 54, 55, 56, 57, 58, 59, 195, 225, 195, - /* 1120 */ 227, 119, 218, 219, 240, 123, 228, 307, 235, 309, - /* 1130 */ 163, 25, 208, 195, 255, 265, 271, 233, 21, 265, - /* 1140 */ 25, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1150 */ 113, 114, 115, 195, 230, 195, 232, 155, 156, 157, - /* 1160 */ 195, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1170 */ 113, 114, 115, 118, 119, 120, 218, 219, 218, 219, - /* 1180 */ 131, 19, 19, 218, 219, 195, 184, 195, 266, 9, - /* 1190 */ 313, 233, 195, 233, 317, 195, 228, 110, 233, 82, - /* 1200 */ 295, 19, 22, 154, 24, 11, 44, 45, 46, 195, - /* 1210 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 1220 */ 58, 59, 35, 195, 137, 68, 234, 45, 46, 142, - /* 1230 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 1240 */ 58, 59, 125, 243, 87, 9, 218, 219, 22, 23, - /* 1250 */ 19, 22, 23, 96, 240, 68, 266, 151, 22, 195, - /* 1260 */ 313, 233, 147, 76, 317, 9, 104, 105, 106, 107, - /* 1270 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 48, - /* 1280 */ 163, 118, 218, 219, 22, 195, 104, 105, 106, 107, - /* 1290 */ 108, 109, 110, 111, 112, 113, 114, 115, 195, 119, - /* 1300 */ 12, 218, 219, 195, 195, 148, 19, 307, 311, 309, - /* 1310 */ 7, 8, 9, 123, 313, 27, 313, 195, 317, 132, - /* 1320 */ 317, 218, 219, 133, 130, 131, 218, 219, 195, 103, - /* 1330 */ 240, 43, 103, 46, 215, 48, 49, 50, 51, 52, - /* 1340 */ 53, 54, 55, 56, 57, 58, 59, 9, 117, 195, - /* 1350 */ 147, 218, 219, 65, 195, 119, 195, 19, 20, 195, - /* 1360 */ 22, 195, 240, 195, 133, 195, 129, 130, 131, 166, - /* 1370 */ 108, 109, 218, 219, 36, 119, 195, 218, 219, 218, - /* 1380 */ 219, 131, 218, 219, 218, 219, 218, 219, 218, 219, - /* 1390 */ 19, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1400 */ 113, 114, 115, 195, 154, 195, 195, 9, 195, 210, - /* 1410 */ 211, 73, 195, 294, 195, 210, 211, 19, 20, 195, - /* 1420 */ 22, 83, 129, 130, 131, 117, 218, 219, 195, 218, - /* 1430 */ 219, 218, 219, 25, 36, 218, 219, 218, 219, 195, - /* 1440 */ 102, 263, 218, 219, 246, 267, 108, 109, 50, 195, - /* 1450 */ 240, 218, 219, 246, 116, 257, 118, 119, 120, 195, - /* 1460 */ 152, 123, 218, 219, 257, 263, 246, 25, 195, 267, - /* 1470 */ 99, 73, 218, 219, 302, 303, 246, 257, 140, 141, - /* 1480 */ 259, 260, 218, 219, 15, 87, 195, 257, 9, 195, - /* 1490 */ 92, 218, 219, 155, 156, 157, 158, 159, 19, 20, - /* 1500 */ 102, 22, 195, 151, 152, 195, 108, 109, 24, 218, - /* 1510 */ 219, 195, 218, 219, 116, 36, 118, 119, 120, 117, - /* 1520 */ 246, 123, 184, 195, 19, 218, 219, 195, 218, 219, - /* 1530 */ 61, 257, 9, 261, 218, 219, 128, 195, 160, 195, - /* 1540 */ 162, 195, 19, 20, 195, 22, 218, 219, 146, 195, - /* 1550 */ 218, 219, 73, 155, 156, 157, 158, 159, 22, 36, - /* 1560 */ 218, 219, 218, 219, 218, 219, 87, 218, 219, 195, - /* 1570 */ 22, 92, 218, 219, 22, 195, 24, 23, 195, 25, - /* 1580 */ 195, 102, 184, 195, 195, 195, 144, 108, 109, 195, - /* 1590 */ 101, 55, 218, 219, 195, 116, 73, 118, 119, 120, - /* 1600 */ 122, 123, 123, 218, 219, 195, 218, 219, 218, 219, - /* 1610 */ 87, 63, 218, 219, 23, 92, 25, 218, 219, 23, - /* 1620 */ 23, 25, 25, 118, 135, 102, 195, 143, 195, 195, - /* 1630 */ 195, 108, 109, 9, 155, 156, 157, 158, 159, 116, - /* 1640 */ 9, 118, 119, 120, 195, 195, 123, 9, 195, 218, - /* 1650 */ 219, 218, 219, 218, 219, 7, 8, 19, 20, 23, - /* 1660 */ 22, 25, 23, 184, 25, 85, 86, 218, 219, 9, - /* 1670 */ 195, 218, 219, 258, 36, 195, 195, 22, 155, 156, - /* 1680 */ 157, 158, 159, 0, 1, 2, 195, 23, 5, 25, - /* 1690 */ 23, 195, 25, 10, 11, 12, 13, 14, 218, 219, - /* 1700 */ 17, 195, 23, 23, 25, 25, 9, 184, 195, 218, - /* 1710 */ 219, 73, 23, 30, 25, 32, 19, 20, 23, 22, - /* 1720 */ 25, 195, 23, 40, 25, 155, 9, 157, 155, 23, - /* 1730 */ 157, 25, 195, 36, 195, 195, 19, 20, 195, 22, - /* 1740 */ 102, 195, 23, 119, 25, 195, 108, 109, 110, 322, - /* 1750 */ 119, 195, 195, 36, 116, 72, 118, 119, 120, 195, - /* 1760 */ 195, 123, 238, 80, 195, 291, 83, 195, 258, 195, - /* 1770 */ 73, 195, 195, 195, 195, 290, 244, 258, 258, 119, - /* 1780 */ 258, 193, 216, 100, 270, 274, 245, 300, 270, 247, - /* 1790 */ 73, 296, 248, 155, 156, 157, 158, 159, 143, 102, - /* 1800 */ 247, 274, 274, 248, 274, 108, 109, 222, 296, 227, - /* 1810 */ 221, 221, 231, 116, 221, 118, 119, 120, 135, 102, - /* 1820 */ 123, 262, 184, 140, 141, 108, 109, 198, 283, 262, - /* 1830 */ 262, 247, 61, 116, 300, 118, 119, 120, 251, 142, - /* 1840 */ 123, 143, 202, 251, 245, 262, 202, 164, 38, 300, - /* 1850 */ 22, 202, 155, 156, 157, 158, 159, 297, 297, 142, - /* 1860 */ 153, 286, 152, 150, 252, 147, 251, 44, 273, 275, - /* 1870 */ 236, 252, 155, 156, 157, 158, 159, 251, 1, 2, - /* 1880 */ 18, 184, 5, 202, 239, 239, 239, 10, 11, 12, - /* 1890 */ 13, 14, 239, 18, 17, 201, 151, 275, 248, 248, - /* 1900 */ 9, 184, 275, 273, 236, 248, 236, 30, 160, 32, - /* 1910 */ 19, 20, 201, 22, 248, 64, 202, 40, 293, 22, - /* 1920 */ 292, 117, 202, 201, 223, 202, 201, 36, 202, 201, - /* 1930 */ 66, 223, 220, 229, 22, 220, 220, 128, 229, 167, - /* 1940 */ 24, 308, 115, 285, 285, 202, 93, 226, 316, 72, - /* 1950 */ 226, 220, 223, 220, 222, 220, 220, 80, 321, 268, - /* 1960 */ 83, 223, 321, 84, 73, 22, 280, 202, 268, 282, - /* 1970 */ 149, 160, 148, 25, 204, 13, 196, 100, 196, 252, - /* 1980 */ 6, 251, 194, 194, 194, 303, 252, 250, 249, 248, - /* 1990 */ 306, 306, 209, 102, 215, 4, 215, 224, 224, 108, - /* 2000 */ 109, 215, 215, 209, 209, 3, 215, 116, 216, 118, - /* 2010 */ 119, 120, 135, 216, 123, 22, 15, 140, 141, 165, - /* 2020 */ 16, 23, 23, 141, 153, 132, 20, 144, 25, 24, - /* 2030 */ 146, 16, 1, 144, 132, 132, 63, 37, 153, 55, - /* 2040 */ 55, 164, 55, 55, 118, 132, 155, 156, 157, 158, - /* 2050 */ 159, 34, 5, 143, 1, 5, 22, 10, 11, 12, - /* 2060 */ 13, 14, 117, 163, 17, 70, 25, 70, 41, 77, - /* 2070 */ 143, 117, 24, 133, 20, 184, 19, 30, 127, 32, - /* 2080 */ 22, 69, 22, 22, 9, 23, 22, 40, 69, 24, - /* 2090 */ 22, 28, 98, 69, 23, 151, 37, 23, 22, 143, - /* 2100 */ 34, 23, 25, 23, 22, 22, 99, 23, 23, 145, - /* 2110 */ 90, 25, 77, 34, 118, 34, 88, 45, 95, 72, - /* 2120 */ 77, 34, 34, 34, 34, 23, 22, 80, 25, 24, - /* 2130 */ 83, 25, 34, 144, 144, 23, 23, 23, 23, 22, - /* 2140 */ 11, 25, 23, 25, 22, 22, 22, 100, 23, 23, - /* 2150 */ 22, 137, 22, 143, 143, 15, 25, 25, 23, 143, - /* 2160 */ 1, 1, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2170 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2180 */ 323, 323, 135, 323, 323, 323, 323, 140, 141, 323, + /* 60 */ 9, 298, 195, 22, 195, 241, 242, 189, 190, 191, + /* 70 */ 192, 23, 9, 25, 205, 197, 207, 199, 254, 195, + /* 80 */ 256, 195, 241, 242, 206, 218, 219, 281, 56, 57, + /* 90 */ 58, 59, 60, 269, 208, 254, 55, 256, 237, 238, + /* 100 */ 259, 260, 215, 103, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 114, 102, 230, 313, 232, 241, + /* 120 */ 242, 317, 255, 19, 240, 301, 318, 319, 318, 319, + /* 130 */ 9, 264, 254, 195, 256, 103, 104, 105, 106, 107, + /* 140 */ 108, 109, 110, 111, 112, 113, 114, 269, 44, 45, + /* 150 */ 46, 114, 48, 49, 50, 51, 52, 53, 54, 55, + /* 160 */ 56, 57, 58, 59, 277, 278, 279, 119, 117, 118, + /* 170 */ 119, 120, 109, 218, 123, 124, 125, 195, 19, 301, + /* 180 */ 117, 118, 119, 24, 133, 109, 110, 111, 112, 113, + /* 190 */ 114, 87, 144, 89, 103, 104, 105, 106, 107, 108, + /* 200 */ 109, 110, 111, 112, 113, 114, 16, 103, 104, 105, + /* 210 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 107, + /* 220 */ 108, 109, 110, 111, 112, 113, 114, 19, 107, 108, + /* 230 */ 82, 241, 242, 25, 195, 74, 48, 116, 117, 118, + /* 240 */ 119, 25, 121, 82, 254, 307, 256, 309, 195, 195, + /* 250 */ 129, 195, 44, 45, 46, 96, 48, 49, 50, 51, + /* 260 */ 52, 53, 54, 55, 56, 57, 58, 59, 78, 121, + /* 270 */ 80, 218, 219, 114, 251, 154, 253, 156, 70, 120, + /* 280 */ 121, 122, 123, 124, 125, 126, 233, 139, 140, 128, + /* 290 */ 218, 132, 77, 77, 312, 313, 240, 74, 19, 317, + /* 300 */ 139, 140, 195, 88, 116, 90, 90, 206, 93, 93, + /* 310 */ 271, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 320 */ 112, 113, 114, 44, 45, 46, 232, 48, 49, 50, + /* 330 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 19, + /* 340 */ 286, 276, 241, 242, 24, 120, 195, 68, 123, 124, + /* 350 */ 125, 128, 129, 130, 203, 254, 221, 256, 133, 208, + /* 360 */ 195, 146, 221, 195, 44, 45, 46, 19, 48, 49, + /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 380 */ 315, 316, 103, 104, 105, 106, 107, 108, 109, 110, + /* 390 */ 111, 112, 113, 114, 46, 200, 48, 49, 50, 51, + /* 400 */ 52, 53, 54, 55, 56, 57, 58, 59, 240, 195, + /* 410 */ 19, 9, 277, 278, 279, 82, 195, 9, 277, 278, + /* 420 */ 279, 129, 130, 103, 104, 105, 106, 107, 108, 109, + /* 430 */ 110, 111, 112, 113, 114, 44, 45, 46, 195, 48, + /* 440 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 450 */ 59, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 460 */ 112, 113, 114, 195, 107, 108, 195, 299, 9, 195, + /* 470 */ 25, 9, 139, 140, 206, 73, 195, 312, 313, 284, + /* 480 */ 206, 73, 317, 288, 22, 26, 218, 219, 48, 49, + /* 490 */ 50, 51, 218, 219, 103, 104, 105, 106, 107, 108, + /* 500 */ 109, 110, 111, 112, 113, 114, 246, 9, 265, 241, + /* 510 */ 242, 154, 195, 156, 19, 241, 242, 257, 23, 117, + /* 520 */ 118, 119, 254, 255, 256, 117, 118, 119, 254, 255, + /* 530 */ 256, 195, 264, 195, 19, 218, 219, 266, 23, 44, + /* 540 */ 45, 46, 151, 48, 49, 50, 51, 52, 53, 54, + /* 550 */ 55, 56, 57, 58, 59, 195, 218, 219, 195, 44, + /* 560 */ 45, 46, 122, 48, 49, 50, 51, 52, 53, 54, + /* 570 */ 55, 56, 57, 58, 59, 77, 117, 118, 119, 117, + /* 580 */ 118, 119, 19, 116, 139, 140, 88, 195, 90, 31, + /* 590 */ 195, 93, 311, 255, 234, 206, 9, 39, 103, 104, + /* 600 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 610 */ 218, 219, 145, 218, 219, 117, 118, 119, 103, 104, + /* 620 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 630 */ 241, 242, 67, 22, 23, 318, 25, 320, 19, 212, + /* 640 */ 213, 214, 23, 254, 146, 256, 135, 255, 137, 138, + /* 650 */ 255, 86, 112, 113, 114, 9, 264, 15, 19, 264, + /* 660 */ 95, 272, 23, 44, 45, 46, 206, 48, 49, 50, + /* 670 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 116, + /* 680 */ 117, 195, 25, 44, 45, 46, 195, 48, 49, 50, + /* 690 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 213, + /* 700 */ 214, 241, 242, 61, 117, 118, 119, 195, 145, 218, + /* 710 */ 219, 195, 147, 102, 254, 9, 256, 195, 195, 206, + /* 720 */ 195, 195, 103, 104, 105, 106, 107, 108, 109, 110, + /* 730 */ 111, 112, 113, 114, 195, 206, 195, 166, 167, 152, + /* 740 */ 218, 219, 103, 104, 105, 106, 107, 108, 109, 110, + /* 750 */ 111, 112, 113, 114, 241, 242, 195, 218, 219, 218, + /* 760 */ 219, 215, 19, 117, 118, 119, 23, 254, 243, 256, + /* 770 */ 241, 242, 233, 287, 233, 139, 140, 255, 266, 218, + /* 780 */ 219, 265, 19, 254, 127, 256, 23, 44, 45, 46, + /* 790 */ 144, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 800 */ 57, 58, 59, 195, 195, 195, 109, 44, 45, 46, + /* 810 */ 215, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 820 */ 57, 58, 59, 117, 118, 119, 218, 219, 218, 219, + /* 830 */ 195, 246, 307, 136, 309, 289, 310, 311, 141, 195, + /* 840 */ 294, 233, 257, 233, 206, 195, 103, 104, 105, 106, + /* 850 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 195, + /* 860 */ 195, 313, 218, 219, 195, 317, 103, 104, 105, 106, + /* 870 */ 107, 108, 109, 110, 111, 112, 113, 114, 9, 241, + /* 880 */ 242, 218, 219, 218, 219, 195, 19, 218, 219, 294, + /* 890 */ 23, 22, 254, 29, 256, 195, 233, 33, 233, 255, + /* 900 */ 265, 9, 233, 23, 195, 25, 19, 56, 57, 58, + /* 910 */ 59, 44, 45, 46, 22, 48, 49, 50, 51, 52, + /* 920 */ 53, 54, 55, 56, 57, 58, 59, 218, 219, 195, + /* 930 */ 66, 44, 45, 46, 9, 48, 49, 50, 51, 52, + /* 940 */ 53, 54, 55, 56, 57, 58, 59, 213, 214, 24, + /* 950 */ 16, 12, 22, 195, 103, 104, 105, 106, 107, 108, + /* 960 */ 109, 110, 111, 112, 113, 114, 27, 11, 195, 19, + /* 970 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 980 */ 113, 114, 43, 130, 9, 295, 117, 118, 119, 9, + /* 990 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1000 */ 113, 114, 22, 64, 195, 195, 153, 9, 101, 117, + /* 1010 */ 118, 119, 78, 74, 80, 246, 243, 195, 25, 19, + /* 1020 */ 22, 287, 242, 23, 266, 118, 257, 218, 219, 122, + /* 1030 */ 212, 213, 214, 22, 254, 21, 256, 107, 108, 19, + /* 1040 */ 218, 219, 195, 118, 44, 45, 46, 160, 48, 49, + /* 1050 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 1060 */ 195, 154, 155, 156, 44, 45, 46, 117, 48, 49, + /* 1070 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 1080 */ 307, 271, 309, 218, 219, 129, 130, 9, 195, 195, + /* 1090 */ 243, 184, 117, 118, 119, 81, 162, 117, 118, 119, + /* 1100 */ 22, 206, 24, 103, 104, 105, 106, 107, 108, 109, + /* 1110 */ 110, 111, 112, 113, 114, 117, 118, 119, 195, 144, + /* 1120 */ 255, 19, 195, 103, 104, 105, 106, 107, 108, 109, + /* 1130 */ 110, 111, 112, 113, 114, 195, 241, 242, 124, 146, + /* 1140 */ 195, 128, 129, 130, 195, 218, 219, 195, 195, 254, + /* 1150 */ 48, 256, 19, 142, 307, 195, 309, 24, 218, 219, + /* 1160 */ 128, 129, 130, 218, 219, 271, 243, 218, 219, 9, + /* 1170 */ 218, 219, 19, 237, 238, 276, 162, 44, 45, 46, + /* 1180 */ 160, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1190 */ 57, 58, 59, 35, 195, 255, 118, 44, 45, 46, + /* 1200 */ 255, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1210 */ 57, 58, 59, 276, 315, 316, 304, 305, 116, 7, + /* 1220 */ 8, 9, 210, 211, 271, 67, 266, 25, 262, 263, + /* 1230 */ 307, 195, 309, 75, 132, 195, 103, 104, 105, 106, + /* 1240 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 25, + /* 1250 */ 195, 195, 315, 316, 218, 219, 103, 104, 105, 106, + /* 1260 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 77, + /* 1270 */ 195, 218, 219, 218, 219, 195, 19, 195, 118, 25, + /* 1280 */ 240, 146, 90, 195, 9, 93, 210, 211, 195, 131, + /* 1290 */ 208, 218, 219, 218, 219, 195, 19, 22, 218, 219, + /* 1300 */ 165, 44, 45, 46, 195, 48, 49, 50, 51, 52, + /* 1310 */ 53, 54, 55, 56, 57, 58, 59, 195, 218, 219, + /* 1320 */ 9, 119, 45, 46, 195, 48, 49, 50, 51, 52, + /* 1330 */ 53, 54, 55, 56, 57, 58, 59, 22, 23, 195, + /* 1340 */ 218, 219, 12, 302, 303, 9, 144, 218, 219, 240, + /* 1350 */ 195, 295, 195, 272, 195, 19, 20, 27, 22, 266, + /* 1360 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1370 */ 113, 114, 36, 43, 150, 218, 219, 218, 219, 195, + /* 1380 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1390 */ 113, 114, 195, 118, 64, 240, 195, 143, 190, 195, + /* 1400 */ 192, 195, 218, 219, 159, 197, 161, 199, 72, 22, + /* 1410 */ 23, 22, 101, 24, 206, 218, 219, 102, 82, 218, + /* 1420 */ 219, 246, 218, 219, 218, 219, 313, 313, 117, 118, + /* 1430 */ 317, 317, 257, 122, 313, 19, 195, 101, 317, 295, + /* 1440 */ 25, 263, 136, 107, 108, 267, 195, 141, 263, 241, + /* 1450 */ 242, 115, 267, 117, 118, 119, 195, 246, 122, 218, + /* 1460 */ 219, 9, 254, 23, 256, 154, 155, 156, 257, 218, + /* 1470 */ 219, 19, 20, 24, 22, 139, 140, 269, 195, 218, + /* 1480 */ 219, 259, 260, 100, 116, 130, 9, 195, 36, 102, + /* 1490 */ 154, 155, 156, 157, 158, 184, 19, 20, 195, 22, + /* 1500 */ 150, 151, 50, 195, 23, 195, 25, 195, 153, 301, + /* 1510 */ 218, 219, 195, 36, 22, 122, 195, 134, 195, 151, + /* 1520 */ 184, 218, 219, 195, 72, 132, 218, 219, 218, 219, + /* 1530 */ 218, 219, 195, 117, 195, 218, 219, 19, 86, 218, + /* 1540 */ 219, 218, 219, 91, 7, 8, 218, 219, 23, 72, + /* 1550 */ 25, 195, 195, 101, 62, 218, 219, 195, 143, 107, + /* 1560 */ 108, 195, 23, 86, 25, 121, 122, 115, 91, 117, + /* 1570 */ 118, 119, 195, 9, 122, 218, 219, 9, 101, 9, + /* 1580 */ 218, 219, 84, 85, 107, 108, 146, 19, 20, 195, + /* 1590 */ 22, 142, 115, 195, 117, 118, 119, 195, 23, 122, + /* 1600 */ 25, 195, 9, 195, 36, 9, 154, 155, 156, 157, + /* 1610 */ 158, 258, 19, 20, 195, 22, 98, 154, 195, 156, + /* 1620 */ 218, 219, 195, 195, 218, 219, 218, 219, 23, 36, + /* 1630 */ 25, 154, 155, 156, 157, 158, 184, 218, 219, 5, + /* 1640 */ 72, 218, 219, 195, 10, 11, 12, 13, 14, 195, + /* 1650 */ 23, 17, 25, 195, 86, 195, 23, 195, 25, 91, + /* 1660 */ 23, 184, 25, 195, 30, 72, 32, 195, 195, 101, + /* 1670 */ 195, 195, 218, 219, 40, 107, 108, 195, 218, 219, + /* 1680 */ 218, 219, 118, 115, 228, 117, 118, 119, 118, 228, + /* 1690 */ 122, 218, 219, 228, 101, 195, 23, 23, 25, 25, + /* 1700 */ 107, 108, 109, 195, 23, 71, 25, 195, 115, 195, + /* 1710 */ 117, 118, 119, 79, 118, 122, 82, 195, 218, 219, + /* 1720 */ 261, 195, 154, 155, 156, 157, 158, 0, 1, 2, + /* 1730 */ 218, 219, 5, 99, 23, 195, 25, 10, 11, 12, + /* 1740 */ 13, 14, 195, 23, 17, 25, 195, 154, 155, 156, + /* 1750 */ 157, 158, 184, 322, 154, 195, 156, 30, 23, 32, + /* 1760 */ 25, 23, 195, 25, 195, 218, 219, 40, 134, 238, + /* 1770 */ 291, 195, 195, 139, 140, 195, 195, 184, 218, 219, + /* 1780 */ 195, 195, 195, 290, 193, 244, 258, 218, 219, 245, + /* 1790 */ 258, 258, 258, 274, 216, 300, 247, 163, 71, 270, + /* 1800 */ 270, 296, 248, 248, 247, 296, 79, 262, 9, 82, + /* 1810 */ 274, 222, 274, 231, 262, 227, 274, 251, 19, 20, + /* 1820 */ 221, 22, 221, 221, 262, 262, 99, 198, 9, 283, + /* 1830 */ 251, 247, 61, 142, 202, 36, 38, 245, 19, 20, + /* 1840 */ 202, 22, 202, 300, 152, 286, 151, 297, 300, 275, + /* 1850 */ 297, 22, 149, 146, 251, 36, 273, 44, 252, 236, + /* 1860 */ 252, 134, 251, 18, 239, 239, 139, 140, 202, 239, + /* 1870 */ 239, 72, 18, 201, 150, 236, 248, 236, 202, 275, + /* 1880 */ 201, 159, 275, 248, 248, 273, 63, 293, 202, 292, + /* 1890 */ 163, 72, 248, 22, 201, 116, 202, 201, 223, 202, + /* 1900 */ 101, 201, 220, 223, 220, 220, 107, 108, 65, 22, + /* 1910 */ 220, 223, 229, 226, 115, 226, 117, 118, 119, 127, + /* 1920 */ 101, 122, 220, 222, 220, 220, 107, 108, 229, 166, + /* 1930 */ 316, 24, 308, 285, 115, 114, 117, 118, 119, 285, + /* 1940 */ 141, 122, 223, 202, 92, 83, 268, 22, 280, 202, + /* 1950 */ 159, 282, 148, 154, 155, 156, 157, 158, 252, 251, + /* 1960 */ 141, 252, 250, 321, 321, 147, 268, 249, 25, 248, + /* 1970 */ 204, 13, 196, 154, 155, 156, 157, 158, 1, 2, + /* 1980 */ 196, 6, 5, 184, 194, 215, 209, 10, 11, 12, + /* 1990 */ 13, 14, 224, 215, 17, 194, 194, 215, 215, 224, + /* 2000 */ 9, 216, 209, 184, 216, 209, 4, 30, 3, 32, + /* 2010 */ 19, 20, 215, 22, 22, 164, 306, 40, 303, 306, + /* 2020 */ 16, 15, 23, 23, 140, 152, 131, 36, 25, 143, + /* 2030 */ 20, 24, 16, 145, 1, 143, 131, 131, 62, 55, + /* 2040 */ 55, 152, 55, 55, 131, 37, 117, 34, 71, 1, + /* 2050 */ 142, 5, 22, 116, 25, 162, 79, 76, 69, 82, + /* 2060 */ 41, 142, 69, 72, 116, 24, 132, 20, 19, 68, + /* 2070 */ 126, 9, 22, 22, 22, 22, 99, 23, 23, 68, + /* 2080 */ 24, 22, 68, 97, 23, 28, 150, 22, 25, 23, + /* 2090 */ 23, 22, 101, 98, 34, 37, 142, 23, 107, 108, + /* 2100 */ 23, 22, 34, 144, 34, 25, 115, 117, 117, 118, + /* 2110 */ 119, 134, 34, 122, 89, 34, 139, 140, 34, 76, + /* 2120 */ 45, 87, 94, 34, 23, 22, 24, 34, 22, 25, + /* 2130 */ 25, 23, 23, 23, 23, 23, 22, 143, 25, 143, + /* 2140 */ 163, 25, 11, 22, 22, 154, 155, 156, 157, 158, + /* 2150 */ 23, 23, 76, 136, 22, 22, 15, 142, 23, 25, + /* 2160 */ 142, 25, 142, 1, 1, 323, 323, 323, 323, 323, + /* 2170 */ 323, 323, 323, 323, 323, 184, 323, 323, 323, 323, + /* 2180 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2190 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2200 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2210 */ 323, 164, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2210 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2220 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2230 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2240 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, @@ -178668,123 +177731,120 @@ static const YYCODETYPE yy_lookahead[] = { /* 2310 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2320 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, /* 2330 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 187, - /* 2350 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2360 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2370 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2380 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2390 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2340 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + /* 2350 */ 323, 323, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2360 */ 187, 187, 187, }; #define YY_SHIFT_COUNT (586) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2160) +#define YY_SHIFT_MAX (2163) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 1877, 1683, 2047, 1338, 1338, 626, 156, 1398, 1479, 1523, - /* 10 */ 1891, 1891, 1891, 776, 626, 626, 626, 626, 626, 0, - /* 20 */ 0, 282, 1057, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 30 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 829, 829, - /* 40 */ 265, 265, 158, 462, 611, 781, 781, 212, 212, 212, - /* 50 */ 212, 105, 210, 323, 395, 500, 520, 544, 649, 669, - /* 60 */ 693, 798, 774, 818, 923, 1037, 1057, 1057, 1057, 1057, - /* 70 */ 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, - /* 80 */ 1057, 1057, 1057, 1057, 1162, 1057, 1182, 1287, 1287, 1638, - /* 90 */ 1697, 1717, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 100 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 110 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 120 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 130 */ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891, - /* 140 */ 1891, 1891, 32, 352, 352, 352, 352, 352, 352, 352, - /* 150 */ 136, 91, 113, 72, 781, 1117, 1231, 781, 781, 534, - /* 160 */ 534, 781, 700, 102, 497, 497, 497, 506, 142, 142, - /* 170 */ 2212, 2212, 51, 51, 51, 465, 614, 614, 614, 614, - /* 180 */ 977, 977, 216, 72, 339, 394, 781, 781, 781, 781, - /* 190 */ 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, - /* 200 */ 781, 781, 781, 781, 781, 775, 925, 925, 781, 1194, - /* 210 */ 266, 266, 1163, 1163, 1256, 1256, 1203, 2212, 2212, 2212, - /* 220 */ 2212, 2212, 2212, 2212, 888, 1002, 1002, 651, 174, 931, - /* 230 */ 551, 948, 521, 667, 1055, 781, 781, 781, 781, 781, - /* 240 */ 781, 781, 781, 781, 781, 346, 781, 781, 781, 781, - /* 250 */ 781, 781, 781, 781, 781, 781, 781, 781, 1187, 1187, - /* 260 */ 1187, 781, 781, 781, 62, 781, 781, 781, 1180, 1157, - /* 270 */ 781, 1288, 781, 781, 781, 781, 781, 781, 781, 781, - /* 280 */ 1237, 101, 722, 229, 229, 229, 229, 373, 722, 722, - /* 290 */ 1087, 1262, 1303, 1469, 1308, 1352, 665, 1352, 1505, 1106, - /* 300 */ 1308, 1308, 1106, 1308, 665, 1505, 1408, 1050, 425, 4, - /* 310 */ 4, 4, 1402, 1402, 1402, 1402, 1115, 1115, 1378, 1442, - /* 320 */ 213, 1552, 1771, 1771, 1698, 1698, 1810, 1810, 1698, 1707, - /* 330 */ 1710, 1828, 1713, 1718, 1823, 1713, 1718, 1862, 1862, 1862, - /* 340 */ 1862, 1698, 1875, 1745, 1710, 1710, 1745, 1828, 1823, 1745, - /* 350 */ 1823, 1745, 1698, 1875, 1748, 1851, 1698, 1875, 1897, 1698, - /* 360 */ 1875, 1698, 1875, 1897, 1804, 1804, 1804, 1864, 1912, 1912, - /* 370 */ 1897, 1804, 1809, 1804, 1864, 1804, 1804, 1772, 1916, 1827, - /* 380 */ 1827, 1897, 1698, 1853, 1853, 1879, 1879, 1713, 1718, 1943, - /* 390 */ 1698, 1811, 1713, 1821, 1824, 1745, 1948, 1962, 1962, 1974, - /* 400 */ 1974, 1974, 2212, 2212, 2212, 2212, 2212, 2212, 2212, 2212, - /* 410 */ 2212, 2212, 2212, 2212, 2212, 2212, 2212, 222, 967, 1226, - /* 420 */ 1229, 48, 1293, 1236, 1554, 1489, 1536, 1484, 1049, 1250, - /* 430 */ 1591, 1548, 1596, 1597, 1636, 1639, 1664, 1679, 1624, 1478, - /* 440 */ 1648, 1190, 1680, 5, 1371, 1631, 1689, 1695, 1580, 1667, - /* 450 */ 1699, 1570, 1573, 1706, 1719, 1660, 1655, 1991, 2002, 1993, - /* 460 */ 1854, 2001, 2004, 1998, 1999, 1882, 1871, 1893, 2003, 2003, - /* 470 */ 2005, 1883, 2006, 1884, 2015, 2031, 1889, 1902, 2003, 1903, - /* 480 */ 1973, 2000, 2003, 1885, 1984, 1985, 1987, 1988, 1913, 1926, - /* 490 */ 2017, 1910, 2053, 2050, 2034, 1945, 1900, 1995, 2041, 1997, - /* 500 */ 1992, 2027, 1927, 1954, 2048, 2054, 2057, 1940, 1951, 2058, - /* 510 */ 2012, 2060, 2061, 2062, 2064, 2019, 2075, 2065, 1994, 2063, - /* 520 */ 2068, 2024, 2059, 2071, 2066, 1944, 2076, 2074, 2078, 2077, - /* 530 */ 2080, 2082, 2007, 1956, 2084, 2085, 1996, 2079, 2083, 1964, - /* 540 */ 2086, 2081, 2087, 2088, 2089, 2020, 2035, 2028, 2072, 2043, - /* 550 */ 2023, 2090, 2102, 2104, 2105, 2103, 2106, 2098, 1989, 1990, - /* 560 */ 2112, 2086, 2113, 2114, 2115, 2117, 2116, 2118, 2119, 2122, - /* 570 */ 2129, 2123, 2124, 2125, 2126, 2128, 2130, 2131, 2014, 2010, - /* 580 */ 2011, 2016, 2132, 2135, 2140, 2159, 2160, + /* 0 */ 1977, 1727, 1634, 1336, 1336, 333, 161, 1452, 1477, 1568, + /* 10 */ 1991, 1991, 1991, 148, 333, 333, 333, 333, 333, 0, + /* 20 */ 0, 279, 1153, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 30 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 121, 121, + /* 40 */ 498, 498, 51, 402, 408, 706, 706, 445, 445, 445, + /* 50 */ 445, 104, 208, 320, 391, 495, 515, 619, 639, 743, + /* 60 */ 763, 867, 887, 1000, 1020, 1133, 1153, 1153, 1153, 1153, + /* 70 */ 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, + /* 80 */ 1153, 1153, 1153, 1153, 1257, 1153, 1277, 348, 348, 1593, + /* 90 */ 1799, 1819, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 100 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 110 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 120 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 130 */ 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991, + /* 140 */ 1991, 1991, 32, 851, 851, 851, 851, 851, 851, 851, + /* 150 */ 91, 112, 76, 459, 706, 1014, 1102, 706, 706, 357, + /* 160 */ 357, 706, 540, 292, 571, 571, 571, 636, 37, 37, + /* 170 */ 2176, 2176, 159, 159, 159, 587, 462, 462, 462, 462, + /* 180 */ 939, 939, 215, 459, 13, 611, 706, 706, 706, 706, + /* 190 */ 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, + /* 200 */ 706, 706, 706, 706, 706, 563, 216, 216, 706, 956, + /* 210 */ 1192, 1192, 950, 950, 1160, 1160, 1135, 2176, 2176, 2176, + /* 220 */ 2176, 2176, 2176, 2176, 1311, 907, 907, 869, 225, 892, + /* 230 */ 63, 980, 646, 975, 998, 706, 706, 706, 706, 706, + /* 240 */ 706, 706, 706, 706, 706, 223, 706, 706, 706, 706, + /* 250 */ 706, 706, 706, 706, 706, 706, 706, 706, 1158, 1158, + /* 260 */ 1158, 706, 706, 706, 48, 706, 706, 706, 1078, 565, + /* 270 */ 706, 1330, 706, 706, 706, 706, 706, 706, 706, 706, + /* 280 */ 1013, 864, 511, 925, 925, 925, 925, 1202, 511, 511, + /* 290 */ 697, 930, 1212, 642, 1368, 1350, 1254, 1350, 1416, 1224, + /* 300 */ 1368, 1368, 1224, 1368, 1254, 1416, 657, 880, 188, 558, + /* 310 */ 558, 558, 467, 467, 467, 467, 993, 993, 1245, 1415, + /* 320 */ 1306, 1389, 1771, 1771, 1691, 1691, 1798, 1798, 1691, 1692, + /* 330 */ 1695, 1829, 1703, 1707, 1813, 1703, 1707, 1845, 1845, 1845, + /* 340 */ 1845, 1691, 1854, 1724, 1695, 1695, 1724, 1829, 1813, 1724, + /* 350 */ 1813, 1724, 1691, 1854, 1722, 1823, 1691, 1854, 1871, 1691, + /* 360 */ 1854, 1691, 1854, 1871, 1779, 1779, 1779, 1843, 1887, 1887, + /* 370 */ 1871, 1779, 1792, 1779, 1843, 1779, 1779, 1763, 1907, 1821, + /* 380 */ 1821, 1871, 1691, 1852, 1852, 1862, 1862, 1703, 1707, 1925, + /* 390 */ 1691, 1791, 1703, 1804, 1818, 1724, 1943, 1958, 1958, 1975, + /* 400 */ 1975, 1975, 2176, 2176, 2176, 2176, 2176, 2176, 2176, 2176, + /* 410 */ 2176, 2176, 2176, 2176, 2176, 2176, 2176, 440, 934, 1315, + /* 420 */ 1387, 190, 1032, 1275, 1481, 1383, 41, 1449, 853, 1355, + /* 430 */ 1525, 1492, 1539, 1575, 1605, 1627, 1633, 1637, 1564, 1444, + /* 440 */ 1537, 1393, 1673, 1440, 1518, 1570, 1674, 1681, 1498, 1711, + /* 450 */ 1720, 1463, 1600, 1735, 1738, 1596, 1011, 2002, 2005, 1992, + /* 460 */ 1851, 2006, 2004, 1999, 2000, 1884, 1873, 1895, 2003, 2003, + /* 470 */ 2007, 1886, 2010, 1888, 2016, 2033, 1892, 1905, 2003, 1906, + /* 480 */ 1976, 2008, 2003, 1889, 1984, 1985, 1987, 1988, 1913, 1929, + /* 490 */ 2013, 1908, 2048, 2046, 2030, 1937, 1893, 1989, 2029, 1993, + /* 500 */ 1981, 2019, 1919, 1948, 2041, 2047, 2049, 1934, 1944, 2050, + /* 510 */ 2001, 2051, 2052, 2054, 2053, 2011, 2062, 2056, 1986, 2057, + /* 520 */ 2059, 2014, 2058, 2055, 2060, 1936, 2065, 2061, 2066, 2063, + /* 530 */ 2067, 2069, 1995, 1954, 2074, 2077, 1990, 2068, 2079, 1959, + /* 540 */ 2080, 2070, 2078, 2081, 2084, 2025, 2043, 2034, 2075, 2076, + /* 550 */ 2028, 2089, 2101, 2103, 2102, 2104, 2105, 2093, 1994, 1996, + /* 560 */ 2108, 2080, 2109, 2110, 2111, 2106, 2113, 2116, 2112, 2114, + /* 570 */ 2131, 2121, 2122, 2127, 2128, 2132, 2133, 2134, 2017, 2015, + /* 580 */ 2018, 2020, 2136, 2135, 2141, 2162, 2163, }; #define YY_REDUCE_COUNT (416) -#define YY_REDUCE_MIN (-277) -#define YY_REDUCE_MAX (1797) +#define YY_REDUCE_MIN (-245) +#define YY_REDUCE_MAX (1802) static const short yy_reduce_ofst[] = { - /* 0 */ -176, -71, -170, 746, 799, -159, -20, -186, -30, 85, - /* 10 */ 94, 260, 277, -180, 159, 164, 275, 279, 284, -98, - /* 20 */ 145, -274, 401, -116, 577, 701, 904, 958, -178, 960, - /* 30 */ 965, 273, 744, 1028, 803, 207, 426, 879, 299, 424, - /* 40 */ -26, 696, 924, 750, 771, 820, 1000, 228, 421, 228, - /* 50 */ 421, -277, -277, -277, -277, -277, -277, -277, -277, -277, - /* 60 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, -277, - /* 70 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, -277, - /* 80 */ -277, -277, -277, -277, -277, -277, -277, -277, -277, 570, - /* 90 */ 573, 616, 621, 852, 1064, 1083, 1103, 1108, 1133, 1154, - /* 100 */ 1159, 1161, 1164, 1166, 1168, 1170, 1208, 1211, 1213, 1217, - /* 110 */ 1219, 1224, 1233, 1244, 1254, 1264, 1273, 1291, 1294, 1307, - /* 120 */ 1310, 1316, 1328, 1332, 1342, 1344, 1346, 1349, 1354, 1374, - /* 130 */ 1385, 1388, 1390, 1394, 1399, 1431, 1433, 1435, 1449, 1453, - /* 140 */ 1480, 1491, -277, -277, -277, -277, -277, -277, -277, -277, - /* 150 */ -277, -277, -277, 479, -177, 199, 893, 2, 650, -206, - /* 160 */ -145, 319, -277, 703, 420, 639, 680, 770, -277, -277, - /* 170 */ -277, -277, -183, -183, -183, -99, 291, 316, 396, 865, - /* 180 */ -200, 445, -11, 1, 590, 590, -135, 422, 870, 874, - /* 190 */ 884, 1014, 1090, 1122, -101, 80, 641, 719, 796, 905, - /* 200 */ 922, 1210, 303, 992, 990, 681, 877, 947, 997, 1119, - /* 210 */ 1001, 1003, 1178, 1202, 1199, 1205, 772, 1172, 1198, 1207, - /* 220 */ 1220, 1230, 1221, 1274, -208, -193, -102, 98, 97, 285, - /* 230 */ 294, 366, 427, 515, 545, 670, 695, 763, 844, 938, - /* 240 */ 1109, 1181, 1380, 1383, 1389, 135, 1410, 1434, 1450, 1475, - /* 250 */ 1481, 1496, 1506, 1513, 1526, 1537, 1539, 1540, 306, 898, - /* 260 */ 968, 1543, 1546, 1550, 1272, 1556, 1557, 1564, 1415, 1427, - /* 270 */ 1565, 1524, 1569, 294, 1572, 1574, 1576, 1577, 1578, 1579, - /* 280 */ 1474, 1485, 1532, 1510, 1519, 1520, 1522, 1272, 1532, 1532, - /* 290 */ 1541, 1566, 1588, 1487, 1511, 1514, 1542, 1518, 1495, 1544, - /* 300 */ 1527, 1528, 1555, 1530, 1553, 1512, 1585, 1581, 1582, 1589, - /* 310 */ 1590, 1593, 1559, 1567, 1568, 1583, 1587, 1592, 1545, 1584, - /* 320 */ 1599, 1629, 1534, 1549, 1640, 1644, 1560, 1561, 1649, 1575, - /* 330 */ 1594, 1595, 1612, 1615, 1634, 1619, 1626, 1645, 1646, 1647, - /* 340 */ 1653, 1681, 1694, 1650, 1622, 1627, 1651, 1630, 1668, 1657, - /* 350 */ 1670, 1666, 1714, 1711, 1625, 1628, 1720, 1722, 1701, 1723, - /* 360 */ 1725, 1726, 1728, 1708, 1712, 1715, 1716, 1704, 1721, 1724, - /* 370 */ 1729, 1731, 1732, 1733, 1709, 1735, 1736, 1632, 1633, 1658, - /* 380 */ 1659, 1738, 1743, 1637, 1641, 1691, 1700, 1727, 1730, 1686, - /* 390 */ 1765, 1687, 1734, 1737, 1739, 1741, 1770, 1780, 1782, 1788, - /* 400 */ 1789, 1790, 1684, 1685, 1682, 1783, 1779, 1781, 1786, 1787, - /* 410 */ 1794, 1773, 1774, 1792, 1797, 1791, 1795, + /* 0 */ -176, -122, 1208, 268, 274, -159, 389, -192, 317, -190, + /* 10 */ -133, 392, 395, 101, 460, 513, 529, 638, 895, 135, + /* 20 */ 141, -237, -113, 53, 539, 541, 608, 610, 338, 663, + /* 30 */ 665, 522, 644, 669, 865, -194, 940, 945, 486, 734, + /* 40 */ -18, 165, -114, 525, 773, 847, 923, -234, -10, -234, + /* 50 */ -10, -245, -245, -245, -245, -245, -245, -245, -245, -245, + /* 60 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, -245, + /* 70 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, -245, + /* 80 */ -245, -245, -245, -245, -245, -245, -245, -245, -245, 491, + /* 90 */ 561, 709, 809, 822, 927, 949, 952, 1036, 1053, 1055, + /* 100 */ 1073, 1075, 1080, 1100, 1122, 1129, 1157, 1159, 1184, 1197, + /* 110 */ 1201, 1204, 1206, 1241, 1251, 1261, 1292, 1303, 1308, 1310, + /* 120 */ 1312, 1317, 1321, 1323, 1328, 1337, 1357, 1362, 1402, 1406, + /* 130 */ 1408, 1419, 1423, 1454, 1460, 1462, 1473, 1500, 1512, 1547, + /* 140 */ 1560, 1569, -245, -245, -245, -245, -245, -245, -245, -245, + /* 150 */ -245, -245, -245, -131, 168, 195, -225, -62, 526, 427, + /* 160 */ 818, 151, -245, 546, 65, 899, 937, 780, -245, -245, + /* 170 */ -245, -245, -208, -208, -208, 54, 39, 810, 894, 953, + /* 180 */ -139, 936, -196, -189, 912, 912, 1082, 243, 516, 635, + /* 190 */ -116, 56, 1040, 1109, 690, 271, 1056, 512, 758, 1144, + /* 200 */ 960, 1155, -191, 360, 1093, 966, 548, 1113, 281, 595, + /* 210 */ 1114, 1121, 1178, 1185, 1012, 1076, 23, 1041, 260, 585, + /* 220 */ 769, 1175, 1222, 1211, -181, -45, 72, 107, 94, 214, + /* 230 */ 221, 336, 363, 523, 609, 650, 664, 700, 893, 999, + /* 240 */ 1088, 1283, 1339, 1356, 1366, 1081, 1377, 1394, 1398, 1427, + /* 250 */ 1428, 1448, 1458, 1468, 1472, 1475, 1476, 1482, 1456, 1461, + /* 260 */ 1465, 1508, 1514, 1522, 1459, 1526, 1540, 1551, 1353, 1431, + /* 270 */ 1567, 1531, 1576, 221, 1577, 1580, 1581, 1585, 1586, 1587, + /* 280 */ 1479, 1493, 1541, 1528, 1532, 1533, 1534, 1459, 1541, 1541, + /* 290 */ 1544, 1578, 1591, 1495, 1519, 1529, 1549, 1530, 1505, 1554, + /* 300 */ 1536, 1538, 1555, 1542, 1557, 1509, 1589, 1582, 1588, 1599, + /* 310 */ 1601, 1602, 1545, 1552, 1562, 1563, 1566, 1579, 1546, 1584, + /* 320 */ 1592, 1629, 1543, 1548, 1632, 1638, 1550, 1553, 1640, 1559, + /* 330 */ 1574, 1583, 1606, 1603, 1623, 1608, 1611, 1625, 1626, 1630, + /* 340 */ 1631, 1666, 1672, 1628, 1604, 1607, 1635, 1612, 1639, 1636, + /* 350 */ 1641, 1644, 1676, 1679, 1594, 1597, 1686, 1693, 1675, 1694, + /* 360 */ 1696, 1697, 1700, 1680, 1682, 1684, 1685, 1683, 1687, 1689, + /* 370 */ 1688, 1690, 1701, 1702, 1699, 1704, 1705, 1614, 1624, 1648, + /* 380 */ 1654, 1719, 1741, 1642, 1643, 1678, 1698, 1706, 1708, 1668, + /* 390 */ 1747, 1669, 1709, 1712, 1718, 1721, 1766, 1776, 1784, 1790, + /* 400 */ 1801, 1802, 1710, 1713, 1715, 1777, 1770, 1778, 1782, 1783, + /* 410 */ 1793, 1768, 1775, 1785, 1788, 1797, 1796, }; static const YYACTIONTYPE yy_default[] = { /* 0 */ 1667, 1667, 1667, 1495, 1258, 1371, 1258, 1258, 1258, 1258, @@ -178927,7 +177987,6 @@ static const YYCODETYPE yyFallback[] = { 0, /* GE => nothing */ 0, /* ESCAPE => nothing */ 9, /* COLUMNKW => ID */ - 9, /* CONCURRENT => ID */ 9, /* DO => ID */ 9, /* FOR => ID */ 9, /* IGNORE => ID */ @@ -179043,6 +178102,7 @@ static const YYCODETYPE yyFallback[] = { 0, /* UMINUS => nothing */ 0, /* TRUTH => nothing */ 0, /* REGISTER => nothing */ + 0, /* CONCURRENT => nothing */ 0, /* VECTOR => nothing */ 0, /* SELECT_COLUMN => nothing */ 0, /* IF_NULL_ROW => nothing */ @@ -179197,122 +178257,122 @@ static const char *const yyTokenName[] = { /* 59 */ "GE", /* 60 */ "ESCAPE", /* 61 */ "COLUMNKW", - /* 62 */ "CONCURRENT", - /* 63 */ "DO", - /* 64 */ "FOR", - /* 65 */ "IGNORE", - /* 66 */ "INITIALLY", - /* 67 */ "INSTEAD", - /* 68 */ "NO", - /* 69 */ "KEY", - /* 70 */ "OF", - /* 71 */ "OFFSET", - /* 72 */ "PRAGMA", - /* 73 */ "RAISE", - /* 74 */ "RECURSIVE", - /* 75 */ "REPLACE", - /* 76 */ "RESTRICT", - /* 77 */ "ROW", - /* 78 */ "ROWS", - /* 79 */ "TRIGGER", - /* 80 */ "VACUUM", - /* 81 */ "VIEW", - /* 82 */ "VIRTUAL", - /* 83 */ "WITH", - /* 84 */ "NULLS", - /* 85 */ "FIRST", - /* 86 */ "LAST", - /* 87 */ "CURRENT", - /* 88 */ "FOLLOWING", - /* 89 */ "PARTITION", - /* 90 */ "PRECEDING", - /* 91 */ "RANGE", - /* 92 */ "UNBOUNDED", - /* 93 */ "EXCLUDE", - /* 94 */ "GROUPS", - /* 95 */ "OTHERS", - /* 96 */ "TIES", - /* 97 */ "GENERATED", - /* 98 */ "ALWAYS", - /* 99 */ "MATERIALIZED", - /* 100 */ "REINDEX", - /* 101 */ "RENAME", - /* 102 */ "CTIME_KW", - /* 103 */ "ANY", - /* 104 */ "BITAND", - /* 105 */ "BITOR", - /* 106 */ "LSHIFT", - /* 107 */ "RSHIFT", - /* 108 */ "PLUS", - /* 109 */ "MINUS", - /* 110 */ "STAR", - /* 111 */ "SLASH", - /* 112 */ "REM", - /* 113 */ "CONCAT", - /* 114 */ "PTR", - /* 115 */ "COLLATE", - /* 116 */ "BITNOT", - /* 117 */ "ON", - /* 118 */ "INDEXED", - /* 119 */ "STRING", - /* 120 */ "JOIN_KW", - /* 121 */ "CONSTRAINT", - /* 122 */ "DEFAULT", - /* 123 */ "NULL", - /* 124 */ "PRIMARY", - /* 125 */ "UNIQUE", - /* 126 */ "CHECK", - /* 127 */ "REFERENCES", - /* 128 */ "AUTOINCR", - /* 129 */ "INSERT", - /* 130 */ "DELETE", - /* 131 */ "UPDATE", - /* 132 */ "SET", - /* 133 */ "DEFERRABLE", - /* 134 */ "FOREIGN", - /* 135 */ "DROP", - /* 136 */ "UNION", - /* 137 */ "ALL", - /* 138 */ "EXCEPT", - /* 139 */ "INTERSECT", - /* 140 */ "SELECT", - /* 141 */ "VALUES", - /* 142 */ "DISTINCT", - /* 143 */ "DOT", - /* 144 */ "FROM", - /* 145 */ "JOIN", - /* 146 */ "USING", - /* 147 */ "ORDER", - /* 148 */ "GROUP", - /* 149 */ "HAVING", - /* 150 */ "LIMIT", - /* 151 */ "WHERE", - /* 152 */ "RETURNING", - /* 153 */ "INTO", - /* 154 */ "NOTHING", - /* 155 */ "FLOAT", - /* 156 */ "BLOB", - /* 157 */ "INTEGER", - /* 158 */ "VARIABLE", - /* 159 */ "CASE", - /* 160 */ "WHEN", - /* 161 */ "THEN", - /* 162 */ "ELSE", - /* 163 */ "INDEX", - /* 164 */ "ALTER", - /* 165 */ "ADD", - /* 166 */ "WINDOW", - /* 167 */ "OVER", - /* 168 */ "FILTER", - /* 169 */ "COLUMN", - /* 170 */ "AGG_FUNCTION", - /* 171 */ "AGG_COLUMN", - /* 172 */ "TRUEFALSE", - /* 173 */ "FUNCTION", - /* 174 */ "UPLUS", - /* 175 */ "UMINUS", - /* 176 */ "TRUTH", - /* 177 */ "REGISTER", + /* 62 */ "DO", + /* 63 */ "FOR", + /* 64 */ "IGNORE", + /* 65 */ "INITIALLY", + /* 66 */ "INSTEAD", + /* 67 */ "NO", + /* 68 */ "KEY", + /* 69 */ "OF", + /* 70 */ "OFFSET", + /* 71 */ "PRAGMA", + /* 72 */ "RAISE", + /* 73 */ "RECURSIVE", + /* 74 */ "REPLACE", + /* 75 */ "RESTRICT", + /* 76 */ "ROW", + /* 77 */ "ROWS", + /* 78 */ "TRIGGER", + /* 79 */ "VACUUM", + /* 80 */ "VIEW", + /* 81 */ "VIRTUAL", + /* 82 */ "WITH", + /* 83 */ "NULLS", + /* 84 */ "FIRST", + /* 85 */ "LAST", + /* 86 */ "CURRENT", + /* 87 */ "FOLLOWING", + /* 88 */ "PARTITION", + /* 89 */ "PRECEDING", + /* 90 */ "RANGE", + /* 91 */ "UNBOUNDED", + /* 92 */ "EXCLUDE", + /* 93 */ "GROUPS", + /* 94 */ "OTHERS", + /* 95 */ "TIES", + /* 96 */ "GENERATED", + /* 97 */ "ALWAYS", + /* 98 */ "MATERIALIZED", + /* 99 */ "REINDEX", + /* 100 */ "RENAME", + /* 101 */ "CTIME_KW", + /* 102 */ "ANY", + /* 103 */ "BITAND", + /* 104 */ "BITOR", + /* 105 */ "LSHIFT", + /* 106 */ "RSHIFT", + /* 107 */ "PLUS", + /* 108 */ "MINUS", + /* 109 */ "STAR", + /* 110 */ "SLASH", + /* 111 */ "REM", + /* 112 */ "CONCAT", + /* 113 */ "PTR", + /* 114 */ "COLLATE", + /* 115 */ "BITNOT", + /* 116 */ "ON", + /* 117 */ "INDEXED", + /* 118 */ "STRING", + /* 119 */ "JOIN_KW", + /* 120 */ "CONSTRAINT", + /* 121 */ "DEFAULT", + /* 122 */ "NULL", + /* 123 */ "PRIMARY", + /* 124 */ "UNIQUE", + /* 125 */ "CHECK", + /* 126 */ "REFERENCES", + /* 127 */ "AUTOINCR", + /* 128 */ "INSERT", + /* 129 */ "DELETE", + /* 130 */ "UPDATE", + /* 131 */ "SET", + /* 132 */ "DEFERRABLE", + /* 133 */ "FOREIGN", + /* 134 */ "DROP", + /* 135 */ "UNION", + /* 136 */ "ALL", + /* 137 */ "EXCEPT", + /* 138 */ "INTERSECT", + /* 139 */ "SELECT", + /* 140 */ "VALUES", + /* 141 */ "DISTINCT", + /* 142 */ "DOT", + /* 143 */ "FROM", + /* 144 */ "JOIN", + /* 145 */ "USING", + /* 146 */ "ORDER", + /* 147 */ "GROUP", + /* 148 */ "HAVING", + /* 149 */ "LIMIT", + /* 150 */ "WHERE", + /* 151 */ "RETURNING", + /* 152 */ "INTO", + /* 153 */ "NOTHING", + /* 154 */ "FLOAT", + /* 155 */ "BLOB", + /* 156 */ "INTEGER", + /* 157 */ "VARIABLE", + /* 158 */ "CASE", + /* 159 */ "WHEN", + /* 160 */ "THEN", + /* 161 */ "ELSE", + /* 162 */ "INDEX", + /* 163 */ "ALTER", + /* 164 */ "ADD", + /* 165 */ "WINDOW", + /* 166 */ "OVER", + /* 167 */ "FILTER", + /* 168 */ "COLUMN", + /* 169 */ "AGG_FUNCTION", + /* 170 */ "AGG_COLUMN", + /* 171 */ "TRUEFALSE", + /* 172 */ "FUNCTION", + /* 173 */ "UPLUS", + /* 174 */ "UMINUS", + /* 175 */ "TRUTH", + /* 176 */ "REGISTER", + /* 177 */ "CONCURRENT", /* 178 */ "VECTOR", /* 179 */ "SELECT_COLUMN", /* 180 */ "IF_NULL_ROW", @@ -181563,11 +180623,7 @@ static YYACTIONTYPE yy_reduce( case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; - if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0 - || sqlite3ReadSchema(pParse)==SQLITE_OK - ){ - sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); - } + sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); } break; @@ -183337,153 +182393,152 @@ const unsigned char ebcdicToAscii[] = { ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ -/* Hash score: 233 */ -/* zKWText[] encodes 1018 bytes of keyword text in 669 bytes */ -/* CONCURRENT_DATEMPORARYREINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXP */ -/* LAINSTEADDATABASELECTABLEFTHENDEFERRABLELSEXCLUDELETEXCEPTIES */ -/* AVEPOINTERSECTRANSACTIONOTNULLSISNULLIKEXCLUSIVEXISTS */ -/* CONSTRAINTOFFSETRIGGERAISEUNIQUERYWITHOUTERANGENERATEDETACH */ -/* AVINGLOBEGINNEREFERENCESATTACHBETWEENATURALTERELEASECASCADE */ -/* FAULTCASECOLLATECREATEIMMEDIATEJOINSERTMATCHPLANALYZEPRAGMA */ -/* TERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENOTHINGROUPS */ -/* WHERECURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCAST */ -/* COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILAST */ -/* FILTEREPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ +/* Hash score: 231 */ +/* zKWText[] encodes 1007 bytes of keyword text in 667 bytes */ +/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ +/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */ +/* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */ +/* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */ +/* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */ +/* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */ +/* PRAGMATERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENWHERE */ +/* CURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCASTCOLUMN */ +/* COMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILASTFILTER */ +/* EPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ /* ETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBY */ /* INITIALLYPRIMARY */ -static const char zKWText[668] = { - 'C','O','N','C','U','R','R','E','N','T','_','D','A','T','E','M','P','O', - 'R','A','R','Y','R','E','I','N','D','E','X','E','D','E','S','C','A','P', - 'E','A','C','H','E','C','K','E','Y','B','E','F','O','R','E','I','G','N', - 'O','R','E','G','E','X','P','L','A','I','N','S','T','E','A','D','D','A', - 'T','A','B','A','S','E','L','E','C','T','A','B','L','E','F','T','H','E', - 'N','D','E','F','E','R','R','A','B','L','E','L','S','E','X','C','L','U', - 'D','E','L','E','T','E','X','C','E','P','T','I','E','S','A','V','E','P', - 'O','I','N','T','E','R','S','E','C','T','R','A','N','S','A','C','T','I', - 'O','N','O','T','N','U','L','L','S','I','S','N','U','L','L','I','K','E', - 'X','C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T', - 'R','A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A', - 'I','S','E','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T', - 'E','R','A','N','G','E','N','E','R','A','T','E','D','E','T','A','C','H', - 'A','V','I','N','G','L','O','B','E','G','I','N','N','E','R','E','F','E', - 'R','E','N','C','E','S','A','T','T','A','C','H','B','E','T','W','E','E', - 'N','A','T','U','R','A','L','T','E','R','E','L','E','A','S','E','C','A', - 'S','C','A','D','E','F','A','U','L','T','C','A','S','E','C','O','L','L', - 'A','T','E','C','R','E','A','T','E','I','M','M','E','D','I','A','T','E', - 'J','O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A', - 'L','Y','Z','E','P','R','A','G','M','A','T','E','R','I','A','L','I','Z', - 'E','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','U','P', - 'D','A','T','E','V','A','L','U','E','S','V','I','R','T','U','A','L','W', - 'A','Y','S','W','H','E','N','O','T','H','I','N','G','R','O','U','P','S', - 'W','H','E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A', - 'F','T','E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T', - 'I','T','I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T', - 'C','A','S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O', - 'N','F','L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T', - '_','T','I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G', - 'F','A','I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C', - 'E','F','I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O', - 'M','F','U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S', - 'T','R','I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U', - 'R','N','I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K', - 'R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N', - 'U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D', - 'O','W','B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A', - 'R','Y', +static const char zKWText[666] = { + 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', + 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', + 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', + 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', + 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', + 'T','E','M','P','O','R','A','R','Y','I','S','N','U','L','L','S','A','V', + 'E','P','O','I','N','T','E','R','S','E','C','T','I','E','S','N','O','T', + 'N','U','L','L','I','K','E','X','C','E','P','T','R','A','N','S','A','C', + 'T','I','O','N','A','T','U','R','A','L','T','E','R','A','I','S','E','X', + 'C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T','R', + 'A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A','N', + 'G','E','N','E','R','A','T','E','D','E','T','A','C','H','A','V','I','N', + 'G','L','O','B','E','G','I','N','N','E','R','E','F','E','R','E','N','C', + 'E','S','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T','E', + 'R','E','L','E','A','S','E','A','T','T','A','C','H','B','E','T','W','E', + 'E','N','O','T','H','I','N','G','R','O','U','P','S','C','A','S','C','A', + 'D','E','F','A','U','L','T','C','A','S','E','C','O','L','L','A','T','E', + 'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E', + 'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M', + 'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M', + 'A','T','E','R','I','A','L','I','Z','E','D','E','F','E','R','R','E','D', + 'I','S','T','I','N','C','T','U','P','D','A','T','E','V','A','L','U','E', + 'S','V','I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H', + 'E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A','F','T', + 'E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T','I','T', + 'I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T','C','A', + 'S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O','N','F', + 'L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T','_','T', + 'I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G','F','A', + 'I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C','E','F', + 'I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O','M','F', + 'U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S','T','R', + 'I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U','R','N', + 'I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O', + 'W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S', + 'I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W', + 'B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { - 82, 90, 135, 80, 106, 4, 0, 0, 92, 0, 83, 96, 0, - 52, 34, 84, 20, 0, 37, 95, 53, 87, 136, 24, 0, 0, - 141, 0, 46, 130, 0, 27, 108, 0, 14, 0, 0, 124, 79, - 0, 77, 11, 0, 57, 104, 148, 0, 137, 116, 0, 0, 47, - 0, 88, 29, 0, 22, 0, 32, 69, 28, 31, 10, 65, 143, - 111, 123, 0, 97, 89, 70, 146, 66, 121, 98, 0, 48, 0, - 16, 33, 0, 114, 0, 0, 0, 110, 15, 112, 117, 126, 19, - 49, 125, 0, 101, 0, 23, 122, 145, 61, 131, 140, 86, 81, - 41, 5, 127, 0, 0, 109, 50, 132, 129, 0, 36, 0, 0, - 133, 0, 99, 42, 44, 0, 25, 71, 118, 91, + 84, 92, 134, 82, 105, 29, 0, 0, 94, 0, 85, 72, 0, + 53, 35, 86, 15, 0, 42, 97, 54, 89, 135, 19, 0, 0, + 140, 0, 40, 129, 0, 22, 107, 0, 9, 0, 0, 123, 80, + 0, 78, 6, 0, 65, 103, 147, 0, 136, 115, 0, 0, 48, + 0, 90, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 142, + 110, 122, 0, 73, 91, 71, 145, 61, 120, 74, 0, 49, 0, + 11, 41, 0, 113, 0, 0, 0, 109, 10, 111, 116, 125, 14, + 50, 124, 0, 100, 0, 18, 121, 144, 56, 130, 139, 88, 83, + 37, 30, 126, 0, 0, 108, 51, 131, 128, 0, 34, 0, 0, + 132, 0, 98, 38, 39, 0, 20, 45, 117, 93, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ -static const unsigned char aKWNext[149] = {0, - 0, 0, 0, 0, 120, 0, 0, 0, 0, 9, 0, 38, 0, - 0, 107, 115, 0, 0, 0, 7, 0, 0, 144, 0, 0, 0, - 18, 0, 0, 0, 0, 142, 0, 17, 0, 138, 134, 0, 0, - 0, 0, 67, 0, 0, 51, 139, 3, 76, 1, 0, 0, 0, - 64, 0, 0, 0, 0, 0, 73, 0, 55, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 40, 0, 0, 0, 63, 0, 6, 74, - 0, 0, 45, 0, 0, 0, 0, 0, 128, 0, 105, 0, 56, - 58, 68, 0, 0, 0, 147, 8, 0, 0, 0, 72, 0, 21, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 102, - 0, 113, 26, 12, 59, 0, 78, 94, 119, 0, 0, 60, 0, - 0, 100, 39, 0, 54, 0, 75, 0, 93, 43, 35, 62, 30, - 0, 103, 0, 0, 85, +static const unsigned char aKWNext[148] = {0, + 0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0, + 0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0, + 141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0, + 138, 0, 133, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0, + 0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 69, 0, 0, 0, 0, 0, 146, 3, 0, 58, 0, 1, + 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 127, 0, 104, + 0, 64, 66, 63, 0, 0, 0, 0, 0, 46, 0, 16, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 101, 0, + 112, 21, 7, 67, 0, 79, 96, 118, 0, 0, 68, 0, 0, + 99, 44, 0, 55, 0, 76, 0, 95, 32, 33, 57, 25, 0, + 102, 0, 0, 87, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[149] = {0, - 10, 12, 9, 4, 2, 7, 7, 5, 4, 6, 4, 5, 3, - 6, 7, 3, 6, 6, 7, 7, 3, 8, 2, 6, 5, 4, - 4, 3, 10, 4, 7, 6, 6, 4, 9, 9, 11, 6, 2, - 7, 3, 2, 5, 4, 6, 4, 9, 6, 10, 4, 6, 2, - 3, 7, 5, 6, 5, 7, 4, 5, 5, 9, 6, 6, 4, - 5, 5, 10, 6, 7, 7, 5, 7, 7, 3, 7, 4, 7, - 6, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, 2, 6, - 6, 7, 6, 4, 7, 6, 5, 5, 9, 5, 5, 6, 3, - 4, 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, - 9, 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, - 6, 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, - 2, 2, 9, 3, 7, +static const unsigned char aKWLen[148] = {0, + 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, + 6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4, + 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6, + 2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5, + 7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4, + 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, + 2, 6, 6, 7, 6, 4, 5, 9, 5, 5, 6, 3, 4, + 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, + 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, + 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, + 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[149] = {0, - 0, 3, 13, 13, 17, 22, 24, 24, 30, 31, 36, 38, 42, - 45, 47, 47, 51, 55, 58, 63, 68, 70, 75, 76, 81, 84, - 87, 89, 91, 100, 103, 108, 113, 118, 121, 127, 135, 140, 144, - 145, 145, 145, 148, 148, 153, 158, 161, 169, 175, 182, 185, 185, - 188, 190, 196, 201, 204, 209, 209, 213, 217, 220, 228, 233, 238, - 241, 244, 248, 258, 264, 270, 275, 279, 286, 287, 291, 298, 302, - 309, 315, 324, 326, 332, 337, 339, 346, 350, 361, 368, 369, 376, - 382, 388, 393, 399, 402, 408, 408, 414, 417, 426, 431, 435, 441, - 443, 446, 455, 457, 459, 468, 472, 478, 484, 492, 497, 497, 497, - 513, 522, 525, 529, 534, 541, 546, 555, 559, 562, 567, 569, 573, - 581, 587, 590, 599, 604, 612, 612, 616, 625, 630, 635, 641, 644, - 647, 650, 652, 657, 661, +static const unsigned short int aKWOffset[148] = {0, + 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, + 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, + 86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126, + 129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184, + 184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239, + 244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295, + 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 359, 370, 377, + 378, 385, 391, 397, 402, 408, 412, 415, 424, 429, 433, 439, 441, + 444, 453, 455, 457, 466, 470, 476, 482, 490, 495, 495, 495, 511, + 520, 523, 527, 532, 539, 544, 553, 557, 560, 565, 567, 571, 579, + 585, 588, 597, 602, 610, 610, 614, 623, 628, 633, 639, 642, 645, + 648, 650, 655, 659, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[149] = {0, - TK_CONCURRENT, TK_CTIME_KW, TK_TEMP, TK_TEMP, TK_OR, +static const unsigned char aKWCode[148] = {0, TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCLUDE, TK_DELETE, TK_EXCEPT, TK_TIES, TK_SAVEPOINT, - TK_INTERSECT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_NOTNULL, - TK_NOT, TK_NO, TK_NULLS, TK_NULL, TK_ISNULL, - TK_LIKE_KW, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, TK_INTO, - TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, TK_RAISE, - TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, TK_JOIN_KW, + TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, + TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, + TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, + TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW, - TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_ATTACH, TK_BETWEEN, - TK_JOIN_KW, TK_ALTER, TK_RELEASE, TK_CASCADE, TK_ASC, - TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, TK_IMMEDIATE, - TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, - TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, TK_DISTINCT, TK_IS, - TK_UPDATE, TK_VALUES, TK_VIRTUAL, TK_ALWAYS, TK_WHEN, - TK_NOTHING, TK_GROUPS, TK_GROUP, TK_WHERE, TK_RECURSIVE, - TK_ABORT, TK_AFTER, TK_RENAME, TK_AND, TK_DROP, - TK_PARTITION, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, - TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, - TK_CTIME_KW, TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, - TK_FILTER, TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, - TK_JOIN_KW, TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, - TK_OTHERS, TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, - TK_ROWS, TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, - TK_VACUUM, TK_VIEW, TK_WINDOW, TK_DO, TK_BY, - TK_INITIALLY, TK_ALL, TK_PRIMARY, + TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY, + TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH, + TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE, + TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, + TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, + TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, + TK_DISTINCT, TK_IS, TK_UPDATE, TK_VALUES, TK_VIRTUAL, + TK_ALWAYS, TK_WHEN, TK_WHERE, TK_RECURSIVE, TK_ABORT, + TK_AFTER, TK_RENAME, TK_AND, TK_DROP, TK_PARTITION, + TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, + TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, + TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, + TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, + TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, + TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, + TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, + TK_VIEW, TK_WINDOW, TK_DO, TK_BY, TK_INITIALLY, + TK_ALL, TK_PRIMARY, }; /* Hash table decoded: ** 0: INSERT @@ -183577,7 +182632,7 @@ static const unsigned char aKWCode[149] = {0, ** 88: CURRENT AFTER ALTER ** 89: FULL FAIL CONFLICT ** 90: EXPLAIN -** 91: CONSTRAINT CONCURRENT +** 91: CONSTRAINT ** 92: FROM ALWAYS ** 93: ** 94: ABORT @@ -183638,154 +182693,153 @@ static int keywordCode(const char *z, int n, int *pType){ while( j=2 ) keywordCode((char*)z, n, &id); return id; } -#define SQLITE_N_KEYWORD 148 +#define SQLITE_N_KEYWORD 147 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; i++; @@ -185029,9 +184083,6 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_EXTRA_AUTOEXT SQLITE_EXTRA_AUTOEXT, #endif -#ifdef SQLITE_ENABLE_HCT - sqlite3HctVtabInit, -#endif }; #ifndef SQLITE_AMALGAMATION @@ -185105,6 +184156,32 @@ SQLITE_API char *sqlite3_temp_directory = 0; */ SQLITE_API char *sqlite3_data_directory = 0; +/* +** Determine whether or not high-precision (long double) floating point +** math works correctly on CPU currently running. +*/ +static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){ + if( sizeof(LONGDOUBLE_TYPE)<=8 ){ + /* If the size of "long double" is not more than 8, then + ** high-precision math is not possible. */ + return 0; + }else{ + /* Just because sizeof(long double)>8 does not mean that the underlying + ** hardware actually supports high-precision floating point. For example, + ** clearing the 0x100 bit in the floating-point control word on Intel + ** processors will make long double work like double, even though long + ** double takes up more space. The only way to determine if long double + ** actually works is to run an experiment. */ + LONGDOUBLE_TYPE a, b, c; + rc++; + a = 1.0+rc*0.1; + b = 1.0e+18+rc*25.0; + c = a+b; + return b!=c; + } +} + + /* ** Initialize SQLite. ** @@ -185299,6 +184376,13 @@ SQLITE_API int sqlite3_initialize(void){ rc = SQLITE_EXTRA_INIT(0); } #endif + + /* Experimentally determine if high-precision floating point is + ** available. */ +#ifndef SQLITE_OMIT_WSD + sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc); +#endif + return rc; } @@ -186369,6 +185453,10 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); +#if SQLITE_USER_AUTHENTICATION + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); +#endif db->eOpenState = SQLITE_STATE_ERROR; @@ -187871,8 +186959,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ - }else if( newLimitaLimit[limitId] = newLimit; } @@ -188391,7 +187479,6 @@ static int openDatabase( if( ((1<<(flags&7)) & 0x46)==0 ){ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */ }else{ - if( zFilename==0 ) zFilename = ":memory:"; rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); } if( rc!=SQLITE_OK ){ @@ -189546,21 +188633,24 @@ SQLITE_API int sqlite3_test_control(int op, ...){ *pI2 = sqlite3LogEst(*pU64); break; } - /* sqlite3_test_control(SQLITE_TESTCTRL_HCT_MTCOMMIT, - ** sqlite3 *db, - ** void(*xMtCommit)(void*, int), - ** void *pCtx - ** ); + +#if !defined(SQLITE_OMIT_WSD) + /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X); ** - ** Install xMtCommit hook on "main" hct database. + ** X<0 Make no changes to the bUseLongDouble. Just report value. + ** X==0 Disable bUseLongDouble + ** X==1 Enable bUseLongDouble + ** X>=2 Set bUseLongDouble to its default value for this platform */ - case SQLITE_TESTCTRL_HCT_MTCOMMIT: { - typedef void (*mt_commit_hook)(void*,int); - sqlite3 *db = va_arg(ap, sqlite3*); - db->xMtCommit = va_arg(ap, mt_commit_hook); - db->pMtCommitCtx = va_arg(ap, void*); + case SQLITE_TESTCTRL_USELONGDOUBLE: { + int b = va_arg(ap, int); + if( b>=2 ) b = hasHighPrecisionDouble(b); + if( b>=0 ) sqlite3Config.bUseLongDouble = b>0; + rc = sqlite3Config.bUseLongDouble!=0; break; - }; + } +#endif + #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) @@ -189869,11 +188959,7 @@ SQLITE_API int sqlite3_snapshot_get( if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ - Pager *pPager = sqlite3BtreePager(pBt); - i64 dummy = 0; - sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy); rc = sqlite3BtreeBeginTrans(pBt, 0, 0); - sqlite3PagerSnapshotOpen(pPager, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } @@ -193692,15 +192778,10 @@ static int fts3PoslistPhraseMerge( if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); - /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN - ** entry, so this is actually end-of-doclist. */ - if( iCol1==0 ) return 0; } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); - /* As above, iCol2==0 indicates corruption. */ - if( iCol2==0 ) return 0; } while( 1 ){ @@ -196871,7 +195952,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX); + aTmp = sqlite3_malloc64(nTmp*2); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; @@ -197522,7 +196603,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ } #endif -#if !defined(SQLITE_CORE) +#if !SQLITE_CORE /* ** Initialize API pointer table, if required. */ @@ -221813,7 +220894,7 @@ SQLITE_API int sqlite3_rtree_query_callback( ); } -#ifndef SQLITE_CORE +#if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -222404,7 +221485,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ return rc; } -#ifndef SQLITE_CORE +#if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -223662,27 +222743,6 @@ struct RbuFrame { u32 iWalFrame; }; -#ifndef UNUSED_PARAMETER -/* -** The following macros are used to suppress compiler warnings and to -** make it clear to human readers when a function parameter is deliberately -** left unused within the body of a function. This usually happens when -** a function is called via a function pointer. For example the -** implementation of an SQL aggregate step callback may not use the -** parameter indicating the number of arguments passed to the aggregate, -** if it knows that this is enforced elsewhere. -** -** When a function parameter is not used at all within the body of a function, -** it is generally named "NotUsed" or "NotUsed2" to make things even clearer. -** However, these macros may also be used to suppress warnings related to -** parameters that may or may not be used depending on compilation options. -** For example those parameters only used in assert() statements. In these -** cases the parameters are named as per the usual conventions. -*/ -#define UNUSED_PARAMETER(x) (void)(x) -#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y) -#endif - /* ** RBU handle. ** @@ -223734,7 +222794,7 @@ struct sqlite3rbu { int rc; /* Value returned by last rbu_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ int nStep; /* Rows processed for current object */ - sqlite3_int64 nProgress; /* Rows processed for all objects */ + int nProgress; /* Rows processed for all objects */ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ @@ -223851,7 +222911,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ v = (v<<6) + c; } z--; - *pLen -= (int)(z - zStart); + *pLen -= z - zStart; *pz = (char*)z; return v; } @@ -224036,7 +223096,6 @@ static void rbuFossilDeltaFunc( char *aOut; assert( argc==2 ); - UNUSED_PARAMETER(argc); nOrig = sqlite3_value_bytes(argv[0]); aOrig = (const char*)sqlite3_value_blob(argv[0]); @@ -225616,13 +224675,13 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ else if( c==')' ){ nParen--; if( nParen==0 ){ - int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan); + int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; i++; break; } }else if( c==',' && nParen==1 ){ - int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan); + int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1]; }else if( c=='"' || c=='\'' || c=='`' ){ @@ -226312,8 +225371,6 @@ static void rbuFileSuffix3(const char *zBase, char *z){ for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } -#else - UNUSED_PARAMETER2(zBase,z); #endif } @@ -226898,7 +225955,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ "(%d, %Q), " "(%d, %Q), " "(%d, %d), " - "(%d, %lld), " + "(%d, %d), " "(%d, %lld), " "(%d, %lld), " "(%d, %lld), " @@ -227256,7 +226313,6 @@ static void rbuIndexCntFunc( sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain); assert( nVal==1 ); - UNUSED_PARAMETER(nVal); rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg, sqlite3_mprintf("SELECT count(*) FROM sqlite_schema " @@ -227532,7 +226588,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( ){ if( zTarget==0 ){ return rbuMisuseError(); } if( zState ){ - size_t n = strlen(zState); + int n = strlen(zState); if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){ return rbuMisuseError(); } @@ -227749,7 +226805,6 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ */ static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){ int rc = SQLITE_OK; - UNUSED_PARAMETER(pArg); #if defined(_WIN32_WCE) { LPWSTR zWideOld; @@ -228654,9 +227709,6 @@ static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ ** No-op. */ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ - UNUSED_PARAMETER(pVfs); - UNUSED_PARAMETER(a); - UNUSED_PARAMETER(b); return 0; } @@ -229713,13 +228765,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } ** ** The data field of sqlite_dbpage table can be updated. The new ** value must be a BLOB which is the correct page size, otherwise the -** update fails. INSERT operations also work, and operate as if they -** where REPLACE. The size of the database can be extended by INSERT-ing -** new pages on the end. -** -** Rows may not be deleted. However, doing an INSERT to page number N -** with NULL page data causes the N-th page and all subsequent pages to be -** deleted and the database to be truncated. +** update fails. Rows may not be deleted or inserted. */ /* #include "sqliteInt.h" ** Requires access to internal data structures ** */ @@ -229742,8 +228788,6 @@ struct DbpageCursor { struct DbpageTable { sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* The database */ - int iDbTrunc; /* Database to truncate */ - Pgno pgnoTrunc; /* Size to truncate to */ }; /* Columns */ @@ -229752,6 +228796,7 @@ struct DbpageTable { #define DBPAGE_COLUMN_SCHEMA 2 + /* ** Connect to or create a dbpagevfs virtual table. */ @@ -230013,11 +229058,11 @@ static int dbpageUpdate( DbPage *pDbPage = 0; int rc = SQLITE_OK; char *zErr = 0; + const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; - int isInsert; (void)pRowid; if( pTab->db->flags & SQLITE_Defensive ){ @@ -230028,29 +229073,21 @@ static int dbpageUpdate( zErr = "cannot delete"; goto update_fail; } - if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ - pgno = (Pgno)sqlite3_value_int(argv[2]); - isInsert = 1; - }else{ - pgno = sqlite3_value_int(argv[0]); - if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ - zErr = "cannot insert"; - goto update_fail; - } - isInsert = 0; + pgno = sqlite3_value_int(argv[0]); + if( sqlite3_value_type(argv[0])==SQLITE_NULL + || (Pgno)sqlite3_value_int(argv[1])!=pgno + ){ + zErr = "cannot insert"; + goto update_fail; } - if( sqlite3_value_type(argv[4])==SQLITE_NULL ){ - iDb = 0; - }else{ - const char *zSchema = (const char*)sqlite3_value_text(argv[4]); - iDb = sqlite3FindDbName(pTab->db, zSchema); - if( iDb<0 ){ - zErr = "no such schema"; - goto update_fail; - } + zSchema = (const char*)sqlite3_value_text(argv[4]); + iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1; + if( NEVER(iDb<0) ){ + zErr = "no such schema"; + goto update_fail; } pBt = pTab->db->aDb[iDb].pBt; - if( pgno<1 || NEVER(pBt==0) ){ + if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){ zErr = "bad page number"; goto update_fail; } @@ -230058,25 +229095,18 @@ static int dbpageUpdate( if( sqlite3_value_type(argv[3])!=SQLITE_BLOB || sqlite3_value_bytes(argv[3])!=szPage ){ - if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){ - /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and - ** all subsequent pages to be deleted. */ - pTab->iDbTrunc = iDb; - pgno--; - pTab->pgnoTrunc = pgno; - }else{ - zErr = "bad page value"; - goto update_fail; - } + zErr = "bad page value"; + goto update_fail; } pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ const void *pData = sqlite3_value_blob(argv[3]); - if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){ - unsigned char *aPage = sqlite3PagerGetData(pDbPage); - memcpy(aPage, pData, szPage); - pTab->pgnoTrunc = 0; + assert( pData!=0 || pTab->db->mallocFailed ); + if( pData + && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK + ){ + memcpy(sqlite3PagerGetData(pDbPage), pData, szPage); } } sqlite3PagerUnref(pDbPage); @@ -230100,31 +229130,9 @@ static int dbpageBegin(sqlite3_vtab *pVtab){ Btree *pBt = db->aDb[i].pBt; if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0); } - pTab->pgnoTrunc = 0; return SQLITE_OK; } -/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT -*/ -static int dbpageSync(sqlite3_vtab *pVtab){ - DbpageTable *pTab = (DbpageTable *)pVtab; - if( pTab->pgnoTrunc>0 ){ - Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt; - Pager *pPager = sqlite3BtreePager(pBt); - sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc); - } - pTab->pgnoTrunc = 0; - return SQLITE_OK; -} - -/* Cancel any pending truncate. -*/ -static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){ - DbpageTable *pTab = (DbpageTable *)pVtab; - pTab->pgnoTrunc = 0; - (void)notUsed1; - return SQLITE_OK; -} /* ** Invoke this routine to register the "dbpage" virtual table module @@ -230146,14 +229154,14 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ dbpageRowid, /* xRowid - read data */ dbpageUpdate, /* xUpdate */ dbpageBegin, /* xBegin */ - dbpageSync, /* xSync */ + 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - dbpageRollbackTo, /* xRollbackTo */ + 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; @@ -230248,10 +229256,6 @@ struct SessionBuffer { ** input data. Input data may be supplied either as a single large buffer ** (e.g. sqlite3changeset_start()) or using a stream function (e.g. ** sqlite3changeset_start_strm()). -** -** bNoDiscard: -** If true, then the only time data is discarded is as a result of explicit -** sessionDiscardData() calls. Not within every sessionInputBuffer() call. */ struct SessionInput { int bNoDiscard; /* If true, do not discard in InputBuffer() */ @@ -231936,19 +230940,16 @@ static void sessionPreupdateOneChange( for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ - /* This may fail if the column has a non-NULL default and was added - ** using ALTER TABLE ADD COLUMN after this record was created. */ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p); + TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); + assert( trc==SQLITE_OK ); }else if( pTab->abPK[i] ){ TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); assert( trc==SQLITE_OK ); } - if( rc==SQLITE_OK ){ - /* This may fail if SQLite value p contains a utf-16 string that must - ** be converted to utf-8 and an OOM error occurs while doing so. */ - rc = sessionSerializeValue(0, p, &nByte); - } + /* This may fail if SQLite value p contains a utf-16 string that must + ** be converted to utf-8 and an OOM error occurs while doing so. */ + rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } if( pTab->bRowid ){ @@ -235329,21 +234330,15 @@ static int sessionChangesetApply( int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ int bPatchset; - u64 savedFlag = db->flags & SQLITE_FkNoAction; assert( xConflict!=0 ); - sqlite3_mutex_enter(sqlite3_db_mutex(db)); - if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ - db->flags |= ((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } - pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); + sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } @@ -235505,12 +234500,6 @@ static int sessionChangesetApply( sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_free((char*)sApply.constraints.aBuf); sqlite3_free((char*)sApply.rebase.aBuf); - - if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ - assert( db->flags & SQLITE_FkNoAction ); - db->flags &= ~((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } sqlite3_mutex_leave(sqlite3_db_mutex(db)); return rc; } @@ -235539,6 +234528,12 @@ SQLITE_API int sqlite3changeset_apply_v2( sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); + u64 savedFlag = db->flags & SQLITE_FkNoAction; + + if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ + db->flags |= ((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } if( rc==SQLITE_OK ){ rc = sessionChangesetApply( @@ -235546,6 +234541,11 @@ SQLITE_API int sqlite3changeset_apply_v2( ); } + if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ + assert( db->flags & SQLITE_FkNoAction ); + db->flags &= ~((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } return rc; } @@ -235866,9 +234866,6 @@ static int sessionChangesetExtendRecord( sessionAppendBlob(pOut, aRec, nRec, &rc); if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt); - if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){ - rc = sqlite3_errcode(pGrp->db); - } } for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){ int eType = sqlite3_column_type(pTab->pDfltStmt, ii); @@ -235885,7 +234882,6 @@ static int sessionChangesetExtendRecord( } if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); - pOut->nBuf += 8; } break; } @@ -236025,8 +235021,6 @@ static int sessionOneChangeToHash( u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; - assert( nRec>0 ); - /* Ensure that only changesets, or only patchsets, but not a mixture ** of both, are being combined. It is an error to try to combine a ** changeset and a patchset. */ @@ -236104,7 +235098,6 @@ static int sessionChangesetToHash( int nRec; int rc = SQLITE_OK; - pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ rc = sessionOneChangeToHash(pGrp, pIter, bRebase); if( rc!=SQLITE_OK ) break; @@ -236737,27 +235730,7 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ /************** End of sqlite3session.c **************************************/ /************** Begin file fts5.c ********************************************/ -/* -** This, the "fts5.c" source file, is a composite file that is itself -** assembled from the following files: -** -** fts5.h -** fts5Int.h -** fts5parse.h <--- Generated from fts5parse.y by Lemon -** fts5parse.c <--- Generated from fts5parse.y by Lemon -** fts5_aux.c -** fts5_buffer.c -** fts5_config.c -** fts5_expr.c -** fts5_hash.c -** fts5_index.c -** fts5_main.c -** fts5_storage.c -** fts5_tokenize.c -** fts5_unicode2.c -** fts5_varint.c -** fts5_vocab.c -*/ + #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) @@ -236767,12 +235740,6 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ # undef NDEBUG #endif -#ifdef HAVE_STDINT_H -/* #include */ -#endif -#ifdef HAVE_INTTYPES_H -/* #include */ -#endif /* ** 2014 May 31 ** @@ -237171,6 +236138,7 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting +** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -237739,7 +236707,6 @@ struct Fts5Config { int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ int eContent; /* An FTS5_CONTENT value */ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */ - int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */ char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ @@ -237778,10 +236745,9 @@ struct Fts5Config { #define FTS5_CURRENT_VERSION 4 #define FTS5_CURRENT_VERSION_SECUREDELETE 5 -#define FTS5_CONTENT_NORMAL 0 -#define FTS5_CONTENT_NONE 1 -#define FTS5_CONTENT_EXTERNAL 2 -#define FTS5_CONTENT_UNINDEXED 3 +#define FTS5_CONTENT_NORMAL 0 +#define FTS5_CONTENT_NONE 1 +#define FTS5_CONTENT_EXTERNAL 2 #define FTS5_DETAIL_FULL 0 #define FTS5_DETAIL_NONE 1 @@ -238153,14 +237119,17 @@ static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); static int sqlite3Fts5FlushToDisk(Fts5Table*); -static void sqlite3Fts5ClearLocale(Fts5Config *pConfig); -static void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc); - -static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal); -static int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal, - const char **ppText, int *pnText, const char **ppLoc, int *pnLoc +static int sqlite3Fts5ExtractText( + Fts5Config *pConfig, + sqlite3_value *pVal, /* Value to extract text from */ + int bContent, /* Loaded from content table */ + int *pbResetTokenizer, /* OUT: True if ClearLocale() required */ + const char **ppText, /* OUT: Pointer to text buffer */ + int *pnText /* OUT: Size of (*ppText) in bytes */ ); +static void sqlite3Fts5ClearLocale(Fts5Config *pConfig); + /* ** End of interface to code in fts5.c. **************************************************************************/ @@ -238241,7 +237210,7 @@ static int sqlite3Fts5DropAll(Fts5Config*); static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int); -static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*); +static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); @@ -241448,7 +240417,6 @@ static int fts5ConfigParseSpecial( ){ int rc = SQLITE_OK; int nCmd = (int)strlen(zCmd); - if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){ const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES; const char *p; @@ -241568,16 +240536,6 @@ static int fts5ConfigParseSpecial( return rc; } - if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){ - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ - *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive"); - rc = SQLITE_ERROR; - }else{ - pConfig->bContentlessUnindexed = (zArg[0]=='1'); - } - return rc; - } - if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){ if( pConfig->zContentRowid ){ *pzErr = sqlite3_mprintf("multiple content_rowid=... directives"); @@ -241695,8 +240653,7 @@ static int fts5ConfigParseColumn( Fts5Config *p, char *zCol, char *zArg, - char **pzErr, - int *pbUnindexed + char **pzErr ){ int rc = SQLITE_OK; if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) @@ -241707,7 +240664,6 @@ static int fts5ConfigParseColumn( }else if( zArg ){ if( 0==sqlite3_stricmp(zArg, "unindexed") ){ p->abUnindexed[p->nCol] = 1; - *pbUnindexed = 1; }else{ *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg); rc = SQLITE_ERROR; @@ -241728,26 +240684,11 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){ sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid); if( p->eContent!=FTS5_CONTENT_NONE ){ - assert( p->eContent==FTS5_CONTENT_EXTERNAL - || p->eContent==FTS5_CONTENT_NORMAL - || p->eContent==FTS5_CONTENT_UNINDEXED - ); for(i=0; inCol; i++){ if( p->eContent==FTS5_CONTENT_EXTERNAL ){ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]); - }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){ - sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i); - }else{ - sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL"); - } - } - } - if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){ - for(i=0; inCol; i++){ - if( p->abUnindexed[i]==0 ){ - sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i); }else{ - sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL"); + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i); } } } @@ -241781,7 +240722,6 @@ static int sqlite3Fts5ConfigParse( Fts5Config *pRet; /* New object to return */ int i; sqlite3_int64 nByte; - int bUnindexed = 0; /* True if there are one or more UNINDEXED */ *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; @@ -241841,7 +240781,7 @@ static int sqlite3Fts5ConfigParse( pzErr ); }else{ - rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed); + rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); zOne = 0; } } @@ -241873,19 +240813,6 @@ static int sqlite3Fts5ConfigParse( rc = SQLITE_ERROR; } - /* We only allow contentless_unindexed=1 if the table is actually a - ** contentless one. - */ - if( rc==SQLITE_OK - && pRet->bContentlessUnindexed - && pRet->eContent!=FTS5_CONTENT_NONE - ){ - *pzErr = sqlite3_mprintf( - "contentless_unindexed=1 requires a contentless table" - ); - rc = SQLITE_ERROR; - } - /* If no zContent option was specified, fill in the default values. */ if( rc==SQLITE_OK && pRet->zContent==0 ){ const char *zTail = 0; @@ -241894,9 +240821,6 @@ static int sqlite3Fts5ConfigParse( ); if( pRet->eContent==FTS5_CONTENT_NORMAL ){ zTail = "content"; - }else if( bUnindexed && pRet->bContentlessUnindexed ){ - pRet->eContent = FTS5_CONTENT_UNINDEXED; - zTail = "content"; }else if( pRet->bColumnsize ){ zTail = "docsize"; } @@ -247438,7 +246362,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){ if( p->pDataVersion==0 ){ p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb) - ); + ); if( p->rc ) return 0; } @@ -251070,11 +249994,6 @@ static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){ nBest = nPercent; } } - - /* If pLvl is already the input level to an ongoing merge, look no - ** further for a merge candidate. The caller should be allowed to - ** continue merging from pLvl first. */ - if( pLvl->nMerge ) break; } } return iRet; @@ -254999,7 +253918,7 @@ static int fts5structConnectMethod( /* ** We must have a single struct=? constraint that will be passed through -** into the xFilter method. If there is no valid struct=? constraint, +** into the xFilter method. If there is no valid stmt=? constraint, ** then return an SQLITE_CONSTRAINT error. */ static int fts5structBestIndexMethod( @@ -255341,17 +254260,8 @@ struct Fts5Global { Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */ Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */ Fts5Cursor *pCsr; /* First in list of all open cursors */ - u32 aLocaleHdr[4]; }; -/* -** Size of header on fts5_locale() values. And macro to access a buffer -** containing a copy of the header from an Fts5Config pointer. -*/ -#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr )) -#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr)) - - /* ** Each auxiliary function registered with the FTS5 module is represented ** by an object of the following type. All such objects are stored as part @@ -255514,6 +254424,12 @@ struct Fts5Cursor { #define BitFlagAllTest(x,y) (((x) & (y))==(y)) #define BitFlagTest(x,y) (((x) & (y))!=0) +/* +** The subtype value and header bytes used by fts5_locale(). +*/ +#define FTS5_LOCALE_SUBTYPE ((unsigned int)'L') +#define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB" + /* ** Macros to Set(), Clear() and Test() cursor flags. @@ -255590,16 +254506,10 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){ #endif /* -** Return true if pTab is a contentless table. If parameter bIncludeUnindexed -** is true, this includes contentless tables that store UNINDEXED columns -** only. +** Return true if pTab is a contentless table. */ -static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){ - int eContent = pTab->p.pConfig->eContent; - return ( - eContent==FTS5_CONTENT_NONE - || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED) - ); +static int fts5IsContentless(Fts5FullTable *pTab){ + return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE; } /* @@ -255890,7 +254800,6 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ if( p->usable==0 || iCol<0 ){ /* As there exists an unusable MATCH constraint this is an ** unusable plan. Return SQLITE_CONSTRAINT. */ - idxStr[iIdxStr] = 0; return SQLITE_CONSTRAINT; }else{ if( iCol==nCol+1 ){ @@ -256524,7 +255433,7 @@ static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ ** valid until after the final call to sqlite3Fts5Tokenize() that will use ** the locale. */ -static void sqlite3Fts5SetLocale( +static void fts5SetLocale( Fts5Config *pConfig, const char *zLocale, int nLocale @@ -256535,74 +255444,127 @@ static void sqlite3Fts5SetLocale( } /* -** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale(). +** Clear any locale configured by an earlier call to fts5SetLocale() or +** sqlite3Fts5ExtractText(). */ static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){ - sqlite3Fts5SetLocale(pConfig, 0, 0); + fts5SetLocale(pConfig, 0, 0); } /* -** Return true if the value passed as the only argument is an -** fts5_locale() value. +** This function is used to extract utf-8 text from an sqlite3_value. This +** is usually done in order to tokenize it. For example, when: +** +** * a value is written to an fts5 table, +** * a value is deleted from an FTS5_CONTENT_NORMAL table, +** * a value containing a query expression is passed to xFilter() +** +** and so on. +** +** This function handles 2 cases: +** +** 1) Ordinary values. The text can be extracted from these using +** sqlite3_value_text(). +** +** 2) Combination text/locale blobs created by fts5_locale(). There +** are several cases for these: +** +** * Blobs tagged with FTS5_LOCALE_SUBTYPE. +** * Blobs read from the content table of a locale=1 external-content +** table, and +** * Blobs read from the content table of a locale=1 regular +** content table. +** +** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER +** header. It is an error if a blob with the subtype or a blob read +** from the content table of an external content table does not have +** the required header. A blob read from the content table of a regular +** locale=1 table does not have the header. This is to save space. +** +** If successful, SQLITE_OK is returned and output parameters (*ppText) +** and (*pnText) are set to point to a buffer containing the extracted utf-8 +** text and its length in bytes, respectively. The buffer is not +** nul-terminated. It has the same lifetime as the sqlite3_value object +** from which it is extracted. +** +** Parameter bContent must be true if the value was read from an indexed +** column (i.e. not UNINDEXED) of the on disk content. +** +** If pbResetTokenizer is not NULL and if case (2) is used, then +** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls +** use the locale. In this case (*pbResetTokenizer) is set to true before +** returning, to indicate that the caller must call sqlite3Fts5ClearLocale() +** to clear the locale after tokenizing the text. */ -static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){ - int ret = 0; +static int sqlite3Fts5ExtractText( + Fts5Config *pConfig, + sqlite3_value *pVal, /* Value to extract text from */ + int bContent, /* True if indexed table content */ + int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */ + const char **ppText, /* OUT: Pointer to text buffer */ + int *pnText /* OUT: Size of (*ppText) in bytes */ +){ + const char *pText = 0; + int nText = 0; + int rc = SQLITE_OK; + int bDecodeBlob = 0; + + assert( pbResetTokenizer==0 || *pbResetTokenizer==0 ); + assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE ); + assert( bContent==0 || sqlite3_value_subtype(pVal)==0 ); + if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ - /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case. - ** If the blob was created using zeroblob(), then sqlite3_value_blob() - ** may call malloc(). If this malloc() fails, then the values returned - ** by both value_blob() and value_bytes() will be 0. If value_bytes() were - ** called first, then the NULL pointer returned by value_blob() might - ** be dereferenced. */ - const u8 *pBlob = sqlite3_value_blob(pVal); - int nBlob = sqlite3_value_bytes(pVal); - if( nBlob>FTS5_LOCALE_HDR_SIZE - && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE) + if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE + || (bContent && pConfig->bLocale) ){ - ret = 1; + bDecodeBlob = 1; } } - return ret; -} -/* -** Value pVal is guaranteed to be an fts5_locale() value, according to -** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale -** from the value and returns them separately. -** -** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set -** to point to buffers containing the text and locale, as utf-8, -** respectively. In this case output parameters (*pnText) and (*pnLoc) are -** set to the sizes in bytes of these two buffers. -** -** Or, if an error occurs, then an SQLite error code is returned. The final -** value of the four output parameters is undefined in this case. -*/ -static int sqlite3Fts5DecodeLocaleValue( - sqlite3_value *pVal, - const char **ppText, - int *pnText, - const char **ppLoc, - int *pnLoc -){ - const char *p = sqlite3_value_blob(pVal); - int n = sqlite3_value_bytes(pVal); - int nLoc = 0; + if( bDecodeBlob ){ + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; + const u8 *pBlob = sqlite3_value_blob(pVal); + int nBlob = sqlite3_value_bytes(pVal); - assert( sqlite3_value_type(pVal)==SQLITE_BLOB ); - assert( n>FTS5_LOCALE_HDR_SIZE ); + /* Unless this blob was read from the %_content table of an + ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale() + ** header. Check for this. If it is not found, return an error. */ + if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){ + if( nBlobeContent==FTS5_CONTENT_NONE ){ fts5SetVtabError(pTab, "'rebuild' may not be used with a contentless fts5 table" ); @@ -257060,7 +256024,7 @@ static void fts5StorageInsert( ){ int rc = *pRc; if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid); + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid); @@ -257068,67 +256032,6 @@ static void fts5StorageInsert( *pRc = rc; } -/* -** -** This function is called when the user attempts an UPDATE on a contentless -** table. Parameter bRowidModified is true if the UPDATE statement modifies -** the rowid value. Parameter apVal[] contains the new values for each user -** defined column of the fts5 table. pConfig is the configuration object of the -** table being updated (guaranteed to be contentless). The contentless_delete=1 -** and contentless_unindexed=1 options may or may not be set. -** -** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite -** error code if it cannot. In this case an error message is also loaded into -** pConfig. Output parameter (*pbContent) is set to true if the caller should -** update the %_content table only - not the FTS index or any other shadow -** table. This occurs when an UPDATE modifies only UNINDEXED columns of the -** table. -** -** An UPDATE may proceed if: -** -** * The only columns modified are UNINDEXED columns, or -** -** * The contentless_delete=1 option was specified and all of the indexed -** columns (not a subset) have been modified. -*/ -static int fts5ContentlessUpdate( - Fts5Config *pConfig, - sqlite3_value **apVal, - int bRowidModified, - int *pbContent -){ - int ii; - int bSeenIndex = 0; /* Have seen modified indexed column */ - int bSeenIndexNC = 0; /* Have seen unmodified indexed column */ - int rc = SQLITE_OK; - - for(ii=0; iinCol; ii++){ - if( pConfig->abUnindexed[ii]==0 ){ - if( sqlite3_value_nochange(apVal[ii]) ){ - bSeenIndexNC++; - }else{ - bSeenIndex++; - } - } - } - - if( bSeenIndex==0 && bRowidModified==0 ){ - *pbContent = 1; - }else{ - if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){ - rc = SQLITE_ERROR; - sqlite3Fts5ConfigErrmsg(pConfig, - (pConfig->bContentlessDelete ? - "%s a subset of columns on fts5 contentless-delete table: %s" : - "%s contentless fts5 table: %s") - , "cannot UPDATE", pConfig->zName - ); - } - } - - return rc; -} - /* ** This function is the implementation of the xUpdate callback used by ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be @@ -257215,34 +256118,44 @@ static int fts5UpdateMethod( assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); assert( nArg!=1 || eType0==SQLITE_INTEGER ); + /* Filter out attempts to run UPDATE or DELETE on contentless tables. + ** This is not suported. Except - they are both supported if the CREATE + ** VIRTUAL TABLE statement contained "contentless_delete=1". */ + if( eType0==SQLITE_INTEGER + && pConfig->eContent==FTS5_CONTENT_NONE + && pConfig->bContentlessDelete==0 + ){ + pTab->p.base.zErrMsg = sqlite3_mprintf( + "cannot %s contentless fts5 table: %s", + (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName + ); + rc = SQLITE_ERROR; + } + /* DELETE */ - if( nArg==1 ){ - /* It is only possible to DELETE from a contentless table if the - ** contentless_delete=1 flag is set. */ - if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){ - fts5SetVtabError(pTab, - "cannot DELETE from contentless fts5 table: %s", pConfig->zName - ); - rc = SQLITE_ERROR; - }else{ - i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); - bUpdateOrDelete = 1; - } + else if( nArg==1 ){ + i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); + bUpdateOrDelete = 1; } /* INSERT or UPDATE */ else{ int eType1 = sqlite3_value_numeric_type(apVal[1]); - /* It is an error to write an fts5_locale() value to a table without - ** the locale=1 option. */ - if( pConfig->bLocale==0 ){ - int ii; - for(ii=0; iinCol; ii++){ - sqlite3_value *pVal = apVal[ii+2]; - if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ - fts5SetVtabError(pTab, "fts5_locale() requires locale=1"); + /* Ensure that no fts5_locale() values are written to locale=0 tables. + ** And that no blobs except fts5_locale() blobs are written to indexed + ** (i.e. not UNINDEXED) columns of locale=1 tables. */ + int ii; + for(ii=0; iinCol; ii++){ + if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){ + int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE); + if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0) + || (pConfig->bLocale==0 && bSub) + ){ + if( pConfig->bLocale==0 ){ + fts5SetVtabError(pTab, "fts5_locale() requires locale=1"); + } rc = SQLITE_MISMATCH; goto update_out; } @@ -257262,55 +256175,35 @@ static int fts5UpdateMethod( /* UPDATE */ else{ - Fts5Storage *pStorage = pTab->pStorage; i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ - int bContent = 0; /* Content only update */ - - /* If this is a contentless table (including contentless_unindexed=1 - ** tables), check if the UPDATE may proceed. */ - if( fts5IsContentless(pTab, 1) ){ - rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent); - if( rc!=SQLITE_OK ) goto update_out; - } - if( eType1!=SQLITE_INTEGER ){ rc = SQLITE_MISMATCH; }else if( iOld!=iNew ){ - assert( bContent==0 ); if( eConflict==SQLITE_REPLACE ){ - rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); }else{ - rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld); + rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid); + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid); } if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); } if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid); + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); } } - }else if( bContent ){ - /* This occurs when an UPDATE on a contentless table affects *only* - ** UNINDEXED columns. This is a no-op for contentless_unindexed=0 - ** tables, or a write to the %_content table only for =1 tables. */ - assert( fts5IsContentless(pTab, 1) ); - rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid); - } }else{ - rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); fts5StorageInsert(&rc, pTab, apVal, pRowid); } bUpdateOrDelete = 1; - sqlite3Fts5StorageReleaseDeleteRow(pStorage); + sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage); } } @@ -257424,11 +256317,11 @@ static int fts5ApiTokenize_v2( Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); int rc = SQLITE_OK; - sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc); + fts5SetLocale(pTab->pConfig, pLoc, nLoc); rc = sqlite3Fts5Tokenize(pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken ); - sqlite3Fts5SetLocale(pTab->pConfig, 0, 0); + fts5SetLocale(pTab->pConfig, 0, 0); return rc; } @@ -257456,49 +256349,6 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); } -/* -** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This -** function extracts the text value of column iCol of the current row. -** Additionally, if there is an associated locale, it invokes -** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller -** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point -** after this function returns. -** -** If successful, (*ppText) is set to point to a buffer containing the text -** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that -** buffer in bytes. It is not guaranteed to be nul-terminated. If an error -** occurs, an SQLite error code is returned. The final values of the two -** output parameters are undefined in this case. -*/ -static int fts5TextFromStmt( - Fts5Config *pConfig, - sqlite3_stmt *pStmt, - int iCol, - const char **ppText, - int *pnText -){ - sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1); - const char *pLoc = 0; - int nLoc = 0; - int rc = SQLITE_OK; - - if( pConfig->bLocale - && pConfig->eContent==FTS5_CONTENT_EXTERNAL - && sqlite3Fts5IsLocaleValue(pConfig, pVal) - ){ - rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc); - }else{ - *ppText = (const char*)sqlite3_value_text(pVal); - *pnText = sqlite3_value_bytes(pVal); - if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){ - pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol); - nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol); - } - } - sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); - return rc; -} - static int fts5ApiColumnText( Fts5Context *pCtx, int iCol, @@ -257512,14 +256362,16 @@ static int fts5ApiColumnText( assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); if( iCol<0 || iCol>=pTab->pConfig->nCol ){ rc = SQLITE_RANGE; - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){ + }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){ *pz = 0; *pn = 0; }else{ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ - rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn); - sqlite3Fts5ClearLocale(pTab->pConfig); + Fts5Config *pConfig = pTab->pConfig; + int bContent = (pConfig->abUnindexed[iCol]==0); + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); + sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn); } } return rc; @@ -257545,7 +256397,7 @@ static int fts5CsrPoslist( if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ rc = SQLITE_RANGE; }else if( pConfig->eDetail!=FTS5_DETAIL_FULL - && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1) + && pConfig->eContent==FTS5_CONTENT_NONE ){ *pa = 0; *pn = 0; @@ -257561,15 +256413,17 @@ static int fts5CsrPoslist( rc = fts5SeekCursor(pCsr, 0); } for(i=0; inCol && rc==SQLITE_OK; i++){ + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); const char *z = 0; int n = 0; - rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n); + int bReset = 0; + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprPopulatePoslists( pConfig, pCsr->pExpr, aPopulator, i, z, n ); } - sqlite3Fts5ClearLocale(pConfig); + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } sqlite3_free(aPopulator); @@ -257741,7 +256595,7 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ if( pConfig->bColumnsize ){ i64 iRowid = fts5CursorRowid(pCsr); rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize); - }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ + }else if( pConfig->zContent==0 ){ int i; for(i=0; inCol; i++){ if( pConfig->abUnindexed[i]==0 ){ @@ -257755,14 +256609,17 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ if( pConfig->abUnindexed[i]==0 ){ const char *z = 0; int n = 0; + int bReset = 0; + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); + pCsr->aColumnSize[i] = 0; - rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n); + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); if( rc==SQLITE_OK ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX, z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb ); + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } - sqlite3Fts5ClearLocale(pConfig); } } } @@ -258029,19 +256886,42 @@ static int fts5ApiColumnLocale( rc = SQLITE_RANGE; }else if( pConfig->abUnindexed[iCol]==0 - && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1) + && pConfig->eContent!=FTS5_CONTENT_NONE && pConfig->bLocale ){ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ - const char *zDummy = 0; - int nDummy = 0; - rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy); - if( rc==SQLITE_OK ){ - *pzLocale = pConfig->t.pLocale; - *pnLocale = pConfig->t.nLocale; + /* Load the value into pVal. pVal is a locale/text pair iff: + ** + ** 1) It is an SQLITE_BLOB, and + ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the + ** value was loaded from an FTS5_CONTENT_NORMAL table, and + ** 3) It does not begin with an 0x00 byte. + */ + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); + if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ + const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); + int nBlob = sqlite3_value_bytes(pVal); + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; + if( nBlobeContent!=FTS5_CONTENT_NONE ); + + if( pConfig->bLocale + && sqlite3_value_type(pVal)==SQLITE_BLOB + && pConfig->abUnindexed[iCol]==0 + ){ + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; + const u8 *pBlob = sqlite3_value_blob(pVal); + int nBlob = sqlite3_value_bytes(pVal); + int ii; + + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ + if( nBlobeContent!=FTS5_CONTENT_NONE ){ + /* A column created by the user containing values. */ + int bNochange = sqlite3_vtab_nochange(pCtx); + + if( fts5IsContentless(pTab) ){ + if( bNochange && pConfig->bContentlessDelete ){ + fts5ResultError(pCtx, "cannot UPDATE a subset of " + "columns on fts5 contentless-delete table: %s", pConfig->zName + ); + } + }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){ pConfig->pzErrmsg = &pTab->p.base.zErrMsg; rc = fts5SeekCursor(pCsr, 1); if( rc==SQLITE_OK ){ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); - if( pConfig->bLocale - && pConfig->eContent==FTS5_CONTENT_EXTERNAL - && sqlite3Fts5IsLocaleValue(pConfig, pVal) - ){ - const char *z = 0; - int n = 0; - rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n); - if( rc==SQLITE_OK ){ - sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT); - } - sqlite3Fts5ClearLocale(pConfig); - }else{ - sqlite3_result_value(pCtx, pVal); - } + fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal); } - pConfig->pzErrmsg = 0; } } @@ -258847,7 +257773,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2024-11-13 14:42:32 35aa893d4537d0b3605084a1f2f5529794e82af59b8893053815d3fcb4719a27", -1, SQLITE_TRANSIENT); } /* @@ -258886,12 +257812,13 @@ static void fts5LocaleFunc( if( zLocale==0 || zLocale[0]=='\0' ){ sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT); }else{ - Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx); u8 *pBlob = 0; u8 *pCsr = 0; int nBlob = 0; + const int nHdr = 4; + assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 ); - nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText; + nBlob = nHdr + nLocale + 1 + nText; pBlob = (u8*)sqlite3_malloc(nBlob); if( pBlob==0 ){ sqlite3_result_error_nomem(pCtx); @@ -258899,8 +257826,8 @@ static void fts5LocaleFunc( } pCsr = pBlob; - memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE); - pCsr += FTS5_LOCALE_HDR_SIZE; + memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr); + pCsr += nHdr; memcpy(pCsr, zLocale, nLocale); pCsr += nLocale; (*pCsr++) = 0x00; @@ -258908,6 +257835,7 @@ static void fts5LocaleFunc( assert( &pCsr[nText]==&pBlob[nBlob] ); sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free); + sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE); } } @@ -259009,16 +257937,6 @@ static int fts5Init(sqlite3 *db){ pGlobal->api.xFindTokenizer = fts5FindTokenizer; pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2; pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2; - - /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector. - ** The constants below were generated randomly. */ - sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr); - pGlobal->aLocaleHdr[0] ^= 0xF924976D; - pGlobal->aLocaleHdr[1] ^= 0x16596E13; - pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA; - pGlobal->aLocaleHdr[3] ^= 0x9B03A67F; - assert( sizeof(pGlobal->aLocaleHdr)==16 ); - rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); @@ -259245,35 +258163,20 @@ static int fts5StorageGetStmt( case FTS5_STMT_INSERT_CONTENT: case FTS5_STMT_REPLACE_CONTENT: { - char *zBind = 0; + int nCol = pC->nCol + 1; + char *zBind; int i; - assert( pC->eContent==FTS5_CONTENT_NORMAL - || pC->eContent==FTS5_CONTENT_UNINDEXED - ); - - /* Add bindings for the "c*" columns - those that store the actual - ** table content. If eContent==NORMAL, then there is one binding - ** for each column. Or, if eContent==UNINDEXED, then there are only - ** bindings for the UNINDEXED columns. */ - for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){ - if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){ - zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1); - } - } - - /* Add bindings for any "l*" columns. Only non-UNINDEXED columns - ** require these. */ - if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){ - for(i=0; rc==SQLITE_OK && inCol; i++){ - if( pC->abUnindexed[i]==0 ){ - zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2); - } + zBind = sqlite3_malloc64(1 + nCol*2); + if( zBind ){ + for(i=0; izDb, pC->zName, zBind); + sqlite3_free(zBind); } - - zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind); - sqlite3_free(zBind); break; } @@ -259459,11 +258362,9 @@ static int sqlite3Fts5StorageOpen( p->pIndex = pIndex; if( bCreate ){ - if( pConfig->eContent==FTS5_CONTENT_NORMAL - || pConfig->eContent==FTS5_CONTENT_UNINDEXED - ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20); + char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10); if( zDefn==0 ){ rc = SQLITE_NOMEM; }else{ @@ -259472,20 +258373,8 @@ static int sqlite3Fts5StorageOpen( sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); iOff = (int)strlen(zDefn); for(i=0; inCol; i++){ - if( pConfig->eContent==FTS5_CONTENT_NORMAL - || pConfig->abUnindexed[i] - ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } - } - if( pConfig->bLocale ){ - for(i=0; inCol; i++){ - if( pConfig->abUnindexed[i]==0 ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } - } + sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); + iOff += (int)strlen(&zDefn[iOff]); } rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); } @@ -259638,8 +258527,7 @@ static int fts5StorageDeleteFromIndex( sqlite3_value *pVal = 0; const char *pText = 0; int nText = 0; - const char *pLoc = 0; - int nLoc = 0; + int bReset = 0; assert( pSeek==0 || apVal==0 ); assert( pSeek!=0 || apVal!=0 ); @@ -259649,19 +258537,10 @@ static int fts5StorageDeleteFromIndex( pVal = apVal[iCol-1]; } - if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ - rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); - }else{ - pText = (const char*)sqlite3_value_text(pVal); - nText = sqlite3_value_bytes(pVal); - if( pConfig->bLocale && pSeek ){ - pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol); - nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol); - } - } - + rc = sqlite3Fts5ExtractText( + pConfig, pVal, pSeek!=0, &bReset, &pText, &nText + ); if( rc==SQLITE_OK ){ - sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, fts5StorageInsertCallback @@ -259670,7 +258549,7 @@ static int fts5StorageDeleteFromIndex( if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){ rc = FTS5_CORRUPT; } - sqlite3Fts5ClearLocale(pConfig); + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } } @@ -259715,9 +258594,7 @@ static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){ int rc = SQLITE_OK; assert( p->pConfig->bContentlessDelete ); - assert( p->pConfig->eContent==FTS5_CONTENT_NONE - || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED - ); + assert( p->pConfig->eContent==FTS5_CONTENT_NONE ); /* Look up the origin of the document in the %_docsize table. Store ** this in stack variable iOrigin. */ @@ -259841,12 +258718,6 @@ static int sqlite3Fts5StorageDelete( if( rc==SQLITE_OK ){ if( p->pConfig->bContentlessDelete ){ rc = fts5StorageContentlessDelete(p, iDel); - if( rc==SQLITE_OK - && bSaveRow - && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED - ){ - rc = sqlite3Fts5StorageFindDeleteRow(p, iDel); - } }else{ rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow); } @@ -259863,9 +258734,7 @@ static int sqlite3Fts5StorageDelete( } /* Delete the %_content record */ - if( pConfig->eContent==FTS5_CONTENT_NORMAL - || pConfig->eContent==FTS5_CONTENT_UNINDEXED - ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ if( rc==SQLITE_OK ){ rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0); } @@ -259897,13 +258766,8 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ ); if( rc==SQLITE_OK && pConfig->bColumnsize ){ rc = fts5ExecPrintf(pConfig->db, 0, - "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName - ); - } - - if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ - rc = fts5ExecPrintf(pConfig->db, 0, - "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName + "DELETE FROM %Q.'%q_docsize';", + pConfig->zDb, pConfig->zName ); } @@ -259944,35 +258808,20 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ + int bReset = 0; /* True if tokenizer locale must be reset */ int nText = 0; /* Size of pText in bytes */ const char *pText = 0; /* Pointer to buffer containing text value */ - int nLoc = 0; /* Size of pLoc in bytes */ - const char *pLoc = 0; /* Pointer to buffer containing text value */ - sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1); - if( pConfig->eContent==FTS5_CONTENT_EXTERNAL - && sqlite3Fts5IsLocaleValue(pConfig, pVal) - ){ - rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); - }else{ - pText = (const char*)sqlite3_value_text(pVal); - nText = sqlite3_value_bytes(pVal); - if( pConfig->bLocale ){ - int iCol = ctx.iCol + 1 + pConfig->nCol; - pLoc = (const char*)sqlite3_column_text(pScan, iCol); - nLoc = sqlite3_column_bytes(pScan, iCol); - } - } + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText); if( rc==SQLITE_OK ){ - sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, fts5StorageInsertCallback ); - sqlite3Fts5ClearLocale(pConfig); + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); @@ -260039,7 +258888,6 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ */ static int sqlite3Fts5StorageContentInsert( Fts5Storage *p, - int bReplace, /* True to use REPLACE instead of INSERT */ sqlite3_value **apVal, i64 *piRowid ){ @@ -260047,9 +258895,7 @@ static int sqlite3Fts5StorageContentInsert( int rc = SQLITE_OK; /* Insert the new row into the %_content table. */ - if( pConfig->eContent!=FTS5_CONTENT_NORMAL - && pConfig->eContent!=FTS5_CONTENT_UNINDEXED - ){ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ *piRowid = sqlite3_value_int64(apVal[1]); }else{ @@ -260058,52 +258904,33 @@ static int sqlite3Fts5StorageContentInsert( }else{ sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ int i; /* Counter variable */ - - assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT ); - assert( bReplace==0 || bReplace==1 ); - rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0); - if( pInsert ) sqlite3_clear_bindings(pInsert); - - /* Bind the rowid value */ - sqlite3_bind_value(pInsert, 1, apVal[1]); - - /* Loop through values for user-defined columns. i=2 is the leftmost - ** user-defined column. As is column 1 of pSavedRow. */ - for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ - int bUnindexed = pConfig->abUnindexed[i-2]; - if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){ - sqlite3_value *pVal = apVal[i]; - - if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ - /* This is an UPDATE statement, and user-defined column (i-2) was not - ** modified. Retrieve the value from Fts5Storage.pSavedRow. */ - pVal = sqlite3_column_value(p->pSavedRow, i-1); - if( pConfig->bLocale && bUnindexed==0 ){ - sqlite3_bind_value(pInsert, pConfig->nCol + i, - sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1) - ); - } - }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); + for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ + sqlite3_value *pVal = apVal[i]; + if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ + /* This is an UPDATE statement, and column (i-2) was not modified. + ** Retrieve the value from Fts5Storage.pSavedRow instead. */ + pVal = sqlite3_column_value(p->pSavedRow, i-1); + }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){ + assert( pConfig->bLocale ); + assert( i>1 ); + if( pConfig->abUnindexed[i-2] ){ + /* At attempt to insert an fts5_locale() value into an UNINDEXED + ** column. Strip the locale away and just bind the text. */ const char *pText = 0; - const char *pLoc = 0; int nText = 0; - int nLoc = 0; - assert( pConfig->bLocale ); - - rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); - if( rc==SQLITE_OK ){ - sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT); - if( bUnindexed==0 ){ - int iLoc = pConfig->nCol + i; - sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT); - } - } - - continue; + rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText); + sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT); + }else{ + const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); + int nBlob = sqlite3_value_bytes(pVal); + assert( nBlob>4 ); + sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT); } - - rc = sqlite3_bind_value(pInsert, i, pVal); + continue; } + + rc = sqlite3_bind_value(pInsert, i, pVal); } if( rc==SQLITE_OK ){ sqlite3_step(pInsert); @@ -260138,37 +258965,23 @@ static int sqlite3Fts5StorageIndexInsert( for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ + int bReset = 0; /* True if tokenizer locale must be reset */ int nText = 0; /* Size of pText in bytes */ const char *pText = 0; /* Pointer to buffer containing text value */ - int nLoc = 0; /* Size of pText in bytes */ - const char *pLoc = 0; /* Pointer to buffer containing text value */ - sqlite3_value *pVal = apVal[ctx.iCol+2]; + int bDisk = 0; if( p->pSavedRow && sqlite3_value_nochange(pVal) ){ pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1); - if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){ - int iCol = ctx.iCol + 1 + pConfig->nCol; - pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol); - nLoc = sqlite3_column_bytes(p->pSavedRow, iCol); - } - }else{ - pVal = apVal[ctx.iCol+2]; + bDisk = 1; } - - if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ - rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); - }else{ - pText = (const char*)sqlite3_value_text(pVal); - nText = sqlite3_value_bytes(pVal); - } - + rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText); if( rc==SQLITE_OK ){ - sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); + assert( bReset==0 || pConfig->bLocale ); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, fts5StorageInsertCallback ); - sqlite3Fts5ClearLocale(pConfig); + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); @@ -260333,62 +259146,38 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } for(i=0; rc==SQLITE_OK && inCol; i++){ - if( pConfig->abUnindexed[i]==0 ){ - const char *pText = 0; - int nText = 0; - const char *pLoc = 0; - int nLoc = 0; - sqlite3_value *pVal = sqlite3_column_value(pScan, i+1); - - if( pConfig->eContent==FTS5_CONTENT_EXTERNAL - && sqlite3Fts5IsLocaleValue(pConfig, pVal) - ){ - rc = sqlite3Fts5DecodeLocaleValue( - pVal, &pText, &nText, &pLoc, &nLoc - ); - }else{ - if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){ - int iCol = i + 1 + pConfig->nCol; - pLoc = (const char*)sqlite3_column_text(pScan, iCol); - nLoc = sqlite3_column_bytes(pScan, iCol); - } - pText = (const char*)sqlite3_value_text(pVal); - nText = sqlite3_value_bytes(pVal); - } - - ctx.iCol = i; - ctx.szCol = 0; - - if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); - } + if( pConfig->abUnindexed[i] ) continue; + ctx.iCol = i; + ctx.szCol = 0; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + int bReset = 0; /* True if tokenizer locale must be reset */ + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ + rc = sqlite3Fts5ExtractText(pConfig, + sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText + ); if( rc==SQLITE_OK ){ - sqlite3Fts5SetLocale(pConfig, pLoc, nLoc); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, fts5StorageIntegrityCallback ); - sqlite3Fts5ClearLocale(pConfig); - } - - /* If this is not a columnsize=0 database, check that the number - ** of tokens in the value matches the aColSize[] value read from - ** the %_docsize table. */ - if( rc==SQLITE_OK - && pConfig->bColumnsize - && ctx.szCol!=aColSize[i] - ){ - rc = FTS5_CORRUPT; - } - aTotalSize[i] += ctx.szCol; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } } sqlite3Fts5TermsetFree(ctx.pTermset); ctx.pTermset = 0; @@ -260813,7 +259602,7 @@ static const unsigned char sqlite3Utf8Trans1[] = { c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ - while( zIn=zEof ) return SQLITE_OK; READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) return SQLITE_OK; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); WRITE_UTF8(zOut, iCode); @@ -262000,11 +260789,8 @@ static int fts5TriTokenize( /* Read characters from the input up until the first non-diacritic */ do { iNext = zIn - (const unsigned char*)pText; - if( zIn>=zEof ){ - iCode = 0; - break; - } READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); @@ -264041,7 +262827,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ } -/* Here ends the fts5.c composite file. */ + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ @@ -264395,21268 +263181,6 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ -/************** Begin file hct_pman.c ****************************************/ -/* -** 2022 April 10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - - -/************** Include hctInt.h in the middle of hct_pman.c *****************/ -/************** Begin file hctInt.h ******************************************/ - -/* #include */ -/************** Include sqlite3hct.h in the middle of hctInt.h ***************/ -/************** Begin file sqlite3hct.h **************************************/ -/* -** 2023 May 16 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - - - -#ifndef SQLITE3HCT_H -#define SQLITE3HCT_H - -/* -** Make sure we can call this stuff from C++. -*/ -#if 0 -extern "C" { -#endif - -#define SQLITE_HCT_JOURNAL_HASHSIZE 16 - -/* -** Initialize the main database for replication. -*/ -SQLITE_API int sqlite3_hct_journal_init(sqlite3 *db); - -/* -** Write a transaction into the database. -*/ -SQLITE_API int sqlite3_hct_journal_write( - sqlite3 *db, /* Write to "main" db of this handle */ - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid -); - -SQLITE_API int sqlite3_hct_journal_truncate(sqlite3 *db, sqlite3_int64 iMinCid); - -/* -** Candidate values for second arg to sqlite3_hct_journal_setmode() -*/ -#define SQLITE_HCT_JOURNAL_MODE_FOLLOWER 0 -#define SQLITE_HCT_JOURNAL_MODE_LEADER 1 - -/* -** Query the LEADER/FOLLOWER setting of the db passed as the only argument. -*/ -SQLITE_API int sqlite3_hct_journal_mode(sqlite3 *db); - -/* -** Set the LEADER/FOLLOWER setting of the db passed as the first argument. -** Return SQLITE_OK if successful. Otherwise, return an SQLite error code -** and leave an English language error message (accessible using -** sqlite3_errmsg()) in the database handle. -*/ -SQLITE_API int sqlite3_hct_journal_setmode(sqlite3 *db, int eMode); - -/* -** Rollback transactions that follow the first hole in the journal. -*/ -SQLITE_API int sqlite3_hct_journal_rollback(sqlite3 *db, sqlite3_int64 iCid); - -/* -** Special values that may be passed as second argument to -** sqlite3_hct_journal_rollback(). -*/ -#define SQLITE_HCT_ROLLBACK_MAXIMUM 0 -#define SQLITE_HCT_ROLLBACK_PRESERVE -1 - -/* -** Set output variable (*piCid) to the CID of the newest available -** database snapshot. Return SQLITE_OK if successful, or an SQLite -** error code if something goes wrong. -*/ -SQLITE_API int sqlite3_hct_journal_snapshot(sqlite3 *db, sqlite3_int64 *piCid); - -/* -** Register a custom validation callback with the database handle. -*/ -SQLITE_API int sqlite3_hct_journal_hook( - sqlite3 *db, - void *pArg, - int(*xValidate)( - void *pCopyOfArg, - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid - ) -); - -/* -** Both arguments are assumed to point to SQLITE_HCT_JOURNAL_HASHSIZE -** byte buffers. This function updates the hash stored in buffer pHash -** based on the contents of buffer pData. -*/ -SQLITE_API void sqlite3_hct_journal_hash(void *pHash, const void *pData); - -/* -** It is assumed that buffer pHash points to a buffer -** SQLITE_HCT_JOURNAL_HASHSIZE bytes in size. This function populates this -** buffer with a hash based on the remaining arguments. -*/ -SQLITE_API void sqlite3_hct_journal_hashentry( - void *pHash, /* OUT: Hash of other arguments */ - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid -); - -SQLITE_API void sqlite3_hct_migrate_mode(sqlite3 *db, int bActivate); - -#if 0 -} -#endif -#endif /* SQLITE3HCT_H */ - -/************** End of sqlite3hct.h ******************************************/ -/************** Continuing where we left off in hctInt.h *********************/ - -typedef sqlite3_int64 i64; -typedef unsigned char u8; -typedef unsigned int u32; - -/* -** Primitives for atomic load and store. -*/ -#define HctAtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL), __ATOMIC_SEQ_CST) -#define HctAtomicLoad(PTR) __atomic_load_n((PTR), __ATOMIC_SEQ_CST) - -#define HctCASBool(PTR,OLD,NEW) \ - (int)__sync_bool_compare_and_swap((PTR),(OLD),(NEW)) - - -/* -*/ -typedef struct HctConfig HctConfig; -struct HctConfig { - int nDbFile; /* Number of files (hct_file.c) */ - int nPageSet; /* Used by hct_pman.c */ - int nPageScan; /* Used by hct_pman.c */ - int szLogChunk; /* Used by hctree.c */ - int nTryBeforeUnevict; - int bQuiescentIntegrityCheck; /* PRAGMA hct_quiescent_integrity_check */ - int pgsz; - sqlite3 *db; -}; - -#define HCT_TID_MASK ((((u64)0x00FFFFFF) << 32)|0xFFFFFFFF) -#define HCT_PGNO_MASK ((u64)0xFFFFFFFF) - -#define HCT_MAX_NDBFILE 128 - -#define HCT_DEFAULT_NDBFILE 1 -#define HCT_DEFAULT_NPAGESET 256 -#define HCT_DEFAULT_NTRYBEFOREUNEVICT 100 -#define HCT_DEFAULT_NPAGESCAN 1024 -#define HCT_DEFAULT_SZLOGCHUNK 16384 -#define HCT_DEFAULT_PAGESIZE 4096 - - - -/************** Include hctTMapInt.h in the middle of hctInt.h ***************/ -/************** Begin file hctTMapInt.h **************************************/ -/* -** 2021 February 24 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This header file describes the transaction map implementation. It -** serves two tasks: -** -** * Provides the transaction map itself, a mapping from 56-bit TID values -** to a combination of a CID value (also 56 bits) and some flags. -** -** * Provides the read-lock system required by readers to ensure that old -** database pages and other resources are not reused before they -** are guaranteed to be finished with them. -*/ - -/* -*/ - -/* #define HCT_TMAP_PAGESIZE 1024 */ - -#define HCT_TMAP_PGSZBITS 10 -#define HCT_TMAP_PAGESIZE (1 << HCT_TMAP_PGSZBITS) - -#define HCT_TMAP_ENTRYSLOT(iEntry) \ - (((iEntry) >> 3) + (((iEntry) & 0x07) << (HCT_TMAP_PGSZBITS-3))) -// #define HCT_TMAP_ENTRYSLOT(iEntry) (((iEntry) >> 3) + (((iEntry) & 0x07) << 10)) - -/* -** Transaction state - stored in the MSB of the 8-byte transaction map entry. -*/ -#define HCT_TMAP_WRITING (((u64)0x00) << 56) -#define HCT_TMAP_VALIDATING (((u64)0x01) << 56) -#define HCT_TMAP_ROLLBACK (((u64)0x02) << 56) -#define HCT_TMAP_COMMITTED (((u64)0x03) << 56) - -#define HCT_TMAP_STATE_MASK (((u64)0x07) << 56) -#define HCT_TMAP_CID_MASK ~(((u64)0xFF) << 56) - -/* -** There is a single object of this type for each distinct database -** opened within the process. All connections to said database have -** a pointer to the same HctTMapServer object. -*/ -typedef struct HctTMapServer HctTMapServer; - -/* -** Each separate database connection holds a handle of this type for -** the lifetime of the connection. Obtained and later released using -** functions: -** -** sqlite3HctTMapServerNew() -** sqlite3HctTMapServerFree() -*/ -typedef struct HctTMapClient HctTMapClient; - -/* -*/ -typedef struct HctTMap HctTMap; - -/* -** A transaction-map object. -** -** iMinTid: -** This, and all smaller TID values have been finalized (fully committed -** or rolled back). The client may not query the map for any TID values -** less than or equal to this one. -** -** iMinCid: -** This an all smaller CID values were committed -*/ -struct HctTMap { - /* Snapshot locking values */ -#if 0 - u64 iMinCid; /* This + all smaller CIDs fully committed */ - u64 iMinTid; /* This + all smaller TIDs fully committed */ -#endif - - /* Transaction map */ - u64 iFirstTid; /* TID corresponding to aaMap[0][0] */ - int nMap; /* Number of mapping pages in aaMap[] */ - u64 **aaMap; /* Array of u64[HCT_TMAP_PAGESIZE] arrays */ -}; - -/* -** Create or delete a tmap server object. -*/ -SQLITE_PRIVATE int sqlite3HctTMapServerNew(u64 iFirstTid, u64 iLastTid, HctTMapServer **pp); -SQLITE_PRIVATE void sqlite3HctTMapServerFree(HctTMapServer *p); - -/* -** Connect/disconnect a tmap client object. -*/ -SQLITE_PRIVATE int sqlite3HctTMapClientNew(HctTMapServer*, HctConfig*, HctTMapClient**); -SQLITE_PRIVATE void sqlite3HctTMapClientFree(HctTMapClient *pClient); - -/* -** Obtain, update or release a reference to a transaction map object. -*/ -SQLITE_PRIVATE int sqlite3HctTMapBegin(HctTMapClient *p, u64 iSnapshot, HctTMap **ppMap); -SQLITE_PRIVATE int sqlite3HctTMapUpdate(HctTMapClient *p, HctTMap **ppMap); -SQLITE_PRIVATE int sqlite3HctTMapEnd(HctTMapClient *p, u64 iCID); - -/* -** Return a TID value for which: -** -** 1. the transactions associated with it and all smaller TID values -** have been finalized (marked as committed or rolled back), and -** -** 2. the transactions associated with it and all smaller TID values -** are included in the snapshots accessed by all current and future -** readers. -** -** All physical and logical pages freed by transactions with TIDs equal to -** or smaller than the returned value may now be reused without disturbing -** current or future readers. -*/ -SQLITE_PRIVATE u64 sqlite3HctTMapSafeTID(HctTMapClient*); - -SQLITE_PRIVATE int sqlite3HctTMapNewTID(HctTMapClient *p, u64 iTid, HctTMap **ppMap); - -/* -** Return TID value T for all transactions with tid values less than or -** equal to T were finished (marked as committed or rolled back), last -** time sqlite3HctTMapBegin() was called. -*/ -SQLITE_PRIVATE u64 sqlite3HctTMapCommitedTID(HctTMapClient*); - -SQLITE_PRIVATE i64 sqlite3HctTMapStats(sqlite3 *db, int iStat, const char **pzStat); - -SQLITE_PRIVATE void sqlite3HctTMapScan(HctTMapClient*); - - -/* -** The following API is used when recovering a replication-enabled database. -** In that case, a new HctTMap object must be created during recovery to -** reflect the contents of the sqlite_hct_journal table. -*/ -SQLITE_PRIVATE int sqlite3HctTMapRecoverySet(HctTMapClient*, u64 iTid, u64 iCid); -SQLITE_PRIVATE void sqlite3HctTMapRecoveryFinish(HctTMapClient*, int rc); - -SQLITE_PRIVATE int sqlite3HctTMapServerSet(HctTMapServer *pServer, u64 iTid, u64 iCid); - - - - -/************** End of hctTMapInt.h ******************************************/ -/************** Continuing where we left off in hctInt.h *********************/ -/************** Include hctFileInt.h in the middle of hctInt.h ***************/ -/************** Begin file hctFileInt.h **************************************/ -/* -** 2023 January 6 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ - -typedef struct HctFileServer HctFileServer; -typedef struct HctFile HctFile; - -SQLITE_PRIVATE HctFile *sqlite3HctFileOpen( - int *pRc, - const char *zFile, - HctConfig *pConfig -); -SQLITE_PRIVATE void sqlite3HctFileClose(HctFile *pFile); - -/* -** If the database has not yet been created on disk, create it. Or, if -** the db has already been created, then this function is a no-op. -*/ -SQLITE_PRIVATE int sqlite3HctFileNewDb(HctFile *pFile); - -/* -** Return true if the db has not yet been created on disk. Or false -** if it already has. -*/ -SQLITE_PRIVATE int sqlite3HctFileIsNewDb(HctFile *pFile); - -SQLITE_PRIVATE u32 sqlite3HctFileMaxpage(HctFile *pFile); - -typedef struct HctFilePage HctFilePage; -struct HctFilePage { - u8 *aOld; /* Current buffer, or NULL */ - u8 *aNew; /* New buffer (to be populated) */ - - /* Used internally by hct_file.c. Mostly... */ - u32 iPg; /* logical page number */ - u32 iNewPg; /* New physical page number */ - u32 iOldPg; /* Original physical page number */ - HctFile *pFile; -}; - -/* -** Allocate logical root page numbers. And free the same (required if the -** transaction is rolled back). -*/ -SQLITE_PRIVATE int sqlite3HctFileRootPgno(HctFile *pFile, u32 *piRoot); -SQLITE_PRIVATE int sqlite3HctFileRootFree(HctFile *pFile, u32 iRoot); -SQLITE_PRIVATE int sqlite3HctFileRootNew(HctFile *pFile, u32 iRoot, HctFilePage*); - - -SQLITE_PRIVATE int sqlite3HctFilePageNew(HctFile *pFile, HctFilePage *pPg); - -/* -** Obtain a read-only reference to logical page iPg. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageGet(HctFile *pFile, u32 iPg, HctFilePage *pPg); - -/* -** If the page is not already writable (if pPg->aNew==0), make it writable. -** This involves allocating a new physical page and setting pPg->aNew -** to point to the buffer. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageWrite(HctFilePage *pPg); - -/* -** This is a no-op if the page is not writable. -** -** If the page is already writable, reverse this so that will not be -** written out when PageRelease() or PageCommit() is called. This reclaims -** the physical page that was allocated by the earlier PageWrite() call -** and sets pPg->aNew to NULL. -*/ -SQLITE_PRIVATE void sqlite3HctFilePageUnwrite(HctFilePage *pPg); - -/* -** This is a no-op if the page is not writable. -** -** Commit the new version of the page to disk (i.e. set the page-map entry -** so that the logical page number now maps to the new version of the page -** in pPg->aNew). Then make pPg a non-writable reference to the logical -** page (so that pPg->aOld points to the new version of the page and -** pPg->aNew is NULL). -*/ -SQLITE_PRIVATE int sqlite3HctFilePageCommit(HctFilePage *pPg); - -/* -** Evict the page from the data structure - i.e. set the LOGICAL_EVICTED -** flag for it. This operation fails if the LOGICAL_EVICTED flag has -** already been set, or if the page has been written since it was read. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageEvict(HctFilePage *pPg, int bIrrevocable); - -SQLITE_PRIVATE void sqlite3HctFilePageUnevict(HctFilePage *pPg); - -SQLITE_PRIVATE int sqlite3HctFilePageIsEvicted(HctFile *pFile, u32 iPgno); -SQLITE_PRIVATE int sqlite3HctFilePageIsFree(HctFile *pFile, u32 iPgno, int bLogical); - -/* -** Release a page reference obtained via an earlier call to -** sqlite3HctFilePageGet() or sqlite3HctFilePageNew(). After this call -** pPg->aOld is NULL. -** -** If the page is writable, it is committed (see sqlite3HctFilePageCommit) -** before the reference is released. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageRelease(HctFilePage *pPg); - - -SQLITE_PRIVATE int sqlite3HctFilePageGetPhysical(HctFile *pFile, u32 iPg, HctFilePage *pPg); -SQLITE_PRIVATE int sqlite3HctFilePageNewPhysical(HctFile *pFile, HctFilePage *pPg); - -SQLITE_PRIVATE u64 sqlite3HctFileAllocateTransid(HctFile *pFile); -SQLITE_PRIVATE u64 sqlite3HctFileAllocateCID(HctFile *pFile, int); -SQLITE_PRIVATE u64 sqlite3HctFileGetSnapshotid(HctFile *pFile); - -SQLITE_PRIVATE void sqlite3HctFileSetCID(HctFile *pFile, u64); - -/* -** Increment the global write-count by nIncr, and return the final value. -*/ -SQLITE_PRIVATE u64 sqlite3HctFileIncrWriteCount(HctFile *pFile, int nIncr); - -SQLITE_PRIVATE HctTMapClient *sqlite3HctFileTMapClient(HctFile*); - -SQLITE_PRIVATE int sqlite3HctFilePgsz(HctFile *pFile); -SQLITE_PRIVATE int sqlite3HctFileVtabInit(sqlite3 *db); - -SQLITE_PRIVATE u64 sqlite3HctFileSafeTID(HctFile*); -SQLITE_PRIVATE u32 sqlite3HctFilePageRangeAlloc(HctFile*, int bLogical, int nPg); - -SQLITE_PRIVATE int sqlite3HctFileClearInUse(HctFilePage *pPg, int bReuseNow); -SQLITE_PRIVATE int sqlite3HctFileClearPhysInUse(HctFile *pFile, u32 pgno, int bReuseNow); - -SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...); - -SQLITE_PRIVATE char *sqlite3HctFileLogFile(HctFile *pFile); -SQLITE_PRIVATE int sqlite3HctFileStartRecovery(HctFile *pFile, int iStage); -SQLITE_PRIVATE int sqlite3HctFileFinishRecovery(HctFile *pFile, int iStage, int rc); -SQLITE_PRIVATE int sqlite3HctFileRecoverFreelists( - HctFile *pFile, /* File to recover freelists for */ - int nRoot, i64 *aRoot, /* Array of root page numbers */ - int nPhys, i64 *aPhys /* Sorted array of phys. pages to preserve */ -); - -SQLITE_PRIVATE int sqlite3HctFileFindLogs(HctFile*, void*, int(*)(void*, const char*)); - -SQLITE_PRIVATE u32 sqlite3HctFilePageMapping(HctFile *pFile, u32 iLogical, int *pbEvicted); - -SQLITE_PRIVATE void sqlite3HctFileICArrays(HctFile*, u8**, u32*, u8**, u32*); -SQLITE_PRIVATE int sqlite3HctFileTreeFree(HctFile *, u32, int); -SQLITE_PRIVATE int sqlite3HctFilePageClearIsRoot(HctFile*, u32); -SQLITE_PRIVATE int sqlite3HctFilePageClearInUse(HctFile *pFile, u32 iPg, int bLogic); - -/************** Include hctPManInt.h in the middle of hctFileInt.h ***********/ -/************** Begin file hctPManInt.h **************************************/ -/* -** 2022 March 20 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ - -/* -** There is a single object of this type for each distinct database opened -** by the process. Allocated and later freed using the following functions. -** -** sqlite3HctPManServerNew() -** sqlite3HctPManServerFree() -** -** Once an HctPManServer object has been created, it is configured with -** the set of free logical and physical pages, which the caller presumably -** discovers by scanning the page-map. -*/ -typedef struct HctPManServer HctPManServer; -typedef struct HctFile HctFile; - -SQLITE_PRIVATE HctPManServer *sqlite3HctPManServerNew( - int *pRc, /* IN/OUT: Error code */ - HctFileServer *pFileServer /* Associated file-server object */ -); -SQLITE_PRIVATE void sqlite3HctPManServerFree(HctPManServer*); - -/* -** This function is called multiple times while scanning the page-map -** during initialization. To load the initial set of free physical and -** logical pages. -*/ -SQLITE_PRIVATE void sqlite3HctPManServerInit( - int *pRc, HctPManServer*, u64 iTid, u32 iPg, int bLogical -); - -/* -** Each separate database connection holds a handle of this type for -** the lifetime of the connection. -*/ -typedef struct HctPManClient HctPManClient; - -SQLITE_PRIVATE HctPManClient *sqlite3HctPManClientNew( - int *pRc, - HctConfig*, - HctPManServer*, - HctFile* -); -SQLITE_PRIVATE void sqlite3HctPManClientFree(HctPManClient*); - -/* -** Allocate a new logical or physical page. -*/ -SQLITE_PRIVATE u32 sqlite3HctPManAllocPg( - int *pRc, /* IN/OUT: Error code */ - HctPManClient *p, /* page-manager client handle */ - HctFile *pFile, - int bLogical -); - -/* -** Mark a logical or physical page as no longer in use. Parameter iTid -** is the transaction-id associated with the transaction that freed the -** page. The page may be reused once all clients are accessing a -** snapshot that includes this transaction. In other words, once the -** snapshot id of all readers is greater than or equal to the commit id -** that maps to transaction id iTid. -** -** Sometimes this function is called with iTid==0, to indicate that the -** page in question may be reused immediately. -*/ -SQLITE_PRIVATE void sqlite3HctPManFreePg( - int *pRc, /* IN/OUT: Error code */ - HctPManClient *p, /* page-manager client handle */ - i64 iTid, /* Associated TID value */ - u32 iPg, /* Page number */ - int bLogical /* True for logical, false for physical */ -); - -SQLITE_PRIVATE void sqlite3HctPManClientHandoff(HctPManClient *p); - -SQLITE_PRIVATE void sqlite3HctPManServerReset(HctPManServer *pServer); - -SQLITE_PRIVATE int sqlite3HctPManVtabInit(sqlite3 *db); - -/* -** Mark an entire tree of logical and physical pages as free. The iTid -** parameter works just as it does for sqlite3HctPManFreePg(). -** -** SQLITE_OK is returned if successful, or an error code (e.g. SQLITE_NOMEM) -** otherwise. -*/ -SQLITE_PRIVATE int sqlite3HctPManFreeTree(HctPManClient *p, HctFile*, u32 iRoot, u64 iTid); - -SQLITE_PRIVATE int sqlite3HctPManServerInitRoot(int *pRc, HctPManServer*, u64, HctFile*, u32); -SQLITE_PRIVATE i64 sqlite3HctPManStats(sqlite3 *db, int iStat, const char **pzStat); - -/************** End of hctPManInt.h ******************************************/ -/************** Continuing where we left off in hctFileInt.h *****************/ -SQLITE_PRIVATE HctPManClient *sqlite3HctFilePManClient(HctFile*); - -SQLITE_PRIVATE int sqlite3HctFileRootArray(HctFile*, u32**, int*); - -/* Interface used by hct_stats virtual table */ -SQLITE_PRIVATE i64 sqlite3HctFileStats(sqlite3*, int, const char**); - -/* -** Return the total number of physical page allocations made during -** the entire lifetime of this object. -*/ -SQLITE_PRIVATE u64 sqlite3HctFileWriteCount(HctFile *pFile); - -/* -** Return the number of files used to store data within the database (the -** value to return for "PRAGMA hct_ndbfile"). Before returning, set output -** parameter *pbFixed if the database has been created and the number -** of files is therefore fixed, or clear it if the db has yet to be created. -*/ -SQLITE_PRIVATE int sqlite3HctFileNFile(HctFile *pFile, int *pbFixed); - -SQLITE_PRIVATE void sqlite3HctFileSetJrnlPtr(HctFile *pFile, void *pPtr, void(*xDel)(void*)); -SQLITE_PRIVATE void *sqlite3HctFileGetJrnlPtr(HctFile *pFile); - -SQLITE_PRIVATE int sqlite3HctIoerr(int rc); - - -/************** End of hctFileInt.h ******************************************/ -/************** Continuing where we left off in hctInt.h *********************/ - -#ifdef SQLITE_DEBUG -# define SQLITE_LOCKED_ERR(x,y) sqlite3HctLockedErr(x,y) -SQLITE_PRIVATE int sqlite3HctLockedErr(u32 pgno, const char *zReason); -#else -# define SQLITE_LOCKED_ERR(x,y) SQLITE_LOCKED -#endif - -#define HCT_TREE_SCHEMAOP_ROOT 3 - -/* -** Growable buffer type used for various things. -*/ -typedef struct HctBuffer HctBuffer; -struct HctBuffer { - u8 *aBuf; - int nBuf; - int nAlloc; -}; -SQLITE_PRIVATE int sqlite3HctBufferGrow(HctBuffer *pBuf, int nSize); -SQLITE_PRIVATE void sqlite3HctBufferFree(HctBuffer *pBuf); - - - -/************************************************************************* -** Interface to code in hct_tree.c -*/ -typedef struct HctTree HctTree; -typedef struct HctTreeCsr HctTreeCsr; - -SQLITE_PRIVATE int sqlite3HctTreeNew(HctTree **ppTree); -SQLITE_PRIVATE void sqlite3HctTreeFree(HctTree *pTree); - -SQLITE_PRIVATE int sqlite3HctTreeInsert(HctTreeCsr*, UnpackedRecord*, i64, int, const u8*,int); -SQLITE_PRIVATE int sqlite3HctTreeAppend(HctTreeCsr*, KeyInfo*, i64, int, const u8*,int); -SQLITE_PRIVATE int sqlite3HctTreeDelete(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeDeleteKey(HctTreeCsr *, UnpackedRecord *, i64, int,const u8*); - -/* -** These functions are used to open and close transactions and nested -** sub-transactions. -** -** The Begin() function is used to open transactions and sub-transactions. -** A successful call to Begin() ensures that there are at least iLevel -** nested transactions open. To open a top-level transaction, pass iLevel=1. -** To open a sub-transaction within the top-level transaction, iLevel=2. -** Passing iLevel=0 is a no-op. -** -** Release() is used to commit transactions and sub-transactions. A -** successful call to Release() ensures that there are at most iLevel -** nested transactions open. To commit a top-level transaction, pass iLevel=0. -** To commit all sub-transactions inside the main transaction, pass iLevel=1. -** -** Function lsm_rollback() is used to roll back transactions and -** sub-transactions. A successful call to lsm_rollback() restores the database -** to the state it was in when the iLevel'th nested sub-transaction (if any) -** was first opened. And then closes transactions to ensure that there are -** at most iLevel nested transactions open. Passing iLevel=0 rolls back and -** closes the top-level transaction. iLevel=1 also rolls back the top-level -** transaction, but leaves it open. iLevel=2 rolls back the sub-transaction -** nested directly inside the top-level transaction (and leaves it open). -*/ -SQLITE_PRIVATE int sqlite3HctTreeBegin(HctTree *pTree, int iStmt); -SQLITE_PRIVATE int sqlite3HctTreeRelease(HctTree *pTree, int iStmt); -SQLITE_PRIVATE int sqlite3HctTreeRollbackTo(HctTree *pTree, int iStmt); - -SQLITE_PRIVATE int sqlite3HctTreeClearOne(HctTree *pTree, u32 iRoot, i64 *pnRow); - -SQLITE_PRIVATE int sqlite3HctTreeCsrOpen(HctTree *pTree, u32 iRoot, HctTreeCsr **ppCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrClose(HctTreeCsr *pCsr); - -SQLITE_PRIVATE int sqlite3HctTreeCsrNext(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrPrev(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrEof(HctTreeCsr *pCsr); - -SQLITE_PRIVATE int sqlite3HctTreeCsrSeek(HctTreeCsr*, UnpackedRecord*, i64 iKey, int *pRes); -SQLITE_PRIVATE int sqlite3HctTreeCsrFirst(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrLast(HctTreeCsr *pCsr); - -SQLITE_PRIVATE int sqlite3HctTreeCsrKey(HctTreeCsr *pCsr, i64 *piKey); -SQLITE_PRIVATE int sqlite3HctTreeCsrData(HctTreeCsr *pCsr, int *pnData, const u8 **paData); -SQLITE_PRIVATE int sqlite3HctTreeCsrIsDelete(HctTreeCsr *pCsr); - -SQLITE_PRIVATE void sqlite3HctTreeCsrPin(HctTreeCsr *pCsr); -SQLITE_PRIVATE void sqlite3HctTreeCsrUnpin(HctTreeCsr *pCsr); - -SQLITE_PRIVATE int sqlite3HctTreeCsrHasMoved(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrRestore(HctTreeCsr *pCsr, int *pIsDifferent); -SQLITE_PRIVATE void sqlite3HctTreeCsrClear(HctTreeCsr *pCsr); - -SQLITE_PRIVATE u32 sqlite3HctTreeCsrRoot(HctTreeCsr *pCsr); - - -/* -** Iterate through non-empty tables/indexes within an HctTree structure. Used -** when flushing contents to disk. -** -** If parameter bSchemaOp is false, then no callback is issued for the table -** with root page number HCT_TREE_SCHEMAOP_ROOT. If bSchemaOp is non-zero, -** then HCT_TREE_SCHEMAOP_ROOT is treated like any other table. -*/ - -SQLITE_PRIVATE int sqlite3HctTreeForeach( - HctTree *pTree, - int bSchemOp, - void *pCtx, - int (*x)(void *, u32, KeyInfo*) -); -SQLITE_PRIVATE void sqlite3HctTreeClear(HctTree *pTree); - -SQLITE_PRIVATE void sqlite3HctTreeCsrIncrblob(HctTreeCsr *pCsr); -SQLITE_PRIVATE int sqlite3HctTreeCsrReseek(HctTreeCsr *pCsr, int*); - -SQLITE_PRIVATE int sqlite3HctTreeUpdateMeta(HctTree*, const u8*, int); - -/************************************************************************* -** Interface to code in hct_database.c -*/ -typedef struct HctDatabase HctDatabase; -typedef struct HctDbCsr HctDbCsr; - -typedef struct HctJournal HctJournal; - -SQLITE_PRIVATE HctDatabase *sqlite3HctDbFind(sqlite3*, int); -SQLITE_PRIVATE int sqlite3HctDetectJournals(sqlite3 *db); - -SQLITE_PRIVATE HctDatabase *sqlite3HctDbOpen(int*, const char *zFile, HctConfig*); -SQLITE_PRIVATE void sqlite3HctDbClose(HctDatabase *pDb); - -SQLITE_PRIVATE int sqlite3HctDbRootNew(HctDatabase *p, u32 *piRoot); -SQLITE_PRIVATE int sqlite3HctDbRootFree(HctDatabase *p, u32 iRoot); - -SQLITE_PRIVATE int sqlite3HctDbRootInit(HctDatabase *p, int bIndex, u32 iRoot); -SQLITE_PRIVATE void sqlite3HctDbRootPageInit(int bIndex, u8 *aPage, int szPage); -SQLITE_PRIVATE int sqlite3HctDbGetMeta(HctDatabase *p, u8 *aBuf, int nBuf); - -SQLITE_PRIVATE int sqlite3HctDbInsert( - HctDatabase *pDb, - u32 iRoot, - UnpackedRecord *pRec, i64 iKey, - int bDel, int nData, const u8 *aData, - int *pnRetry -); -SQLITE_PRIVATE int sqlite3HctDbInsertFlush(HctDatabase *pDb, int *pnRetry); -SQLITE_PRIVATE int sqlite3HctDbStartRead(HctDatabase*,HctJournal*); -SQLITE_PRIVATE int sqlite3HctDbStartWrite(HctDatabase*, u64*); -SQLITE_PRIVATE int sqlite3HctDbEndWrite(HctDatabase*, u64, int); -SQLITE_PRIVATE int sqlite3HctDbEndRead(HctDatabase*); -SQLITE_PRIVATE int sqlite3HctDbValidate(sqlite3*, HctDatabase*, u64 *piCid, int*); - -SQLITE_PRIVATE i64 sqlite3HctDbTid(HctDatabase *); - -SQLITE_PRIVATE void sqlite3HctDbRollbackMode(HctDatabase*,int); - -SQLITE_PRIVATE int sqlite3HctDbCsrOpen(HctDatabase*, struct KeyInfo*, u32 iRoot, HctDbCsr**); -SQLITE_PRIVATE void sqlite3HctDbCsrClose(HctDbCsr *pCsr); - -SQLITE_PRIVATE void sqlite3HctDbCsrNosnap(HctDbCsr *pCsr, int bNosnap); - -SQLITE_PRIVATE void sqlite3HctDbCsrDir(HctDbCsr*, int eDir); -SQLITE_PRIVATE int sqlite3HctDbCsrSeek(HctDbCsr*, UnpackedRecord*, i64 iKey, int *pRes); - -SQLITE_PRIVATE int sqlite3HctDbCsrEof(HctDbCsr*); -SQLITE_PRIVATE int sqlite3HctDbCsrFirst(HctDbCsr*); -SQLITE_PRIVATE int sqlite3HctDbCsrLast(HctDbCsr*); -SQLITE_PRIVATE int sqlite3HctDbCsrNext(HctDbCsr*); -SQLITE_PRIVATE int sqlite3HctDbCsrPrev(HctDbCsr*); -SQLITE_PRIVATE void sqlite3HctDbCsrClear(HctDbCsr*); - -SQLITE_PRIVATE void sqlite3HctDbCsrKey(HctDbCsr*, i64 *piKey); -SQLITE_PRIVATE int sqlite3HctDbCsrData(HctDbCsr *pCsr, int *pnData, const u8 **paData); -SQLITE_PRIVATE int sqlite3HctDbCsrLoadAndDecode(HctDbCsr *pCsr, UnpackedRecord **ppRec); - -SQLITE_PRIVATE int sqlite3HctDbIsIndex(HctDatabase *pDb, u32 iRoot, int *pbIndex); - -SQLITE_PRIVATE int sqlite3HctDbStartRecovery(HctDatabase *pDb, int iStage); -SQLITE_PRIVATE int sqlite3HctDbFinishRecovery(HctDatabase *db, int iStage, int rc); -SQLITE_PRIVATE void sqlite3HctDbRecoverTid(HctDatabase *db, u64 iTid); - -SQLITE_PRIVATE char *sqlite3HctDbLogFile(HctDatabase*); - -SQLITE_PRIVATE i64 sqlite3HctDbNCasFail(HctDatabase*); - -SQLITE_PRIVATE char *sqlite3HctDbIntegrityCheck(HctDatabase*, u32 *aRoot,Mem*,int nRoot, int*); -SQLITE_PRIVATE i64 sqlite3HctDbStats(sqlite3 *db, int iStat, const char **pzStat); - -SQLITE_PRIVATE int sqlite3HctDbCsrRollbackSeek(HctDbCsr*, UnpackedRecord*, i64, int *pOp); - -SQLITE_PRIVATE void sqlite3HctDbSetSavePhysical( - HctDatabase *pDb, - int (*xSave)(void*, i64 iPhys), - void *pSave -); - -SQLITE_PRIVATE char *sqlite3HctDbRecordToText(sqlite3 *db, const u8 *aRec, int nRec); - -SQLITE_PRIVATE void sqlite3HctDbTMapScan(HctDatabase *pDb); - -SQLITE_PRIVATE void sqlite3HctDbTransIsConcurrent(HctDatabase *pDb, int bConcurrent); - -SQLITE_PRIVATE HctFile *sqlite3HctDbFile(HctDatabase *pDb); - -SQLITE_PRIVATE int sqlite3HctDbWalkTree( - HctFile *pFile, /* File tree resides in */ - u32 iRoot, /* Root page of tree */ - int (*x)(void*, u32, u32), /* Callback function */ - void *pCtx /* First argument to pass to x() */ -); - -SQLITE_PRIVATE int sqlite3HctDbPagesize(HctDatabase *pDb); - -SQLITE_PRIVATE void sqlite3HctDbRecordTrim(UnpackedRecord *pRec); - -/* -** This function returns the current snapshot-id. It may only be called -** when a read transaction is active. -*/ -SQLITE_PRIVATE i64 sqlite3HctDbSnapshotId(HctDatabase *pDb); - -SQLITE_PRIVATE int sqlite3HctDbCsrFindLastWrite( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index/without rowid tables */ - i64 iKey, /* Key for intkey tables */ - u64 *piCid /* Last CID to write to this key */ -); - -SQLITE_PRIVATE void sqlite3HctDbJrnlWriteCid(HctDatabase *pDb, u64 iVal); - -/************************************************************************* -** Interface to code in hct_file.c -*/ - -/************************************************************************* -** Interface to code in hct_record.c -*/ -SQLITE_PRIVATE int sqlite3HctSerializeRecord( - UnpackedRecord *pRec, /* Record to serialize */ - u8 **ppRec, /* OUT: buffer containing serialization */ - int *pnRec /* OUT: size of (*ppRec) in bytes */ -); - -/************************************************************************* -** Interface to code in hct_stats.c -*/ -SQLITE_PRIVATE int sqlite3HctStatsInit(sqlite3*); - -/************************************************************************* -** Utility functions: -*/ -SQLITE_PRIVATE void *sqlite3HctMalloc(int *pRc, i64 nByte); - -/************************************************************************* -** hctree.c: -**/ - -/************** Include hctJrnlInt.h in the middle of hctInt.h ***************/ -/************** Begin file hctJrnlInt.h **************************************/ -/* -** 2023 January 6 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ - -typedef struct HctJournal HctJournal; - -/* -** If schema pSchema contains the special tables sqlite_hct_journal and -** sqlite_hct_baseline, allocate a new HctJournal object, set (*pp) -** to point to it and return SQLITE_OK. Or, if neither table can be -** found, set (*pp) to NULL and return SQLITE_OK. -** -** If only one of the required tables is found (SQLITE_CORRUPT), or if an -** OOM error occurs (SQLITE_NOMEM), return an SQLite error code. The final -** value of (*pp) is NULL in this case. -*/ -SQLITE_PRIVATE int sqlite3HctJournalNewIf(Schema*, HctTree*, HctDatabase*, HctJournal **pp); - -SQLITE_PRIVATE void sqlite3HctJournalClose(HctJournal*); - - -SQLITE_PRIVATE int sqlite3HctJrnlLog( - HctJournal *pJrnl, - sqlite3 *db, - Schema *pSchema, - u64 iCid, - u64 iTid, - int *pbCustomValid -); - -/* -** This is called as part of stage 1 recovery (the bit after the upper layer -** has loaded the database schema). The recovery mutex is held, so the client -** has exclusive access to the database on disk. -*/ -SQLITE_PRIVATE int sqlite3HctJrnlRecovery(HctJournal *pJrnl, HctDatabase *pDb); - -SQLITE_PRIVATE int sqlite3HctJrnlSavePhysical(sqlite3 *db, HctJournal *pJrnl, - int (*xSave)(void*, i64 iPhys), void *pSave -); - -/* -** Register the hct_journal_entry() SQL user-function with the database -** handle. For decoding the "data" column of the sqlite_hct_journal table. -*/ -SQLITE_PRIVATE int sqlite3HctJrnlInit(sqlite3 *db); - -/* -** Return non-zero if (1) argument pJrnl is not NULL, and either (2a) argument -** iTable is the logical root page of either the journal or baseline table -** represented by pJrnl, or (2b) the connection is in follower mode. -** -** Before returning, set output variable (*pbNosnap) to non-zero if condition -** (2a) was true. To indicate that the table does not use snapshots - all -** committed rows are visible. -*/ -SQLITE_PRIVATE int sqlite3HctJournalIsReadonly(HctJournal *pJrnl, u64 iTable, int *pbNosnap); - -SQLITE_PRIVATE int sqlite3HctJrnlRollbackEntry(HctJournal *pJrnl, i64 iTid); - -SQLITE_PRIVATE int sqlite3HctJrnlWriteEmpty(HctJournal *Jrnl, u64 iCid, u64 iTid, sqlite3 *db); - -SQLITE_PRIVATE u64 sqlite3HctJrnlWriteTid(HctJournal *pJrnl, u64 *piCid); - -SQLITE_PRIVATE u64 sqlite3HctJournalSnapshot(HctJournal *pJrnl); - -SQLITE_PRIVATE void sqlite3HctJournalFixSchema(HctJournal *pJrnl, sqlite3*, void *pSchema); - -SQLITE_PRIVATE void sqlite3HctJournalSchemaVersion(HctJournal *pJrnl, u32 *pSchemaVersion); - -SQLITE_PRIVATE void sqlite3HctJrnlInvokeHook(HctJournal *pJrnl, sqlite3 *db); - -/************** End of hctJrnlInt.h ******************************************/ -/************** Continuing where we left off in hctInt.h *********************/ -SQLITE_PRIVATE HctJournal *sqlite3HctJrnlFind(sqlite3*); - -SQLITE_PRIVATE int sqlite3HctBtreeIsNewTable(Btree *pBt, u64 iRoot); -SQLITE_PRIVATE u64 sqlite3HctBtreeSnapshotId(Btree *pBt); - -SQLITE_PRIVATE i64 sqlite3HctMainStats(sqlite3 *db, int iStat, const char **pzStat); - - - -/************** End of hctInt.h **********************************************/ -/************** Continuing where we left off in hct_pman.c *******************/ - -typedef struct HctPManPageset HctPManPageset; -typedef struct HctPManTree HctPManTree; - -#define PAGESET_INIT_SIZE 1000 - -typedef struct HctPManFreePg HctPManFreePg; -typedef struct HctPManFreePgSet HctPManFreePgSet; - -struct HctPManFreePg { - i64 pgno; /* The free page number */ - i64 iTid; /* TID of transaction that freed page */ -}; - -struct HctPManFreePgSet { - HctPManFreePg *aPg; /* Page buffer */ - int nAlloc; /* Allocated size of aPg[] */ - int iFirst; /* Index of first entry in aPg[] */ - int nPg; /* Number of valid pages in aPg[] */ -}; - - - - -/****************************************************************/ - -/* -** A basket of free page ids - a pageset - is represented by an instance -** of the following type. -** -** nAlloc: -** Allocated size of aPg[] array, in entries (not bytes). -** -** nPg: -** Number of valid entries in aPg[]. -** -** aPg: -** Array of free logical or physical page ids. -** -** iMaxTid: -** When a page is freed, it is associated with a TID. Such that the page -** may be reused once it is guaranteed that all current and future readers -** include in their snapshots all transactions with TID values less than -** the associated TID. The maximum of all these values for pages in the -** page set is stored in this variable. -** -** pNext: -** Used to link the HctPManServer.apList[] lists together. -*/ -struct HctPManPageset { - i64 iMaxTid; /* Max associated TID of aPg[] entries */ - int nAlloc; /* Allocated size of aPg[] array */ - int nPg; /* Number of valid entries in aPg[] */ - u32 *aPg; /* Array of page numbers */ - HctPManPageset *pNext; /* Next in list */ -}; - -/* -** A tree of free logical and physical pages. -*/ -struct HctPManTree { - u32 iRoot; /* Logical root of free tree */ - i64 iTid; /* Associated TID value */ -}; - -/* -** Indexes into HctPManServer.apList[], HctPManClient.apAcc[] and -** HctPManClient.apUse[] arrays. -*/ -#define PAGESET_PHYSICAL 0 -#define PAGESET_LOGICAL 1 - -/* -** aList[]: -** aList[0].pHead is a pointer to the first element of a singly-linked -** list of pagesets containing free physical page ids. aList[0].pTail -** always points to the last element of this list. The list is sorted -** in order of HctPManPageset.iMaxTid values. -** -** aList[1] is similar, but for logical page ids. -** -** aTree[]: -** Array of tree structures to eventually walk and free -*/ -struct HctPManServer { - sqlite3_mutex *pMutex; /* Mutex to protect this object */ - HctFileServer *pFileServer; /* Associated file-server object */ - struct HctPManServerList { - HctPManPageset *pHead; - HctPManPageset *pTail; - } aList[2]; - - int nTree; - HctPManTree *aTree; -}; - -/* -** Event counters used by the hctstats virtual table. -*/ -typedef struct HctPManStats HctPManStats; -struct HctPManStats { - i64 nMutex; - i64 nMutexBlock; -}; - -/* -** apAcc[]: -** These two pagesets are used to accumulate physical (apAcc[0]) and -** logical (apAcc[1]) page ids as they are freed by the client. Once -** sufficient page ids have been accumulated the pageset will be handed -** to the server object. -** -** apUse[]: -** These two pagesets are guaranteed to contain page ids that can be -** reused immediately. For the client to use as it requires. -*/ -struct HctPManClient { - HctConfig *pConfig; - HctPManServer *pServer; - HctFile *pFile; - - HctPManFreePgSet aPgSet[2]; /* Free physical and logical pages */ - - HctPManStats stats; -}; - -static void hctPManMutexEnter(HctPManClient *pClient){ - sqlite3_mutex *pMutex = pClient->pServer->pMutex; - pClient->stats.nMutex++; - if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ - pClient->stats.nMutexBlock++; - sqlite3_mutex_enter(pMutex); - } -} - - -#define ENTER_PMAN_MUTEX(pClient) hctPManMutexEnter(pClient) -#define LEAVE_PMAN_MUTEX(pClient) sqlite3_mutex_leave(pClient->pServer->pMutex) - -/* -** Utility malloc function for hct. Allocate nByte bytes of zeroed memory. -*/ -SQLITE_PRIVATE void *sqlite3HctMalloc(int *pRc, i64 nByte){ - void *pRet = 0; - assert( nByte!=0 ); - if( *pRc==SQLITE_OK ){ - pRet = sqlite3MallocZero(nByte); - if( pRet==0 ){ - *pRc = SQLITE_NOMEM_BKPT; - } - } - return pRet; -} - - -/* -** Allocate and return a new HctPManServer object. -*/ -SQLITE_PRIVATE HctPManServer *sqlite3HctPManServerNew( - int *pRc, - HctFileServer *pFileServer -){ - int rc = *pRc; - HctPManServer *pRet = 0; - pRet = sqlite3HctMalloc(&rc, sizeof(*pRet)); - if( pRet ){ - pRet->pFileServer = pFileServer; - pRet->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); - if( pRet->pMutex==0 ){ - rc = SQLITE_NOMEM_BKPT; - } - } - - if( rc!=SQLITE_OK ){ - sqlite3HctPManServerFree(pRet); - pRet = 0; - } - *pRc = rc; - return pRet; -} - - -SQLITE_PRIVATE void sqlite3HctPManServerReset(HctPManServer *pServer){ - int ii = 0; - for(ii=0; ii<2; ii++){ - HctPManPageset *pNext = pServer->aList[ii].pHead; - while( pNext ){ - HctPManPageset *pDel = pNext; - pNext = pNext->pNext; - sqlite3_free(pDel); - } - memset(&pServer->aList[ii], 0, sizeof(struct HctPManServerList)); - } -} - -/* -** Free an HctPManServer object allocated by an earlier call to -** sqlite3HctPManServerNew(). -*/ -SQLITE_PRIVATE void sqlite3HctPManServerFree(HctPManServer *pServer){ - if( pServer ){ - sqlite3HctPManServerReset(pServer); - sqlite3_mutex_free(pServer->pMutex); - sqlite3_free(pServer->aTree); - sqlite3_free(pServer); - } -} - -/* -** Allocate and return a pointer to a new pageset object with enough -** space for up to nAlloc page ids. -*/ -static HctPManPageset *hctPManPagesetNew(int *pRc, int nAlloc){ - const int nByte = sizeof(HctPManPageset) + nAlloc*sizeof(u32); - HctPManPageset *pRet = 0; - - pRet = (HctPManPageset*)sqlite3HctMalloc(pRc, nByte); - if( pRet ){ - pRet->aPg = (u32*)&pRet[1]; - pRet->nAlloc = nAlloc; - } - - return pRet; -} - -/* -** Add page iPg directly to the list of free pages managed by server pServer. -** iPg may be either a logical (if bLogical==1) or a physical (if bLogical==0) -** page id. It is available for reuse immediately. -** -** This function is not threadsafe. It is only called during initialization, -** when there is only one thread that may be accessing object pServer. -*/ -SQLITE_PRIVATE void sqlite3HctPManServerInit( - int *pRc, - HctPManServer *pServer, - u64 iTid, - u32 iPg, - int bLogical -){ - struct HctPManServerList *p = &pServer->aList[bLogical]; - assert( bLogical==0 || bLogical==1 ); - - if( p->pHead==0 || p->pHead->nPg==p->pHead->nAlloc ){ - HctPManPageset *pNew = hctPManPagesetNew(pRc, PAGESET_INIT_SIZE); - if( pNew==0 ) return; - pNew->pNext = p->pHead; - pNew->iMaxTid = iTid; - p->pHead = pNew; - if( p->pTail==0 ) p->pTail = pNew; - } - p->pHead->aPg[p->pHead->nPg++] = iPg; -} - -/* -** Allocate a new page-manager client. -*/ -SQLITE_PRIVATE HctPManClient *sqlite3HctPManClientNew( - int *pRc, /* IN/OUT: Error code */ - HctConfig *pConfig, /* Connection configuration object */ - HctPManServer *pServer, /* Page-manager server to connect to */ - HctFile *pFile /* File object */ -){ - HctPManClient *pClient = 0; - pClient = (HctPManClient*)sqlite3HctMalloc(pRc, sizeof(HctPManClient)); - if( pClient ){ - pClient->pConfig = pConfig; - pClient->pServer = pServer; - pClient->pFile = pFile; - } - return pClient; -} - -/* -** Hand off a page-set object to the server passed as the first argument. -*/ -static void hctPManServerHandoff( - HctPManServer *p, /* Server object */ - HctPManPageset *pPageSet, /* Pageset to pass to the server */ - int bLogical, /* True for logical, false for physical ids */ - int bUsable /* Page ids are immediately usable */ -){ - if( pPageSet ){ - struct HctPManServerList *pList = &p->aList[bLogical]; - if( bUsable ){ - pPageSet->pNext = pList->pHead; - pList->pHead = pPageSet; - if( pList->pTail==0 ) pList->pTail = pPageSet; - }else{ - pPageSet->pNext = 0; - if( pList->pTail==0 ){ - pList->pTail = pList->pHead = pPageSet; - }else{ - pList->pTail->pNext = pPageSet; - pList->pTail = pPageSet; - } - } - } -} - -/* -** -*/ -static int hctPManHandback( - HctPManClient *pClient, /* Client to hand pages back from */ - int bLogical, /* True for logical pages, false for phys. */ - int nPg /* Number of pages to hand back */ -){ - u64 iSafeTid = sqlite3HctFileSafeTID(pClient->pFile); - const int nPageSet = pClient->pConfig->nPageSet; - HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; - int nRem = nPg; - int rc = SQLITE_OK; - - HctPManPageset *pList = 0; - - assert( bLogical==0 || bLogical==1 ); - assert( nPg<=pSet->nPg ); - - while( nRem>0 ){ - int ii = 0; - HctPManPageset *pNew = 0; - int nCopy = MIN(nRem, nPageSet); - - nRem -= nCopy; - pNew = hctPManPagesetNew(&rc, nCopy); - if( !pNew ) break; - for(ii=0; iiiFirst + ii) % pSet->nAlloc; - pNew->aPg[pNew->nPg++] = (u32)(pSet->aPg[iPg].pgno); - pNew->iMaxTid = pSet->aPg[iPg].iTid; - } - pSet->iFirst = (pSet->iFirst+nCopy) % pSet->nAlloc; - pSet->nPg -= nCopy; - - pNew->pNext = pList; - pList = pNew; - } - assert( pList || nPg==0 || rc!=SQLITE_OK ); - - ENTER_PMAN_MUTEX(pClient); - while( pList ){ - int bSafe = (pList->iMaxTid<=iSafeTid); - HctPManPageset *pNext = pList->pNext; - pList->pNext = 0; - hctPManServerHandoff(pClient->pServer, pList, bLogical, bSafe); - pList = pNext; - } - LEAVE_PMAN_MUTEX(pClient); - - return rc; -} - -/* -** Free a page-manager client. -*/ -SQLITE_PRIVATE void sqlite3HctPManClientFree(HctPManClient *pClient){ - if( pClient ){ - /* Return all pages to the server object */ - hctPManHandback(pClient, 0, pClient->aPgSet[0].nPg); - hctPManHandback(pClient, 1, pClient->aPgSet[1].nPg); - - /* Free allocations */ - sqlite3_free(pClient->aPgSet[0].aPg); - sqlite3_free(pClient->aPgSet[1].aPg); - sqlite3_free(pClient); - } -} - - -typedef struct FreeTreeCtx FreeTreeCtx; -struct FreeTreeCtx { - HctFile *pFile; - HctPManClient *pPManClient; -}; - -static int pmanFreeTreeCb(void *pCtx, u32 iLogic, u32 iPhys){ - FreeTreeCtx *p = (FreeTreeCtx*)pCtx; - int rc = SQLITE_OK; - - if( iLogic && !sqlite3HctFilePageIsFree(p->pFile, iLogic, 1) ){ - rc = sqlite3HctFilePageClearInUse(p->pFile, iLogic, 1); - sqlite3HctPManFreePg(&rc, p->pPManClient, 0, iLogic, 1); - } - if( iPhys && !sqlite3HctFilePageIsFree(p->pFile, iPhys, 0) && rc==SQLITE_OK ){ - rc = sqlite3HctFilePageClearInUse(p->pFile, iPhys, 0); - sqlite3HctPManFreePg(&rc, p->pPManClient, 0, iPhys, 0); - } - - return rc; -} - -static int hctPManFreeTreeNow( - HctPManClient *p, - HctFile *pFile, - u32 iRoot -){ - int rc = SQLITE_OK; - FreeTreeCtx ctx; - ctx.pPManClient = p; - ctx.pFile = pFile; - rc = sqlite3HctDbWalkTree(pFile, iRoot, pmanFreeTreeCb, (void*)&ctx); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageClearIsRoot(pFile, iRoot); - } - return rc; -} - -#if 0 -static void pman_debug( - HctPManClient *pClient, - const char *zOp, - int bLogical, - u32 iPg, - i64 iTid -){ - printf("pman: (%p) %s %s page %d - tid=%lld\n", pClient, - zOp, bLogical ? "LOGICAL" : "PHYSICAL", (int)iPg, iTid - ); - fflush(stdout); -} - -static void pman_debug_new_pageset( - HctPManPageset *pPageSet, - int bLogical, - u64 iSafeTid, - u64 iServerTid -){ - printf( - "pman: new %s pageset - safetid=%lld servertid=%lld\n", - bLogical ? "LOGICAL" : "PHYSICAL", iSafeTid, iServerTid - ); - fflush(stdout); -} -#else - -# define pman_debug(a,b,c,d,e) -# define pman_debug_new_pageset(a,b,c,d) - -#endif - -/* -** Ensure that the circular buffer identified by bLogical has at least -** nPg free slots in it. -*/ -static int hctPManMakeSpace( - HctPManClient *pClient, - int bLogical, - int nPg -){ - int rc = SQLITE_OK; - HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; - - if( (pSet->nAlloc-pSet->nPg)nPg + nPg; - int nByte = nNew * sizeof(HctPManFreePg); - HctPManFreePg *aNew = (HctPManFreePg*)sqlite3_realloc(pSet->aPg, nByte); - - if( aNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pSet->aPg = aNew; - if( (pSet->iFirst + pSet->nPg)>pSet->nAlloc ){ - int nExtra = nNew - pSet->nAlloc; - int nStart = pSet->nPg - (pSet->nAlloc - pSet->iFirst); - - if( nExtra>=nStart ){ - memcpy(&aNew[pSet->nAlloc], aNew, nStart*sizeof(HctPManFreePg)); - }else{ - memcpy(&aNew[pSet->nAlloc], aNew, nExtra*sizeof(HctPManFreePg)); - memmove(aNew, &aNew[nExtra], (nStart-nExtra)*sizeof(HctPManFreePg)); - } - } - pSet->nAlloc = nNew; - } - } - - return rc; -} - -static void hctPManAddFree( - HctPManClient *pClient, - int bLogical, - i64 iPg, - i64 iTid -){ - HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; - int iIdx = 0; - - assert( pSet->nPgnAlloc ); - if( iTid==0 ){ - if( pSet->iFirst==0 ) pSet->iFirst = pSet->nAlloc; - pSet->iFirst--; - iIdx = pSet->iFirst; - }else{ - iIdx = (pSet->iFirst + pSet->nPg) % pSet->nAlloc; - } - - pSet->nPg++; - pSet->aPg[iIdx].pgno = iPg; - pSet->aPg[iIdx].iTid = iTid; -} - - -/* -** Allocate a new logical or physical page. -*/ -SQLITE_PRIVATE u32 sqlite3HctPManAllocPg( - int *pRc, /* IN/OUT: Error code */ - HctPManClient *pClient, /* page-manager client handle */ - HctFile *pFile, - int bLogical -){ - HctPManServer *p = pClient->pServer; - u64 iSafeTid = sqlite3HctFileSafeTID(pFile); - HctPManFreePgSet *pSet = &pClient->aPgSet[bLogical]; - u32 iRoot = 0; - HctPManPageset *pPgset = 0; - int rc = SQLITE_OK; - - /* Check if the client has a usable page already. If so, return early. */ - if( pSet->nPg>0 && pSet->aPg[pSet->iFirst].iTid<=iSafeTid ){ - u32 pgno = pSet->aPg[pSet->iFirst].pgno; - - pman_debug(pClient, "alloc", bLogical, pgno, pSet->aPg[pSet->iFirst].iTid); - - pSet->iFirst = (pSet->iFirst+1) % pSet->nAlloc; - pSet->nPg--; - return pgno; - } - - do{ - iRoot = 0; - - /* Attempt to allocate a page from the page-manager server. */ - ENTER_PMAN_MUTEX(pClient); - if( p->nTree>0 && p->aTree[0].iTid<=iSafeTid ){ - /* A tree structure that can be traversed to find free pages. */ - iRoot = p->aTree[0].iRoot; - p->nTree--; - memmove(&p->aTree[0], &p->aTree[1], (p->nTree)*sizeof(HctPManTree)); - }else{ - struct HctPManServerList *pList = &p->aList[bLogical]; - if( pList->pHead && pList->pHead->iMaxTid<=iSafeTid ){ - /* A page-set object full of usable pages */ - pPgset = pList->pHead; - pList->pHead = pList->pHead->pNext; - if( pList->pHead==0 ) pList->pTail = 0; - } - } - LEAVE_PMAN_MUTEX(pClient); - - /* If a free tree structure was found, iterate through it, returning - ** all physical and logical pages to the server. Then retry the above. - */ - if( iRoot ){ - rc = hctPManFreeTreeNow(pClient, pFile, iRoot); - } - }while( iRoot ); - - if( rc==SQLITE_OK ){ - int ii; - if( pPgset ){ - pman_debug_new_pageset(pPgset, bLogical, iSafeTid, pPgset->iMaxTid); - rc = hctPManMakeSpace(pClient, bLogical, pPgset->nPg); - if( rc==SQLITE_OK ){ - for(ii=pPgset->nPg-1; ii>=0; ii--){ - hctPManAddFree(pClient, bLogical, pPgset->aPg[ii], 0); - } - } - }else{ - const int nPageSet = pClient->pConfig->nPageSet; - rc = hctPManMakeSpace(pClient, bLogical, nPageSet); - if( rc==SQLITE_OK ){ - u32 iPg = sqlite3HctFilePageRangeAlloc(pFile, bLogical, nPageSet); - pman_debug_new_pageset(0, bLogical, iSafeTid, -1); - for(ii=nPageSet-1; ii>=0; ii--){ - hctPManAddFree(pClient, bLogical, iPg+ii, 0); - } - } - } - } - sqlite3_free(pPgset); - - if( rc==SQLITE_OK ){ - assert( pSet->nPg>0 && pSet->aPg[pSet->iFirst].iTid<=iSafeTid ); - return sqlite3HctPManAllocPg(pRc, pClient, pFile, bLogical); - } - - /* An error has occurred. Return 0. */ - *pRc = rc; - return 0; -} - -/* -** Free a physical or logical page. -*/ -SQLITE_PRIVATE void sqlite3HctPManFreePg( - int *pRc, /* IN/OUT: Error code */ - HctPManClient *pClient, /* page-manager client handle */ - i64 iTid, /* Associated TID value */ - u32 iPg, /* Page number */ - int bLogical /* True for logical, false for physical */ -){ - int rc = SQLITE_OK; - pman_debug(pClient, "free", bLogical, iPg, iTid); - assert( iPg>0 ); - rc = hctPManMakeSpace(pClient, bLogical, 1); - if( rc==SQLITE_OK ){ - hctPManAddFree(pClient, bLogical, iPg, iTid); - } -} - -SQLITE_PRIVATE void sqlite3HctPManClientHandoff(HctPManClient *pClient){ - hctPManHandback(pClient, 0, pClient->aPgSet[0].nPg); - hctPManHandback(pClient, 1, pClient->aPgSet[1].nPg); -} - -SQLITE_PRIVATE int sqlite3HctPManFreeTree( - HctPManClient *p, - HctFile *pFile, - u32 iRoot, - u64 iTid -){ - int rc = SQLITE_OK; - if( iTid==0 ){ - rc = hctPManFreeTreeNow(p, pFile, iRoot); - }else{ - HctPManServer *pServer = p->pServer; - int nNew; - HctPManTree *aNew; - - ENTER_PMAN_MUTEX(p); - nNew = pServer->nTree + 1; - aNew = (HctPManTree*)sqlite3_realloc( - pServer->aTree, nNew*sizeof(HctPManTree) - ); - if( aNew==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - aNew[pServer->nTree].iRoot = iRoot; - aNew[pServer->nTree].iTid = iTid; - pServer->nTree++; - pServer->aTree = aNew; - } - LEAVE_PMAN_MUTEX(p); - } - return rc; -} - -typedef struct InitRootCtx InitRootCtx; -struct InitRootCtx { - HctFile *pFile; - HctPManServer *pServer; - u64 iTid; - u64 iRoot; /* Logical root page of this tree */ -}; - -static int pmanInitRootCb(void *pCtx, u32 iLogic, u32 iPhys){ - InitRootCtx *p = (InitRootCtx*)pCtx; - int rc = SQLITE_OK; - - if( iLogic && !sqlite3HctFilePageIsFree(p->pFile, iLogic, 1) ){ - rc = sqlite3HctFilePageClearInUse(p->pFile, iLogic, 1); - if( iLogiciRoot ){ - sqlite3HctPManServerInit(&rc, p->pServer, p->iTid, iLogic, 1); - } - } - if( iPhys && !sqlite3HctFilePageIsFree(p->pFile, iPhys, 0) && rc==SQLITE_OK ){ - rc = sqlite3HctFilePageClearInUse(p->pFile, iPhys, 0); - if( iPhysiRoot ){ - sqlite3HctPManServerInit(&rc, p->pServer, p->iTid, iPhys, 0); - } - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctPManServerInitRoot( - int *pRc, - HctPManServer *pServer, - u64 iTid, - HctFile *pFile, - u32 iRoot -){ - int rc = SQLITE_OK; - InitRootCtx ctx; - ctx.pServer = pServer; - ctx.pFile = pFile; - ctx.iTid = iTid; - ctx.iRoot = iRoot; - rc = sqlite3HctDbWalkTree(pFile, iRoot, pmanInitRootCb, (void*)&ctx); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageClearIsRoot(pFile, iRoot); - } - return rc; -} - -/************************************************************************* -** Beginning of vtab implemetation. -*************************************************************************/ - -#define HCT_PMAN_SCHEMA \ -" CREATE TABLE hctpman(" \ -" type TEXT," \ -" location TEXT," \ -" pgno INTEGER," \ -" tid INTEGER" \ -" );" - -typedef struct pman_vtab pman_vtab; -typedef struct pman_cursor pman_cursor; -typedef struct HctPmanRow HctPmanRow; - -/* -** Virtual table type for "hctpman". -*/ -struct pman_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; - -/* -** Virtual cursor type for "hctpman". -*/ -struct pman_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - int nRow; - int iRow; - HctPmanRow *aRow; -}; - -/* -** Values to return for a single row of the hctpman table. -*/ -struct HctPmanRow { - u8 eType; /* HCT_PMAN_TYPE_* value */ - u8 eLoc; /* HCT_PMAN_LOC_* value */ - u32 pgno; /* Page number */ - i64 iTid; /* Associated TID */ -}; - -#define HCT_PMAN_TYPE_PHYSICAL 0 -#define HCT_PMAN_TYPE_LOGICAL 1 - -#define HCT_PMAN_LOC_USE 0 -#define HCT_PMAN_LOC_ACC 1 -#define HCT_PMAN_LOC_SERVER 2 - -/* -** This xConnect() method is invoked to create a new hctpman virtual table. -*/ -static int pmanConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - pman_vtab *pNew; - int rc; - - rc = sqlite3_declare_vtab(db, HCT_PMAN_SCHEMA); - pNew = (pman_vtab*)sqlite3HctMalloc(&rc, sizeof(*pNew)); - if( pNew ){ - pNew->db = db; - } - - *ppVtab = (sqlite3_vtab*)pNew; - return rc; -} - -/* -** This method is the destructor for pman_vtab objects. -*/ -static int pmanDisconnect(sqlite3_vtab *pVtab){ - pman_vtab *p = (pman_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Constructor for a new pman_cursor object. -*/ -static int pmanOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - pman_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a pman_cursor. -*/ -static int pmanClose(sqlite3_vtab_cursor *cur){ - pman_cursor *pCur = (pman_cursor*)cur; - sqlite3_free(pCur->aRow); - sqlite3_free(pCur); - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last row of output. -*/ -static int pmanEof(sqlite3_vtab_cursor *cur){ - pman_cursor *pCur = (pman_cursor*)cur; - return pCur->iRow>=pCur->nRow; -} - -/* -** Advance a pman_cursor to its next row of output. -*/ -static int pmanNext(sqlite3_vtab_cursor *cur){ - pman_cursor *pCur = (pman_cursor*)cur; - pCur->iRow++; - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the pgmap_cursor -** is currently pointing. -*/ -static int pmanColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - const char *aType[] = {"physical", "logical"}; - const char *aLoc[] = {"use", "acc", "server"}; - pman_cursor *pCur = (pman_cursor*)cur; - - HctPmanRow *pRow = &pCur->aRow[pCur->iRow]; - switch( i ){ - case 0: { /* type */ - sqlite3_result_text(ctx, aType[pRow->eType], -1, SQLITE_STATIC); - break; - } - case 1: { /* location */ - sqlite3_result_text(ctx, aLoc[pRow->eLoc], -1, SQLITE_STATIC); - break; - } - case 2: { /* pgno */ - sqlite3_result_int64(ctx, pRow->pgno); - break; - } - case 3: { /* tid */ - sqlite3_result_int64(ctx, pRow->iTid); - break; - } - } - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the slotno value. -*/ -static int pmanRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - pman_cursor *pCur = (pman_cursor*)cur; - *pRowid = pCur->iRow+1; - return SQLITE_OK; -} - -static int hctPagesetSize(HctPManPageset *pPageset){ - return pPageset ? pPageset->nPg : 0; -} - -static void hctPagesetRows( - pman_cursor *pCur, - HctPManPageset *pPageset, - u8 eType, - u8 eLoc -){ - if( pPageset ){ - int ii; - for(ii=0; iinPg; ii++){ - HctPmanRow *pRow = &pCur->aRow[pCur->nRow++]; - pRow->eType = eType; - pRow->eLoc = eLoc; - pRow->pgno = pPageset->aPg[ii]; - pRow->iTid = pPageset->iMaxTid; - } - } -} - -/* -** This method is called to "rewind" the pman_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to pmanColumn() or pmanRowid() or -** pmanEof(). -*/ -static int pmanFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - pman_cursor *pCur = (pman_cursor*)pVtabCursor; - pman_vtab *pTab = (pman_vtab*)(pCur->base.pVtab); - HctPManClient *pClient = 0; - int nRow = 0; - int ii = 0; - HctPManPageset *pSet = 0; - int rc = SQLITE_OK; - - pCur->iRow = 0; - pCur->nRow = 0; - sqlite3_free(pCur->aRow); - pCur->aRow = 0; - - pClient = sqlite3HctFilePManClient( - sqlite3HctDbFile(sqlite3HctDbFind(pTab->db, 0)) - ); - - ENTER_PMAN_MUTEX(pClient); - for(ii=0; ii<2; ii++){ - nRow += pClient->aPgSet[ii].nPg; - for(pSet=pClient->pServer->aList[ii].pHead; pSet; pSet=pSet->pNext){ - nRow += hctPagesetSize(pSet); - } - } - pCur->aRow = sqlite3HctMalloc(&rc, sizeof(HctPmanRow) * nRow); - if( pCur->aRow ){ - for(ii=0; ii<2; ii++){ - int i2; - HctPManFreePgSet *pPgSet = &pClient->aPgSet[ii]; - for(i2=0; i2nPg; i2++){ - HctPmanRow *pRow = &pCur->aRow[pCur->nRow++]; - int idx = (pPgSet->iFirst + i2) % pPgSet->nAlloc; - pRow->eType = ii; - pRow->eLoc = HCT_PMAN_LOC_USE; - pRow->pgno = pPgSet->aPg[idx].pgno; - pRow->iTid = pPgSet->aPg[idx].iTid; - } - for(pSet=pClient->pServer->aList[ii].pHead; pSet; pSet=pSet->pNext){ - hctPagesetRows(pCur, pSet, ii, HCT_PMAN_LOC_SERVER); - } - } - } - LEAVE_PMAN_MUTEX(pClient); - - return rc; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -*/ -static int pmanBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - pIdxInfo->estimatedCost = (double)10; - pIdxInfo->estimatedRows = 10; - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctPManVtabInit(sqlite3 *db){ - static sqlite3_module pmanModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ pmanConnect, - /* xBestIndex */ pmanBestIndex, - /* xDisconnect */ pmanDisconnect, - /* xDestroy */ 0, - /* xOpen */ pmanOpen, - /* xClose */ pmanClose, - /* xFilter */ pmanFilter, - /* xNext */ pmanNext, - /* xEof */ pmanEof, - /* xColumn */ pmanColumn, - /* xRowid */ pmanRowid, - /* xUpdate */ 0, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - return sqlite3_create_module(db, "hctpman", &pmanModule, 0); -} - - -SQLITE_PRIVATE i64 sqlite3HctPManStats(sqlite3 *db, int iStat, const char **pzStat){ - HctPManClient *pClient = 0; - i64 iVal = -1; - - pClient = sqlite3HctFilePManClient(sqlite3HctDbFile(sqlite3HctDbFind(db, 0))); - switch( iStat ){ - case 0: - *pzStat = "mutex_attempt"; - iVal = pClient->stats.nMutex; - break; - case 1: - *pzStat = "mutex_block"; - iVal = pClient->stats.nMutexBlock; - break; - default: - break; - } - - return iVal; -} - - - -/************** End of hct_pman.c ********************************************/ -/************** Begin file hctree.c ******************************************/ -/* -** 2004 April 6 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ - -/* #include "sqliteInt.h" */ -/* #include "hctInt.h" */ - -/* #include */ -/* #include */ -/* #include */ -/* #include */ -#include - -#ifdef SQLITE_ENABLE_HCT - -typedef struct BtSchemaOp BtSchemaOp; - -typedef struct HBtree HBtree; -typedef struct HBtCursor HBtCursor; -typedef struct HctLogFile HctLogFile; -typedef struct HctMainStats HctMainStats; - - -/* -** An object to help with writing a log file. -*/ -struct HctLogFile { - int fd; /* File descriptor open on log file */ - char *zLogFile; /* Full path to log file */ - u8 *aBuf; /* malloc'd buffer for writing log file */ - int nBuf; /* Size of aBuf[] in bytes */ - i64 iFileOff; /* Current write offset in file */ - int iBufferOff; /* Current write offset in buffer */ -}; - -struct HctMainStats { - i64 nRetry; - i64 nRetryKey; - i64 nKeyOp; -}; - -/* -** aSchemaOp[]: -** Array of nSchemaOp BtSchemaOp structures. Each such structure represents -** a new table or index created by the current transaction. -** aSchemaOp[x].iSavepoint contains the open savepoint count when the table -** with root page aSchemaOp[x].pgnoRoot was created. The value -** HBtree.db->nSavepoint. -** -** eTrans: -** Set to SQLITE_TXN_NONE, READ or WRITE to indicate the type of -** transaction that is open. This is set by the following functions: -** -** sqlite3HctBtreeBeginTrans() -** sqlite3HctBtreeCommitPhaseTwo() -** sqlite3HctBtreeRollback() -*/ -struct HBtree { - BtreeMethods *pMethods; - - HctConfig config; /* Configuration for this connection */ - HctTree *pHctTree; /* In-memory part of database */ - HctDatabase *pHctDb; /* On-disk part of db, if any */ - void *pSchema; /* Memory from sqlite3HctBtreeSchema() */ - void(*xSchemaFree)(void*); /* Function to free pSchema */ - int eTrans; /* SQLITE_TXN_NONE, READ or WRITE */ - HBtCursor *pCsrList; /* List of all open cursors */ - - int nSchemaOp; - BtSchemaOp *aSchemaOp; - int nRollbackOp; - - int openFlags; - HctLogFile *pLog; /* Object for writing to log file */ - u32 iNextRoot; /* Next root page to allocate if pHctDb==0 */ - u32 aMeta[SQLITE_N_BTREE_META]; /* 16 database meta values */ - int eMetaState; - - int bRecoveryDone; -#if 0 - u64 iJrnlRoot; /* Root of sqlite_hct_journal */ - u64 iBaseRoot; /* Root of sqlite_hct_baseline */ -#endif - HctJournal *pHctJrnl; - - Pager *pFakePager; - HctMainStats stats; -}; - -/* -** Another candidate value for HBtree.eTrans. Must be different from -** SQLITE_TXN_NONE, SQLITE_TXN_READ and SQLITE_TXN_WRITE. -*/ -#define SQLITE_TXN_ERROR 4 - -/* -** Candidate values for HBtree.eMetaState. -*/ -#define HCT_METASTATE_NONE 0 -#define HCT_METASTATE_READ 1 - -/* -** A schema op. -*/ -struct BtSchemaOp { - int iSavepoint; - int eSchemaOp; - u32 pgnoRoot; -}; - -/* -** Candidate values for BtSchemaOp.eSchemaOp -*/ -#define HCT_SCHEMAOP_DROP 1 -#define HCT_SCHEMAOP_CREATE_INTKEY 2 -#define HCT_SCHEMAOP_CREATE_INDEX 3 - - -struct HBtCursor { - BtCursorMethods *pMethods; - - HBtree *pBtree; - HctTreeCsr *pHctTreeCsr; - HctDbCsr *pHctDbCsr; - int bUseTree; /* 1 if tree-csr is current entry, else 0 */ - int eDir; /* One of BTREE_DIR_NONE, FORWARD, REVERSE */ - - int isLast; /* Csr has not moved since BtreeLast() */ - - KeyInfo *pKeyInfo; /* For non-intkey tables */ - int errCode; - int wrFlag; /* Value of wrFlag when cursor opened */ - HBtCursor *pCsrNext; /* Next element in Btree.pCsrList list */ -}; - - -#ifdef SQLITE_TEST -SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; -#endif - -#ifndef SQLITE_OMIT_SHARED_CACHE -/* -** Enable or disable the shared pager and schema features. -** -** This routine has no effect on existing database connections. -** The shared cache setting effects only future calls to -** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). -*/ -SQLITE_API int sqlite3_enable_shared_cache(int enable){ - sqlite3GlobalConfig.sharedCacheEnabled = enable; - return SQLITE_OK; -} -#endif - - -/* -** Return an reset the seek counter for a Btree object. -*/ -SQLITE_PRIVATE sqlite3_uint64 sqlite3HctBtreeSeekCount(Btree *pBt){ - assert( 0 ); - return 0; -} - -/* -** Clear the current cursor position. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeClearCursor(BtCursor *pCur){ - HBtCursor *pCsr = (HBtCursor*)pCur; - sqlite3HctDbCsrClear(pCsr->pHctDbCsr); - sqlite3HctTreeCsrClear(pCsr->pHctTreeCsr); -} - -/* -** Determine whether or not a cursor has moved from the position where -** it was last placed, or has been invalidated for any other reason. -** Cursors can move when the row they are pointing at is deleted out -** from under them, for example. Cursor might also move if a btree -** is rebalanced. -** -** Calling this routine with a NULL cursor pointer returns false. -** -** Use the separate sqlite3HctBtreeCursorRestore() routine to restore a cursor -** back to where it ought to be if this routine returns true. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursorHasMoved(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - return sqlite3HctTreeCsrHasMoved(pCur->pHctTreeCsr); -} - -/* -** Return a pointer to a fake BtCursor object that will always answer -** false to the sqlite3HctBtreeCursorHasMoved() routine above. The fake -** cursor returned must not be used with any other Btree interface. -*/ -#if 0 -SQLITE_PRIVATE BtCursor *sqlite3HctBtreeFakeValidCursor(void){ - static BtCursor csr = {0,0,0}; - return &csr; -} -#endif - -/* -** This routine restores a cursor back to its original position after it -** has been moved by some outside activity (such as a btree rebalance or -** a row having been deleted out from under the cursor). -** -** On success, the *pDifferentRow parameter is false if the cursor is left -** pointing at exactly the same row. *pDifferntRow is the row the cursor -** was pointing to has been deleted, forcing the cursor to point to some -** nearby row. -** -** This routine should only be called for a cursor that just returned -** TRUE from sqlite3HctBtreeCursorHasMoved(). -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursorRestore(BtCursor *pCursor, int *pDifferentRow){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - return sqlite3HctTreeCsrRestore(pCur->pHctTreeCsr, pDifferentRow); -} - -/* -** Return the size of the database file in pages. If there is any kind of -** error, return ((unsigned int)-1). -*/ -SQLITE_PRIVATE Pgno sqlite3HctBtreeLastPage(Btree *p){ - return 0xFFFFFFFF; -} - -/* -** Provide flag hints to the cursor. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeCursorHintFlags(BtCursor *pCur, unsigned x){ - /* no-op */ - assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); -} - -typedef struct RecoverCsr RecoverCsr; -struct RecoverCsr { - HctDbCsr *pCsr; /* Cursor to read from database on disk */ - HctTreeCsr *pTreeCsr; /* Cursor to write to in-memory tree */ - UnpackedRecord *pRec; /* Used to seek both cursors */ - KeyInfo *pKeyInfo; -}; - -static void hctRecoverCursorClose(HBtree *p, RecoverCsr *pCsr){ - sqlite3HctDbCsrClose(pCsr->pCsr); - sqlite3HctTreeCsrClose(pCsr->pTreeCsr); - sqlite3DbFree(p->config.db, pCsr->pRec); - sqlite3KeyInfoUnref(pCsr->pKeyInfo); - memset(pCsr, 0, sizeof(RecoverCsr)); -} - -static int hctFindKeyInfo(HBtree *p, u32 iRoot, KeyInfo **ppKeyInfo){ - Schema *pSchema = (Schema*)p->pSchema; - int rc = SQLITE_OK; - HashElem *pE = 0; - KeyInfo *pKeyInfo = 0; - - /* Search the database schema for an index with root page iRoot. If - ** one is found, extract a KeyInfo reference. */ - for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ - Index *pIdx = 0; - Table *pTab = (Table*)sqliteHashData(pE); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->tnum==iRoot ){ - Parse sParse; - Parse *pSave = 0; - memset(&sParse, 0, sizeof(sParse)); - sParse.db = p->config.db; - pSave = sParse.db->pParse; - sParse.db->pParse = &sParse; - pKeyInfo = sqlite3KeyInfoOfIndex(&sParse, pIdx); - sParse.db->pParse = pSave; - rc = sParse.rc; - sqlite3DbFree(sParse.db, sParse.zErrMsg); - break; - } - } - if( pTab->tnum==iRoot ) break; - } - - *ppKeyInfo = pKeyInfo; - return rc; -} - -/* -** -*/ -static int hctRecoverCursorOpen( - HBtree *p, - u32 iRoot, - RecoverCsr *pCsr -){ - int rc = SQLITE_OK; - memset(pCsr, 0, sizeof(RecoverCsr)); - - rc = hctFindKeyInfo(p, iRoot, &pCsr->pKeyInfo); - assert( rc==SQLITE_OK || pCsr->pKeyInfo==0 ); - if( pCsr->pKeyInfo ){ - pCsr->pRec = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo); - if( pCsr->pRec==0 ) rc = SQLITE_NOMEM_BKPT; - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrOpen(p->pHctDb, pCsr->pKeyInfo, iRoot, &pCsr->pCsr); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr->pTreeCsr); - } - - return rc; -} - -#if 1 -# define hctRecoverDebug(v,w,x,y,z) -#else -static void hctRecoverDebug( - RecoverCsr *p, - const char *zType, - i64 iKey, - const u8 *aKey, - int nKey -){ - if( p->pRec==0 ){ - printf("recover-%s: %lld\n", zType, iKey); - }else{ - char *zText = sqlite3HctDbRecordToText(0, aKey, nKey); - printf("recover-%s: %s\n", zType, zText); - sqlite3_free(zText); - } - fflush(stdout); -} -#endif - -/* -** This object is used to read a log file from disk. It is manipulated using -** the following API: -** -** hctLogReaderOpen() -** hctLogReaderNext() -** hctLogReaderClose() -** -** Log file format consists of an 8-byte TID value followed by one or more -** records. Each record is: -** -** * 32-bit root page number, -** * 32-bit size of key field (nKey), -** * if( nKey==0 ) 64-bit rowid key, -** * if( nKey!=0 ) nKey byte blob key. -*/ -typedef struct HctLogReader HctLogReader; -struct HctLogReader { - u8 *aFile; /* Buffer containing log file contents */ - int nFile; /* Size of aFile[] in bytes */ - int iFile; /* Offset of next record in aFile[] */ - - i64 iTid; /* TID value for log file */ - int bEof; /* True if reader has hit EOF */ - - /* Valid only if bEof==0 */ - i64 iRoot; /* Root page for current entry */ - i64 iKey; /* Integer key for current entry (aKey==0) */ - int nKey; /* Size of aKey[] buffer */ - u8 *aKey; /* Blob key for current entry */ -}; - -static void hctLogReaderNext(HctLogReader *pReader){ - u32 aInt[2]; - - if( (pReader->iFile + sizeof(aInt))>pReader->nFile ){ - pReader->bEof = 1; - }else{ - memcpy(aInt, &pReader->aFile[pReader->iFile], sizeof(aInt)); - pReader->iRoot = (i64)aInt[0]; - if( pReader->iRoot==0 ){ - pReader->bEof = 1; - }else{ - pReader->nKey = (int)aInt[1]; - pReader->iFile += sizeof(aInt); - if( pReader->nKey==0 ){ - pReader->aKey = 0; - if( pReader->iFile+sizeof(i64)>pReader->nFile ){ - pReader->bEof = 1; - }else{ - memcpy(&pReader->iKey, &pReader->aFile[pReader->iFile], sizeof(i64)); - pReader->iFile += sizeof(i64); - } - }else{ - pReader->iKey = 0; - if( pReader->iFile+pReader->nKey>pReader->nFile ){ - pReader->bEof = 1; - }else{ - pReader->aKey = &pReader->aFile[pReader->iFile]; - pReader->iFile += pReader->nKey; - } - } - } - } -} - -static void hctLogReaderClose(HctLogReader *pReader){ - sqlite3_free(pReader->aFile); - memset(pReader, 0, sizeof(*pReader)); -} - -static int hctLogReaderOpen(const char *zFile, HctLogReader *pReader){ - int rc = SQLITE_OK; - int fd = -1; - - memset(pReader, 0, sizeof(*pReader)); - fd = open(zFile, O_RDONLY); - if( fd<0 ){ - rc = sqlite3HctIoerr(SQLITE_IOERR); - }else{ - struct stat sStat; - - memset(&sStat, 0, sizeof(sStat)); - fstat(fd, &sStat); - pReader->nFile = (int)sStat.st_size; - pReader->aFile = (u8*)sqlite3HctMalloc(&rc, pReader->nFile + 8); - if( pReader->aFile ){ - int nRead = read(fd, pReader->aFile, pReader->nFile); - if( nRead!=pReader->nFile ){ - rc = sqlite3HctIoerr(SQLITE_IOERR); - }else{ - memcpy(&pReader->iTid, pReader->aFile, sizeof(i64)); - pReader->iFile = sizeof(i64); - if( pReader->iTid==0 ){ - pReader->bEof = 1; - }else{ - hctLogReaderNext(pReader); - } - } - } - - close(fd); - } - - return rc; -} - - -static int btreeFlushData(HBtree *p, int bRollback); - -static int hctRecoverOne(void *pCtx, const char *zFile){ - HBtree *p = (HBtree*)pCtx; - int rc = SQLITE_OK; - u32 iPrevRoot = 0; - RecoverCsr csr; - HctLogReader rdr; - - memset(&csr, 0, sizeof(csr)); - rc = hctLogReaderOpen(zFile, &rdr); - if( rc==SQLITE_OK && rdr.bEof==0 ){ - - assert( rdr.iTid!=0 ); - sqlite3HctDbRollbackMode(p->pHctDb, 2); - sqlite3HctDbRecoverTid(p->pHctDb, rdr.iTid); - for(/* no-op */; rdr.bEof==0; hctLogReaderNext(&rdr)){ - int op = 0; - - if( rdr.iRoot!=iPrevRoot ){ - iPrevRoot = rdr.iRoot; - hctRecoverCursorClose(p, &csr); - rc = hctRecoverCursorOpen(p, rdr.iRoot, &csr); - } - - if( rdr.nKey ){ - sqlite3VdbeRecordUnpack(csr.pKeyInfo, rdr.nKey, rdr.aKey, csr.pRec); - } - rc = sqlite3HctDbCsrRollbackSeek(csr.pCsr, csr.pRec, rdr.iKey, &op); - - if( rc==SQLITE_OK && op!=0 ){ - HctTreeCsr *pTCsr = csr.pTreeCsr; - if( op<0 ){ - /* rollback requires deleting the key */ - hctRecoverDebug(&csr, "delete", rdr.iKey, rdr.aKey, rdr.nKey); - rc = sqlite3HctTreeDeleteKey( - pTCsr, csr.pRec, rdr.iKey, rdr.nKey, rdr.aKey - ); - }else if( op>0 ){ - const u8 *aOld = 0; - int nOld = 0; - rc = sqlite3HctDbCsrData(csr.pCsr, &nOld, &aOld); - if( rc==SQLITE_OK ){ - hctRecoverDebug(&csr, "insert", rdr.iKey, aOld, nOld); - rc = sqlite3HctTreeInsert(pTCsr, csr.pRec, rdr.iKey, nOld, aOld, 0); - } - } - } - } - hctRecoverCursorClose(p, &csr); - - if( rc==SQLITE_OK ){ - rc = btreeFlushData(p, 0); - } - sqlite3HctDbRollbackMode(p->pHctDb, 0); - if( rc==SQLITE_OK && p->pHctJrnl ){ - rc = sqlite3HctJrnlRollbackEntry(p->pHctJrnl, rdr.iTid); - } - sqlite3HctDbRecoverTid(p->pHctDb, 0); - } - - if( rc==SQLITE_OK ){ - /* TODO!!! */ - unlink(zFile); - } - hctLogReaderClose(&rdr); - return rc; -} - -static int hctRecoverLogs(HBtree *p){ - HctFile *pFile = sqlite3HctDbFile(p->pHctDb); - return sqlite3HctFileFindLogs(pFile, (void*)p, hctRecoverOne); -} - - -/* -** Free a pLog object and close the associated log file handle. If parameter -** bUnlink is true, also unlink() the log file. -*/ -static void hctLogFileClose(HctLogFile *pLog, int bUnlink){ - if( pLog ){ - close(pLog->fd); - if( bUnlink ) unlink(pLog->zLogFile); - sqlite3_free(pLog->zLogFile); - sqlite3_free(pLog->aBuf); - sqlite3_free(pLog); - } -} - -/* -** Open a log file object. -*/ -static int hctLogFileOpen(char *zLogFile, int nBuf, HctLogFile **ppLog){ - int rc = SQLITE_OK; - HctLogFile *pLog; - - pLog = (HctLogFile*)sqlite3HctMalloc(&rc, sizeof(HctLogFile)); - if( pLog ){ - pLog->zLogFile = zLogFile; - pLog->fd = open(zLogFile, O_CREAT|O_RDWR, 0644); - if( pLog->fd<0 ){ - rc = SQLITE_CANTOPEN_BKPT; - }else{ - pLog->nBuf = nBuf; - pLog->aBuf = sqlite3HctMalloc(&rc, nBuf); - } - } - - if( rc!=SQLITE_OK ){ - hctLogFileClose(pLog, 0); - pLog = 0; - } - - *ppLog = pLog; - return rc; -} - -static int hctLogFileWrite(HctLogFile *pLog, const void *aData, int nData){ - int nRem = nData; - const u8 *aRem = (u8*)aData; - - assert( pLog->iBufferOff<=pLog->nBuf ); - while( 1 ){ - - int nCopy = MIN(pLog->nBuf - pLog->iBufferOff, nRem); - if( nCopy>0 ){ - memcpy(&pLog->aBuf[pLog->iBufferOff], aRem, nCopy); - pLog->iBufferOff += nCopy; - nRem -= nCopy; - if( nRem==0 ) break; - aRem += nCopy; - } - - if( write(pLog->fd, pLog->aBuf, pLog->nBuf)!=pLog->nBuf ){ - return sqlite3HctIoerr(SQLITE_IOERR_WRITE); - } - pLog->iFileOff += pLog->nBuf; - pLog->iBufferOff = 0; - } - - return SQLITE_OK; -} - - -static void hctLogFileRestart(HctLogFile *pLog){ - memset(pLog->aBuf, 0, 8); - lseek(pLog->fd, 0, SEEK_SET); - pLog->iFileOff = 0; - pLog->iBufferOff = 8; -} - - -static int hctLogFileWriteTid(HctLogFile *pLog, u64 iTid){ - lseek(pLog->fd, 0, SEEK_SET); - if( write(pLog->fd, &iTid, sizeof(iTid))!=sizeof(iTid) ){ - return sqlite3HctIoerr(SQLITE_IOERR_WRITE); - } - return SQLITE_OK; -} - -static int hctLogFileFinish(HctLogFile *pLog, u64 iTid){ - int rc = SQLITE_OK; - int bDone = 0; - if( pLog->iFileOff==0 ){ - bDone = 1; - memcpy(pLog->aBuf, &iTid, sizeof(iTid)); - } - if( rc==SQLITE_OK ){ - static const u8 aZero[8] = {0,0,0,0, 0,0,0,0}; - rc = hctLogFileWrite(pLog, aZero, sizeof(aZero)); - if( rc==SQLITE_OK ){ - assert( pLog->iBufferOff>0 ); - if( write(pLog->fd, pLog->aBuf, pLog->iBufferOff)!=pLog->iBufferOff ){ - rc = sqlite3HctIoerr(SQLITE_IOERR_WRITE); - } - } - } - if( bDone==0 && rc==SQLITE_OK ){ - rc = hctLogFileWriteTid(pLog, iTid); - } - return rc; -} - -static int btreeLogFileZero(HctLogFile *pLog){ - return hctLogFileWriteTid(pLog, 0); -} - - -/* -** Open a database file. -** -** zFilename is the name of the database file. If zFilename is NULL -** then an ephemeral database is created. The ephemeral database might -** be exclusively in memory, or it might use a disk-based memory cache. -** Either way, the ephemeral database will be automatically deleted -** when sqlite3HctBtreeClose() is called. -** -** If zFilename is ":memory:" then an in-memory database is created -** that is automatically destroyed when it is closed. -** -** The "flags" parameter is a bitmask that might contain bits like -** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY. -** -** If the database is already opened in the same database connection -** and we are in shared cache mode, then the open will fail with an -** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared -** objects in the same database connection since doing so will lead -** to problems with locking. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeOpen( - sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ - const char *zFilename, /* Name of the file containing the BTree database */ - sqlite3 *db, /* Associated database handle */ - Btree **ppBtree, /* Pointer to new Btree object written here */ - int flags, /* Options */ - int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ -){ - int rc = SQLITE_OK; - HBtree *pNew; - - assert( (flags & BTREE_SINGLE)==0 && zFilename && zFilename[0] ); - - pNew = (HBtree*)sqlite3_malloc(sizeof(HBtree)); - if( pNew ){ - memset(pNew, 0, sizeof(HBtree)); - pNew->iNextRoot = 2; - pNew->config.db = db; - pNew->openFlags = flags; - pNew->config.nDbFile = HCT_DEFAULT_NDBFILE; - pNew->config.nPageSet = HCT_DEFAULT_NPAGESET; - pNew->config.nTryBeforeUnevict = HCT_DEFAULT_NTRYBEFOREUNEVICT; - pNew->config.nPageScan = HCT_DEFAULT_NPAGESCAN; - pNew->config.szLogChunk = HCT_DEFAULT_SZLOGCHUNK; - pNew->config.pgsz = HCT_DEFAULT_PAGESIZE; - rc = sqlite3HctTreeNew(&pNew->pHctTree); - pNew->pFakePager = (Pager*)sqlite3HctMalloc(&rc, 4096); - }else{ - rc = SQLITE_NOMEM; - } - - if( rc==SQLITE_OK && zFilename && zFilename[0] ){ - pNew->pHctDb = sqlite3HctDbOpen(&rc, zFilename, &pNew->config); - } - - if( rc!=SQLITE_OK ){ - sqlite3HctBtreeClose((Btree*)pNew); - pNew = 0; - } - *ppBtree = (Btree*)pNew; - return rc; -} - -/* -** Close an open database and invalidate all cursors. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeClose(Btree *pBt){ - HBtree *const p = (HBtree*)pBt; - if( p ){ - while(p->pCsrList){ - sqlite3HctBtreeCloseCursor((BtCursor*)p->pCsrList); - } - hctLogFileClose(p->pLog, 1); - sqlite3HctBtreeRollback((Btree*)p, SQLITE_OK, 0); - sqlite3HctBtreeCommit((Btree*)p); - if( p->xSchemaFree ){ - p->xSchemaFree(p->pSchema); - } - sqlite3_free(p->pSchema); - sqlite3HctJournalClose(p->pHctJrnl); - sqlite3HctTreeFree(p->pHctTree); - sqlite3HctDbClose(p->pHctDb); - sqlite3_free(p->aSchemaOp); - sqlite3_free(p->pFakePager); - sqlite3_free(p); - } - return SQLITE_OK; -} - -/* -** Change the "soft" limit on the number of pages in the cache. -** Unused and unmodified pages will be recycled when the number of -** pages in the cache exceeds this soft limit. But the size of the -** cache is allowed to grow larger than this limit if it contains -** dirty pages or pages still in active use. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetCacheSize(Btree *p, int mxPage){ - /* no-op in hct */ - return SQLITE_OK; -} - -/* -** Change the "spill" limit on the number of pages in the cache. -** If the number of pages exceeds this limit during a write transaction, -** the pager might attempt to "spill" pages to the journal early in -** order to free up memory. -** -** The value returned is the current spill size. If zero is passed -** as an argument, no changes are made to the spill size setting, so -** using mxPage of 0 is a way to query the current spill size. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetSpillSize(Btree *p, int mxPage){ - return 1024; -} - -#if SQLITE_MAX_MMAP_SIZE>0 -/* -** Change the limit on the amount of the database file that may be -** memory mapped. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ - /* assert( 0 ); */ - return SQLITE_OK; -} -#endif /* SQLITE_MAX_MMAP_SIZE>0 */ - -/* -** Change the way data is synced to disk in order to increase or decrease -** how well the database resists damage due to OS crashes and power -** failures. Level 1 is the same as asynchronous (no syncs() occur and -** there is a high probability of damage) Level 2 is the default. There -** is a very low but non-zero probability of damage. Level 3 reduces the -** probability of damage to near zero but with a write performance reduction. -*/ -#ifndef SQLITE_OMIT_PAGER_PRAGMAS -SQLITE_PRIVATE int sqlite3HctBtreeSetPagerFlags( - Btree *p, /* The btree to set the safety level on */ - unsigned pgFlags /* Various PAGER_* flags */ -){ - /* HCT - does this need fixing? */ - return SQLITE_OK; -} -#endif - -/* -** Change the default pages size and the number of reserved bytes per page. -** Or, if the page size has already been fixed, return SQLITE_READONLY -** without changing anything. -** -** The page size must be a power of 2 between 512 and 65536. If the page -** size supplied does not meet this constraint then the page size is not -** changed. -** -** Page sizes are constrained to be a power of two so that the region -** of the database file used for locking (beginning at PENDING_BYTE, -** the first byte past the 1GB boundary, 0x40000000) needs to occur -** at the beginning of a page. -** -** If parameter nReserve is less than zero, then the number of reserved -** bytes per page is left unchanged. -** -** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size -** and autovacuum mode can no longer be changed. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetPageSize(Btree *pBt, int pgsz, int nReserve, int iFix){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_READONLY; - if( p->pHctDb && pgsz>=512 && pgsz<=32768 && 0==(pgsz & (pgsz-1)) ){ - int orig = sqlite3HctDbPagesize(p->pHctDb); - if( orig==0 ){ - p->config.pgsz = pgsz; - rc = SQLITE_OK; - } - } - return rc; -} - -/* -** Return the currently defined page size -*/ -SQLITE_PRIVATE int sqlite3HctBtreeGetPageSize(Btree *pBt){ - HBtree *const p = (HBtree*)pBt; - int pgsz = 1024; - if( p->pHctDb ){ - pgsz = sqlite3HctDbPagesize(p->pHctDb); - if( pgsz==0 ){ - pgsz = p->config.pgsz; - } - } - p->config.pgsz = pgsz; - return pgsz; -} - -/* -** This function is similar to sqlite3HctBtreeGetReserve(), except that it -** may only be called if it is guaranteed that the b-tree mutex is already -** held. -** -** This is useful in one special case in the backup API code where it is -** known that the shared b-tree mutex is held, but the mutex on the -** database handle that owns *p is not. In this case if sqlite3HctBtreeEnter() -** were to be called, it might collide with some other operation on the -** database handle that owns *p, causing undefined behavior. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeGetReserveNoMutex(Btree *p){ - assert( 0 ); - return 0; -} - -/* -** Return the number of bytes of space at the end of every page that -** are intentually left unused. This is the "reserved" space that is -** sometimes used by extensions. -** -** The value returned is the larger of the current reserve size and -** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES. -** The amount of reserve can only grow - never shrink. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeGetRequestedReserve(Btree *p){ - return 0; -} - - -/* -** Set the maximum page count for a database if mxPage is positive. -** No changes are made if mxPage is 0 or negative. -** Regardless of the value of mxPage, return the maximum page count. -*/ -SQLITE_PRIVATE Pgno sqlite3HctBtreeMaxPageCount(Btree *p, Pgno mxPage){ - return 0xFFFFFFFF; -} - -/* -** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: -** -** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared -** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared -** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set -** newFlag==(-1) No changes -** -** This routine acts as a query if newFlag is less than zero -** -** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but -** freelist leaf pages are not written back to the database. Thus in-page -** deleted content is cleared, but freelist deleted content is not. -** -** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition -** that freelist leaf pages are written back into the database, increasing -** the amount of disk I/O. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSecureDelete(Btree *p, int newFlag){ - return 0; -} - -/* -** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' -** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it -** is disabled. The default value for the auto-vacuum property is -** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetAutoVacuum(Btree *p, int autoVacuum){ - return SQLITE_OK; -} - -/* -** Return the value of the 'auto-vacuum' property. If auto-vacuum is -** enabled 1 is returned. Otherwise 0. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeGetAutoVacuum(Btree *p){ - /* hct is never in auto-vacuum mode */ - return 0; -} - -/* -** Initialize the first page of the database file (creating a database -** consisting of a single page and no schema objects). Return SQLITE_OK -** if successful, or an SQLite error code otherwise. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeNewDb(Btree *p){ - int rc = SQLITE_OK; - assert( 0 ); - return rc; -} - -static int hctDetectJournals(HBtree *p){ - int rc = SQLITE_OK; - if( p->pHctJrnl==0 ){ - rc = sqlite3HctJournalNewIf( - (Schema*)p->pSchema, p->pHctTree, p->pHctDb, &p->pHctJrnl - ); - } - return rc; -} - -/* -** This is called by sqlite3_hct_journal_init() after the journal and -** baseline tables have been created in the database to initialize the -** journal sub-system. -** -** Return SQLITE_OK if successful, or an SQLite error code if an error -** occurs. -*/ -SQLITE_PRIVATE int sqlite3HctDetectJournals(sqlite3 *db){ - HBtree *p = (HBtree*)db->aDb[0].pBt; - int rc = hctDetectJournals(p); - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbStartRead(p->pHctDb, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctJrnlRecovery(p->pHctJrnl, p->pHctDb); - } - sqlite3HctDbEndRead(p->pHctDb); - return rc; -} - -typedef struct HctFreelistCtx HctFreelistCtx; -struct HctFreelistCtx { - /* Physical pages that need to be preserved for log and journal rollback */ - int nAlloc; - int nPg; - i64 *aPg; - - /* Root pages in the current schema */ - int nRootAlloc; - int nRoot; - i64 *aRoot; - - HBtree *p; -}; - -static int hctTopDownMerge( - i64 *aB, - int iBegin1, int iEnd1, - int iBegin2, int iEnd2, - i64 *aA -){ - int i = iBegin1; - int j = iBegin2; - int k; - for(k=iBegin1; i=iEnd2 || aA[i]<=aA[j]) ){ - if( j1 ){ - int iMid = (iEnd + iBegin) / 2; - int i1 = hctTopDownSplitMerge(aA, iBegin, iMid, aB); - int i2 = hctTopDownSplitMerge(aA, iMid, iEnd, aB); - return hctTopDownMerge(aB, iBegin, i1, iMid, i2, aA); - } - return iEnd; -} - -/* -** Sort the array of aPg[] page numbers in ascending order. Discard -** any duplicates. -*/ -static void hctFreelistSort(int *pRc, HctFreelistCtx *p){ - if( *pRc==SQLITE_OK && p->nPg>1 ){ - i64 *aWork = (i64*)sqlite3HctMalloc(pRc, p->nPg * sizeof(i64)); - if( aWork ){ - memcpy(aWork, p->aPg, p->nPg * sizeof(i64)); - p->nPg = hctTopDownSplitMerge(p->aPg, 0, p->nPg, aWork); - sqlite3_free(aWork); -#ifdef SQLITE_DEBUG - { - int ii; - for(ii=1; iinPg; ii++){ - assert( p->aPg[ii]>p->aPg[ii-1] ); - } - } -#endif - } - } -} - -static int hctSavePhysical(void *pCtx, i64 iPhys){ - HctFreelistCtx *p = (HctFreelistCtx*)pCtx; - if( p->nPg==p->nAlloc ){ - int nNew = (p->nPg>0) ? p->nPg * 4 : 64; - i64 *aNew = (i64*)sqlite3_realloc(p->aPg, nNew*sizeof(i64));; - if( aNew==0 ) return SQLITE_NOMEM; - p->aPg = aNew; - p->nAlloc = nNew; - } - p->aPg[p->nPg++] = iPhys; - return SQLITE_OK; -} - -static int hctScanOne(void *pCtx, const char *zFile){ - HctFreelistCtx *p = (HctFreelistCtx*)pCtx; - int rc = SQLITE_OK; - HctLogReader rdr; - - sqlite3HctDbSetSavePhysical(p->p->pHctDb, hctSavePhysical, pCtx); - - rc = hctLogReaderOpen(zFile, &rdr); - if( rc==SQLITE_OK && rdr.bEof==0 ){ - u32 iPrevRoot =0; - RecoverCsr csr; - memset(&csr, 0, sizeof(csr)); - sqlite3HctDbRecoverTid(p->p->pHctDb, rdr.iTid); - for(/* no-op */; rc==SQLITE_OK && rdr.bEof==0; hctLogReaderNext(&rdr)){ - - if( rdr.iRoot!=iPrevRoot ){ - hctRecoverCursorClose(p->p, &csr); - rc = hctRecoverCursorOpen(p->p, rdr.iRoot, &csr); - } - - if( rc==SQLITE_OK ){ - int dummy = 0; - if( rdr.nKey ){ - sqlite3VdbeRecordUnpack(csr.pKeyInfo, rdr.nKey, rdr.aKey, csr.pRec); - } - rc = sqlite3HctDbCsrRollbackSeek(csr.pCsr, csr.pRec, rdr.iKey, &dummy); - } - } - - hctRecoverCursorClose(p->p, &csr); - } - - sqlite3HctDbSetSavePhysical(p->p->pHctDb, 0, 0); - hctLogReaderClose(&rdr); - return rc; -} - -static void hctRootpageAdd(int *pRc, HctFreelistCtx *pCtx, i64 iRoot){ - if( *pRc==SQLITE_OK ){ - if( pCtx->nRoot==pCtx->nRootAlloc ){ - int nNew = (pCtx->nRoot>0) ? pCtx->nRoot * 4 : 64; - i64 *aNew = (i64*)sqlite3_realloc(pCtx->aRoot, nNew*sizeof(i64));; - if( aNew==0 ){ - *pRc = SQLITE_NOMEM; - return; - } - pCtx->aRoot = aNew; - pCtx->nRootAlloc = nNew; - } - - pCtx->aRoot[pCtx->nRoot++] = iRoot; - } -} - -/* -** Assemble a list of the root pages in the current schema in the -** pCtx->aRoot[] array. -*/ -static void hctRootpageList(int *pRc, HctFreelistCtx *pCtx){ - Schema *pSchema = (Schema*)pCtx->p->pSchema; - HashElem *pE = 0; - for(pE=sqliteHashFirst(&pSchema->tblHash); pE; pE=sqliteHashNext(pE)){ - Table *pTab = (Table*)sqliteHashData(pE); - Index *pIdx = 0; - hctRootpageAdd(pRc, pCtx, pTab->tnum); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - hctRootpageAdd(pRc, pCtx, pIdx->tnum); - } - } -} - -/* -** This is called as part of recovery, before any log files are rolled back, -** to rebuild the free-page list (or, if you like, to initialize the -** page-manager). This involves the following: -** -** 1) Scanning the sqlite_hct_journal table, if any, from the first hole -** to the last entry to determine the list of physical database pages -** that will be required if sqlite3_hct_journal_rollback() is called. -** -** 2) Scanning each log file that will be rolled back, accumulating a -** list of the physical database pages that will be required to find -** the "old" values required to roll them back. -** -** 3) Scanning the page map, checking for pages with the PHYSICAL_IN_USE -** flag clear. Each such page is added to the free-page list. If the -** page was one of those found in the scans in steps (1) or (2), then -** it is not available for reuse until after tid $TID, and all previous -** tids, have been committed. Otherwise, it is available for reuse -** immediately. -** -** $TID is set to the TID of the next transaction that will be written -** to this database (page-map entry TRANSID_EOF+1). -** -** This is a complicated procedure. -*/ -static int hctRecoverFreeList(HBtree *p){ - HctFreelistCtx ctx; - HctFile *pFile = sqlite3HctDbFile(p->pHctDb); - int rc = SQLITE_OK; - - memset(&ctx, 0, sizeof(ctx)); - ctx.p = p; - - /* If this is a replication database, scan all journal entries that may - ** be rolled back using a call to sqlite3_hct_journal_rollback(). Record - ** the set of physical pages that may be required by this call in the - ** ctx.aPg[] array. */ - if( p->pHctJrnl ){ - void *pCtx = (void*)&ctx; - rc = sqlite3HctJrnlSavePhysical( - p->config.db, p->pHctJrnl, hctSavePhysical, pCtx - ); - } - - /* Also scan any log files, adding the list of physical pages that must - ** be preserved to the ctx.aPg[] array. */ - if( rc==SQLITE_OK ){ - sqlite3HctDbRollbackMode(p->pHctDb, 2); - rc = sqlite3HctFileFindLogs(pFile, (void*)&ctx, hctScanOne); - sqlite3HctDbRollbackMode(p->pHctDb, 0); - } - - /* Sort the list of physical page numbers accumulated above. */ - hctFreelistSort(&rc, &ctx); - - /* Assemble a list of root pages. */ - hctRootpageList(&rc, &ctx); - - /* Scan the page-map, taking into account the physical pages that must - ** be preserved, and the set of root pages in the current db schema. */ - if( rc==SQLITE_OK ){ - rc = sqlite3HctFileRecoverFreelists( - pFile, ctx.nRoot, ctx.aRoot, ctx.nPg, ctx.aPg - ); - } - - sqlite3_free(ctx.aPg); - sqlite3_free(ctx.aRoot); - return rc; -} - -static int hctAttemptRecovery(HBtree *p){ - int rc = SQLITE_OK; - if( p->bRecoveryDone==0 ){ - HctFile *pFile = sqlite3HctDbFile(p->pHctDb); - if( p->pHctDb && sqlite3HctFileStartRecovery(pFile, 0) ){ - p->bRecoveryDone = 1; - rc = hctRecoverFreeList(p); - - if( rc==SQLITE_OK ){ - rc = hctRecoverLogs(p); - } - - if( rc==SQLITE_OK && p->pHctJrnl ){ - sqlite3HctDbRollbackMode(p->pHctDb, 0); - rc = sqlite3HctJrnlRecovery(p->pHctJrnl, p->pHctDb); - } - rc = sqlite3HctDbFinishRecovery(p->pHctDb, 0, rc); - } - - p->bRecoveryDone = (rc==SQLITE_OK); - } - - return rc; -} - -/* -** Attempt to start a new transaction. A write-transaction -** is started if the second argument is nonzero, otherwise a read- -** transaction. If the second argument is 2 or more and exclusive -** transaction is started, meaning that no other process is allowed -** to access the database. A preexisting transaction may not be -** upgraded to exclusive by calling this routine a second time - the -** exclusivity flag only works for a new transaction. -** -** A write-transaction must be started before attempting any -** changes to the database. None of the following routines -** will work unless a transaction is started first: -** -** sqlite3HctBtreeCreateTable() -** sqlite3HctBtreeCreateIndex() -** sqlite3HctBtreeClearTable() -** sqlite3HctBtreeDropTable() -** sqlite3HctBtreeInsert() -** sqlite3HctBtreeDelete() -** sqlite3HctBtreeUpdateMeta() -*/ -SQLITE_PRIVATE int sqlite3HctBtreeBeginTrans(Btree *pBt, int wrflag, int *pSchemaVersion){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - int req = wrflag ? SQLITE_TXN_WRITE : SQLITE_TXN_READ; - - assert( wrflag==0 || p->pHctDb==0 || pSchemaVersion ); - - if( p->eTrans==SQLITE_TXN_ERROR ) return SQLITE_BUSY_SNAPSHOT; - - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbStartRead(p->pHctDb, p->pHctJrnl); - } - - if( rc==SQLITE_OK && pSchemaVersion ){ - sqlite3HctBtreeGetMeta((Btree*)p, 1, (u32*)pSchemaVersion); - sqlite3HctDbTransIsConcurrent(p->pHctDb, p->config.db->eConcurrent); - } - - if( rc==SQLITE_OK && wrflag ){ - rc = sqlite3HctTreeBegin(p->pHctTree, 1 + p->config.db->nSavepoint); - } - if( rc==SQLITE_OK && p->eTranseTrans = req; - } - return rc; -} - -/* -** This is called just after the schema is loaded for b-tree pBt. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSchemaLoaded(Btree *pBt){ - int rc = SQLITE_OK; - HBtree *const p = (HBtree*)pBt; - if( p->bRecoveryDone==0 ){ - rc = hctDetectJournals(p); - if( rc==SQLITE_OK ){ - rc = hctAttemptRecovery(p); - } - if( rc==SQLITE_OK ){ - sqlite3HctDbEndRead(p->pHctDb); - } - } - if( rc==SQLITE_OK && p->pHctJrnl ){ - sqlite3HctJournalFixSchema(p->pHctJrnl, p->config.db, p->pSchema); - } - return rc; -} - -/* -** A write-transaction must be opened before calling this function. -** It performs a single unit of work towards an incremental vacuum. -** -** If the incremental vacuum is finished after this function has run, -** SQLITE_DONE is returned. If it is not finished, but no error occurred, -** SQLITE_OK is returned. Otherwise an SQLite error code. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeIncrVacuum(Btree *p){ - return SQLITE_DONE; -} - -/* -** This routine does the first phase of a two-phase commit. This routine -** causes a rollback journal to be created (if it does not already exist) -** and populated with enough information so that if a power loss occurs -** the database can be restored to its original state by playing back -** the journal. Then the contents of the journal are flushed out to -** the disk. After the journal is safely on oxide, the changes to the -** database are written into the database file and flushed to oxide. -** At the end of this call, the rollback journal still exists on the -** disk and we are still holding all locks, so the transaction has not -** committed. See sqlite3HctBtreeCommitPhaseTwo() for the second phase of the -** commit process. -** -** This call is a no-op if no write-transaction is currently active on pBt. -** -** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to -** the name of a super-journal file that should be written into the -** individual journal file, or is NULL, indicating no super-journal file -** (single database transaction). -** -** When this is called, the super-journal should already have been -** created, populated with this journal pointer and synced to disk. -** -** Once this is routine has returned, the only thing required to commit -** the write-transaction for this database file is to delete the journal. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ - /* Everything happens in sqlite3HctBtreeCommitPhaseTwo() */ - return SQLITE_OK; -} - -typedef struct FlushOneCtx FlushOneCtx; -struct FlushOneCtx { - HBtree *p; - int bRollback; -}; - -static int btreeFlushOneToDisk(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ - FlushOneCtx *pFC = (FlushOneCtx*)pCtx; - HBtree *p = pFC->p; - int iRollbackDir = pFC->bRollback ? -1 : 1; - - HctDatabase *pDb = p->pHctDb; - HctTreeCsr *pCsr = 0; - int rc; - UnpackedRecord *pRec = 0; - - if( pKeyInfo ){ - pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); - if( pRec==0 ) return SQLITE_NOMEM_BKPT; - } - - rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr); - if( rc==SQLITE_OK ){ - for(rc=sqlite3HctTreeCsrFirst(pCsr); rc==SQLITE_OK ; /* no-op */){ - int nRetry = 0; - int ii; - i64 iKey = 0; - int nData = 0; - int bDel = 0; - const u8 *aData = 0; - sqlite3HctTreeCsrKey(pCsr, &iKey); - sqlite3HctTreeCsrData(pCsr, &nData, &aData); - bDel = sqlite3HctTreeCsrIsDelete(pCsr); - if( pRec ) sqlite3VdbeRecordUnpack(pKeyInfo, nData, aData, pRec); - rc = sqlite3HctDbInsert(pDb, iRoot, pRec, iKey, bDel,nData,aData,&nRetry); - p->nRollbackOp += (iRollbackDir * (1 - nRetry)); - if( rc ) break; - p->stats.nKeyOp++; - - if( pFC->bRollback && p->nRollbackOp==0 ){ - assert( nRetry==0 ); - rc = sqlite3HctDbInsertFlush(pDb, &nRetry); - if( rc ) break; - if( nRetry==0 ){ - rc = SQLITE_DONE; - break; - } - p->nRollbackOp = nRetry; - if( sqlite3HctTreeCsrEof(pCsr) ){ - sqlite3HctTreeCsrLast(pCsr); - } - } - - if( nRetry==0 ){ - sqlite3HctTreeCsrNext(pCsr); - if( sqlite3HctTreeCsrEof(pCsr) ){ - rc = sqlite3HctDbInsertFlush(pDb, &nRetry); - if( nRetry ){ - sqlite3HctTreeCsrLast(pCsr); - assert( sqlite3HctTreeCsrEof(pCsr)==0 ); - p->nRollbackOp -= (iRollbackDir * nRetry); - }else{ - /* Done - the table has been successfully flushed to disk */ - break; - } - } - }else{ - p->stats.nRetry++; - p->stats.nRetryKey += nRetry; - } - for(ii=1; iidb, pRec); - } - return rc; -} - -static int btreeLogIntkey(HctLogFile *pLog, u32 iRoot, i64 iRowid){ - u8 aBuf[16]; - memcpy(&aBuf[0], &iRoot, sizeof(u32)); - memset(&aBuf[4], 0, sizeof(u32)); - memcpy(&aBuf[8], &iRowid, sizeof(i64)); - return hctLogFileWrite(pLog, aBuf, sizeof(aBuf)); -} - -static int btreeLogIndex( - HctLogFile *pLog, - u32 iRoot, - const u8 *aData, int nData -){ - if( hctLogFileWrite(pLog, &iRoot, sizeof(iRoot)) - || hctLogFileWrite(pLog, &nData, sizeof(nData)) - || hctLogFileWrite(pLog, aData, nData) - ){ - return sqlite3HctIoerr(SQLITE_IOERR_WRITE); - } - return SQLITE_OK; -} - -static int btreeLogOneToDisk(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ - HBtree *p = (HBtree*)pCtx; - HctTreeCsr *pCsr = 0; - int rc; - - rc = sqlite3HctTreeCsrOpen(p->pHctTree, iRoot, &pCsr); - if( rc==SQLITE_OK ){ - for(rc=sqlite3HctTreeCsrFirst(pCsr); - rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; - rc=sqlite3HctTreeCsrNext(pCsr) - ){ - if( pKeyInfo ){ - int nData = 0; - const u8 *aData = 0; - sqlite3HctTreeCsrData(pCsr, &nData, &aData); - rc = btreeLogIndex(p->pLog, iRoot, aData, nData); - }else{ - i64 iRowid = 0; - sqlite3HctTreeCsrKey(pCsr, &iRowid); - rc = btreeLogIntkey(p->pLog, iRoot, iRowid); - } - - if( rc!=SQLITE_OK ) break; - } - sqlite3HctTreeCsrClose(pCsr); - } - - return rc; -} - -static int btreeFlushData(HBtree *p, int bRollback){ - int rc = SQLITE_OK; - - if( bRollback ) sqlite3HctDbRollbackMode(p->pHctDb, 1); - if( bRollback && p->nRollbackOp==0 ){ - rc = SQLITE_DONE; - } - - if( rc==SQLITE_OK ){ - FlushOneCtx ctx; - ctx.p = p; - ctx.bRollback = bRollback; - rc = sqlite3HctTreeForeach(p->pHctTree, 0, (void*)&ctx,btreeFlushOneToDisk); - } - if( bRollback ) sqlite3HctDbRollbackMode(p->pHctDb, 0); - return rc; -} - -static int btreeWriteLog(HBtree *p){ - int rc = SQLITE_OK; - - if( p->pLog==0 ){ - char *zLog = sqlite3HctDbLogFile(p->pHctDb); - if( zLog==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - rc = hctLogFileOpen(zLog, p->config.szLogChunk, &p->pLog); - } - } - - if( rc==SQLITE_OK ){ - hctLogFileRestart(p->pLog); - rc = sqlite3HctTreeForeach(p->pHctTree, 0, (void*)p, btreeLogOneToDisk); - } - - return rc; -} - -/* -** Flush the contents of Btree.pHctTree to Btree.pHctDb. -*/ -static int btreeFlushToDisk(HBtree *p){ - int i; - int rc = SQLITE_OK; - int rcok = SQLITE_OK; - u64 iTid = 0; - u64 iCid = 0; - int bTmapScan = 0; - int bCustomValid = 0; /* True if xValidate() was invoked */ - - /* Write a log file for this transaction. The TID field is still set - ** to zero at this point. */ - if( p->config.db->bHctMigrate==0 ){ - rc = btreeWriteLog(p); - } - - if( rc==SQLITE_OK ){ - /* Obtain the TID for this transaction. */ - iTid = sqlite3HctJrnlWriteTid(p->pHctJrnl, &iCid); - if( iTid==0 ){ - sqlite3HctDbStartWrite(p->pHctDb, &iTid); - } - - /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ - if( p->config.db->xMtCommit ){ - p->config.db->xMtCommit(p->config.db->pMtCommitCtx, 0); - } - - assert( iTid>0 ); - if( p->pLog ) rc = hctLogFileFinish(p->pLog, iTid); - } - - /* Initialize the root pages of any new tables or indexes created by this - ** transaction. At this point the logical root page numbers have been - ** assigned by the page-manager, but there is no mapped physical page, - ** and the LOGICAL_IN_USE and LOGICAL_IS_ROOT flags are not yet set - ** for the page. This allocates and populates the physical root page, - ** and sets the two flags on the logical page slot. - ** - ** If the current transaction does not commit (i.e. failed validiation), - ** then the new tree is returned to the page-manage to be recycled - ** immediately. Or, if a crash occurs, then recovery will see the - ** LOGICAL_IS_ROOT flag on a root page that is not in the sqlite_schema - ** table and free the pages then. */ - for(i=0; rc==SQLITE_OK && inSchemaOp; i++){ - BtSchemaOp *pOp = &p->aSchemaOp[i]; - assert( - pOp->eSchemaOp==HCT_SCHEMAOP_DROP - || pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INTKEY - || pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INDEX - ); - if( pOp->eSchemaOp!=HCT_SCHEMAOP_DROP ){ - int bIndex = (pOp->eSchemaOp==HCT_SCHEMAOP_CREATE_INDEX); - rc = sqlite3HctDbRootInit(p->pHctDb, bIndex, pOp->pgnoRoot); - } - } - - /* Write all the new database entries to the database. Any write/write - ** conflicts are detected here - SQLITE_BUSY is returned in that case. */ - p->nRollbackOp = 0; - if( rc==SQLITE_OK ){ - rc = btreeFlushData(p, 0); - } - - /* Assuming the data has been flushed to disk without error or a - ** write/write conflict, allocate a CID and validate the transaction. */ - if( rc==SQLITE_OK ){ - /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ - if( p->config.db->xMtCommit ){ - p->config.db->xMtCommit(p->config.db->pMtCommitCtx, 1); - } - - /* Validate the transaction */ - rc = sqlite3HctDbValidate(p->config.db, p->pHctDb, &iCid, &bTmapScan); - - /* If validation passed and this database is configured for replication, - ** write the journal entry and invoke the custom validation hook */ - if( rc==SQLITE_OK && p->pHctJrnl ){ - rc = sqlite3HctJrnlLog( - p->pHctJrnl, - p->config.db, - (Schema*)p->pSchema, - iCid, iTid, &bCustomValid - ); - } - } - - /* If conflicts have been detected, roll back the transaction */ - assert( rc!=SQLITE_BUSY ); - if( rc==SQLITE_BUSY_SNAPSHOT ){ - rcok = SQLITE_BUSY_SNAPSHOT; - rc = btreeFlushData(p, 1); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - if( iCid>0 && p->pHctJrnl ){ - rc = sqlite3HctJrnlWriteEmpty(p->pHctJrnl, iCid, iTid, - (bCustomValid ? 0 : p->config.db) - ); - } - } - - for(i=0; rc==SQLITE_OK && inSchemaOp; i++){ - BtSchemaOp *pOp = &p->aSchemaOp[i]; - if( (rcok==SQLITE_OK && pOp->eSchemaOp==HCT_SCHEMAOP_DROP) - || (rcok!=SQLITE_OK && pOp->eSchemaOp!=HCT_SCHEMAOP_DROP) - ){ - HctFile *pFile = sqlite3HctDbFile(p->pHctDb); - rc = sqlite3HctFileTreeFree(pFile, pOp->pgnoRoot, rcok!=SQLITE_OK); - } - } - - /* Zero the log file and set the entry in the transaction-map to - ** finish the transaction. */ - if( rc==SQLITE_OK && p->pLog ){ - rc = btreeLogFileZero(p->pLog); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbEndWrite(p->pHctDb, iCid, rcok!=SQLITE_OK); - } - assert( rc==SQLITE_OK ); - if( bTmapScan ){ - sqlite3HctDbTMapScan(p->pHctDb); - } - - sqlite3HctJrnlInvokeHook(p->pHctJrnl, p->config.db); - return (rc==SQLITE_OK ? rcok : rc); -} - -static void hctEndTransaction(HBtree *p){ - if( p->eTrans>SQLITE_TXN_NONE - && p->pCsrList==0 - && p->config.db->nVdbeRead<=1 - ){ - if( p->pHctDb ){ - sqlite3HctDbEndRead(p->pHctDb); - } - p->eTrans = SQLITE_TXN_NONE; - p->eMetaState = HCT_METASTATE_NONE; - } -} - - -static int hctBtreeMigrateInsert( - HBtCursor *pCur, - UnpackedRecord *pRec, - i64 iKey, - int nData, - const u8 *aData -){ - int rc = SQLITE_OK; - HBtree *p = pCur->pBtree; - int nRetry = 0; - - if( 0==sqlite3HctDbTid(p->pHctDb) ){ - i64 iDummy = 0; - rc = sqlite3HctDbStartWrite(p->pHctDb, &iDummy); - if( rc!=SQLITE_OK ) return rc; - } - - rc = sqlite3HctDbInsert( - p->pHctDb, - sqlite3HctTreeCsrRoot(pCur->pHctTreeCsr), - pRec, iKey, 0, nData, aData, &nRetry - ); - if( nRetry>0 ){ - rc = SQLITE_ABORT; - } - - return rc; -} - -static int hctBtreeMigrateCommit(HBtree *p){ - int rc = SQLITE_OK; - i64 iCid = 0; - int bTmapScan = 0; - int nRetry = 0; - - rc = sqlite3HctDbInsertFlush(p->pHctDb, &nRetry); - if( nRetry>0 ){ - rc = SQLITE_ABORT; - } - - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbValidate(p->config.db, p->pHctDb, &iCid, &bTmapScan); - } - - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbEndWrite(p->pHctDb, iCid, 0); - } - - if( bTmapScan ){ - sqlite3HctDbTMapScan(p->pHctDb); - } - - return rc; -} - -#define BT_IS_MIGRATE(pBt) (pBt->config.db->bHctMigrate) -#define CSR_IS_MIGRATE(pCsr) (pCsr->pBtree->config.db->bHctMigrate) - -/* -** Commit the transaction currently in progress. -** -** This routine implements the second phase of a 2-phase commit. The -** sqlite3HctBtreeCommitPhaseOne() routine does the first phase and should -** be invoked prior to calling this routine. The sqlite3HctBtreeCommitPhaseOne() -** routine did all the work of writing information out to disk and flushing the -** contents so that they are written onto the disk platter. All this -** routine has to do is delete or truncate or zero the header in the -** the rollback journal (which causes the transaction to commit) and -** drop locks. -** -** Normally, if an error occurs while the pager layer is attempting to -** finalize the underlying journal file, this function returns an error and -** the upper layer will attempt a rollback. However, if the second argument -** is non-zero then this b-tree transaction is part of a multi-file -** transaction. In this case, the transaction has already been committed -** (by deleting a super-journal file) and the caller will ignore this -** functions return code. So, even if an error occurs in the pager layer, -** reset the b-tree objects internal state to indicate that the write -** transaction has been closed. This is quite safe, as the pager will have -** transitioned to the error state. -** -** This will release the write lock on the database file. If there -** are no active cursors, it also releases the read lock. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCommitPhaseTwo(Btree *pBt, int bCleanup){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - - if( p->eTrans==SQLITE_TXN_ERROR ) return SQLITE_BUSY_SNAPSHOT; - - if( BT_IS_MIGRATE(p) ){ - rc = hctBtreeMigrateCommit(p); - }else{ - if( p->eTrans==SQLITE_TXN_WRITE ){ - if( p->pCsrList ){ - /* Cannot commit with open cursors in hctree */ - return SQLITE_LOCKED; - } - - sqlite3HctTreeRelease(p->pHctTree, 0); - if( p->pHctDb ){ - rc = btreeFlushToDisk(p); - sqlite3HctTreeClear(p->pHctTree); - p->nSchemaOp = 0; - } - p->eTrans = SQLITE_TXN_READ; - } - } - - if( rc==SQLITE_OK ){ - hctEndTransaction(p); - }else{ - p->eTrans = SQLITE_TXN_ERROR; - } - return rc; -} - -/* -** Do both phases of a commit. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCommit(Btree *pBt){ - int rc; - HBtree *const p = (HBtree*)pBt; - rc = sqlite3HctBtreeCommitPhaseOne((Btree*)p, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3HctBtreeCommitPhaseTwo((Btree*)p, 0); - } - return rc; -} - -/* -** This routine sets the state to CURSOR_FAULT and the error -** code to errCode for every cursor on any BtShared that pBtree -** references. Or if the writeOnly flag is set to 1, then only -** trip write cursors and leave read cursors unchanged. -** -** Every cursor is a candidate to be tripped, including cursors -** that belong to other database connections that happen to be -** sharing the cache with pBtree. -** -** This routine gets called when a rollback occurs. If the writeOnly -** flag is true, then only write-cursors need be tripped - read-only -** cursors save their current positions so that they may continue -** following the rollback. Or, if writeOnly is false, all cursors are -** tripped. In general, writeOnly is false if the transaction being -** rolled back modified the database schema. In this case b-tree root -** pages may be moved or deleted from the database altogether, making -** it unsafe for read cursors to continue. -** -** If the writeOnly flag is true and an error is encountered while -** saving the current position of a read-only cursor, all cursors, -** including all read-cursors are tripped. -** -** SQLITE_OK is returned if successful, or if an error occurs while -** saving a cursor position, an SQLite error code. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeTripAllCursors(Btree *pBt, int errCode, int writeOnly){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - if( p ){ - HBtCursor *pCur; - for(pCur=p->pCsrList; pCur; pCur=pCur->pCsrNext){ - if( writeOnly==0 || pCur->wrFlag ){ - sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); - pCur->pHctTreeCsr = 0; - pCur->errCode = errCode; - } - } - } - return rc; -} - -/* -** Rollback the transaction in progress. -** -** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). -** Only write cursors are tripped if writeOnly is true but all cursors are -** tripped if writeOnly is false. Any attempt to use -** a tripped cursor will result in an error. -** -** This will release the write lock on the database file. If there -** are no active cursors, it also releases the read lock. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeRollback(Btree *pBt, int tripCode, int writeOnly){ - HBtree *const p = (HBtree*)pBt; - - assert( SQLITE_TXN_ERROR==4 && SQLITE_TXN_WRITE==2 ); - assert( SQLITE_TXN_READ==1 && SQLITE_TXN_NONE==0 ); - assert( p->eTrans!=SQLITE_TXN_ERROR || p->pCsrList==0 ); - - if( p->eTrans>=SQLITE_TXN_WRITE ){ - sqlite3HctTreeRollbackTo(p->pHctTree, 0); - if( p->pHctDb ){ - sqlite3HctTreeClear(p->pHctTree); - } - p->eTrans = SQLITE_TXN_READ; - p->nSchemaOp = 0; - } - hctEndTransaction(p); - return SQLITE_OK; -} - -/* -** Start a statement subtransaction. The subtransaction can be rolled -** back independently of the main transaction. You must start a transaction -** before starting a subtransaction. The subtransaction is ended automatically -** if the main transaction commits or rolls back. -** -** Statement subtransactions are used around individual SQL statements -** that are contained within a BEGIN...COMMIT block. If a constraint -** error occurs within the statement, the effect of that one statement -** can be rolled back without having to rollback the entire transaction. -** -** A statement sub-transaction is implemented as an anonymous savepoint. The -** value passed as the second parameter is the total number of savepoints, -** including the new anonymous savepoint, open on the B-Tree. i.e. if there -** are no active savepoints and no other statement-transactions open, -** iStatement is 1. This anonymous savepoint can be released or rolled back -** using the sqlite3HctBtreeSavepoint() function. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeBeginStmt(Btree *pBt, int iStatement){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - assert( p->eTrans!=SQLITE_TXN_ERROR ); - rc = sqlite3HctTreeBegin(p->pHctTree, iStatement+1); - return rc; -} - -static int btreeRollbackRoot(HBtree *p, int iSavepoint){ - int i; - int rc = SQLITE_OK; - for(i=p->nSchemaOp-1; rc==SQLITE_OK && i>=0; i--){ - if( p->aSchemaOp[i].iSavepoint<=iSavepoint ) break; - rc = sqlite3HctDbRootFree(p->pHctDb, p->aSchemaOp[i].pgnoRoot); - } - p->nSchemaOp = i+1; - return rc; -} - -/* -** The second argument to this function, op, is always SAVEPOINT_ROLLBACK -** or SAVEPOINT_RELEASE. This function either releases or rolls back the -** savepoint identified by parameter iSavepoint, depending on the value -** of op. -** -** Normally, iSavepoint is greater than or equal to zero. However, if op is -** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the -** contents of the entire transaction are rolled back. This is different -** from a normal transaction rollback, as no locks are released and the -** transaction remains open. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSavepoint(Btree *pBt, int op, int iSavepoint){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - if( p && p->eTrans==SQLITE_TXN_WRITE ){ - int i; - assert( op==SAVEPOINT_ROLLBACK || op==SAVEPOINT_RELEASE ); - if( op==SAVEPOINT_RELEASE ){ - for(i=0; inSchemaOp; i++){ - if( p->aSchemaOp[i].iSavepoint>iSavepoint ){ - p->aSchemaOp[i].iSavepoint = iSavepoint; - } - } - sqlite3HctTreeRelease(p->pHctTree, iSavepoint+1); - }else{ - sqlite3HctTreeRollbackTo(p->pHctTree, iSavepoint+2); - btreeRollbackRoot(p, iSavepoint); - p->eMetaState = HCT_METASTATE_NONE; - } - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctBtreeIsNewTable(Btree *pBt, u64 iRoot){ - HBtree *const p = (HBtree*)pBt; - int ii; - for(ii=0; iinSchemaOp && p->aSchemaOp[ii].pgnoRoot!=iRoot; ii++); - return iinSchemaOp; -} - -SQLITE_PRIVATE u64 sqlite3HctBtreeSnapshotId(Btree *pBt){ - HBtree *const p = (HBtree*)pBt; - return sqlite3HctDbSnapshotId(p->pHctDb); -} - -/* -** Open a new cursor -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursor( - Btree *pBt, /* The btree */ - Pgno iTable, /* Root page of table to open */ - int wrFlag, /* 1 to write. 0 read-only */ - struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ - BtCursor *pCursor /* Write new cursor here */ -){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - int bNosnap = 0; - int bReadonly = sqlite3HctJournalIsReadonly(p->pHctJrnl, iTable, &bNosnap); - - assert( p->eTrans!=SQLITE_TXN_NONE ); - assert( p->eTrans!=SQLITE_TXN_ERROR ); - assert( pCur->pHctTreeCsr==0 ); - assert( BT_IS_MIGRATE(p)==0 || wrFlag ); - - /* If this is an attempt to open a read/write cursor on either the - ** sqlite_hct_journal or sqlite_hct_baseline tables, return an error - ** immediately. */ - if( wrFlag && bReadonly ){ - return SQLITE_READONLY; - } - - pCur->pKeyInfo = pKeyInfo; - rc = sqlite3HctTreeCsrOpen(p->pHctTree, iTable, &pCur->pHctTreeCsr); - if( rc==SQLITE_OK && p->pHctDb ){ - int ii; - for(ii=0; iinSchemaOp && p->aSchemaOp[ii].pgnoRoot!=iTable; ii++); - if( ii==p->nSchemaOp ){ - rc = sqlite3HctDbCsrOpen(p->pHctDb, pKeyInfo, iTable, &pCur->pHctDbCsr); - sqlite3HctDbCsrNosnap(pCur->pHctDbCsr, bNosnap); - } - } - if( rc==SQLITE_OK ){ - pCur->pCsrNext = p->pCsrList; - pCur->pBtree = p; - pCur->wrFlag = wrFlag; - p->pCsrList = pCur; - }else{ - sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); - pCur->pHctTreeCsr = 0; - pCur->pKeyInfo = 0; - } - - return rc; -} - -/* -** Return the size of a BtCursor object in bytes. -** -** This interfaces is needed so that users of cursors can preallocate -** sufficient storage to hold a cursor. The BtCursor object is opaque -** to users so they cannot do the sizeof() themselves - they must call -** this routine. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursorSize(void){ - return ROUND8(sizeof(HBtCursor)); -} - -/* -** Initialize memory that will be converted into a BtCursor object. -** -** The simple approach here would be to memset() the entire object -** to zero. But it turns out that the apPage[] and aiIdx[] arrays -** do not need to be zeroed and they are large, so we can save a lot -** of run-time by skipping the initialization of those elements. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeCursorZero(BtCursor *p){ - /* hct takes the simple approach mentioned above */ - memset(p, 0, sizeof(HBtCursor)); -} - -/* -** Close a cursor. The read lock on the database file is released -** when the last cursor is closed. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCloseCursor(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - HBtree *const pBtree = pCur->pBtree; - if( pBtree ){ - HBtCursor **pp; - sqlite3HctTreeCsrClose(pCur->pHctTreeCsr); - sqlite3HctDbCsrClose(pCur->pHctDbCsr); - for(pp=&pBtree->pCsrList; *pp!=pCur; pp=&(*pp)->pCsrNext); - *pp = pCur->pCsrNext; - pCur->pHctTreeCsr = 0; - pCur->pBtree = 0; - pCur->pCsrNext = 0; - if( (pBtree->openFlags & BTREE_SINGLE) && pBtree->pCsrList==0 ){ - sqlite3HctBtreeClose((Btree*)pBtree); - } - } - return SQLITE_OK; -} - -/* -** Return true if the given BtCursor is valid. A valid cursor is one -** that is currently pointing to a row in a (non-empty) table. -** This is a verification routine is used only within assert() statements. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValid(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - return pCur && ( - !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) - || !sqlite3HctDbCsrEof(pCur->pHctDbCsr) - ); -} -SQLITE_PRIVATE int sqlite3HctBtreeCursorIsValidNN(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - return ( - !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) - || !sqlite3HctDbCsrEof(pCur->pHctDbCsr) - ); -} - -/* -** Return the value of the integer key or "rowid" for a table btree. -** This routine is only valid for a cursor that is pointing into a -** ordinary table btree. If the cursor points to an index btree or -** is invalid, the result of this routine is undefined. -*/ -SQLITE_PRIVATE i64 sqlite3HctBtreeIntegerKey(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - i64 iKey; - if( pCur->bUseTree ){ - sqlite3HctTreeCsrKey(pCur->pHctTreeCsr, &iKey); - }else{ - sqlite3HctDbCsrKey(pCur->pHctDbCsr, &iKey); - } - return iKey; -} - -/* -** Pin or unpin a cursor. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeCursorPin(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - sqlite3HctTreeCsrPin(pCur->pHctTreeCsr); -} -SQLITE_PRIVATE void sqlite3HctBtreeCursorUnpin(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - sqlite3HctTreeCsrUnpin(pCur->pHctTreeCsr); -} - -#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC -/* -** Return the offset into the database file for the start of the -** payload to which the cursor is pointing. -*/ -SQLITE_PRIVATE i64 sqlite3HctBtreeOffset(BtCursor *pCur){ - assert( 0 ); - return 0; -} -#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ - -/* -** Return the number of bytes of payload for the entry that pCur is -** currently pointing to. For table btrees, this will be the amount -** of data. For index btrees, this will be the size of the key. -** -** The caller must guarantee that the cursor is pointing to a non-NULL -** valid entry. In other words, the calling procedure must guarantee -** that the cursor has Cursor.eState==CURSOR_VALID. -*/ -SQLITE_PRIVATE u32 sqlite3HctBtreePayloadSize(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int nData; - if( pCur->bUseTree ){ - sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nData, 0); - }else{ - sqlite3HctDbCsrData(pCur->pHctDbCsr, &nData, 0); - } - return nData; -} - -/* -** Return an upper bound on the size of any record for the table -** that the cursor is pointing into. -** -** This is an optimization. Everything will still work if this -** routine always returns 2147483647 (which is the largest record -** that SQLite can handle) or more. But returning a smaller value might -** prevent large memory allocations when trying to interpret a -** corrupt datrabase. -** -** The current implementation merely returns the size of the underlying -** database file. -*/ -SQLITE_PRIVATE sqlite3_int64 sqlite3HctBtreeMaxRecordSize(BtCursor *pCur){ - assert( 0 ); - return 0x7FFFFFFF; -} - -/* -** Read part of the payload for the row at which that cursor pCur is currently -** pointing. "amt" bytes will be transferred into pBuf[]. The transfer -** begins at "offset". -** -** pCur can be pointing to either a table or an index b-tree. -** If pointing to a table btree, then the content section is read. If -** pCur is pointing to an index b-tree then the key section is read. -** -** For sqlite3HctBtreePayload(), the caller must ensure that pCur is pointing -** to a valid row in the table. For sqlite3HctBtreePayloadChecked(), the -** cursor might be invalid or might need to be restored before being read. -** -** Return SQLITE_OK on success or an error code if anything goes -** wrong. An error is returned if "offset+amt" is larger than -** the available payload. -*/ -SQLITE_PRIVATE int sqlite3HctBtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - u32 n = 0; - const u8 *p = 0; - - p = (const u8*)sqlite3HctBtreePayloadFetch(pCur, &n); - assert( offset+amt<=n ); - memcpy(pBuf, &p[offset], amt); - - return SQLITE_OK; -} - - -static int btreeSetUseTree(HBtCursor *pCur){ - int rc = SQLITE_OK; - int bTreeEof = sqlite3HctTreeCsrEof(pCur->pHctTreeCsr); - int bDbEof = sqlite3HctDbCsrEof(pCur->pHctDbCsr); - - assert( pCur->eDir==BTREE_DIR_FORWARD || pCur->eDir==BTREE_DIR_REVERSE ); - assert( pCur->pHctTreeCsr ); - - if( bTreeEof ){ - pCur->bUseTree = 0; - }else if( bDbEof ){ - pCur->bUseTree = 1; - }else if( pCur->pKeyInfo==0 ){ - i64 iKeyTree; - i64 iKeyDb; - - sqlite3HctTreeCsrKey(pCur->pHctTreeCsr, &iKeyTree); - sqlite3HctDbCsrKey(pCur->pHctDbCsr, &iKeyDb); - - if( iKeyTree==iKeyDb ){ - pCur->bUseTree = 2; - }else{ - pCur->bUseTree = (iKeyTree < iKeyDb); - if( pCur->eDir==BTREE_DIR_REVERSE ) pCur->bUseTree = !pCur->bUseTree; - } - }else{ - UnpackedRecord *pKeyDb = 0; - const u8 *aKeyTree = 0; - int nKeyTree = 0; - - rc = sqlite3HctDbCsrLoadAndDecode(pCur->pHctDbCsr, &pKeyDb); - if( rc==SQLITE_OK ){ - int res; - int nSave = pKeyDb->nField; - sqlite3HctDbRecordTrim(pKeyDb); - sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nKeyTree, &aKeyTree); - res = sqlite3VdbeRecordCompare(nKeyTree, aKeyTree, pKeyDb); - pKeyDb->nField = nSave; - if( res==0 ){ - pCur->bUseTree = 2; - }else{ - pCur->bUseTree = (res<0); - if( pCur->eDir==BTREE_DIR_REVERSE ) pCur->bUseTree = !pCur->bUseTree; - } - } - } - - return rc; -} - -static int hctReseekBlobCsr(HBtCursor *pCsr){ - int rc = SQLITE_OK; - assert( pCsr->pKeyInfo==0 ); - if( sqlite3HctTreeCsrHasMoved(pCsr->pHctTreeCsr) ){ - int res = 0; - rc = sqlite3HctTreeCsrReseek(pCsr->pHctTreeCsr, &res); - if( rc==SQLITE_OK && res==0 ){ - pCsr->bUseTree = 1; - } - } - return rc; -} - -/* -** This variant of sqlite3HctBtreePayload() works even if the cursor has not -** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() -** interface. -*/ -#ifndef SQLITE_OMIT_INCRBLOB -SQLITE_PRIVATE int sqlite3HctBtreePayloadChecked( - BtCursor *pCur, - u32 offset, - u32 amt, - void *pBuf -){ - HBtCursor *pCsr = (HBtCursor*)pCur; - int rc = SQLITE_OK; - rc = hctReseekBlobCsr(pCsr); - if( rc==SQLITE_OK ){ - rc = sqlite3HctBtreePayload(pCur, offset, amt, pBuf); - } - return rc; -} -#endif /* SQLITE_OMIT_INCRBLOB */ - -/* -** For the entry that cursor pCur is point to, return as -** many bytes of the key or data as are available on the local -** b-tree page. Write the number of available bytes into *pAmt. -** -** The pointer returned is ephemeral. The key/data may move -** or be destroyed on the next call to any Btree routine, -** including calls from other threads against the same cache. -** Hence, a mutex on the BtShared should be held prior to calling -** this routine. -** -** These routines is used to get quick access to key and data -** in the common case where no overflow pages are used. -*/ -SQLITE_PRIVATE const void *sqlite3HctBtreePayloadFetch(BtCursor *pCursor, u32 *pAmt){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - const u8 *aData; - int nData; - if( pCur->bUseTree ){ - sqlite3HctTreeCsrData(pCur->pHctTreeCsr, &nData, &aData); - }else{ - sqlite3HctDbCsrData(pCur->pHctDbCsr, &nData, &aData); - } - *pAmt = (u32)nData; - return aData; -} - -/* Move the cursor to the first entry in the table. Return SQLITE_OK -** on success. Set *pRes to 0 if the cursor actually points to something -** or set *pRes to 1 if the table is empty. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeFirst(BtCursor *pCursor, int *pRes){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int rc = SQLITE_OK; - - sqlite3HctTreeCsrFirst(pCur->pHctTreeCsr); - if( pCur->pHctDbCsr ){ - rc = sqlite3HctDbCsrFirst(pCur->pHctDbCsr); - } - if( rc==SQLITE_OK ){ - pCur->eDir = BTREE_DIR_FORWARD; - btreeSetUseTree(pCur); - if( pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ - rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - *pRes = sqlite3HctBtreeEof((BtCursor*)pCur); - } - - return rc; -} - -/* Move the cursor to the last entry in the table. Return SQLITE_OK -** on success. Set *pRes to 0 if the cursor actually points to something -** or set *pRes to 1 if the table is empty. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeLast(BtCursor *pCursor, int *pRes){ - int rc = SQLITE_OK; - HBtCursor *const pCur = (HBtCursor*)pCursor; - - if( pCur->isLast==0 ){ - sqlite3HctTreeCsrLast(pCur->pHctTreeCsr); - if( pCur->pHctDbCsr ){ - rc = sqlite3HctDbCsrLast(pCur->pHctDbCsr); - } - if( rc==SQLITE_OK ){ - int bTreeEof = sqlite3HctTreeCsrEof(pCur->pHctTreeCsr); - int bDbEof = sqlite3HctDbCsrEof(pCur->pHctDbCsr); - *pRes = (bTreeEof && bDbEof); - pCur->eDir = BTREE_DIR_REVERSE; - btreeSetUseTree(pCur); - if( pCur->bUseTree ){ - if( sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ - rc = sqlite3HctBtreePrevious((BtCursor*)pCur, 0); - if( rc==SQLITE_DONE ){ - *pRes = sqlite3HctBtreeEof((BtCursor*)pCur); - rc = SQLITE_OK; - } - }else{ - pCur->isLast = 1; - } - } - } - } - - return rc; -} - -/* Move the cursor so that it points to an entry near the key -** specified by pIdxKey or intKey. Return a success code. -** -** For INTKEY tables, the intKey parameter is used. pIdxKey -** must be NULL. For index tables, pIdxKey is used and intKey -** is ignored. -** -** If an exact match is not found, then the cursor is always -** left pointing at a leaf page which would hold the entry if it -** were present. The cursor might point to an entry that comes -** before or after the key. -** -** An integer is written into *pRes which is the result of -** comparing the key with the entry to which the cursor is -** pointing. The meaning of the integer written into -** *pRes is as follows: -** -** *pRes<0 The cursor is left pointing at an entry that -** is smaller than intKey/pIdxKey or if the table is empty -** and the cursor is therefore left point to nothing. -** -** *pRes==0 The cursor is left pointing at an entry that -** exactly matches intKey/pIdxKey. -** -** *pRes>0 The cursor is left pointing at an entry that -** is larger than intKey/pIdxKey. -** -** For index tables, the pIdxKey->eqSeen field is set to 1 if there -** exists an entry in the table that exactly matches pIdxKey. -*/ -static int hctBtreeMovetoUnpacked( - HBtCursor *pCur, /* The cursor to be moved */ - UnpackedRecord *pIdxKey, /* Unpacked index key */ - i64 intKey, /* The table key */ - int biasRight, /* If true, bias the search to the high end */ - int *pRes /* Write search results here */ -){ - int rc = SQLITE_OK; - int res1 = 0; - int res2 = -1; - - pCur->isLast = 0; - rc = sqlite3HctTreeCsrSeek(pCur->pHctTreeCsr, pIdxKey, intKey, &res1); - if( rc==SQLITE_OK && pCur->pHctDbCsr ){ - rc = sqlite3HctDbCsrSeek(pCur->pHctDbCsr, pIdxKey, intKey, &res2); - } - - if( pCur->eDir==BTREE_DIR_NONE ){ - if( res1==0 || pCur->pHctDbCsr==0 ){ - *pRes = res1; - pCur->bUseTree = 1; - if( sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ - *pRes = -1; - } - }else{ - pCur->bUseTree = 0; - *pRes = res2; - } - }else{ - if( pCur->eDir==BTREE_DIR_FORWARD ){ - if( rc==SQLITE_OK && res2<0 && !sqlite3HctDbCsrEof(pCur->pHctDbCsr) ){ - rc = sqlite3HctDbCsrNext(pCur->pHctDbCsr); - } - if( rc==SQLITE_OK && res1<0 && !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) ){ - rc = sqlite3HctTreeCsrNext(pCur->pHctTreeCsr); - } - - if( res1==0 || (res2==0 && pCur->pHctDbCsr) ){ - *pRes = 0; - }else if( sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) - && sqlite3HctDbCsrEof(pCur->pHctDbCsr) - ){ - *pRes = -1; - }else{ - *pRes = +1; - } - }else{ - assert( pCur->eDir==BTREE_DIR_REVERSE ); - assert( res2<=0 ); - if( rc==SQLITE_OK && res1>0 && !sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) ){ - rc = sqlite3HctTreeCsrPrev(pCur->pHctTreeCsr); - } - if( res1==0 || res2==0 ){ - *pRes = 0; - }else{ - *pRes = -1; - } - } - - btreeSetUseTree(pCur); - if( pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) ){ - if( pCur->eDir==BTREE_DIR_FORWARD ){ - rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0); - if( rc==SQLITE_DONE ){ - /* Cursor points at EOF. *pRes must be -ve in this case. */ - rc = SQLITE_OK; - *pRes = -1; - }else if( pIdxKey==0 ){ - *pRes = 1; - }else{ - u32 nKey; - const void *a = sqlite3HctBtreePayloadFetch((BtCursor*)pCur, &nKey); - *pRes = sqlite3VdbeRecordCompareWithSkip(nKey, a, pIdxKey, 0); - } - }else{ - rc = sqlite3HctBtreePrevious((BtCursor*)pCur, 0); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - *pRes = -1; - } - } - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctBtreeTableMoveto( - BtCursor *pCursor, /* The cursor to be moved */ - i64 intKey, /* The table key */ - int biasRight, /* If true, bias the search to the high end */ - int *pRes /* Write search results here */ -){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - assert( CSR_IS_MIGRATE(pCur)==0 ); - if( pCur->isLast && sqlite3HctBtreeIntegerKey(pCursor)eDir = eDir; - if( pCur->pHctDbCsr ){ - sqlite3HctDbCsrDir(pCur->pHctDbCsr, eDir); - } -} - -/* -** Return TRUE if the cursor is not pointing at an entry of the table. -** -** TRUE will be returned after a call to sqlite3HctBtreeNext() moves -** past the last entry in the table or sqlite3HctBtreePrev() moves past -** the first entry. TRUE is also returned if the table is empty. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeEof(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries - ** have been deleted? This API will need to change to return an error code - ** as well as the boolean result value. - */ - return ( - sqlite3HctTreeCsrEof(pCur->pHctTreeCsr) - && sqlite3HctDbCsrEof(pCur->pHctDbCsr) - ); -} - -/* -** Return an estimate for the number of rows in the table that pCur is -** pointing to. Return a negative number if no estimate is currently -** available. -*/ -SQLITE_PRIVATE i64 sqlite3HctBtreeRowCountEst(BtCursor *pCur){ - /* TODO: Fix this so that it returns a meaningful value. */ - return -1; -} - -/* -** Advance the cursor to the next entry in the database. -** Return value: -** -** SQLITE_OK success -** SQLITE_DONE cursor is already pointing at the last element -** otherwise some kind of error occurred -** -** The main entry point is sqlite3HctBtreeNext(). That routine is optimized -** for the common case of merely incrementing the cell counter BtCursor.aiIdx -** to the next cell on the current page. The (slower) btreeNext() helper -** routine is called when it is necessary to move to a different page or -** to restore the cursor. -** -** If bit 0x01 of the F argument in sqlite3HctBtreeNext(C,F) is 1, then the -** cursor corresponds to an SQL index and this routine could have been -** skipped if the SQL index had been a unique index. The F argument -** is a hint to the implement. SQLite btree implementation does not use -** this hint, but COMDB2 does. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeNext(BtCursor *pCursor, int flags){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int rc = SQLITE_OK; - int bDummy; - - assert( pCur->isLast==0 ); - rc = sqlite3HctBtreeCursorRestore((BtCursor*)pCur, &bDummy); - if( rc!=SQLITE_OK ) return rc; - - if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ - rc = SQLITE_DONE; - }else{ - assert( pCur->eDir==BTREE_DIR_FORWARD ); - do{ - if( pCur->bUseTree ){ - rc = sqlite3HctTreeCsrNext(pCur->pHctTreeCsr); - } - if( rc==SQLITE_OK && (pCur->bUseTree==0 || pCur->bUseTree==2) ){ - rc = sqlite3HctDbCsrNext(pCur->pHctDbCsr); - } - if( rc==SQLITE_OK ){ - if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ - rc = SQLITE_DONE; - }else{ - btreeSetUseTree(pCur); - } - } - }while( rc==SQLITE_OK - && pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) - ); - } - return rc; -} - -/* -** Step the cursor to the back to the previous entry in the database. -** Return values: -** -** SQLITE_OK success -** SQLITE_DONE the cursor is already on the first element of the table -** otherwise some kind of error occurred -** -** The main entry point is sqlite3HctBtreePrevious(). That routine is optimized -** for the common case of merely decrementing the cell counter BtCursor.aiIdx -** to the previous cell on the current page. The (slower) btreePrevious() -** helper routine is called when it is necessary to move to a different page -** or to restore the cursor. -** -** If bit 0x01 of the F argument to sqlite3HctBtreePrevious(C,F) is 1, then -** the cursor corresponds to an SQL index and this routine could have been -** skipped if the SQL index had been a unique index. The F argument is a -** hint to the implement. The native SQLite btree implementation does not -** use this hint, but COMDB2 does. -*/ -SQLITE_PRIVATE int sqlite3HctBtreePrevious(BtCursor *pCursor, int flags){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int rc = SQLITE_OK; - int bDummy; - assert( pCur->eDir==BTREE_DIR_REVERSE ); - - pCur->isLast = 0; - rc = sqlite3HctBtreeCursorRestore((BtCursor*)pCur, &bDummy); - if( rc!=SQLITE_OK ) return rc; - - do{ - if( pCur->bUseTree ){ - rc = sqlite3HctTreeCsrPrev(pCur->pHctTreeCsr); - } - if( rc==SQLITE_OK && (pCur->bUseTree==0 || pCur->bUseTree==2) ){ - rc = sqlite3HctDbCsrPrev(pCur->pHctDbCsr); - } - if( rc==SQLITE_OK ){ - if( sqlite3HctBtreeEof((BtCursor*)pCur) ){ - rc = SQLITE_DONE; - }else{ - btreeSetUseTree(pCur); - } - } - }while( rc==SQLITE_OK - && pCur->bUseTree && sqlite3HctTreeCsrIsDelete(pCur->pHctTreeCsr) - ); - return rc; -} - -static void hctBtreeClearIsLast(HBtree *pBt, HBtCursor *pExcept){ - HBtCursor *p; - for(p=pBt->pCsrList; p; p=p->pCsrNext){ - if( p!=pExcept ) p->isLast = 0; - } -} - -/* -** Insert a new record into the BTree. The content of the new record -** is described by the pX object. The pCur cursor is used only to -** define what table the record should be inserted into, and is left -** pointing at a random location. -** -** For a table btree (used for rowid tables), only the pX.nKey value of -** the key is used. The pX.pKey value must be NULL. The pX.nKey is the -** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields -** hold the content of the row. -** -** For an index btree (used for indexes and WITHOUT ROWID tables), the -** key is an arbitrary byte sequence stored in pX.pKey,nKey. The -** pX.pData,nData,nZero fields must be zero. -** -** If the seekResult parameter is non-zero, then a successful call to -** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already -** been performed. In other words, if seekResult!=0 then the cursor -** is currently pointing to a cell that will be adjacent to the cell -** to be inserted. If seekResult<0 then pCur points to a cell that is -** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell -** that is larger than (pKey,nKey). -** -** If seekResult==0, that means pCur is pointing at some unknown location. -** In that case, this routine must seek the cursor to the correct insertion -** point for (pKey,nKey) before doing the insertion. For index btrees, -** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked -** key values and pX->aMem can be used instead of pX->pKey to avoid having -** to decode the key. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeInsert( - BtCursor *pCursor, /* Insert data into the table of this cursor */ - const BtreePayload *pX, /* Content of the row to be inserted */ - int flags, /* True if this is likely an append */ - int seekResult /* Result of prior MovetoUnpacked() call */ -){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - HctTreeCsr *pTreeCsr = pCur->pHctTreeCsr; - int rc = SQLITE_OK; - UnpackedRecord r; - UnpackedRecord *pRec = 0; - const u8 *aData; - int nData; - int nZero; - i64 iKey = 0; - int bMigrate = pCur->pBtree->config.db->bHctMigrate; - - hctBtreeClearIsLast(pCur->pBtree, pCur); - if( pX->pKey ){ - aData = pX->pKey; - nData = pX->nKey; - nZero = 0; - if( pX->nMem ){ - memset(&r, 0, sizeof(r)); - r.pKeyInfo = pCur->pKeyInfo; - r.aMem = pX->aMem; - r.nField = pX->nMem; - pRec = &r; - }else{ - pRec = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); - if( pRec==0 ) return SQLITE_NOMEM_BKPT; - sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nData, aData, pRec); - } - iKey = 0; - }else{ - aData = pX->pData; - nData = pX->nData; - nZero = pX->nZero; - iKey = pX->nKey; - } - - if( CSR_IS_MIGRATE(pCur) ){ - assert( nZero==0 ); - rc = hctBtreeMigrateInsert(pCur, pRec, iKey, nData, aData); - }else{ - if( pCur->isLast && seekResult<0 ){ - rc = sqlite3HctTreeAppend( - pTreeCsr, pCur->pKeyInfo, iKey, nData, aData, nZero - ); - }else{ - rc = sqlite3HctTreeInsert(pTreeCsr, pRec, iKey, nData, aData, nZero); - pCur->isLast = 0; - } - } - - if( pRec && pRec!=&r ){ - sqlite3DbFree(pCur->pKeyInfo->db, pRec); - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctSchemaOp(Btree *pBt, const char *zSql){ - int rc = SQLITE_OK; - HBtree *const p = (HBtree*)pBt; - if( p->pHctJrnl ){ - HctTreeCsr *pCsr = 0; - - rc = sqlite3HctTreeCsrOpen(p->pHctTree, HCT_TREE_SCHEMAOP_ROOT, &pCsr); - if( rc==SQLITE_OK ){ - int nSql = sqlite3Strlen30(zSql); - i64 iRowid = 1; - sqlite3HctTreeCsrLast(pCsr); - if( sqlite3HctTreeCsrEof(pCsr)==0 ){ - sqlite3HctTreeCsrKey(pCsr, &iRowid); - iRowid++; - } - - rc = sqlite3HctTreeInsert(pCsr, 0, iRowid, nSql, (const u8*)zSql, 0); - sqlite3HctTreeCsrClose(pCsr); - } - } - return rc; -} - -/* -** Delete the entry that the cursor is pointing to. -** -** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then -** the cursor is left pointing at an arbitrary location after the delete. -** But if that bit is set, then the cursor is left in a state such that -** the next call to BtreeNext() or BtreePrev() moves it to the same row -** as it would have been on if the call to BtreeDelete() had been omitted. -** -** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes -** associated with a single table entry and its indexes. Only one of those -** deletes is considered the "primary" delete. The primary delete occurs -** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete -** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. -** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, -** but which might be used by alternative storage engines. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeDelete(BtCursor *pCursor, u8 flags){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int rc = SQLITE_OK; - - hctBtreeClearIsLast(pCur->pBtree, 0); - if( pCur->pHctDbCsr==0 ){ - rc = sqlite3HctTreeDelete(pCur->pHctTreeCsr); - }else if( pCur->pKeyInfo==0 ){ - i64 iKey = sqlite3HctBtreeIntegerKey((BtCursor*)pCur); - rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, 0, iKey, 0, 0); - }else{ - u32 nKey; - const u8 *aKey = (u8*)sqlite3HctBtreePayloadFetch((BtCursor*)pCur, &nKey); - UnpackedRecord *pRec = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); - - if( pRec==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, aKey, pRec); - rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, pRec, 0, nKey, aKey); - sqlite3DbFree(pCur->pBtree->config.db, pRec); - } - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctBtreeIdxDelete(BtCursor *pCursor, UnpackedRecord *pKey){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - int rc = SQLITE_OK; - - hctBtreeClearIsLast(pCur->pBtree, 0); - if( pCur->pHctDbCsr ){ - u8 *aRec = 0; - int nRec = 0; - rc = sqlite3HctSerializeRecord(pKey, &aRec, &nRec); - if( rc==SQLITE_OK ){ - rc = sqlite3HctTreeDeleteKey(pCur->pHctTreeCsr, pKey, 0, nRec, aRec); - sqlite3_free(aRec); - } - }else{ - int res = 0; - rc = sqlite3HctTreeCsrSeek(pCur->pHctTreeCsr, pKey, 0, &res); - if( res==0 ){ - rc = sqlite3HctTreeDelete(pCur->pHctTreeCsr); - } - } - return rc; -} - -static int hctreeAddNewSchemaOp(HBtree *p, u32 iRoot, int eOp){ - BtSchemaOp *aSchemaOp; - - /* Grow the Btree.aSchemaOp array */ - assert( p->pHctDb ); - aSchemaOp = (BtSchemaOp*)sqlite3_realloc( - p->aSchemaOp, sizeof(BtSchemaOp)*(p->nSchemaOp+1) - ); - if( aSchemaOp==0 ) return SQLITE_NOMEM_BKPT; - - p->aSchemaOp = aSchemaOp; - p->aSchemaOp[p->nSchemaOp].pgnoRoot = iRoot; - p->aSchemaOp[p->nSchemaOp].iSavepoint = p->config.db->nSavepoint; - p->aSchemaOp[p->nSchemaOp].eSchemaOp = eOp; - p->nSchemaOp++; - - return SQLITE_OK; -} - -static int hctreeAddNewRoot(HBtree *p, u32 iRoot, int bIndex){ - int eOp = bIndex ? HCT_SCHEMAOP_CREATE_INDEX : HCT_SCHEMAOP_CREATE_INTKEY; - return hctreeAddNewSchemaOp(p, iRoot, eOp); -} - -/* -** Create a new BTree table. Write into *piTable the page -** number for the root page of the new table. -** -** The type of type is determined by the flags parameter. Only the -** following values of flags are currently in use. Other values for -** flags might not work: -** -** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys -** BTREE_ZERODATA Used for SQL indices -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCreateTable(Btree *pBt, Pgno *piTable, int flags){ - HBtree *const p = (HBtree*)pBt; - Pgno iNew = 0; - int rc = SQLITE_OK; - if( p->pHctDb ){ - rc = sqlite3HctDbRootNew(p->pHctDb, &iNew); - if( rc==SQLITE_OK ){ - rc = hctreeAddNewRoot(p, iNew, (flags & BTREE_INTKEY)==0); - } - }else{ - iNew = p->iNextRoot++; - } - *piTable = iNew; - return rc; -} - -/* -** Delete all information from a single table in the database. iTable is -** the page number of the root of the table. After this routine returns, -** the root page is empty, but still exists. -** -** This routine will fail with SQLITE_LOCKED if there are any open -** read cursors on the table. Open write cursors are moved to the -** root of the table. -** -** If pnChange is not NULL, then table iTable must be an intkey table. The -** integer value pointed to by pnChange is incremented by the number of -** entries in the table. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeClearTable(Btree *pBt, int iTable, i64 *pnChange){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - KeyInfo *pKeyInfo = 0; - - rc = hctFindKeyInfo(p, iTable, &pKeyInfo); - if( rc==SQLITE_OK ){ - i64 nChange = 0; - BtCursor *pCsr = 0; - HctTreeCsr *pTreeCsr = 0; - UnpackedRecord *pRec = 0; - - if( pKeyInfo ){ - pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); - if( pRec==0 ) rc = SQLITE_NOMEM_BKPT; - } - pCsr = (BtCursor*)sqlite3HctMalloc(&rc, sizeof(HBtCursor)); - if( rc==SQLITE_OK ){ - rc = sqlite3HctBtreeCursor(pBt, iTable, 0, pKeyInfo, pCsr); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctTreeCsrOpen(p->pHctTree, iTable, &pTreeCsr); - } - - if( rc==SQLITE_OK ){ - int res = 0; - rc = sqlite3HctBtreeFirst(pCsr, &res); - if( res==0 ){ - while( rc==SQLITE_OK ){ - nChange++; - if( pKeyInfo ){ - const u8 *aData = 0; - u32 nData = 0; - aData = (const u8*)sqlite3HctBtreePayloadFetch(pCsr, &nData); - sqlite3VdbeRecordUnpack(pKeyInfo, nData, aData, pRec); - rc = sqlite3HctTreeDeleteKey(pTreeCsr, pRec, 0, nData, aData); - }else{ - i64 iKey = sqlite3HctBtreeIntegerKey((BtCursor*)pCsr); - rc = sqlite3HctTreeDeleteKey(pTreeCsr, 0, iKey, 0, 0); - } - rc = sqlite3HctBtreeNext(pCsr, 0); - } - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - } - if( pnChange ) *pnChange = nChange; - - sqlite3KeyInfoUnref(pKeyInfo); - sqlite3HctBtreeCloseCursor(pCsr); - sqlite3HctTreeCsrClose(pTreeCsr); - sqlite3DbFree(p->config.db, pRec); - sqlite3_free(pCsr); - } - return rc; -} - -/* -** Delete all information from the single table that pCur is open on. -** -** This routine only work for pCur on an ephemeral table. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeClearTableOfCursor(BtCursor *pCursor){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - return sqlite3HctTreeClearOne( - pCur->pBtree->pHctTree, sqlite3HctTreeCsrRoot(pCur->pHctTreeCsr), 0 - ); -} - -/* -** Drop the table with root page iTable. Set (*piMoved) to 0 before -** returning. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeDropTable(Btree *pBt, int iTable, int *piMoved){ - HBtree *const p = (HBtree*)pBt; - *piMoved = 0; - return hctreeAddNewSchemaOp(p, iTable, HCT_SCHEMAOP_DROP); -} - - -/* -** This function may only be called if the b-tree connection already -** has a read or write transaction open on the database. -** -** Read the meta-information out of a database file. Meta[0] -** is the number of free pages currently in the database. Meta[1] -** through meta[15] are available for use by higher layers. Meta[0] -** is read-only, the others are read/write. -** -** The schema layer numbers meta values differently. At the schema -** layer (and the SetCookie and ReadCookie opcodes) the number of -** free pages is not visible. So Cookie[0] is the same as Meta[1]. -** -** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead -** of reading the value out of the header, it instead loads the "DataVersion" -** from the pager. The BTREE_DATA_VERSION value is not actually stored in the -** database file. It is a number computed by the pager. But its access -** pattern is the same as header meta values, and so it is convenient to -** read it from this routine. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){ - HBtree *const p = (HBtree*)pBt; - - assert( idx>=0 && idxpHctDb ); - if( idx==BTREE_DATA_VERSION ){ - /* TODO: Fix this so that the data_version does not change when the - ** database is written by the current connection. */ - i64 iSnapshot = sqlite3HctDbSnapshotId(p->pHctDb); - *pMeta = (u32)iSnapshot; - }else{ - if( p->eMetaState==HCT_METASTATE_NONE ){ - int rc = SQLITE_OK; - if( p->eTrans==SQLITE_TXN_NONE ){ - rc = sqlite3HctDbGetMeta( - p->pHctDb, (u8*)p->aMeta, SQLITE_N_BTREE_META*4 - ); - }else{ - int res = 0; - HBtCursor csr; - BtCursor *pCsr = (BtCursor*)&csr; - memset(&csr, 0, sizeof(csr)); - - sqlite3HctBtreeCursor(pBt, 2, 0, 0, pCsr); - rc = sqlite3HctBtreeTableMoveto(pCsr, 0, 0, &res); - assert( rc==SQLITE_OK ); - if( rc==SQLITE_OK && res==0 ){ - const void *aMeta = 0; - u32 nMeta = 0; - aMeta = sqlite3HctBtreePayloadFetch(pCsr, &nMeta); - memcpy(p->aMeta, aMeta, MAX(nMeta, SQLITE_N_BTREE_META*4)); - } - sqlite3HctBtreeCloseCursor(pCsr); - } - sqlite3HctJournalSchemaVersion( - p->pHctJrnl, &p->aMeta[BTREE_SCHEMA_VERSION] - ); - } - *pMeta = p->aMeta[idx]; - } -} - -/* -** Write meta-information back into the database. Meta[0] is -** read-only and may not be written. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){ - HBtree *const p = (HBtree*)pBt; - u32 dummy; - sqlite3HctBtreeGetMeta((Btree*)p, 0, &dummy); - p->aMeta[idx] = iMeta; - return sqlite3HctTreeUpdateMeta( - p->pHctTree, (u8*)p->aMeta, SQLITE_N_BTREE_META*4 - ); -} - -static char *hctDbMPrintf(int *pRc, const char *zFormat, ...){ - char *zRet = 0; - if( *pRc==SQLITE_OK ){ - va_list ap; - va_start(ap, zFormat); - zRet = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - if( !zRet ) *pRc = SQLITE_NOMEM_BKPT; - } - return zRet; -} - -SQLITE_PRIVATE int sqlite3HctBtreePragma(Btree *pBt, char **aFnctl){ - HBtree *const p = (HBtree*)pBt; - int rc = SQLITE_OK; - const char *zLeft = aFnctl[1]; - const char *zRight = aFnctl[2]; - char *zRet = 0; - - if( 0==sqlite3_stricmp("hct_ndbfile", zLeft) ){ - HctFile *pFile = sqlite3HctDbFile(p->pHctDb); - int iCurrent = 0; - int bFixed = 0; - if( zRight ){ - int iVal = sqlite3Atoi(zRight); - if( iVal<1 || iVal>HCT_MAX_NDBFILE ){ - rc = SQLITE_RANGE; - }else{ - p->config.nDbFile = iVal; - } - } - if( rc==SQLITE_OK ){ - iCurrent = sqlite3HctFileNFile(pFile, &bFixed); - if( bFixed==0 ) iCurrent = p->config.nDbFile; - zRet = hctDbMPrintf(&rc, "%d", iCurrent); - } - } - - else if( 0==sqlite3_stricmp("hct_try_before_unevict", zLeft) ){ - int iVal = 0; - if( zRight ){ - iVal = sqlite3Atoi(zRight); - } - if( iVal>0 ){ - p->config.nTryBeforeUnevict = iVal; - } - zRet = hctDbMPrintf(&rc, "%d", p->config.nTryBeforeUnevict); - } - else if( 0==sqlite3_stricmp("hct_npageset", zLeft) ){ - int iVal = 0; - if( zRight ){ - iVal = sqlite3Atoi(zRight); - } - if( iVal>0 ){ - p->config.nPageSet = iVal; - } - zRet = hctDbMPrintf(&rc, "%d", p->config.nPageSet); - } - else if( 0==sqlite3_stricmp("hct_ncasfail", zLeft) ){ - zRet = hctDbMPrintf(&rc, "%lld", sqlite3HctDbNCasFail(p->pHctDb)); - } - else if( p->pHctDb && 0==sqlite3_stricmp("hct_npagescan", zLeft) ){ - int iVal = 0; - if( zRight ){ - iVal = sqlite3Atoi(zRight); - } - if( iVal>0 ){ - p->config.nPageScan = iVal; - } - zRet = hctDbMPrintf(&rc, "%d", p->config.nPageScan); - } - else if( 0==sqlite3_stricmp("hct_quiescent_integrity_check", zLeft) ){ - int iVal = 0; - if( zRight ){ - iVal = sqlite3Atoi(zRight); - } - if( iVal>0 ){ - p->config.bQuiescentIntegrityCheck = (iVal==0 ? 0 : 1); - } - zRet = hctDbMPrintf(&rc, "%d", p->config.bQuiescentIntegrityCheck); - }else{ - rc = SQLITE_NOTFOUND; - } - - aFnctl[0] = zRet; - return rc; -} - -/* -** The first argument, pCur, is a cursor opened on some b-tree. Count the -** number of entries in the b-tree and write the result to *pnEntry. -** -** SQLITE_OK is returned if the operation is successfully executed. -** Otherwise, if an error is encountered (i.e. an IO error or database -** corruption) an SQLite error code is returned. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCount(sqlite3 *db, BtCursor *pCursor, i64 *pnEntry){ - HBtCursor *const pCur = (HBtCursor*)pCursor; - i64 nEntry = 0; - int dummy = 0; - int rc; - for(rc = sqlite3HctBtreeFirst((BtCursor*)pCur, &dummy); - rc==SQLITE_OK && 0==sqlite3HctBtreeEof((BtCursor*)pCur); - rc = sqlite3HctBtreeNext((BtCursor*)pCur, 0) - ){ - nEntry++; - } - *pnEntry = nEntry; - return SQLITE_OK; -} - -/* -** Return the pager associated with a BTree. This routine is used for -** testing and debugging only. -*/ -SQLITE_PRIVATE Pager *sqlite3HctBtreePager(Btree *pBt){ - HBtree *const p = (HBtree*)pBt; - return p->pFakePager; -} - -#ifndef SQLITE_OMIT_INTEGRITY_CHECK -/* -** This routine does a complete check of the given BTree file. aRoot[] is -** an array of pages numbers were each page number is the root page of -** a table. nRoot is the number of entries in aRoot. -** -** A read-only or read-write transaction must be opened before calling -** this function. -** -** Write the number of error seen in *pnErr. Except for some memory -** allocation errors, an error message held in memory obtained from -** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is -** returned. If a memory allocation error occurs, NULL is returned. -** -** If the first entry in aRoot[] is 0, that indicates that the list of -** root pages is incomplete. This is a "partial integrity-check". This -** happens when performing an integrity check on a single table. The -** zero is skipped, of course. But in addition, the freelist checks -** and the checks to make sure every page is referenced are also skipped, -** since obviously it is not possible to know which pages are covered by -** the unverified btrees. Except, if aRoot[1] is 1, then the freelist -** checks are still performed. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeIntegrityCheck( - sqlite3 *db, /* Database connection that is running the check */ - Btree *pBt, /* The btree to be checked */ - Pgno *aRoot, /* An array of root pages numbers for individual trees */ - Mem *aCnt, - int nRoot, /* Number of entries in aRoot[] */ - int mxErr, /* Stop reporting errors after this many */ - int *pnErr, /* Write number of errors seen to this variable */ - char **pzErr -){ - HBtree *const p = (HBtree*)pBt; - char *zRet = 0; /* Return value */ - *pnErr = 0; - int ii; - for(ii=0; iiconfig.bQuiescentIntegrityCheck && nRoot>0 && aRoot[0]!=0 ){ - zRet = sqlite3HctDbIntegrityCheck(p->pHctDb, aRoot, aCnt, nRoot, pnErr); - assert( zRet==0 || (*pnErr)>0 ); - } - *pzErr = zRet; - return 0; -} -#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ - -/* -** Return the full pathname of the underlying database file. Return -** an empty string if the database is in-memory or a TEMP database. -** -** The pager filename is invariant as long as the pager is -** open so it is safe to access without the BtShared mutex. -*/ -SQLITE_PRIVATE const char *sqlite3HctBtreeGetFilename(Btree *p){ - return 0; -} - -/* -** Return the pathname of the journal file for this database. The return -** value of this routine is the same regardless of whether the journal file -** has been created or not. -** -** The pager journal filename is invariant as long as the pager is -** open so it is safe to access without the BtShared mutex. -*/ -SQLITE_PRIVATE const char *sqlite3HctBtreeGetJournalname(Btree *p){ - return 0; -} - -/* -** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE -** to describe the current transaction state of Btree p. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeTxnState(Btree *pBt){ - HBtree *const p = (HBtree*)pBt; - return p ? p->eTrans : SQLITE_TXN_NONE; -} - -#ifndef SQLITE_OMIT_WAL -/* -** Run a checkpoint on the Btree passed as the first argument. -** -** Return SQLITE_LOCKED if this or any other connection has an open -** transaction on the shared-cache the argument Btree is connected to. -** -** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ - return SQLITE_OK; -} -#endif - -/* -** Return true if there is currently a backup running on Btree p. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeIsInBackup(Btree *p){ - return 0; -} - -/* -** This function returns a pointer to a blob of memory associated with -** a single shared-btree. The memory is used by client code for its own -** purposes (for example, to store a high-level schema associated with -** the shared-btree). The btree layer manages reference counting issues. -** -** The first time this is called on a shared-btree, nBytes bytes of memory -** are allocated, zeroed, and returned to the caller. For each subsequent -** call the nBytes parameter is ignored and a pointer to the same blob -** of memory returned. -** -** If the nBytes parameter is 0 and the blob of memory has not yet been -** allocated, a null pointer is returned. If the blob has already been -** allocated, it is returned as normal. -** -** Just before the shared-btree is closed, the function passed as the -** xFree argument when the memory allocation was made is invoked on the -** blob of allocated memory. The xFree function should not call sqlite3_free() -** on the memory, the btree layer does that. -*/ -SQLITE_PRIVATE void *sqlite3HctBtreeSchema(Btree *pBt, int nBytes, void(*xFree)(void *)){ - HBtree *const p = (HBtree*)pBt; - void *pRet = 0; - if( p->pSchema ){ - pRet = p->pSchema; - }else if( nBytes>0 ){ - pRet = p->pSchema = sqlite3_malloc(nBytes); - if( pRet ){ - memset(pRet, 0, nBytes); - p->xSchemaFree = xFree; - } - } - return pRet; -} - -/* -** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared -** btree as the argument handle holds an exclusive lock on the -** sqlite_schema table. Otherwise SQLITE_OK. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSchemaLocked(Btree *p){ - return SQLITE_OK; -} - -SQLITE_PRIVATE HctDatabase *sqlite3HctDbFind(sqlite3 *db, int iDb){ - Btree *pBt = db->aDb[iDb].pBt; - return sqlite3IsHct(pBt) ? ((HBtree*)pBt)->pHctDb : 0; -} -SQLITE_PRIVATE HctJournal *sqlite3HctJrnlFind(sqlite3 *db){ - Btree *pBt = db->aDb[0].pBt; - return sqlite3IsHct(pBt) ? ((HBtree*)pBt)->pHctJrnl : 0; -} - -#ifndef SQLITE_OMIT_SHARED_CACHE -/* -** Obtain a lock on the table whose root page is iTab. The -** lock is a write lock if isWritelock is true or a read lock -** if it is false. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ - int rc = SQLITE_OK; - assert( 0 ); - return rc; -} -#endif - -#ifndef SQLITE_OMIT_INCRBLOB -/* -** Argument pCur must be a cursor opened for writing on an -** INTKEY table currently pointing at a valid table entry. -** This function modifies the data stored as part of that entry. -** -** Only the data content may only be modified, it is not possible to -** change the length of the data stored. If this function is called with -** parameters that attempt to write past the end of the existing data, -** no modifications are made and SQLITE_CORRUPT is returned. -*/ -SQLITE_PRIVATE int sqlite3HctBtreePutData(BtCursor *pCur, u32 offset, u32 amt, void *z){ - HBtCursor *pCsr = (HBtCursor*)pCur; - int rc = SQLITE_OK; - - if( pCsr->wrFlag==0 ){ - rc = SQLITE_READONLY; - }else{ - rc = hctReseekBlobCsr(pCsr); - } - if( rc==SQLITE_OK ){ - u32 nData = 0; - const void *aData = sqlite3HctBtreePayloadFetch(pCur, &nData); - if( offset+amt>nData ){ - rc = SQLITE_CORRUPT_BKPT; - }else{ - u8 *aBuf = (u8*)sqlite3_malloc(nData+1); - if( aBuf ){ - BtreePayload payload; - memcpy(aBuf, aData, nData); - memcpy(&aBuf[offset], z, amt); - - memset(&payload, 0, sizeof(payload)); - payload.nKey = sqlite3HctBtreeIntegerKey(pCur); - payload.pData = (const void*)aBuf; - payload.nData = nData; - rc = sqlite3HctBtreeInsert(pCur, &payload, 0, 0); - if( rc==SQLITE_OK ){ - int dummy = 0; - rc = sqlite3HctBtreeTableMoveto(pCur, payload.nKey, 0, &dummy); - assert( dummy==0 ); - } - sqlite3_free(aBuf); - }else{ - rc = SQLITE_NOMEM; - } - } - } - - return rc; -} - -/* -** Mark this cursor as an incremental blob cursor. -*/ -SQLITE_PRIVATE void sqlite3HctBtreeIncrblobCursor(BtCursor *pCur){ - HBtCursor *pCsr = (HBtCursor*)pCur; - sqlite3HctTreeCsrIncrblob(pCsr->pHctTreeCsr); -} -#endif - -/* -** Set both the "read version" (single byte at byte offset 18) and -** "write version" (single byte at byte offset 19) fields in the database -** header to iVersion. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSetVersion(Btree *pBtree, int iVersion){ - assert( 0 ); - return SQLITE_OK; -} - -/* -** Return true if the cursor has a hint specified. This routine is -** only used from within assert() statements -*/ -SQLITE_PRIVATE int sqlite3HctBtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ - return 0; -} - -/* -** Return true if the given Btree is read-only. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeIsReadonly(Btree *p){ - return 0; -} - -#if !defined(SQLITE_OMIT_SHARED_CACHE) -/* -** Return true if the Btree passed as the only argument is sharable. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeSharable(Btree *p){ - assert( 0 ); - return 0; -} - -/* -** Return the number of connections to the BtShared object accessed by -** the Btree handle passed as the only argument. For private caches -** this is always 1. For shared caches it may be 1 or greater. -*/ -SQLITE_PRIVATE int sqlite3HctBtreeConnectionCount(Btree *p){ - assert( 0 ); - return 1; -} -#endif - -SQLITE_PRIVATE int sqlite3HctBtreeExclusiveLock(Btree *p){ - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctBtreeTransferRow(BtCursor *p1, BtCursor *p2, i64 iKey){ - assert( 0 ); - return SQLITE_LOCKED; -} - -SQLITE_PRIVATE int sqlite3HctLockedErr(u32 pgno, const char *zReason){ - return SQLITE_LOCKED; -} - -SQLITE_PRIVATE i64 sqlite3HctMainStats(sqlite3 *db, int iStat, const char **pzStat){ - Btree *pBt = db->aDb[0].pBt; - - i64 iRet = 0; - - if( sqlite3IsHct(pBt) ){ - HBtree *pHct = (HBtree*)pBt; - switch( iStat ){ - case 0: - *pzStat = "nretry"; - iRet = pHct->stats.nRetry; - break; - case 1: - *pzStat = "nretrykey"; - iRet = pHct->stats.nRetryKey; - break; - case 2: - *pzStat = "nkeyop"; - iRet = pHct->stats.nKeyOp; - break; - } - } - - return iRet; -} - - -#endif /* SQLITE_ENABLE_HCT */ - -/************** End of hctree.c **********************************************/ -/************** Begin file hct_tree.c ****************************************/ -/* -** 2020 September 24 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - - -/* #include "hctInt.h" */ -/* #include */ -/* #include */ - -#define HCT_TREE_MAX_DEPTH 60 - -typedef struct HctTreeNode HctTreeNode; -typedef struct HctTreeRoot HctTreeRoot; - -struct HctTree { - int nRootHash; - int nRootEntry; - HctTreeRoot **apRootHash; - HctTreeNode *pRollback; /* List of rollback list items */ - HctTreeNode **apStmt; /* Array of open statement transactions */ - int nStmt; /* Allocated size of apStmt[] */ - int iStmt; /* Current entry in apStmt (-1 == none) */ -}; - -/* -** pReseek: -** Set to non-NULL if the cursor was disrupted by a write. The cursor -** should be seeked to the key in node pReseek. -*/ -struct HctTreeCsr { - HctTree *pTree; - HctTreeRoot *pRoot; - u8 bPin; /* True if cursor is pinned */ - u8 eIncrblob; /* Incrblob cursor state */ - i64 iSeekRowid; /* Last rowid value seeked to */ - int iSkip; /* -ve -> skip Prev(), +ve -> skip Next() */ - int iNode; /* Current depth */ - HctTreeNode *apNode[HCT_TREE_MAX_DEPTH]; - HctTreeNode *pReseek; - HctTreeCsr *pCsrNext; /* Next item in HctTreeRoot.pCsrList list */ -}; - -#define TREE_INCRBLOB_NONE 0 -#define TREE_INCRBLOB_READY 1 -#define TREE_INCRBLOB_ABORT 2 - -struct HctTreeNode { - i64 iKey; /* 64-bit key for this node */ - u8 bBlack; /* 1 for black node, 0 for red node */ - u8 nRef; /* Number of pointers to this node */ - u8 bDelete; /* True if this is a delete key */ - int nData; /* Size of aData[] in bytes */ - u8 *aData; /* Pointer to associated data (or NULL) */ - u32 iRoot; /* Root id of table this node belongs to */ - HctTreeNode *pLeft; /* Left child in tree */ - HctTreeNode *pRight; /* Right child in tree */ - - /* Rollback list related variables */ - HctTreeNode *pPrev; /* Previous entry in rollback list */ - HctTreeNode *pClobber; /* If non-NULL, entry this one clobbered */ -}; - -static HctTreeNode hctTreeGlobalEofNode; -#define TREE_RESEEK_EOF (&hctTreeGlobalEofNode) - -/* -** pCsrCache: -** List of unused cursor objects for this table/index. -*/ -struct HctTreeRoot { - u32 iRoot; /* Name of this tree structure */ - KeyInfo *pKeyInfo; - HctTreeNode *pNode; /* Root node of tree (or NULL) */ - HctTreeRoot *pHashNext; /* Next entry in hash-chain */ - HctTreeCsr *pCsrList; /* Cursors open on this tree */ - HctTreeCsr *pCsrCache; /* Cache of unused cursor objects */ -}; - -/* -** Allocate and return nByte bytes of zeroed memory. -*/ -static void *hctMallocZero(int nByte){ - void *pNew = sqlite3_malloc(nByte); - if( pNew ){ - memset(pNew, 0, nByte); - } - return pNew; -} - -SQLITE_PRIVATE int sqlite3HctTreeNew(HctTree **ppTree){ - HctTree *pNew; - int rc = SQLITE_OK; - - pNew = (HctTree*)hctMallocZero(sizeof(HctTree)); - if( pNew ){ - pNew->apRootHash = (HctTreeRoot**)hctMallocZero(sizeof(HctTreeRoot*)*16); - pNew->nRootHash = 16; - } - if( pNew==0 || pNew->apRootHash==0 ){ - sqlite3_free(pNew); - rc = SQLITE_NOMEM_BKPT; - } - - *ppTree = pNew; - return rc; -} - -static void treeNodeUnref(HctTreeNode *pNode){ - if( pNode!=TREE_RESEEK_EOF ){ - assert( pNode->nRef>0 ); - pNode->nRef--; - if( pNode->nRef==0 ){ - sqlite3_free(pNode); - } - } -} - -static void hctTreeFreeNode(HctTreeNode *pNode){ - if( pNode ){ - hctTreeFreeNode(pNode->pLeft); - hctTreeFreeNode(pNode->pRight); - assert( pNode->nRef==1 ); - treeNodeUnref(pNode); - } -} - -SQLITE_PRIVATE void sqlite3HctTreeFree(HctTree *pTree){ - if( pTree ){ - int i; - sqlite3HctTreeRelease(pTree, 0); - assert( pTree->pRollback==0 ); - for(i=0; inRootHash; i++){ - while( pTree->apRootHash[i] ){ - HctTreeRoot *p = pTree->apRootHash[i]; - HctTreeCsr *pCsr = p->pCsrCache; - sqlite3KeyInfoUnref(p->pKeyInfo); - pTree->apRootHash[i] = p->pHashNext; - while( pCsr ){ - HctTreeCsr *pNext = pCsr->pCsrNext; - sqlite3_free(pCsr); - pCsr = pNext; - } - hctTreeFreeNode(p->pNode); - sqlite3_free(p); - } - } - sqlite3_free(pTree->apRootHash); - sqlite3_free(pTree->apStmt); - sqlite3_free(pTree); - } -} - -#ifdef SQLITE_DEBUG -/* #include */ -static void hct_print_subtree2(HctTreeNode *pNode, char *aPrefix){ - if( pNode ){ - int n = strlen(aPrefix); - fprintf(stdout, "%-8s %s k=%lld\n", - aPrefix, pNode->bBlack ? "BLACK" : "RED ", pNode->iKey - ); - aPrefix[n] = 'L'; - hct_print_subtree2(pNode->pLeft, aPrefix); - aPrefix[n] = 'R'; - hct_print_subtree2(pNode->pRight, aPrefix); - aPrefix[n] = '\0'; - } -} -static void hct_print_subtree(HctTreeNode *pNode){ - if( pNode ){ - char aPrefix[64]; - memset(aPrefix, 0, sizeof(aPrefix)); - hct_print_subtree2(pNode, aPrefix); - fflush(stdout); - } -} - -/* -** To be used as: -** -** assert( hct_tree_check(pTree) ) -** -** An assert() fails if any of the following tree properties are violated: -** -** 1. Root node must be black. -** 2. A red node may not have a red parent. -** 3. Every path from root to NULL passes through the same number -** of black nodes. -*/ -static void hct_tree_check_subtree(HctTreeNode *pNode, int nDepth, int nExpect){ - if( pNode ){ - int nThisDepth = nDepth; - if( pNode->bBlack ){ - nThisDepth++; - }else{ - /* Property 2 - red parents have black children */ - assert( pNode->pLeft==0 || pNode->pLeft->bBlack ); - assert( pNode->pRight==0 || pNode->pRight->bBlack ); - } - - /* Property 3 - Every path from root to NULL has same black-depth */ - assert( (pNode->pLeft && pNode->pRight) || nThisDepth==nExpect ); - - hct_tree_check_subtree(pNode->pLeft, nThisDepth, nExpect); - hct_tree_check_subtree(pNode->pRight, nThisDepth, nExpect); - } - hct_print_subtree(0); /* no-op - just to avoid a warning */ -} -static int hct_tree_check(HctTreeRoot *pRoot){ - if( 0 && pRoot->pNode ){ - int nBlack = 0; - HctTreeNode *pNode = 0; - assert( pRoot->pNode->bBlack ); /* 1. Root is black */ - - /* Calculate the expected number of black nodes between root and NULL. */ - for(pNode=pRoot->pNode; pNode; pNode=pNode->pLeft){ - if( pNode->bBlack ) nBlack++; - } - - hct_tree_check_subtree(pRoot->pNode, 0, nBlack); - } - return 1; -} -#endif - -static HctTreeRoot *hctTreeFindRoot(HctTree *pTree, u32 iRoot){ - HctTreeRoot *pNew = 0; - - /* Search the hash table for an existing root. Return immediately if - ** one is found. */ - HctTreeRoot *pRoot; - for(pRoot = pTree->apRootHash[iRoot % pTree->nRootHash]; - pRoot; - pRoot=pRoot->pHashNext - ){ - if( pRoot->iRoot==iRoot ) return pRoot; - } - - /* If the hash table needs to grow, do that now */ - if( (pTree->nRootEntry+1)*2 > pTree->nRootHash ){ - int ii; - int nOld = pTree->nRootHash; - int nNew = nOld ? nOld*2 : 16; - HctTreeRoot **apNew = (HctTreeRoot**)sqlite3_realloc( - pTree->apRootHash, nNew*sizeof(HctTreeRoot*) - ); - if( apNew==0 ) return 0; - memset(&apNew[nOld], 0, (nNew-nOld)*sizeof(HctTreeRoot*)); - - for(ii=0; iipHashNext; - int iHash = p->iRoot % nNew; - p->pHashNext = apNew[iHash]; - apNew[iHash] = p; - p = pNext; - } - } - - pTree->apRootHash = apNew; - pTree->nRootHash = nNew; - } - - /* Allocate a new root and add it to the hash table */ - pNew = hctMallocZero(sizeof(HctTreeRoot)); - if( pNew ){ - int iHash = iRoot % pTree->nRootHash; - pNew->iRoot = iRoot; - pNew->pHashNext = pTree->apRootHash[iHash]; - pTree->apRootHash[iHash] = pNew; - pTree->nRootEntry++; - } - - return pNew; -} - -static void leftRotate(HctTreeNode **pp){ - HctTreeNode *pG = *pp; - HctTreeNode *pRight = pG->pRight; - - pG->pRight = pRight->pLeft; - pRight->pLeft = pG; - *pp = pRight; -} - -static void rightRotate(HctTreeNode **pp){ - HctTreeNode *pG = *pp; - HctTreeNode *pLeft = pG->pLeft; - - pG->pLeft = pLeft->pRight; - pLeft->pRight = pG; - *pp = pLeft; -} - -static HctTreeNode **hctTreeFindPointer(HctTreeCsr *pCsr, int iNode){ - HctTreeNode **pp; - if( iNode==0 ){ - assert( pCsr->apNode[0]==pCsr->pRoot->pNode ); - pp = &pCsr->pRoot->pNode; - }else{ - HctTreeNode *pParent = pCsr->apNode[iNode-1]; - if( pParent->pLeft==pCsr->apNode[iNode] ){ - pp = &pParent->pLeft; - }else{ - assert( pParent->pRight==pCsr->apNode[iNode] ); - pp = &pParent->pRight; - } - } - return pp; -} - -static void hctTreeFixInsert( - HctTree *pTree, - HctTreeCsr *pCsr, - HctTreeNode *pX -){ - HctTreeNode *pP = pCsr->apNode[pCsr->iNode]; - HctTreeNode *pG = pCsr->apNode[pCsr->iNode-1]; - HctTreeNode *pU; - - assert( pCsr->iNode>=1 ); - - if( pG->pLeft==pP ){ - pU = pG->pRight; - }else{ - pU = pG->pLeft; - } - - if( pU && pU->bBlack==0 ){ - /* Uncle of X is red */ - pP->bBlack = 1; - pU->bBlack = 1; - if( pCsr->iNode>1 ){ - pG->bBlack = 0; - if( pCsr->apNode[pCsr->iNode-2]->bBlack==0 ){ - pCsr->iNode -= 2; - hctTreeFixInsert(pTree, pCsr, pG); - } - } - }else{ - /* Uncle of X is black */ - int iCase = ((pG->pRight==pP) ? 2 : 0) + (pP->pRight==pX ? 1 : 0); - HctTreeNode **ppG = hctTreeFindPointer(pCsr, pCsr->iNode-1); - - switch( iCase ){ - case 1: /* left/right */ - leftRotate(&pG->pLeft); - pP = pX; - /* fall-through */ - case 0: /* left/left */ - rightRotate(ppG); - pP->bBlack = 1; - pG->bBlack = 0; - break; - case 2: /* right/left */ - rightRotate(&pG->pRight); - pP = pX; - /* fall-through */ - case 3: /* right/right */ - leftRotate(ppG); - pP->bBlack = 1; - pG->bBlack = 0; - break; - default: - assert( 0 ); - } - } -} - -static int hctSaveCursors( - HctTreeRoot *pRoot, - HctTreeCsr *pExcept, - int bAbortBlob, - i64 iRowid -){ - int rc = SQLITE_OK; - HctTreeCsr *pCsr; - for(pCsr=pRoot->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ - if( pCsr!=pExcept && pCsr->pReseek==0 ){ - if( pCsr->iNode>=0 ){ - if( pCsr->bPin ){ - return SQLITE_CONSTRAINT_PINNED; - } - pCsr->pReseek = pCsr->apNode[pCsr->iNode]; - pCsr->pReseek->nRef++; - }else{ - pCsr->pReseek = TREE_RESEEK_EOF; - } - } - if( bAbortBlob - && pCsr->eIncrblob==TREE_INCRBLOB_READY - && pCsr->iSeekRowid==iRowid - ){ - pCsr->eIncrblob = TREE_INCRBLOB_ABORT; - } - } - return rc; -} - - -static int hctTreeCsrSeekInt( - HctTreeCsr *pCsr, - i64 iKey, - int *pRes -){ - int rc = SQLITE_OK; /* Return code */ - int res = -1; /* Value to return via *pRes */ - HctTreeNode *pNode = pCsr->pRoot->pNode; - pCsr->iNode = -1; - while( pNode ){ - i64 iNodeKey = pNode->iKey; - pCsr->apNode[++pCsr->iNode] = pNode; - if( iNodeKey==iKey ){ - res = 0; - break; - } - if( iKeypLeft; - }else{ - res = -1; - pNode = pNode->pRight; - } - assert( pCsr->iNodepRoot->pNode; - pCsr->iNode = -1; - while( pNode ){ - pCsr->apNode[++pCsr->iNode] = pNode; - res = sqlite3VdbeRecordCompare(pNode->nData, pNode->aData, pRec); - if( res==0 ) break; - if( res>0 ){ - /* pRec is smaller than this node's key. Go left. */ - pNode = pNode->pLeft; - }else{ - /* pRec is larger than this node's key. Go left. */ - pNode = pNode->pRight; - } - assert( pCsr->iNodepRoot->pKeyInfo==0 ){ - pCsr->pRoot->pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); - } - - if( pRes ) *pRes = res; - return rc; -} - -static int hctTreeCsrSeekPacked( - HctTreeCsr *pCsr, - int nKey, - const u8 *aKey, - int *pRes -){ - int rc; - KeyInfo *pKeyInfo = pCsr->pRoot->pKeyInfo; - UnpackedRecord *pRec; - - assert( pKeyInfo ); - pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); - if( pRec ){ - sqlite3VdbeRecordUnpack(pKeyInfo, nKey, aKey, pRec); - rc = hctTreeCsrSeekUnpacked(pCsr, pRec, pRes); - sqlite3DbFree(pKeyInfo->db, pRec); - }else{ - rc = SQLITE_NOMEM; - } - return rc; -} - - -static int hctRestoreCursor(HctTreeCsr *pCsr, int *pRes){ - int rc = SQLITE_OK; - HctTreeNode *pReseek = pCsr->pReseek; - if( pReseek ){ - if( pReseek!=TREE_RESEEK_EOF ){ - if( pCsr->pRoot->pKeyInfo ){ - rc = hctTreeCsrSeekPacked(pCsr, pReseek->nData, pReseek->aData, pRes); - }else{ - rc = hctTreeCsrSeekInt(pCsr, pReseek->iKey, pRes); - } - treeNodeUnref(pReseek); - } - pCsr->pReseek = 0; - }else{ - *pRes = 0; - } - return rc; -} - -static void hctRestoreDiscard(HctTreeCsr *pCsr){ - if( pCsr->pReseek ){ - treeNodeUnref(pCsr->pReseek); - pCsr->pReseek = 0; - pCsr->iNode = -1; - } - pCsr->iSkip = 0; -} - -static int treeInsertNode( - HctTree *pTree, - int bRollback, - UnpackedRecord *pKey, - i64 iKey, - HctTreeNode *pNew -){ - HctTreeRoot *pRoot = hctTreeFindRoot(pTree, pNew->iRoot); - UnpackedRecord *pFree = 0; - int res = 0; - HctTreeCsr csr; - memset(&csr, 0, sizeof(csr)); - csr.pRoot = pRoot; - csr.pTree = pTree; - - /* Special case. If this insert is to effect a rollback on an index - ** tree, pKey will still be NULL. In this case construct a pKey value - ** with which to do the seek. */ - if( pRoot->pKeyInfo && pKey==0 ){ - assert( bRollback ); - pFree = sqlite3VdbeAllocUnpackedRecord(pRoot->pKeyInfo); - if( pFree==0 ){ - return SQLITE_NOMEM; - } - sqlite3VdbeRecordUnpack(pRoot->pKeyInfo, pNew->nData, pNew->aData, pFree); - pKey = pFree; - } - - sqlite3HctTreeCsrSeek(&csr, pKey, iKey, &res); - if( csr.iNode<0 ){ - assert( pRoot->pNode==0 ); - pRoot->pNode = pNew; - }else{ - HctTreeNode *pNode = csr.apNode[csr.iNode]; - if( res==0 ){ - pNew->pLeft = pNode->pLeft; - pNew->pRight = pNode->pRight; - pNew->bBlack = pNode->bBlack; - *(hctTreeFindPointer(&csr, csr.iNode)) = pNew; - if( bRollback==0 && pTree->iStmt>=0 ){ - pNew->pClobber = pNode; - assert( pNew->iKey==pNode->iKey ); - }else{ - treeNodeUnref(pNode); - } - }else{ - if( res<0 ){ - assert( pNode->pRight==0 ); - pNode->pRight = pNew; - }else{ - assert( pNode->pLeft==0 ); - pNode->pLeft = pNew; - } - if( pNode->bBlack==0 ){ - hctTreeFixInsert(pTree, &csr, pNew); - } - } - } - pNew->nRef++; - - /* Root node is always black */ - pRoot->pNode->bBlack = 1; - assert( hct_tree_check(pRoot) ); - if( pFree ){ - sqlite3DbFree(pFree->pKeyInfo->db, pFree); - } - return SQLITE_OK; -} - -static HctTreeNode *treeNewNode2( - HctTree *pTree, - HctTreeRoot *pRoot, - i64 iKey, - int bDelete, - int nData, - const u8 *aData, - int nZero -){ - HctTreeNode *pNew; - - pNew = (HctTreeNode*)hctMallocZero(sizeof(HctTreeNode) + nData + nZero); - if( pNew ){ - pNew->iKey = iKey; - pNew->nData = nData + nZero; - pNew->iRoot = pRoot->iRoot; - pNew->bDelete = bDelete; - if( (nData+nZero)>0 ){ - pNew->aData = (u8*)&pNew[1]; - memcpy(pNew->aData, aData, nData); - } - - if( pTree->iStmt>0 ){ - pNew->pPrev = pTree->pRollback; - pTree->pRollback = pNew; - pNew->nRef = 1; - } - } - - return pNew; -} - -/* -** Allocate a new tree node. Link it into the rollback list. -*/ -static HctTreeNode *treeNewNode( - HctTreeCsr *pCsr, - i64 iKey, - int bDelete, - int nData, - const u8 *aData, - int nZero -){ - return treeNewNode2( - pCsr->pTree, pCsr->pRoot, iKey, bDelete, nData, aData, nZero - ); -} - -static int treeInsert( - HctTreeCsr *pCsr, - UnpackedRecord *pKey, - i64 iKey, - int bDelete, - int nData, - const u8 *aData, - int nZero -){ - HctTree *pTree = pCsr->pTree; - HctTreeNode *pNew; - int rc = SQLITE_OK; - - assert( bDelete==0 || pKey || (aData==0 && nData==0 && nZero==0) ); - - pNew = treeNewNode(pCsr, iKey, bDelete, nData, aData, nZero); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - int nSave = 0; - int bPinSave = pCsr->bPin; - if( pKey ){ - nSave = pKey->nField; - sqlite3HctDbRecordTrim(pKey); - } - pCsr->bPin = 0; - rc = hctSaveCursors(pCsr->pRoot, 0, (pCsr->eIncrblob==0), iKey); - if( rc==SQLITE_OK && bPinSave ){ - int dummy; - rc = hctRestoreCursor(pCsr, &dummy); - } - pCsr->bPin = bPinSave; - if( rc==SQLITE_OK ){ - rc = treeInsertNode(pTree, pTree->iStmt<=0, pKey, iKey, pNew); - } - if( pKey ) pKey->nField = nSave; - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTreeUpdateMeta( - HctTree *pTree, - const u8 *aMeta, /* Meta data */ - int nMeta /* Size of meta data in bytes */ -){ - HctTreeRoot *pRoot = hctTreeFindRoot(pTree, 2); - HctTreeNode *pNew = treeNewNode2(pTree, pRoot, 0, 0, nMeta, aMeta, 0); - treeInsertNode(pTree, pTree->iStmt<=0, 0, 0, pNew); - return SQLITE_OK; -} - -/* -** This function is like sqlite3HctTreeInsert(), except that: -** -** 1) the new key is always larger than any existing key in the -** tree, and -** -** 2) unless the tree is empty, cursor pCsr is guaranteed to point to the -** largest record in it, and -** -** 3) before returning, this function leaves cursor pCsr pointing to the -** new entry. -*/ -SQLITE_PRIVATE int sqlite3HctTreeAppend( - HctTreeCsr *pCsr, - KeyInfo *pKeyInfo, - i64 iKey, - int nData, - const u8 *aData, - int nZero -){ - HctTreeRoot *pRoot = pCsr->pRoot; - int rc = SQLITE_OK; - - assert( pCsr->pTree->iStmt>0 ); - - if( pKeyInfo && pRoot->pKeyInfo==0 ){ - pRoot->pKeyInfo = sqlite3KeyInfoRef(pKeyInfo); - } - - rc = hctSaveCursors(pRoot, pCsr, pCsr->eIncrblob==0, iKey); - if( rc==SQLITE_OK ){ - HctTreeNode *pNew = treeNewNode(pCsr, iKey, 0, nData, aData, nZero); - if( pNew==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pNew->nRef++; - if( pRoot->pNode==0 ){ - pRoot->pNode = pNew; - pCsr->apNode[0] = pNew; - pCsr->iNode = 0; - }else{ - HctTreeNode *pParent = pCsr->apNode[pCsr->iNode]; - - assert( pCsr->iNode>=0 ); - assert( pParent->pRight==0 ); - pParent->pRight = pNew; - - if( pParent->bBlack==0 ){ - hctTreeFixInsert(pCsr->pTree, pCsr, pNew); - sqlite3HctTreeCsrLast(pCsr); - }else{ - pCsr->apNode[++pCsr->iNode] = pNew; - } - } - - /* Root node is always black */ - pRoot->pNode->bBlack = 1; - assert( hct_tree_check(pRoot) ); - } - } - - return rc; -} - -#if 0 -static void debug_write_op( - HctTreeCsr *pCsr, - const char *zOp, - UnpackedRecord *pKey, - i64 iKey, - int nData, - const u8 *aData -){ - printf("%s(%d) ", zOp, (int)pCsr->pRoot->iRoot); - if( pKey ){ - char *z = sqlite3HctDbRecordToText(0, aData, nData); - printf("[%s]\n", z); - }else{ - printf("%lld\n", iKey); - } - fflush(stdout); -} -#else -# define debug_write_op(r,s,w,x,y,z) -#endif - -SQLITE_PRIVATE int sqlite3HctTreeInsert( - HctTreeCsr *pCsr, - UnpackedRecord *pKey, - i64 iKey, - int nData, - const u8 *aData, - int nZero -){ - assert( pKey==0 || iKey==0 ); - debug_write_op(pCsr, "INSERT", pKey, iKey, nData, aData); - return treeInsert(pCsr, pKey, iKey, 0, nData, aData, nZero); -} - -SQLITE_PRIVATE int sqlite3HctTreeDeleteKey( - HctTreeCsr *pCsr, - UnpackedRecord *pKey, - i64 iKey, - int nData, - const u8 *aData -){ - debug_write_op(pCsr, "DELETE", pKey, iKey, nData, aData); - return treeInsert(pCsr, pKey, iKey, 1, nData, aData, 0); -} - -/* -** Cursor pCsr currently points at a double-black node. Fix it. -*/ -static void hctTreeFixDelete(HctTreeCsr *pCsr){ - assert( pCsr->iNode>0 || pCsr->pRoot->pNode->bBlack ); - if( pCsr->iNode>0 ){ - HctTreeNode *pDB; /* The double-black */ - HctTreeNode *pP; /* Parent of pDB */ - HctTreeNode *pS; /* Sibling of pDB */ - - pDB = pCsr->apNode[pCsr->iNode]; - pP = pCsr->apNode[pCsr->iNode-1]; - pS = pP->pLeft==pDB ? pP->pRight : pP->pLeft; - - if( pS->bBlack ){ - HctTreeNode *pR = 0; - if( pS->pLeft && pS->pLeft->bBlack==0 ){ - pR = pS->pLeft; - }else if( pS->pRight && pS->pRight->bBlack==0 ){ - pR = pS->pRight; - } - - if( pR ){ - /* Sibling is black, pR is a red child */ - HctTreeNode **ppP = hctTreeFindPointer(pCsr, pCsr->iNode-1); - int iCase = ((pP->pRight==pS) ? 2 : 0) + (pS->pRight==pR ? 1 : 0); - switch( iCase ){ - case 0: /* Left/Left */ - pR->bBlack = 1; - pS->bBlack = pP->bBlack; - rightRotate(ppP); - pP->bBlack = 1; - break; - case 1: /* Left/Right */ - leftRotate(&pP->pLeft); - rightRotate(ppP); - pR->bBlack = pP->bBlack; - pP->bBlack = 1; - break; - case 2: /* Right/Left */ - rightRotate(&pP->pRight); - leftRotate(ppP); - pR->bBlack = pP->bBlack; - pP->bBlack = 1; - break; - case 3: /* Right/Right */ - pR->bBlack = 1; - pS->bBlack = pP->bBlack; - leftRotate(ppP); - pP->bBlack = 1; - break; - } - }else{ - /* Sibling is black, with no red children. */ - pS->bBlack = 0; - if( pP->bBlack ){ - pCsr->iNode--; - hctTreeFixDelete(pCsr); - }else{ - pP->bBlack = 1; - } - } - }else{ - HctTreeNode **ppP = hctTreeFindPointer(pCsr, pCsr->iNode-1); - - /* Sibling is red. Because it is the red sibling of a double-black, it - ** must have children on both sides. And because it is red, both those - ** children must be black. */ - assert( pS->pLeft->bBlack && pS->pRight->bBlack ); - - if( pS==pP->pLeft ){ - rightRotate(ppP); - }else{ - leftRotate(ppP); - } - pS->bBlack = 1; - pP->bBlack = 0; - pCsr->apNode[pCsr->iNode-1] = pS; - pCsr->apNode[pCsr->iNode] = pP; - pCsr->apNode[pCsr->iNode+1] = pDB; - pCsr->iNode++; - hctTreeFixDelete(pCsr); - } - } -} - -static int treeDelete(HctTreeCsr *pCsr, int bRollback){ - HctTreeNode *pDel = pCsr->apNode[pCsr->iNode]; - HctTreeNode *pU = 0; - HctTreeNode *pReseek = 0; - int rc; - - /* Save the positions of all cursors on this table */ - rc = hctSaveCursors(pCsr->pRoot, pCsr, 0, 0); - if( rc ) return rc; - - assert( pCsr->pReseek==0 ); - assert( pCsr->iNode>=0 ); -#if 0 - fprintf(stdout, "deleting %lld\n", iKey); - hct_print_subtree(pCsr->pRoot->pNode); -#endif - - if( bRollback==0 ){ - HctTreeNode *pEntry = hctMallocZero(sizeof(*pEntry)); - if( pEntry==0 ) return SQLITE_NOMEM; - pEntry->iKey = pDel->iKey; - pEntry->pClobber = pDel; - pEntry->pPrev = pCsr->pTree->pRollback; - pEntry->nRef = 1; - pEntry->iRoot = pCsr->pRoot->iRoot; - pDel->nRef++; - pCsr->pTree->pRollback = pEntry; - pReseek = pDel; - pReseek->nRef++; - } - - /* If node pDel has two children, swap it with its immediate successor - ** in the tree. This node is guaranteed to have pNode->pLeft==0. */ - if( pDel->pLeft && pDel->pRight ){ - int iDel = pCsr->iNode; - HctTreeNode *pSwap; - sqlite3HctTreeCsrNext(pCsr); - pSwap = pCsr->apNode[pCsr->iNode]; - SWAP(HctTreeNode*, pSwap->pLeft, pDel->pLeft); - SWAP(HctTreeNode*, pSwap->pRight, pDel->pRight); - SWAP(int, pSwap->bBlack, pDel->bBlack); - *hctTreeFindPointer(pCsr, iDel) = pSwap; - pCsr->apNode[iDel] = pSwap; - *hctTreeFindPointer(pCsr, pCsr->iNode) = pDel; - pCsr->apNode[pCsr->iNode] = pDel; - - assert( pDel->pLeft==0 ); - assert( hct_tree_check(pCsr->pRoot) ); - } - - assert( pCsr->apNode[pCsr->iNode]==pDel ); - assert( pDel->pLeft==0 || pDel->pRight==0 ); - - pU = pDel->pLeft ? pDel->pLeft : pDel->pRight; - *hctTreeFindPointer(pCsr, pCsr->iNode) = pU; - if( pDel->bBlack==0 || (pU && pU->bBlack==0) || pCsr->pRoot->pNode==0 ){ - /* Simple case. If either pDel or its child pU are red, then - ** replacing the pDel with the child and ensuring the child is - ** colored black is enough. No change in black-height for the - ** children of pU. */ - if( pU ) pU->bBlack = 1; - }else{ - pCsr->apNode[pCsr->iNode] = pU; - hctTreeFixDelete(pCsr); - } - - treeNodeUnref(pDel); - assert( pCsr->pReseek==0 ); - pCsr->pReseek = pReseek; - -#if 0 - fprintf(stdout, "finished deleting %lld\n", iKey); - hct_print_subtree(pCsr->pRoot->pNode); -#endif - assert( hct_tree_check(pCsr->pRoot) ); - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeDelete(HctTreeCsr *pCsr){ - int rc; - assert( pCsr->pReseek==0 ); - rc = treeDelete(pCsr, 0); - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTreeBegin(HctTree *pTree, int iStmt){ - if( iStmt>pTree->iStmt ){ - int ii; - if( pTree->nStmt<=iStmt ){ - int nNew = iStmt+16; - HctTreeNode **apNew = (HctTreeNode**)hctMallocZero(nNew*sizeof(*apNew)); - if( apNew==0 ) return SQLITE_NOMEM; - if( pTree->apStmt ){ - memcpy(apNew, pTree->apStmt, pTree->nStmt*sizeof(*apNew)); - sqlite3_free(pTree->apStmt); - } - pTree->apStmt = apNew; - pTree->nStmt = nNew; - } - for(ii=pTree->iStmt+1; ii<=iStmt; ii++){ - pTree->apStmt[ii] = pTree->pRollback; - } - pTree->iStmt = iStmt; - } - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeRelease(HctTree *pTree, int iStmt){ - if( iStmtiStmt ){ - if( iStmt==0 ){ - HctTreeNode *pStop = pTree->apStmt[iStmt+1]; - HctTreeNode *pNode; - HctTreeNode *pPrev; - for(pNode=pTree->pRollback; pNode!=pStop; pNode=pPrev){ - pPrev = pNode->pPrev; - if( pNode->pClobber ) treeNodeUnref(pNode->pClobber); - treeNodeUnref(pNode); - } - pTree->pRollback = pStop; - } - pTree->iStmt = iStmt; - } - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeRollbackTo(HctTree *pTree, int iStmt){ - int rc = SQLITE_OK; - if( iStmt<=pTree->iStmt ){ - HctTreeNode *pStop = pTree->apStmt[iStmt]; - HctTreeNode *pNode; - HctTreeNode *pPrev; - for(pNode=pTree->pRollback; pNode!=pStop; pNode=pPrev){ - KeyInfo *pKeyInfo = 0; - UnpackedRecord *pRec = 0; - HctTreeRoot *pRoot = hctTreeFindRoot(pTree, pNode->iRoot); - - pPrev = pNode->pPrev; - - if( (pKeyInfo = pRoot->pKeyInfo) ){ - pRec = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); - if( pRec==0 ){ - rc = SQLITE_NOMEM; - pStop = pNode; - break; - } - sqlite3VdbeRecordUnpack(pKeyInfo, pNode->nData, pNode->aData, pRec); - } - - if( pNode->pClobber ){ - HctTreeNode *pClobber = pNode->pClobber; - assert( pNode->iKey==pNode->pClobber->iKey ); - pClobber->pLeft = pClobber->pRight = 0; - pClobber->bBlack = 0; - if( (rc = hctSaveCursors(pRoot, 0, 0, 0)) - || (rc = treeInsertNode(pTree, 1, pRec, pNode->iKey, pClobber)) ){ - pStop = pNode; - break; - } - treeNodeUnref(pClobber); - }else{ - HctTreeCsr csr; - int res; - memset(&csr, 0, sizeof(csr)); - csr.pRoot = pRoot; - csr.pTree = pTree; - sqlite3HctTreeCsrSeek(&csr, pRec, pNode->iKey, &res); - if( res==0 ) treeDelete(&csr, 1); - } - if( pRec ) sqlite3DbFree(pKeyInfo->db, pRec); - treeNodeUnref(pNode); - } - pTree->pRollback = pStop; - pTree->iStmt = iStmt; - } - return rc; -} - -/* -** Clear the contents of the entire tree. -*/ -SQLITE_PRIVATE void sqlite3HctTreeClear(HctTree *pTree){ - HctTreeRoot **pp; - HctTreeRoot **pEnd = &pTree->apRootHash[pTree->nRootHash]; - for(pp=pTree->apRootHash; pppHashNext){ - hctSaveCursors(p, 0, 0, 0); - hctTreeFreeNode(p->pNode); - p->pNode = 0; - sqlite3KeyInfoUnref(p->pKeyInfo); - p->pKeyInfo = 0; - } - } -} - -SQLITE_PRIVATE int sqlite3HctTreeClearOne(HctTree *pTree, u32 iRoot, i64 *pnRow){ - HctTreeCsr csr; - int rc = SQLITE_OK; - int nRow = 0; - - memset(&csr, 0, sizeof(csr)); - csr.pTree = pTree; - csr.pRoot = hctTreeFindRoot(pTree, iRoot); - csr.iNode = -1; - rc = hctSaveCursors(csr.pRoot, 0, 0, 0); - if( rc ) return rc; - while( rc==SQLITE_OK && csr.pRoot->pNode ){ - sqlite3HctTreeCsrFirst(&csr); - rc = sqlite3HctTreeDelete(&csr); - nRow++; - hctRestoreDiscard(&csr); - } - if( pnRow ) *pnRow = nRow; - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrOpen(HctTree *pTree, u32 iRoot, HctTreeCsr **ppCsr){ - int rc = SQLITE_OK; - HctTreeCsr *pNew = 0; - HctTreeRoot *pRoot = hctTreeFindRoot(pTree, iRoot); - if( pRoot==0 ){ - rc = SQLITE_NOMEM; - }else{ - if( pRoot->pCsrCache ){ - pNew = pRoot->pCsrCache; - pRoot->pCsrCache = pNew->pCsrNext; - pNew->pCsrNext = 0; - assert( pNew->pTree==pTree ); - assert( pNew->pRoot==pRoot ); - assert( pNew->iNode==-1 ); - assert( pNew->eIncrblob==TREE_INCRBLOB_NONE ); - }else{ - pNew = (HctTreeCsr*)hctMallocZero(sizeof(HctTreeCsr)); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pNew->pTree = pTree; - pNew->pRoot = pRoot; - pNew->iNode = -1; - } - } - pNew->pCsrNext = pRoot->pCsrList; - pRoot->pCsrList = pNew; - } - *ppCsr = pNew; - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrClose(HctTreeCsr *pCsr){ - if( pCsr ){ - HctTreeCsr **pp; - for(pp=&pCsr->pRoot->pCsrList; *pp!=pCsr; pp=&(*pp)->pCsrNext); - *pp = pCsr->pCsrNext; - if( pCsr->pReseek ){ - treeNodeUnref(pCsr->pReseek); - pCsr->pReseek = 0; - } - pCsr->pCsrNext = pCsr->pRoot->pCsrCache; - pCsr->pRoot->pCsrCache = pCsr; - pCsr->iSkip = 0; - pCsr->bPin = 0; - pCsr->iNode = -1; - pCsr->eIncrblob = TREE_INCRBLOB_NONE; - } - return SQLITE_OK; -} - -/* -** An integer is written into *pRes which is the result of -** comparing the key with the entry to which the cursor is -** pointing. The meaning of the integer written into -** *pRes is as follows: -** -** *pRes<0 The cursor is left pointing at an entry that -** is smaller than intKey/pIdxKey. Or, the table is empty -** and the cursor is therefore left point to nothing. -** -** *pRes==0 The cursor is left pointing at an entry that -** exactly matches intKey/pIdxKey. -** -** *pRes>0 The cursor is left pointing at an entry that -** is larger than intKey/pIdxKey. -*/ -SQLITE_PRIVATE int sqlite3HctTreeCsrSeek( - HctTreeCsr *pCsr, - UnpackedRecord *pRec, - i64 iKey, - int *pRes -){ - hctRestoreDiscard(pCsr); - pCsr->iSeekRowid = iKey; - if( pRec ){ - return hctTreeCsrSeekUnpacked(pCsr, pRec, pRes); - } - return hctTreeCsrSeekInt(pCsr, iKey, pRes); -} - -/* -** Move the cursor to EOF. -*/ -SQLITE_PRIVATE void sqlite3HctTreeCsrClear(HctTreeCsr *pCsr){ - hctRestoreDiscard(pCsr); - pCsr->iNode = -1; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrNext(HctTreeCsr *pCsr){ - int iNode; - int res = 0; - - assert( pCsr->pReseek==0 || pCsr->iSkip==0 ); - if( pCsr->iSkip>0 ){ - pCsr->iSkip = 0; - return SQLITE_OK; - } - if( hctRestoreCursor(pCsr, &res) ) return SQLITE_NOMEM; - if( res>0 ) return SQLITE_OK; - - iNode = pCsr->iNode; - if( iNode>=0 ){ - HctTreeNode *pNode = pCsr->apNode[iNode]; - assert( iNode>=0 ); - if( pNode->pRight ){ - pNode = pNode->pRight; - while( pNode ){ - iNode++; - pCsr->apNode[iNode] = pNode; - pNode = pNode->pLeft; - } - }else{ - while( (--iNode)>=0 ){ - HctTreeNode *pParent = pCsr->apNode[iNode]; - assert( pNode==pParent->pLeft || pNode==pParent->pRight ); - if( pNode==pParent->pLeft ) break; - pNode = pParent; - } - } - pCsr->iNode = iNode; - } - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrPrev(HctTreeCsr *pCsr){ - int iNode; - int res = 0; - - assert( pCsr->pReseek==0 || pCsr->iSkip==0 ); - if( pCsr->iSkip<0 ){ - pCsr->iSkip = 0; - return SQLITE_OK; - } - if( hctRestoreCursor(pCsr, &res) ) return SQLITE_NOMEM; - if( res<0 ) return SQLITE_OK; - - iNode = pCsr->iNode; - if( iNode>=0 ){ - HctTreeNode *pNode = pCsr->apNode[iNode]; - assert( iNode>=0 ); - if( pNode->pLeft ){ - pNode = pNode->pLeft; - while( pNode ){ - iNode++; - pCsr->apNode[iNode] = pNode; - pNode = pNode->pRight; - } - }else{ - while( (--iNode)>=0 ){ - HctTreeNode *pParent = pCsr->apNode[iNode]; - assert( pNode==pParent->pLeft || pNode==pParent->pRight ); - if( pNode==pParent->pRight ) break; - pNode = pParent; - } - } - pCsr->iNode = iNode; - } - return SQLITE_OK; -} - -/* -** Return false if cursor points to a valid entry, or true otherwise. -*/ -SQLITE_PRIVATE int sqlite3HctTreeCsrEof(HctTreeCsr *pCsr){ - return (pCsr->iNode<0); -} - -static void hctTreeCursorEnd(HctTreeCsr *pCsr, int bLast){ - int iNode = -1; - HctTreeNode *pNode = pCsr->pRoot->pNode; - - hctRestoreDiscard(pCsr); - while( pNode ){ - iNode++; - assert( iNodeapNode[iNode] = pNode; - pNode = (bLast ? pNode->pRight : pNode->pLeft); - } - pCsr->iNode = iNode; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrFirst(HctTreeCsr *pCsr){ - hctTreeCursorEnd(pCsr, 0); - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrLast(HctTreeCsr *pCsr){ - hctTreeCursorEnd(pCsr, 1); - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrKey(HctTreeCsr *pCsr, i64 *piKey){ - assert( pCsr->iNode>=0 ); - assert( pCsr->pReseek==0 ); - *piKey = pCsr->apNode[pCsr->iNode]->iKey; - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrData(HctTreeCsr *pCsr, int *pnData, const u8 **paData){ - HctTreeNode *pNode = pCsr->apNode[pCsr->iNode]; - assert( pCsr->pReseek==0 ); - assert( pCsr->iNode>=0 ); - *pnData = pNode->nData; - if( paData ) *paData = pNode->aData; - return SQLITE_OK; -} - -/* -** Return non-zero if the cursor is pointing to a delete key. Return zero -** if it is pointing to an insert or to EOF. -*/ -SQLITE_PRIVATE int sqlite3HctTreeCsrIsDelete(HctTreeCsr *pCsr){ - assert( pCsr->pReseek==0 ); - return (pCsr->iNode>=0 && pCsr->apNode[pCsr->iNode]->bDelete); -} - -SQLITE_PRIVATE void sqlite3HctTreeCsrPin(HctTreeCsr *pCsr){ - pCsr->bPin = 1; -} -SQLITE_PRIVATE void sqlite3HctTreeCsrUnpin(HctTreeCsr *pCsr){ - pCsr->bPin = 0; -} - -SQLITE_PRIVATE void sqlite3HctTreeCsrIncrblob(HctTreeCsr *pCsr){ - if( pCsr->eIncrblob==TREE_INCRBLOB_NONE ){ - pCsr->eIncrblob = TREE_INCRBLOB_READY; - } -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrHasMoved(HctTreeCsr *pCsr){ - return pCsr && pCsr->pReseek!=0; -} - -SQLITE_PRIVATE int sqlite3HctTreeCsrReseek(HctTreeCsr *pCsr, int *pRes){ - assert( - pCsr->eIncrblob==TREE_INCRBLOB_READY - || pCsr->eIncrblob==TREE_INCRBLOB_ABORT - ); - assert( pCsr->pReseek ); - if( pCsr->eIncrblob==TREE_INCRBLOB_ABORT ) return SQLITE_ABORT; - return sqlite3HctTreeCsrSeek(pCsr, 0, pCsr->iSeekRowid, pRes); -} - - -SQLITE_PRIVATE int sqlite3HctTreeCsrRestore(HctTreeCsr *pCsr, int *pIsDifferent){ - int rc = SQLITE_OK; - if( pCsr->pReseek ){ - assert( pCsr->iSkip==0 ); - rc = hctRestoreCursor(pCsr, &pCsr->iSkip); - } - *pIsDifferent = pCsr->iSkip; - return rc; -} - -SQLITE_PRIVATE u32 sqlite3HctTreeCsrRoot(HctTreeCsr *pCsr){ - return pCsr->pRoot->iRoot; -} - -SQLITE_PRIVATE int sqlite3HctTreeForeach( - HctTree *pTree, - int bSchemaOp, - void *pCtx, - int (*x)(void *, u32, KeyInfo*) -){ - int i; - int rc = SQLITE_OK; - for(i=0; rc==SQLITE_OK && inRootHash; i++){ - HctTreeRoot *p; - for(p=pTree->apRootHash[i]; rc==SQLITE_OK && p; p=p->pHashNext){ - if( p->pNode && (bSchemaOp || p->iRoot!=HCT_TREE_SCHEMAOP_ROOT) ){ - rc = x(pCtx, p->iRoot, p->pKeyInfo); - } - } - } - return rc; -} - - - -/************** End of hct_tree.c ********************************************/ -/************** Begin file hct_file.c ****************************************/ -/* -** 2020 October 13 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - - -/* #include "hctInt.h" */ -/* #include */ -/* #include */ -/* #include */ - -/* #include */ -/* #include */ -#include -/* #include */ -/* #include */ - -/* #include */ -/* #include */ - -#define HCT_DEFAULT_PAGESIZE 4096 - -/* -** The database file is extended and managed in chunks of -** HCT_DEFAULT_PAGEPERCHUNK pages. Since pages are normally 4096 bytes, this -** is 2MiB by default. But, if the file is mmap()ed 2MiB at a time, we -** quickly read the system limit for number of mappings (on Linux, this is -** kernel parameter vm.max_map_count - 65530 by default). So, each mapping -** is made for HCT_MMAP_QUANTA times this amount. Since we need mappings for -** both the database file and page-map, this means we can mmap() a database of: -** -** 32765 * 1024*512*4096 bytes -** -** or around 64TiB. -*/ -#define HCT_DEFAULT_PAGEPERCHUNK 512 -#define HCT_MMAP_QUANTA 1024 - -#define HCT_HEADER_PAGESIZE 4096 - -#define HCT_LOCK_OFFSET (1024*1024) -#define HCT_LOCK_SIZE 1 - - -/* -** Pagemap slots used for special purposes. -*/ -#define HCT_ROOTPAGE_SCHEMA 1 -#define HCT_ROOTPAGE_META 2 - -#define HCT_PAGEMAP_LOGICAL_EOF 3 -#define HCT_PAGEMAP_PHYSICAL_EOF 4 - -#define HCT_PAGEMAP_TRANSID_EOF 16 - -#define HCT_PMF_LOGICAL_EVICTED (((u64)0x00000001)<<56) -#define HCT_PMF_LOGICAL_IRREVICTED (((u64)0x00000002)<<56) -#define HCT_PMF_PHYSICAL_IN_USE (((u64)0x00000004)<<56) -#define HCT_PMF_LOGICAL_IN_USE (((u64)0x00000008)<<56) -#define HCT_PMF_LOGICAL_IS_ROOT (((u64)0x00000010)<<56) - -#define HCT_FIRST_LOGICAL 33 - -/* -** Masks for use with pagemap values. -*/ -#define HCT_PAGEMAP_FMASK (((u64)0xFF) << 56) /* Flags MASK */ -#define HCT_PAGEMAP_VMASK (~HCT_PAGEMAP_FMASK) /* Value MASK */ - -#define assert_pgno_ok(iPg) assert( ((u64)iPg)<((u64)1<<48) && iPg>0 ) - -typedef struct HctFileServer HctFileServer; -typedef struct HctMapping HctMapping; -typedef struct HctMappingChunk HctMappingChunk; - -/* -** Global variables for this module. -** -** pServerList: -** Linked list of distinct files opened by this process. Access to this -** variable is protected by SQLITE_MUTEX_STATIC_VFS1. -** -** nCASFailCnt/nCASFailReset: -** These are used to inject CAS instruction failures for testing purposes. -** Set by the sqlite3_hct_cas_failure() API. They are not threadsafe. -** -** nProcFailCnt -** These are used to inject process failures (i.e. abort() calls) for -** testing purposes. Set by the sqlite3_hct_proc_failure() API. Not -** threadsafe. -*/ -static struct HctFileGlobalVars { - HctFileServer *pServerList; - - int nCASFailCnt; - int nCASFailReset; - - int nProcFailCnt; -} g; - -SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset){ - g.nCASFailCnt = nCASFailCnt; - g.nCASFailReset = nCASFailReset; -} -SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt){ - g.nProcFailCnt = nProcFailCnt; -} - -/* -** This is called to check if a CAS fault should be injected. It returns -** true if a fault should be injected, or false otherwise. -*/ -static int inject_cas_failure(void){ - if( g.nCASFailCnt>0 ){ - if( (--g.nCASFailCnt)==0 ){ - g.nCASFailCnt = g.nCASFailReset; - return 1; - } - } - if( g.nProcFailCnt>0 ){ - if( (--g.nProcFailCnt)==0 ){ - abort(); - } - } - return 0; -} - -/* -** nRef: -** Number of references to this object held by the system. The -** HctFileServer object may hold one reference, each HctFile may -** also hold one. -** -** iLogPPC: -** Log2 of number of pages-per-chunk. e.g. if there are 512 pages -** on each mapping chunk, this value is set to 9. -** -** aPagemap/nPagemap: -** Mapping of the current page-map file. -*/ -struct HctMappingChunk { - void *pData; /* Mapping of chunk in data file */ - u64 *aMap; /* Mapping of chunk in map file */ -}; -struct HctMapping { - int nRef; /* Number of pointers to this array */ - int szPage; /* Size of pages in bytes */ - int nChunk; /* Size of aChunk[] array */ - u32 mapShift; - u32 mapMask; - HctMappingChunk *aChunk; /* Array of database chunk mappings */ -}; - -/* -** eInitState: -** Set to one of the HCT_INIT_XXX constants defined below. See comments -** above those constants for details. -** -** iNextFileId: -** Used to allocate unique ids to each HctFile associated with this -** HctFileServer object. These ids are used for debugging, and also -** to generate log file names. -*/ -struct HctFileServer { - sqlite3_mutex *pMutex; /* Mutex to protect this object */ - HctFile *pFileList; - - u64 iCommitId; /* CID value */ - u64 nWriteCount; /* Write count */ - - int iNextFileId; - char *zPath; /* Path to database (aFdDb[0]) */ - char *zDir; /* Directory component of zPath */ - int fdMap; /* Read/write file descriptor for page-map */ - int nFdDb; /* Number of valid entries in aFdDb[] */ - int aFdDb[HCT_MAX_NDBFILE]; - - int szPage; /* Page size for database */ - int nPagePerChunk; - HctMapping *pMapping; /* Mapping of pagemap and db pages */ - - int bReadOnlyMap; /* True for a read-only mapping of db file */ - - HctTMapServer *pTMapServer; /* Transaction map server */ - HctPManServer *pPManServer; /* Page manager server */ - int eInitState; - - void *pJrnlPtr; - void(*xJrnlDel)(void*); - - i64 st_dev; /* File identification 1 */ - i64 st_ino; /* File identification 2 */ - HctFileServer *pServerNext; /* Next object in g.pServerList list */ -}; - -/* -** System initialization state: -** -** HCT_INIT_NONE: -** No initialization has been done. -** -** HCT_INIT_RECOVER1: -** The sqlite_schema table (root page 1) has been recovered. And the -** page-map scanned to initialize the page-manager. -** -** HCT_INIT_RECOVER2: -** Other tables (apart from sqlite_schema) have been recovered. -** Initialization has finished. -*/ -#define HCT_INIT_NONE 0 -#define HCT_INIT_RECOVER1 1 -#define HCT_INIT_RECOVER2 2 - -/* -** Event counters used by the hctstats virtual table. -*/ -typedef struct HctFileStats HctFileStats; -struct HctFileStats { - i64 nCasAttempt; - i64 nCasFail; - i64 nIncrAttempt; - i64 nIncrFail; - i64 nMutex; - i64 nMutexBlock; -}; - -/* -** iCurrentTid: -** Most recent value returned by sqlite3HctFileAllocateTransid(). This -** is the current TID while the upper layer is writing the database, and -** meaningless at other times. Used by this object as the "current TID" -** when freeing a page. -** -** nPageAlloc: -** The total number of physical page allocations requested by the upper -** layer in the lifetime of this object. -*/ -struct HctFile { - HctConfig *pConfig; /* Connection configuration object */ - HctFileServer *pServer; /* Connection to global db object */ - HctFile *pFileNext; /* Next handle opened on same file */ - int iFileId; /* Id used for debugging output */ - int eInitState; - - HctTMapClient *pTMapClient; /* Transaction map client object */ - HctPManClient *pPManClient; /* Transaction map client object */ - - u64 iCurrentTid; - u64 nPageAlloc; - - /* Copies of HctFileServer variables */ - int szPage; - HctMapping *pMapping; - - /* Event counters used by the hctstats virtual table */ - HctFileStats stats; -}; - -static int hctLog2(int n){ - int i; - assert( (n & (n-1))==0 ); - for(i=0; (1<0 ){ - if( (--g.nCASFailCnt)==0 ){ - g.nCASFailCnt = g.nCASFailReset; - return 0; - } - } -#endif - return HctCASBool(pPtr, iOld, iNew); -} - -/* -** Allocate and return a new HctMapping object with enough space for -** nChunk chunks. -*/ -static HctMapping *hctMappingNew(int *pRc, HctMapping *pOld, int nChunk){ - HctMapping *pNew = 0; - if( *pRc==SQLITE_OK ){ - int nByte = sizeof(HctMapping) + nChunk*sizeof(HctMappingChunk); - pNew = (HctMapping*)sqlite3MallocZero(nByte); - if( pNew ){ - pNew->aChunk = (HctMappingChunk*)&pNew[1]; - pNew->nRef = 1; - pNew->nChunk = nChunk; - if( pOld ){ - assert( nChunk>pOld->nChunk ); - pNew->mapShift = pOld->mapShift; - pNew->mapMask = pOld->mapMask; - pNew->szPage = pOld->szPage; - memcpy(pNew->aChunk,pOld->aChunk,pOld->nChunk*sizeof(HctMappingChunk)); - } - }else{ - *pRc = SQLITE_NOMEM_BKPT; - } - } - return pNew; -} - -static void hctMappingUnref(HctMapping *p){ - if( p ){ - p->nRef--; - if( p->nRef==0 ){ - sqlite3_free(p); - } - } -} - - -static u64 *hctPagemapPtr(HctMapping *p, u32 iSlot){ - return &(p->aChunk[(iSlot-1) >> p->mapShift].aMap[(iSlot-1) & p->mapMask]); -} - -static void *hctPagePtr(HctMapping *p, u32 iPhys){ - return &((u8*)(p->aChunk[(iPhys-1) >> p->mapShift].pData))[ - ((iPhys-1) & p->mapMask) * p->szPage - ]; -} - -/* -** Buffer aBuf[] is p->szPage bytes in size. This function writes the -** contents of said buffer to physical database page iPhys. -*/ -static int hctPageWriteToDisk(HctFileServer *p, u64 iPhys, u8 *aBuf){ - i64 iChunk = ((iPhys-1) / p->nPagePerChunk); - int iFd = iChunk % p->nFdDb; - i64 iOff = p->szPage * ( - ((iChunk / p->nFdDb) * p->nPagePerChunk) - + (iPhys-1) % p->nPagePerChunk - ); - ssize_t res; - assert_pgno_ok( iPhys ); - res = pwrite(p->aFdDb[iFd], aBuf, p->szPage, iOff); - return (res==p->szPage ? SQLITE_OK : SQLITE_ERROR); -} - -static void hctFilePagemapSetDirect(HctMapping *p, u32 iSlot, u64 iNew){ - u64 *pPtr = hctPagemapPtr(p, iSlot); - *pPtr = iNew; -} - -static void hctFilePagemapSetFlag(HctMapping *p, u32 iSlot, u64 mask){ - u64 *pPtr = hctPagemapPtr(p, iSlot); - *pPtr = *pPtr | mask; -} - -/* -** Use a CAS instruction to the value of page-map slot iSlot. Return true -** if the slot is successfully set to value iNew, or false otherwise. -*/ -static int hctFilePagemapSet(HctFile *pFile, u32 iSlot, u64 iOld, u64 iNew){ - u64 *pPtr = hctPagemapPtr(pFile->pMapping, iSlot); - pFile->stats.nCasAttempt++; - if( hctBoolCompareAndSwap64(pPtr, iOld, iNew) ) return 1; - pFile->stats.nCasFail++; - return 0; -} - - -static u64 hctFilePagemapGet(HctMapping *p, u32 iSlot){ - return HctAtomicLoad( hctPagemapPtr(p, iSlot) ); -} - -static u64 hctFilePagemapGetSafe(HctMapping *p, u32 iSlot){ - if( ((iSlot-1)>>p->mapShift)>=p->nChunk ){ - return 0; - } - return hctFilePagemapGet(p, iSlot); -} - -static u64 hctFileAtomicIncr(HctFile *pFile, u64 *pPtr, int nIncr){ - u64 iOld; - while( 1 ){ - iOld = HctAtomicLoad(pPtr); - pFile->stats.nIncrAttempt++; - if( hctBoolCompareAndSwap64(pPtr, iOld, iOld+nIncr) ) return iOld+nIncr; - pFile->stats.nIncrFail++; - } -} - -/* -** Increment the value in slot iSlot by nIncr. Return the new value. -*/ -static u64 hctFilePagemapIncr(HctFile *pFile, u32 iSlot, int nIncr){ - u64 *pPtr = hctPagemapPtr(pFile->pMapping, iSlot); - u64 iOld; - while( 1 ){ - iOld = HctAtomicLoad(pPtr); - pFile->stats.nIncrAttempt++; - if( hctBoolCompareAndSwap64(pPtr, iOld, iOld+nIncr) ) return iOld+nIncr; - pFile->stats.nIncrFail++; - } -} - -/* -** Set the physical page id mapped from logical page iLogical to physical -** page id iNew. Return 1 if successful, or 0 if the operation fails. The -** operation fails if either: -** -** * the LOGICAL_EVICTED flag is already set for the logical page, or -** * the current physical page id to which the logical page is mapped -** is not equal to parameter iOld. -*/ -static int hctFilePagemapSetLogical( - HctFile *pFile, /* Use mapping object of this file */ - u32 iLogical, /* Logical page to set the physical id for */ - u64 iOld, /* Old physical page id */ - u64 iNew /* New physical page id */ -){ - HctMapping *p = pFile->pMapping; - while( 1 ){ - u64 i1 = hctFilePagemapGet(p, iLogical); - u64 iOld1 = (iOld & HCT_PAGEMAP_VMASK) | (i1 & HCT_PAGEMAP_FMASK); - u64 iNew1 = (iNew & HCT_PAGEMAP_VMASK) | (i1 & HCT_PAGEMAP_FMASK); - - iNew1 |= HCT_PMF_LOGICAL_IN_USE; - - /* If a CAS instruction failure injection is scheduled, return 0 - ** to the caller. */ - if( inject_cas_failure() ) return 0; - - /* This operation fails if LOGICAL_EVICTED has been set. */ - iOld1 &= ~HCT_PMF_LOGICAL_EVICTED; - iNew1 &= ~HCT_PMF_LOGICAL_EVICTED; - - if( hctFilePagemapSet(pFile, iLogical, iOld1, iNew1) ){ - return 1; - } - if( i1!=iOld1 ) return 0; - } - - assert( !"unreachable" ); - return 0; -} - -/* -** Set the EVICTED or IRREVICTED flag on page iLogical. -*/ -static int hctFileSetEvicted( - HctFile *pFile, - u32 iLogical, - u32 iOldPg, - int bIrrevocable -){ - u64 *pPtr = hctPagemapPtr(pFile->pMapping, iLogical); - while( 1 ){ - u64 iOld = HctAtomicLoad(pPtr); - u64 iNew = iOld | ( - bIrrevocable ? HCT_PMF_LOGICAL_IRREVICTED : HCT_PMF_LOGICAL_EVICTED - ); - - /* Fail if either the current physical page mapped to logical page iLogical - ** is not iOldPg, or if the LOGICAL_EVICTED flag has already been set. */ - if( (iOld & HCT_PAGEMAP_VMASK)!=iOldPg - || ((iOld & HCT_PMF_LOGICAL_EVICTED) && !bIrrevocable) - || ((iOld & HCT_PMF_LOGICAL_EVICTED)==0 && bIrrevocable) - || ((iOld & HCT_PMF_LOGICAL_IN_USE)==0) - ){ - return 0; - } - if( inject_cas_failure() ) return 0; - - pFile->stats.nCasAttempt++; - if( hctBoolCAS64(pPtr, iOld, iNew) ) return 1; - pFile->stats.nCasFail++; - } - - assert( !"unreachable" ); - return 0; -} - -/* -** Clear the LOGICAL_EVICTED flag from page-map entry iLogical. This will -** fail if the LOGICAL_IRREVICTED flag is already set. Return 1 if the -** flag is successfully cleared, or 0 otherwise. -*/ -static int hctFileClearEvicted(HctFile *pFile, u32 iLogical){ - u64 *pPtr = hctPagemapPtr(pFile->pMapping, iLogical); - while( 1 ){ - u64 iOld = HctAtomicLoad(pPtr); - u64 iNew = iOld & ~HCT_PMF_LOGICAL_EVICTED; - - if( (iOld & HCT_PMF_LOGICAL_IRREVICTED) ) return 0; - if( inject_cas_failure() ) return 0; - - pFile->stats.nCasAttempt++; - if( hctBoolCAS64(pPtr, iOld, iNew) ) return 1; - pFile->stats.nCasFail++; - } - - assert( !"unreachable" ); - return 0; -} - -static void hctFilePagemapZeroValue(HctFile *pFile, u32 iSlot){ - while( 1 ){ - u64 i1 = hctFilePagemapGet(pFile->pMapping, iSlot); - u64 i2 = (i1 & HCT_PMF_PHYSICAL_IN_USE); - if( hctFilePagemapSet(pFile, iSlot, i1, i2) ) return; - } -} - -/* -** Open a file descriptor for read/write access on the filename formed by -** concatenating arguments zFile and zPost (e.g. "test.db" and "-pagemap"). -** Return the file descriptor if successful. -*/ -static int hctFileOpen(int *pRc, const char *zFile, const char *zPost){ - int fd = -1; - if( *pRc==SQLITE_OK ){ - char *zPath = sqlite3_mprintf("%s%s", zFile, zPost); - if( zPath==0 ){ - *pRc = SQLITE_NOMEM_BKPT; - }else{ - while( fd<0 ){ - fd = open(zPath, O_CREAT|O_RDWR, 0644); - if( fd<0 ){ - *pRc = SQLITE_CANTOPEN_BKPT; - break; - } - if( fd<3 ){ - /* Do not use any file-descriptor with values 0, 1 or 2. Using - ** these means that stray calls to printf() etc. may corrupt the - ** database. */ - close(fd); - fd = open("/dev/null", O_RDONLY, 0644); - if( fd<0 ){ - *pRc = SQLITE_CANTOPEN_BKPT; - break; - } - fd = -1; - } - } - sqlite3_free(zPath); - } - } - return fd; -} - -/* -** Take an exclusive POSIX lock on the file-descriptor passed as the -** second argument. -*/ -static void hctFileLock(int *pRc, int fd, const char *zFile){ - if( *pRc==SQLITE_OK ){ - int res; - struct flock l; - memset(&l, 0, sizeof(l)); - l.l_type = F_WRLCK; - l.l_whence = SEEK_SET; - l.l_start = HCT_LOCK_OFFSET; - l.l_len = HCT_LOCK_SIZE; - res = fcntl(fd, F_SETLK, &l); - if( res!=0 ){ - fcntl(fd, F_GETLK, &l); - sqlite3_log(SQLITE_BUSY, "hct file \"%s\" locked by process %lld", - zFile, (i64)l.l_pid - ); - *pRc = SQLITE_BUSY; - } - } -} - -/* -** Argument fd is an open file-handle. Return the size of the file in bytes. -** -** This function is a no-op (returns 0) if *pRc is other than SQLITE_OK -** when it is called. If an error occurs, *pRc is set to an SQLite error -** code before returning. -*/ -static i64 hctFileSize(int *pRc, int fd){ - i64 szRet = 0; - if( *pRc==SQLITE_OK ){ - struct stat sStat; - if( fstat(fd, &sStat) ){ - *pRc = sqlite3HctIoerr(SQLITE_IOERR_FSTAT); - }else{ - szRet = (i64)(sStat.st_size); - } - } - return szRet; -} - -static int hctFileTruncate(int *pRc, int fd, i64 sz){ - if( *pRc==SQLITE_OK ){ - int res = ftruncate(fd, (off_t)sz); - if( res ){ - *pRc = sqlite3HctIoerr(SQLITE_IOERR_TRUNCATE); - } - } - return *pRc; -} - -static void hctFileUnlink(int *pRc, const char *zFile){ - if( *pRc==SQLITE_OK ) unlink(zFile); -} - - -/* -** This function is a no-op if (*pRc) is set to other than SQLITE_OK -** when it is called. -** -** Otherwise, argument fd is assumed to be an open file-descriptor. This -** function attempts to map and return a pointer to a region nByte bytes in -** size at offset iOff of the open file. The mapping is read-only if parameter -** bRO is non-zero, or read/write if it is zero. -** -** If an error occurs, NULL is returned and (*pRc) set to an SQLite error -** code. -*/ -static void *hctFileMmap(int *pRc, int fd, i64 nByte, i64 iOff, int bRO){ - void *pRet = 0; - if( *pRc==SQLITE_OK ){ - const int flags = PROT_READ | (bRO ? 0 : PROT_WRITE); - pRet = mmap(0, nByte, flags, MAP_SHARED, fd, iOff); - if( pRet==MAP_FAILED ){ - pRet = 0; - *pRc = sqlite3HctIoerr(SQLITE_IOERR_MMAP); - } - } - return pRet; -} - -static void hctFileMunmap(void *pMap, i64 nByte){ - if( pMap ) munmap(pMap, nByte); -} - -static char *hctStrdup(int *pRc, const char *zIn){ - char *zRet = 0; - if( *pRc==SQLITE_OK ){ - zRet = sqlite3_mprintf("%s", zIn); - if( zRet==0 ) *pRc = SQLITE_NOMEM_BKPT; - } - return zRet; -} - - -/* -** Given local path zFile, return the associated canonical path in a buffer -** obtained from sqlite3_malloc(). It is the responsibility of the caller -** to eventually free this buffer using sqlite3_free(). -*/ -static char *fileGetFullPath(int *pRc, const char *zFile){ - char *zRet = 0; - if( *pRc==SQLITE_OK ){ - char *zFree = realpath(zFile, 0); - if( zFree==0 ){ - *pRc = SQLITE_CANTOPEN_BKPT; - }else{ - zRet = hctStrdup(pRc, zFree); - free(zFree); - } - } - return zRet; -} - -static int hctFileFindLogs( - HctFileServer *pServer, - void *pCtx, - int (*xLog)(void*, const char*) -){ - DIR *d; - const char *zName = &pServer->zPath[strlen(pServer->zDir)]; - int nName = strlen(zName); - int rc = SQLITE_OK; - - d = opendir(pServer->zDir); - if (d) { - struct dirent *dir; - while( rc==SQLITE_OK && (dir = readdir(d))!=NULL ){ - const char *zFile = (const char*)dir->d_name; - int nFile = strlen(zFile); - if( nFile>(nName+5) - && memcmp(zFile, zName, nName)==0 - && memcmp(&zFile[nName], "-log-", 5)==0 - ){ - char *zFull = sqlite3_mprintf("%s/%s", pServer->zDir, zFile); - rc = xLog(pCtx, zFull); - sqlite3_free(zFull); - } - } - closedir(d); - } - - return rc; -} - -static int hctFileServerInitUnlinkLog(void *pDummy, const char *zFile){ - int rc = SQLITE_OK; - hctFileUnlink(&rc, zFile); - return rc; -} - -static void hctFileReadHdr( - int *pRc, - void *pHdr, - int *pszPage, - int *pnDbFile -){ - *pszPage = 0; - if( *pRc==SQLITE_OK ){ - /* 12345678901234567890123456789012 */ - int szPage = 0; - int nDbFile = 0; - char *zHdr = "Hctree database version 00000001"; - u8 aEmpty[32] = {0}; - - assert( strlen(zHdr)==32 ); - if( memcmp(zHdr, pHdr, 32)==0 ){ - memcpy(&szPage, &((u8*)pHdr)[32], sizeof(int)); - if( szPage<512 || szPage>32768 || (szPage & (szPage-1))!=0 ){ - *pRc = SQLITE_CANTOPEN_BKPT; - return; - } - - memcpy(&nDbFile, &((u8*)pHdr)[36], sizeof(int)); - if( nDbFile<1 || nDbFile>HCT_MAX_NDBFILE ){ - *pRc = SQLITE_CANTOPEN_BKPT; - return; - } - }else if( memcmp(aEmpty, pHdr, 32)==0 ){ - /* no-op */ - }else{ - *pRc = SQLITE_CANTOPEN_BKPT; - } - - *pszPage = szPage; - *pnDbFile = nDbFile; - } -} - -static void *hctFileMmapDbChunk( - int *pRc, - HctFileServer *p, - HctMapping *pMap, - int iChunk -){ - void *pRet = 0; - i64 szChunk = p->nPagePerChunk * p->szPage; - int iFd = iChunk % p->nFdDb; - int iChunkOfFile = (iChunk / p->nFdDb); - - if( (iChunkOfFile % HCT_MMAP_QUANTA)==0 ){ - i64 iOff = szChunk * iChunkOfFile; - pRet = hctFileMmap( - pRc, p->aFdDb[iFd], szChunk*HCT_MMAP_QUANTA, iOff, p->bReadOnlyMap - ); - }else{ - pRet = (void*)(((u8*)pMap->aChunk[iChunk - p->nFdDb].pData) + szChunk); - } - - return pRet; -} - -static void *hctFileMmapPagemapChunk( - int *pRc, - HctFileServer *p, - HctMapping *pMap, - int iChunk -){ - void *pRet = 0; - i64 szChunk = p->nPagePerChunk * sizeof(u64); - - if( (iChunk % HCT_MMAP_QUANTA)==0 ){ - pRet = hctFileMmap( - pRc, p->fdMap, szChunk*HCT_MMAP_QUANTA, (szChunk*iChunk), 0 - ); - }else{ - pRet = (void*)(((u8*)(pMap->aChunk[iChunk-1].aMap)) + szChunk); - } - - return pRet; -} - -static void hctFileOpenDataFiles( - int *pRc, - HctFileServer *p, - int nDbFile -){ - int ii; - int rc = *pRc; - assert( p->nFdDb==1 ); - for(ii=1; iiaFdDb[ii] = hctFileOpen(&rc, p->zPath, z); - sqlite3_free(z); - if( rc==SQLITE_OK ) p->nFdDb = ii+1; - } - - if( rc!=SQLITE_OK ){ - for(ii=1; iinFdDb; ii++){ - if( p->aFdDb[ii]>0 ) close(p->aFdDb[ii]); - p->aFdDb[ii] = -1; - } - p->nFdDb = 1; - } - *pRc = rc; -} - -static i64 round_up(i64 iVal, i64 nQuanta){ - return ((iVal + nQuanta - 1) / nQuanta) * nQuanta; -} - -static void hctFileAllocateMapping( - int *pRc, - HctFileServer *p, - int nChunk -){ - i64 szChunkPagemap = p->nPagePerChunk * sizeof(u64); - i64 szChunkData = p->nPagePerChunk * p->szPage; - int rc = *pRc; - HctMapping *pMapping = 0; - int iFd = 0; - int i = 0; - - p->pMapping = pMapping = hctMappingNew(&rc, 0, nChunk); - if( rc==SQLITE_OK ){ - pMapping->mapShift = hctLog2(p->nPagePerChunk); - pMapping->mapMask = (1<mapShift)-1; - pMapping->szPage = p->szPage; - } - - /* Map all chunks of the pagemap file using a single call to mmap() */ - { - int nAll = round_up(nChunk, HCT_MMAP_QUANTA); - u8 *pMap = (u8*)hctFileMmap(&rc, p->fdMap, nAll*szChunkPagemap,0,0); - for(i=0; rc==SQLITE_OK && iaChunk[i].aMap = (u64*)&pMap[i * szChunkPagemap]; - } - } - - /* Map all chunks of the data files. One call to mmap() for each file. */ - for(iFd=0; iFdnFdDb && rc==SQLITE_OK; iFd++){ - int nFileChunk = (nChunk / p->nFdDb) + (iFd < (nChunk % p->nFdDb)); - i64 n = round_up(nFileChunk, HCT_MMAP_QUANTA) * szChunkData; - u8 *pMap = (u8*)hctFileMmap(&rc, p->aFdDb[iFd], n, 0, p->bReadOnlyMap); - for(i=0; inFdDb; - pMapping->aChunk[iChunk].pData = &pMap[i*szChunkData]; - } - } - - *pRc = rc; -} - -typedef struct Uncommitted Uncommitted; -struct Uncommitted { - int nAlloc; - int nTid; - i64 *aTid; -}; - -static int hctFileServerInitUncommitted(void *pCtx, const char *zFile){ - int fd; - Uncommitted *p = (Uncommitted*)pCtx; - - fd = open(zFile, O_RDONLY); - if( fd>=0 ){ - i64 iTid = 0; - read(fd, &iTid, sizeof(iTid)); - close(fd); - if( iTid>0 ){ - if( p->nTid==p->nAlloc ){ - int nNew = p->nTid ? p->nTid*4 : 64; - i64 *aNew = sqlite3_realloc(p->aTid, nNew*sizeof(i64)); - if( aNew==0 ){ - return SQLITE_NOMEM; - }else{ - p->aTid = aNew; - p->nAlloc = nNew; - } - } - p->aTid[p->nTid++] = iTid; - } - } - return SQLITE_OK; -} - -static int hctFileServerInit( - HctFileServer *p, - HctConfig *pConfig, - const char *zFile -){ - int rc = SQLITE_OK; - assert( sqlite3_mutex_held(p->pMutex) ); - if( p->zPath==0 ){ - i64 szHdr; /* Size of header file */ - i64 szMap; /* Size of pagemap file */ - int nChunk = 0; /* Number of chunks in database */ - int szPage = 0; - int nDbFile = 0; - - Uncommitted unc; - memset(&unc, 0, sizeof(unc)); - - /* Open the data and page-map files */ - p->fdMap = hctFileOpen(&rc, zFile, "-pagemap"); - p->zPath = fileGetFullPath(&rc, zFile); - - if( rc==SQLITE_OK ){ - int n = strlen(p->zPath); - while( p->zPath[n-1]!='/' && n>1 ) n--; - p->zDir = sqlite3_mprintf("%.*s", n, p->zPath); - if( p->zDir==0 ) rc = SQLITE_NOMEM_BKPT; - } - - /* Initialize the page-manager */ - p->pPManServer = sqlite3HctPManServerNew(&rc, p); - - /* If the header file is zero bytes in size, or is not yet populated, - ** then the database is empty, regardless of the contents of the - ** *-data or *-pagemap file. Truncate the pagemap and data files to - ** zero bytes in size to make sure of this. - ** - ** Alternatively, if the header file is the right size, try to read it. - */ - szHdr = hctFileSize(&rc, p->aFdDb[0]); - if( rc==SQLITE_OK ){ - void *pHdr = 0; - if( szHdr==0 ){ - szHdr = HCT_HEADER_PAGESIZE*2; - hctFileTruncate(&rc, p->aFdDb[0], szHdr); - }else if( szHdr<(HCT_HEADER_PAGESIZE*2) ){ - rc = SQLITE_CANTOPEN_BKPT; - } - - pHdr = hctFileMmap(&rc, p->aFdDb[0], HCT_HEADER_PAGESIZE*2, 0, 1); - hctFileReadHdr(&rc, pHdr, &szPage, &nDbFile); - if( rc==SQLITE_OK && szPage==0 ){ - hctFileTruncate(&rc, p->fdMap, 0); - hctFileTruncate(&rc, p->fdMap, HCT_DEFAULT_PAGEPERCHUNK*sizeof(i64)); - szHdr = HCT_HEADER_PAGESIZE*2; - hctFileTruncate(&rc, p->aFdDb[0], szHdr); - if( rc==SQLITE_OK ){ - rc = hctFileFindLogs(p, 0, hctFileServerInitUnlinkLog); - } - }else{ - if( rc==SQLITE_OK ){ - rc = hctFileFindLogs(p, (void*)&unc, hctFileServerInitUncommitted); - } - hctFileOpenDataFiles(&rc, p, nDbFile); - } - hctFileMunmap(pHdr, HCT_HEADER_PAGESIZE*2); - } - p->nPagePerChunk = HCT_DEFAULT_PAGEPERCHUNK; - - assert( szPage==0 || rc==SQLITE_OK ); - if( szPage>0 ){ - i64 szChunkPagemap = p->nPagePerChunk * sizeof(u64); - - p->szPage = szPage; - szMap = hctFileSize(&rc, p->fdMap); - if( rc==SQLITE_OK ){ - if( szMapnFdDb==1 && szHdr!=p->szPage*(szMap/sizeof(u64))) - ){ - rc = SQLITE_CANTOPEN_BKPT; - }else{ - nChunk = szMap / szChunkPagemap; - } - } - - hctFileAllocateMapping(&rc, p, nChunk); - } - - /* Initialize CID value */ - p->iCommitId = 5; - - /* Allocate a transaction map server */ - if( rc==SQLITE_OK && p->pTMapServer==0 ){ - u64 iFirst = 0; /* First tid that will be written in tmap */ - u64 iLast = 0; /* Last such tid */ - int ii; /* To iterate through unc.aTid[] */ - - if( p->pMapping ){ - iFirst = hctFilePagemapGet(p->pMapping, HCT_PAGEMAP_TRANSID_EOF); - iFirst = (iFirst & HCT_TID_MASK) + 1; - }else{ - iFirst = 1; - } - - iLast = iFirst; - for(ii=0; ii=iLast ) iLast = iThis+1; - } - - /* Allocate the tmap-server object. Set all entries between iFirst and - ** iLast to (HCT_TMAP_COMMITTED, cid=1). Ensuring that the contents of - ** these transactions are visible to all readers. - ** - ** Then go back and set the entry for all tid values in unc.aTid[] to - ** (HCT_TMAP_ROLLBACK, 0) - not visible to any readers. */ - rc = sqlite3HctTMapServerNew(iFirst, iLast, &p->pTMapServer); - for(ii=0; iipTMapServer, iThis, HCT_TMAP_ROLLBACK); - } - } - sqlite3_free(unc.aTid); - } - return rc; -} - -/* -** This is called as part of initializing a new database on disk. Mutex -** HctFileServer.mutex must be held to call this function. It writes a -** new, empty, root page to physical page iPhys, to be used for either -** HCT_ROOTPAGE_SCHEMA or HCT_ROOTPAGE_META. -** -** SQLITE_OK is returned if successful, or an SQLite error code otherwise. -*/ -static int hctFileInitSystemRoot(HctFileServer *p, u64 iPhys){ - int rc = SQLITE_OK; - u8 *aBuf = sqlite3_malloc(p->szPage); - - assert( sqlite3_mutex_held(p->pMutex) ); - if( aBuf==0 ){ - rc = SQLITE_NOMEM; - }else{ - sqlite3HctDbRootPageInit(0, aBuf, p->szPage); - - if( p->bReadOnlyMap ){ - rc = hctPageWriteToDisk(p, iPhys, aBuf); - }else{ - u8 *a = (u8*)hctPagePtr(p->pMapping, iPhys); - memcpy(a, aBuf, p->szPage); - } - sqlite3_free(aBuf); - } - return rc; -} - -static int hctFileInitHdr(HctFileServer *p){ - int rc = SQLITE_OK; - u8 *aBuf = sqlite3_malloc(HCT_HEADER_PAGESIZE); - assert( sqlite3_mutex_held(p->pMutex) ); - if( aBuf==0 ){ - rc = SQLITE_NOMEM; - }else{ - char *zHdr = "Hctree database version 00000001"; - assert( strlen(zHdr)==32 ); - memset(aBuf, 0, HCT_HEADER_PAGESIZE); - memcpy(aBuf, zHdr, 32); - memcpy(&aBuf[32], &p->szPage, sizeof(int)); - memcpy(&aBuf[36], &p->nFdDb, sizeof(int)); - if( p->bReadOnlyMap ){ - ssize_t res = pwrite(p->aFdDb[0], aBuf, HCT_HEADER_PAGESIZE, 0); - rc = (res==HCT_HEADER_PAGESIZE ? SQLITE_OK : SQLITE_ERROR); - }else{ - memcpy(p->pMapping->aChunk[0].pData, aBuf, HCT_HEADER_PAGESIZE); - } - } - sqlite3_free(aBuf); - return rc; -} - - -/* -** This is called each time a new snapshot is opened. If HctFile.szPage is -** still set to 0, then: -** -** a) this is the first snapshot opened by connection pFile, and -** b) the database had not been created when pFile was opened. -** -** In this case the server-mutex is taken, and if the db has still not been -** created (HctFileServer.szPage==0), then it is created on disk under the -** cover of the mutex. -*/ -SQLITE_PRIVATE int sqlite3HctFileNewDb(HctFile *pFile){ - int rc = SQLITE_OK; - if( pFile->szPage==0 ){ - HctFileServer *p = pFile->pServer; - sqlite3_mutex_enter(p->pMutex); - if( p->szPage==0 ){ - HctConfig *pConfig = pFile->pConfig; - HctMapping *pMapping = 0; - int szPage = pConfig->pgsz; - int nDbFile = pConfig->nDbFile; - - p->szPage = szPage; - hctFileTruncate(&rc, p->fdMap, p->nPagePerChunk * sizeof(u64)); - hctFileTruncate(&rc, p->aFdDb[0], p->nPagePerChunk * szPage); - - hctFileAllocateMapping(&rc, p, 1); - pMapping = p->pMapping; - - assert( nDbFile>=1 && nDbFile<=HCT_MAX_NDBFILE ); - hctFileOpenDataFiles(&rc, p, nDbFile); - - /* 1. Make logical page 1 an empty intkey root page (SQLite uses this - ** as the root of sqlite_schema). - ** - ** 2. Set the initial values of the largest logical and physical page - ** ids allocated fields. - */ - - /* Set the initial values of the largest logical and physical page - ** ids allocated fields. These will be used when the set of free pages - ** is recovered in sqlite3HctFileRecoverFreelists(). */ - if( rc==SQLITE_OK ){ - const int nPageSet = pConfig->nPageSet; - hctFilePagemapSetDirect(pMapping, HCT_PAGEMAP_LOGICAL_EOF, nPageSet); - hctFilePagemapSetDirect(pMapping, HCT_PAGEMAP_PHYSICAL_EOF, nPageSet); - } - - if( rc==SQLITE_OK ){ - const u64 f = HCT_PMF_LOGICAL_IN_USE | HCT_PMF_LOGICAL_IS_ROOT; - u64 aRoot[] = { - HCT_ROOTPAGE_SCHEMA, - HCT_ROOTPAGE_META, - }; - int ii = 0; - u64 iPhys1 = 1 + (((HCT_HEADER_PAGESIZE*2)+szPage-1) / szPage); - - for(ii=0; iipMapping); - p->pMapping = 0; - } - } - - if( rc==SQLITE_OK ){ - pFile->szPage = p->szPage; - pFile->pMapping = p->pMapping; - pFile->pMapping->nRef++; - pFile->eInitState = p->eInitState; - } - sqlite3_mutex_leave(p->pMutex); - } - return rc; -} - - -/* -** Return true if the db has not yet been created on disk. Or false -** if it already has. -*/ -SQLITE_PRIVATE int sqlite3HctFileIsNewDb(HctFile *pFile){ - int bRet = 0; - if( pFile->szPage==0 ){ - HctFileServer *p = pFile->pServer; - sqlite3_mutex_enter(p->pMutex); - if( p->szPage==0 ){ - bRet = 1; - } - sqlite3_mutex_leave(p->pMutex); - } - return bRet; -} - -static sqlite3_int64 current_time(){ - struct timeval sNow; - gettimeofday(&sNow, 0); - return (sqlite3_int64)sNow.tv_sec*1000 + sNow.tv_usec/1000; -} - -static void hctFileEnterServerMutex(HctFile *pFile){ - sqlite3_mutex *pMutex = pFile->pServer->pMutex; - pFile->stats.nMutex++; - if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ - pFile->stats.nMutexBlock++; - sqlite3_mutex_enter(pMutex); - } -} - -/* -** This is called to ensure that the mapping currently held by client -** pFile contains at least nChunk chunks. -*/ -static int hctFileGrowMapping(HctFile *pFile, int nChunk){ - int rc = SQLITE_OK; - if( pFile->pMapping->nChunkpServer; - HctMapping *pOld; - hctFileEnterServerMutex(pFile); - hctMappingUnref(pFile->pMapping); - pFile->pMapping = 0; - pOld = p->pMapping; - nOld = pOld->nChunk; - if( nOldnPagePerChunk*p->szPage; - i64 szChunkMap = p->nPagePerChunk*sizeof(u64); - int i; - - /* Grow the mapping file */ - hctFileTruncate(&rc, p->fdMap, nChunk*szChunkMap); - - for(i=nOld; iaChunk[i]; - - /* Grow the data file */ - int iFd = (i % p->nFdDb); - i64 sz = ((i / p->nFdDb) + 1) * szChunkData; - hctFileTruncate(&rc, p->aFdDb[iFd], sz); - - /* Map the new chunks of both the data and mapping files. */ - pChunk->aMap = hctFileMmapPagemapChunk(&rc, p, pNew, i); - pChunk->pData = hctFileMmapDbChunk(&rc, p, pNew, i); - } - - if( rc==SQLITE_OK ){ - p->pMapping = pNew; - hctMappingUnref(pOld); - }else{ - hctMappingUnref(pNew); - } - } - } - pFile->pMapping = p->pMapping; - pFile->pMapping->nRef++; - sqlite3_mutex_leave(p->pMutex); - } - return rc; -} - -/* -** Grow the mapping so that it is at least large enough to have an entry -** for slot iSlot. Return SQLITE_OK if successful (or if the mapping does -** not need to grow), or an SQLite error code otherwise. -*/ -static int hctFileGrowMappingForSlot(HctFile *pFile, u32 iSlot){ - assert( iSlot>0 ); - return hctFileGrowMapping(pFile, 1 + ((iSlot-1) / HCT_DEFAULT_PAGEPERCHUNK)); -} - - -static int hctFileServerFind(HctFile *pFile, const char *zFile){ - int rc = SQLITE_OK; - struct stat sStat; - HctFileServer *pServer = 0; - sqlite3_mutex *pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1); - - memset(&sStat, 0, sizeof(sStat)); - - /* Take the VFS1 mutex that protects the globals in this file */ - sqlite3_mutex_enter(pMutex); - - /* Search for an existing HctFileServer already open on this database */ - if( 0==stat(zFile, &sStat) ){ - for(pServer=g.pServerList; pServer; pServer=pServer->pServerNext){ - if( pServer->st_ino==(i64)sStat.st_ino - && pServer->st_dev==(i64)sStat.st_dev - ){ - break; - } - } - } - - if( pServer==0 ){ - int fd = hctFileOpen(&rc, zFile, ""); - if( rc==SQLITE_OK ){ - assert( fd>0 ); - hctFileLock(&rc, fd, zFile); - pServer = (HctFileServer*)sqlite3HctMalloc(&rc, sizeof(*pServer)); - if( pServer==0 ){ - close(fd); - }else{ - int ii; - for(ii=0; iiaFdDb[ii] = -1; - } - fstat(fd, &sStat); - pServer->st_dev = (i64)sStat.st_dev; - pServer->st_ino = (i64)sStat.st_ino; - pServer->pServerNext = g.pServerList; - pServer->aFdDb[0] = fd; - pServer->nFdDb = 1; - pServer->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); - /* pServer->bReadOnlyMap = 1; */ - g.pServerList = pServer; - } - } - } - - if( rc==SQLITE_OK ){ - pFile->pServer = pServer; - pFile->pFileNext = pServer->pFileList; - pServer->pFileList = pFile; - } - - /* Release the global mutex */ - sqlite3_mutex_leave(pMutex); - - return rc; -} - - -/* -** Open a connection to the database zFile. -*/ -SQLITE_PRIVATE HctFile *sqlite3HctFileOpen(int *pRc, const char *zFile, HctConfig *pConfig){ - int rc = *pRc; - HctFile *pNew; - - pNew = (HctFile*)sqlite3HctMalloc(&rc, sizeof(*pNew)); - if( pNew ){ - pNew->pConfig = pConfig; - rc = hctFileServerFind(pNew, zFile); - if( rc==SQLITE_OK ){ - HctFileServer *pServer = pNew->pServer; - - sqlite3_mutex_enter(pServer->pMutex); - rc = hctFileServerInit(pServer, pConfig, zFile); - assert( rc==SQLITE_OK ); - if( rc==SQLITE_OK && pServer->szPage>0 ){ - pNew->szPage = pServer->szPage; - pNew->pMapping = pServer->pMapping; - pNew->pMapping->nRef++; - } - pNew->eInitState = pServer->eInitState; - pNew->iFileId = pServer->iNextFileId++; - sqlite3_mutex_leave(pServer->pMutex); - - if( rc==SQLITE_OK ){ - sqlite3HctTMapClientNew( - pServer->pTMapServer, pConfig, &pNew->pTMapClient - ); - } - if( rc==SQLITE_OK ){ - pNew->pPManClient = sqlite3HctPManClientNew( - &rc, pConfig, pServer->pPManServer, pNew - ); - } - }else{ - sqlite3_free(pNew); - pNew = 0; - } - - if( rc!=SQLITE_OK ){ - sqlite3HctFileClose(pNew); - pNew = 0; - } - } - assert( (rc==SQLITE_OK)==(pNew!=0) ); - *pRc = rc; - return pNew; -} - -SQLITE_PRIVATE HctTMapClient *sqlite3HctFileTMapClient(HctFile *pFile){ - return pFile->pTMapClient; -} -SQLITE_PRIVATE HctPManClient *sqlite3HctFilePManClient(HctFile *pFile){ - return pFile->pPManClient; -} - -SQLITE_PRIVATE void sqlite3HctFileClose(HctFile *pFile){ - if( pFile ){ - HctFileServer *pDel = 0; - HctFile **pp; - HctFileServer *pServer = pFile->pServer; - - /* Release the page-manager client */ - sqlite3HctPManClientFree(pFile->pPManClient); - pFile->pPManClient = 0; - - /* Release the transaction map client */ - sqlite3HctTMapClientFree(pFile->pTMapClient); - pFile->pTMapClient = 0; - - /* Release the reference to the HctMapping object, if any */ - hctMappingUnref(pFile->pMapping); - pFile->pMapping = 0; - - /* Remove this object from the HctFileServer.pFileList list. If this - ** means there are no longer any connections to this server object, - ** remove the HctFileServer object itself from the global list. In - ** this case leave stack variable pDel set to point to the - ** HctFileServer. */ - sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1) ); - for(pp=&pServer->pFileList; *pp!=pFile; pp=&(*pp)->pFileNext); - *pp = pFile->pFileNext; - if( pServer->pFileList==0 ){ - HctFileServer **ppS; - pDel = pServer; - for(ppS=&g.pServerList; *ppS!=pServer; ppS=&(*ppS)->pServerNext); - *ppS = pServer->pServerNext; - } - sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_VFS1) ); - - /* It if was removed from the global list, clean up the HctFileServer - ** object. */ - if( pDel ){ - int szChunkData = pDel->nPagePerChunk*pDel->szPage; - int szChunkMap = pDel->nPagePerChunk*sizeof(u64); - int i; - HctMapping *pMapping = pDel->pMapping; - - sqlite3HctTMapServerFree(pDel->pTMapServer); - pDel->pTMapServer = 0; - - sqlite3HctPManServerFree(pDel->pPManServer); - pDel->pPManServer = 0; - - if( pMapping ){ - pDel->pMapping = 0; - for(i=0; inChunk; i++){ - HctMappingChunk *pChunk = &pMapping->aChunk[i]; - if( pChunk->aMap ) hctFileMunmap(pChunk->aMap, szChunkMap); - if( pChunk->pData ) hctFileMunmap(pChunk->pData, szChunkData); - } - hctMappingUnref(pMapping); - } - - /* Close the data files and the mapping file. */ - for(i=0; inFdDb; i++){ - if( pDel->aFdDb[i]>0 ) close(pDel->aFdDb[i]); - } - if( pDel->fdMap ) close(pDel->fdMap); - - if( pDel->xJrnlDel ){ - pDel->xJrnlDel(pDel->pJrnlPtr); - } - sqlite3_free(pDel->zDir); - sqlite3_free(pDel->zPath); - sqlite3_mutex_free(pDel->pMutex); - sqlite3_free(pDel); - } - - /* Finally, free the HctFile object */ - sqlite3_free(pFile); - } -} - -SQLITE_PRIVATE u32 sqlite3HctFileMaxpage(HctFile *pFile){ - u64 iVal = hctFilePagemapGet(pFile->pMapping, HCT_PAGEMAP_PHYSICAL_EOF); - return (iVal & 0xFFFFFFFF); -} - -/* -** Set the flags in mask within page-map slot iSlot. -*/ -static int hctFileSetFlag(HctFile *pFile, u32 iSlot, u64 mask){ - int rc = hctFileGrowMappingForSlot(pFile, iSlot); - if( rc==SQLITE_OK ){ - HctMapping *pMapping = pFile->pMapping; - while( 1 ){ - u64 iVal = hctFilePagemapGet(pMapping, iSlot); - if( hctFilePagemapSet(pFile, iSlot, iVal, iVal | mask) ) break; - } - } - return rc; -} - -/* -** Clear the flags in mask within page-map slot iSlot. -*/ -static int hctFileClearFlag(HctFile *pFile, u32 iSlot, u64 mask){ - int rc = hctFileGrowMappingForSlot(pFile, iSlot); - if( rc==SQLITE_OK ){ - HctMapping *pMapping = pFile->pMapping; - while( 1 ){ - u64 iVal = hctFilePagemapGet(pMapping, iSlot); - if( hctFilePagemapSet(pFile, iSlot, iVal, iVal & ~mask) ) break; - } - } - return rc; -} - - -SQLITE_PRIVATE int sqlite3HctFileRootFree(HctFile *pFile, u32 iRoot){ - /* TODO - do something with freed root-page */ - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctFilePageClearIsRoot(HctFile *pFile, u32 iRoot){ - return hctFileClearFlag(pFile, iRoot, HCT_PMF_LOGICAL_IS_ROOT); -} -SQLITE_PRIVATE int sqlite3HctFilePageClearInUse(HctFile *pFile, u32 iPg, int bLogic){ - u64 flag = bLogic ? HCT_PMF_LOGICAL_IN_USE : HCT_PMF_PHYSICAL_IN_USE; - return hctFileClearFlag(pFile, iPg, flag); -} - -SQLITE_PRIVATE int sqlite3HctFileTreeFree(HctFile *pFile, u32 iRoot, int bImmediate){ - u64 iTid = bImmediate ? 0 : pFile->iCurrentTid; - return sqlite3HctPManFreeTree(pFile->pPManClient, pFile, iRoot, iTid); -} - -static int hctFilePagemapGetGrow(HctFile *pFile, u32 iPg, u64 *piVal){ - int rc = hctFileGrowMapping(pFile, 1+(iPg>>pFile->pMapping->mapShift)); - if( rc==SQLITE_OK ){ - *piVal = hctFilePagemapGet(pFile->pMapping, iPg); - } - return rc; -} - -/* -** Obtain the lower 32-bits of the value currently stored in slot iSlot. -*/ -static int hctFilePagemapGetGrow32(HctFile *pFile, u32 iSlot, u32 *piVal){ - int rc; - u64 val = 0; - rc = hctFilePagemapGetGrow(pFile, iSlot, &val); - *piVal = (u32)(val & 0xFFFFFFFF); - return rc; -} - - -static int hctFilePagemapPtr(HctFile *pFile, u32 iPg, u8 **paData){ - int rc = hctFileGrowMapping(pFile, 1+(iPg>>pFile->pMapping->mapShift)); - if( rc==SQLITE_OK ){ - *paData = hctPagePtr(pFile->pMapping, iPg); - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctFilePageGet(HctFile *pFile, u32 iPg, HctFilePage *pPg){ - int rc; - assert( iPg!=0 ); - memset(pPg, 0, sizeof(*pPg)); - pPg->pFile = pFile; - pPg->iPg = iPg; - rc = hctFilePagemapGetGrow32(pFile, iPg, &pPg->iOldPg); - if( rc==SQLITE_OK ){ - u32 iPhys = pPg->iOldPg; - assert( iPhys!=0 ); - rc = hctFilePagemapPtr(pFile, iPhys, &pPg->aOld); - } - return rc; -} - -SQLITE_PRIVATE u32 sqlite3HctFilePageMapping(HctFile *pFile, u32 iLogical, int *pbEvicted){ - u64 val = hctFilePagemapGet(pFile->pMapping, iLogical); - *pbEvicted = (val & HCT_PMF_LOGICAL_EVICTED) ? 1 : 0; - return (u32)(val & 0xFFFFFFFF); -} - -/* -** Obtain a reference to physical page iPg. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageGetPhysical(HctFile *pFile, u32 iPg, HctFilePage *pPg){ - u32 iVal; - int rc; - assert( iPg!=0 ); - memset(pPg, 0, sizeof(*pPg)); - rc = hctFilePagemapGetGrow32(pFile, iPg, &iVal); - if( rc==SQLITE_OK ){ - pPg->iOldPg = iPg; - pPg->aOld = (u8*)hctPagePtr(pFile->pMapping, iPg); - } - return rc; -} - -static u32 hctFileAllocPg(int *pRc, HctFile *pFile, int bLogical){ - int rc = *pRc; - u32 iRet = 0; - - if( bLogical==0 ) pFile->nPageAlloc++; - iRet = sqlite3HctPManAllocPg(&rc, pFile->pPManClient, pFile, bLogical); - if( rc==SQLITE_OK ){ - rc = hctFileGrowMappingForSlot(pFile, iRet); - if( rc!=SQLITE_OK ){ - /* TODO: Something about this resource leak */ - iRet = 0; - } - } - - *pRc = rc; - return iRet; -} - -/* -** This function makes the page object pPg writable if it is not already -** so. Specifically, it allocates a new physical page and sets the -** following variables accordingly: -** -** HctFilePage.iNewPg -** HctFilePage.aNew -** -** The PHYSICAL_IN_USE flag is set on the new physical page allocated -** here. -*/ -static void hctFilePageMakeWritable(int *pRc, HctFilePage *pPg){ - if( pPg->aNew==0 ){ - HctFile *pFile = pPg->pFile; - u32 iNewPg = hctFileAllocPg(pRc, pFile, 0); - if( iNewPg ){ - hctFileSetFlag(pPg->pFile, iNewPg, HCT_PMF_PHYSICAL_IN_USE); - pPg->iNewPg = iNewPg; - - if( pFile->pServer->bReadOnlyMap ){ - pPg->aNew = (u8*)sqlite3_malloc(pFile->szPage); - /* todo: handle oom here */ - }else{ - pPg->aNew = (u8*)hctPagePtr(pPg->pFile->pMapping, iNewPg); - } - } - } -} - - -#if 0 -static void debug_printf(const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - vprintf(zFmt, ap); - va_end(ap); -} - -static void debug_slot_value(HctFile *pFile, u32 iSlot){ - u64 iVal = hctFilePagemapGet(pFile->pMapping, iSlot); - printf("[flags=%02x val=%lld]", (u32)(iVal>>56), iVal & HCT_PAGEMAP_VMASK); -} - -#define DEBUG_PAGE_MUTEX_ENTER(pPg) \ - sqlite3_mutex_enter(pPg->pFile->pServer->pMutex) - -#define DEBUG_PAGE_MUTEX_LEAVE(pPg) \ - fflush(stdout); sqlite3_mutex_leave(pPg->pFile->pServer->pMutex) - -#define DEBUG_PRINTF(...) debug_printf(__VA_ARGS__) -#define DEBUG_SLOT_VALUE(pFile, iSlot) debug_slot_value(pFile, iSlot) - -SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...){ - va_list ap; - sqlite3_mutex_enter(pFile->pServer->pMutex); - printf("f=%d: ", pFile->iFileId); - va_start(ap, zFmt); - vprintf(zFmt, ap); - va_end(ap); - sqlite3_mutex_leave(pFile->pServer->pMutex); -} - -#else -# define DEBUG_PAGE_MUTEX_ENTER(x) -# define DEBUG_PAGE_MUTEX_LEAVE(x) -# define DEBUG_PRINTF(...) -# define DEBUG_SLOT_VALUE(x,y) -SQLITE_PRIVATE void sqlite3HctFileDebugPrint(HctFile *pFile, const char *zFmt, ...){ } -#endif - -void hctFileFreePg( - int *pRc, - HctFile *pFile, - i64 iTid, /* Associated TID value */ - u32 iPg, /* Page number */ - int bLogical /* True for logical, false for physical */ -){ - if( pFile->eInitState>=HCT_INIT_RECOVER1 ){ - sqlite3HctPManFreePg(pRc, pFile->pPManClient, iTid, iPg, bLogical); - } -} - - -static int hctFilePageFlush(HctFilePage *pPg){ - int rc = SQLITE_OK; - if( pPg->aNew ){ - u32 iOld = pPg->iOldPg; - - DEBUG_PAGE_MUTEX_ENTER(pPg); - DEBUG_PRINTF("f=%d: Flushing page %d orig=", pPg->pFile->iFileId, pPg->iPg); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - DEBUG_PRINTF(" (ioldpg=%d) (inewpg=%d)", pPg->iOldPg, pPg->iNewPg); - - DEBUG_PRINTF("\n"); - DEBUG_PAGE_MUTEX_LEAVE(pPg); - - if( pPg->pFile->pServer->bReadOnlyMap ){ - rc = hctPageWriteToDisk(pPg->pFile->pServer, pPg->iNewPg, pPg->aNew); - } - - if( rc==SQLITE_OK ){ - if( !hctFilePagemapSetLogical(pPg->pFile, pPg->iPg, iOld, pPg->iNewPg) ){ - rc = SQLITE_LOCKED_ERR(pPg->iPg, "flush"); - }else{ - if( iOld ){ - u64 iTid = pPg->pFile->iCurrentTid; - hctFileFreePg(&rc, pPg->pFile, iTid, iOld, 0); - hctFileClearFlag(pPg->pFile, iOld, HCT_PMF_PHYSICAL_IN_USE); - } - pPg->iOldPg = pPg->iNewPg; - if( pPg->pFile->pServer->bReadOnlyMap ){ - sqlite3_free(pPg->aNew); - pPg->aOld = hctPagePtr(pPg->pFile->pMapping, pPg->iOldPg); - }else{ - pPg->aOld = pPg->aNew; - } - pPg->aNew = 0; - pPg->iNewPg = 0; - } - } - - DEBUG_PAGE_MUTEX_ENTER(pPg); - DEBUG_PRINTF("f=%d:", pPg->pFile->iFileId); - - DEBUG_PRINTF(" rc=%d final=", rc); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - DEBUG_PRINTF("%s\n", rc==SQLITE_LOCKED ? " SQLITE_LOCKED" : ""); - DEBUG_PAGE_MUTEX_LEAVE(pPg); - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctFilePageCommit(HctFilePage *pPg){ - assert( pPg->iPg ); - return hctFilePageFlush(pPg); -} - -SQLITE_PRIVATE int sqlite3HctFilePageEvict(HctFilePage *pPg, int bIrrevocable){ - int ret; - - DEBUG_PAGE_MUTEX_ENTER(pPg); - DEBUG_PRINTF("f=%d: Evicting page %d (irrecocable=%d) orig=", - pPg->pFile->iFileId, pPg->iPg, bIrrevocable - ); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - - ret = hctFileSetEvicted(pPg->pFile, pPg->iPg, pPg->iOldPg, bIrrevocable); - ret = (ret ? SQLITE_OK : SQLITE_LOCKED_ERR(pPg->iPg, "evict")); - - DEBUG_PRINTF(" rc=%d final=", ret); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - DEBUG_PRINTF("%s\n", ret==SQLITE_LOCKED ? " SQLITE_LOCKED" : ""); - DEBUG_PAGE_MUTEX_LEAVE(pPg); - return ret; -} - -SQLITE_PRIVATE void sqlite3HctFilePageUnevict(HctFilePage *pPg){ - DEBUG_PAGE_MUTEX_ENTER(pPg); - DEBUG_PRINTF("f=%d: Unevicting page %d orig=", pPg->pFile->iFileId, pPg->iPg); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - - hctFileClearEvicted(pPg->pFile, pPg->iPg); - - DEBUG_PRINTF(" final="); - DEBUG_SLOT_VALUE(pPg->pFile, pPg->iPg); - DEBUG_PRINTF("\n"); - DEBUG_PAGE_MUTEX_LEAVE(pPg); -} - -SQLITE_PRIVATE int sqlite3HctFilePageIsEvicted(HctFile *pFile, u32 iPgno){ - u64 val; - int rc = hctFilePagemapGetGrow(pFile, iPgno, &val); - return (rc || (val & HCT_PMF_LOGICAL_EVICTED)!=0); -} - -SQLITE_PRIVATE int sqlite3HctFilePageIsFree(HctFile *pFile, u32 iPgno, int bLogical){ - u64 iVal = hctFilePagemapGet(pFile->pMapping, iPgno); - u64 mask = (bLogical ? HCT_PMF_LOGICAL_IN_USE : HCT_PMF_PHYSICAL_IN_USE); - return (iVal & mask) ? 0 : 1; -} - -SQLITE_PRIVATE int sqlite3HctFilePageRelease(HctFilePage *pPg){ - int rc = SQLITE_OK; - if( pPg->iPg ){ - rc = hctFilePageFlush(pPg); - }else if( pPg->aNew && pPg->pFile->pServer->bReadOnlyMap ){ - rc = hctPageWriteToDisk(pPg->pFile->pServer, pPg->iNewPg, pPg->aNew); - sqlite3_free(pPg->aNew); - } - memset(pPg, 0, sizeof(*pPg)); - return rc; -} - - - -/* -** Allocate a new physical page and set (*pPg) to refer to it. The new -** physical page number is available in HctFilePage.iNewPg. -*/ -SQLITE_PRIVATE int sqlite3HctFilePageNewPhysical(HctFile *pFile, HctFilePage *pPg){ - int rc = SQLITE_OK; - memset(pPg, 0, sizeof(*pPg)); - pPg->pFile = pFile; - hctFilePageMakeWritable(&rc, pPg); - return rc; -} - -/* -** Allocate a new logical page. If parameter iPg is zero, then a new -** logical page number is allocated. Otherwise, it must be a logical page -** number obtained by an earlier call to sqlite3HctFileRootPgno(). -*/ -SQLITE_PRIVATE int sqlite3HctFilePageNew(HctFile *pFile, HctFilePage *pPg){ - int rc = SQLITE_OK; /* Return code */ - u32 iLPg = hctFileAllocPg(&rc, pFile, 1); - if( rc==SQLITE_OK ){ - memset(pPg, 0, sizeof(*pPg)); - pPg->pFile = pFile; - pPg->iPg = iLPg; - hctFilePagemapZeroValue(pFile, iLPg); - hctFilePageMakeWritable(&rc, pPg); - } - - return rc; -} - -/* -** Allocate a new logical root page number. -*/ -SQLITE_PRIVATE int sqlite3HctFileRootPgno(HctFile *pFile, u32 *piRoot){ - int rc = SQLITE_OK; - u32 iRoot = hctFileAllocPg(&rc, pFile, 1); - if( rc==SQLITE_OK ){ - hctFilePagemapZeroValue(pFile, iRoot); - *piRoot = iRoot; - } - return rc; -} - -/* -** Parameter iRoot is a root page number previously obtained from -** sqlite3HctFileRootPgno(). This function allocates a physical -** page to go with the logical one. -*/ -SQLITE_PRIVATE int sqlite3HctFileRootNew(HctFile *pFile, u32 iRoot, HctFilePage *pPg){ - int rc = SQLITE_OK; /* Return code */ - - memset(pPg, 0, sizeof(*pPg)); - pPg->pFile = pFile; - pPg->iPg = iRoot; - hctFilePageMakeWritable(&rc, pPg); - - /* Set the LOGICAL_IN_USE and LOGICAL_IS_ROOT flags on page iRoot. At - ** the same time, set the mapping to 0. Take care not to clear the - ** PHYSICAL_IN_USE flag while doing so, in case there is a physical - ** page with page number iRoot currently in use somewhere. */ - while( rc==SQLITE_OK ){ - u64 i1 = hctFilePagemapGet(pFile->pMapping, iRoot); - u64 i2 = (i1 & HCT_PMF_PHYSICAL_IN_USE); - i2 |= (HCT_PMF_LOGICAL_IS_ROOT|HCT_PMF_LOGICAL_IN_USE); - if( hctFilePagemapSet(pFile, iRoot, i1, i2) ) break; - } - - return rc; -} - -SQLITE_PRIVATE void sqlite3HctFilePageUnwrite(HctFilePage *pPg){ - int rc = SQLITE_OK; - if( pPg->aNew ){ - hctFileClearFlag(pPg->pFile, pPg->iNewPg, HCT_PMF_PHYSICAL_IN_USE); - hctFileFreePg(&rc, pPg->pFile, 0, pPg->iNewPg, 0); - if( pPg->pFile->pServer->bReadOnlyMap ){ - sqlite3_free(pPg->aNew); - } - pPg->iNewPg = 0; - pPg->aNew = 0; - if( pPg->iOldPg==0 ){ - assert( pPg->aOld==0 ); - hctFileFreePg(&rc, pPg->pFile, 0, pPg->iPg, 1); - pPg->iPg = 0; - } - } -} - -SQLITE_PRIVATE int sqlite3HctFilePageWrite(HctFilePage *pPg){ - int rc = SQLITE_OK; /* Return code */ - hctFilePageMakeWritable(&rc, pPg); - return rc; -} - -SQLITE_PRIVATE u64 sqlite3HctFileAllocateTransid(HctFile *pFile){ - u64 iVal = hctFilePagemapIncr(pFile, HCT_PAGEMAP_TRANSID_EOF, 1); - pFile->iCurrentTid = (iVal & HCT_TID_MASK); - return pFile->iCurrentTid; -} -SQLITE_PRIVATE u64 sqlite3HctFileAllocateCID(HctFile *pFile, int nWrite){ - assert( nWrite>0 ); - return hctFileAtomicIncr(pFile, &pFile->pServer->iCommitId, nWrite); -} - -SQLITE_PRIVATE void sqlite3HctFileSetCID(HctFile *pFile, u64 iVal){ - HctAtomicStore(&pFile->pServer->iCommitId, iVal); -} - -SQLITE_PRIVATE u64 sqlite3HctFileIncrWriteCount(HctFile *pFile, int nIncr){ - return hctFileAtomicIncr(pFile, &pFile->pServer->nWriteCount, nIncr); -} - -SQLITE_PRIVATE u64 sqlite3HctFileGetSnapshotid(HctFile *pFile){ - return HctAtomicLoad( &pFile->pServer->iCommitId ); -} - -SQLITE_PRIVATE int sqlite3HctFilePgsz(HctFile *pFile){ - return pFile->szPage; -} - -SQLITE_PRIVATE void sqlite3HctFileSetJrnlPtr( - HctFile *pFile, - void *pPtr, - void(*xDel)(void*) -){ - assert( pFile->pServer->pJrnlPtr==0 ); - assert( pFile->pServer->xJrnlDel==0 ); - pFile->pServer->pJrnlPtr = pPtr; - pFile->pServer->xJrnlDel = xDel; -} - -SQLITE_PRIVATE void *sqlite3HctFileGetJrnlPtr(HctFile *pFile){ - return pFile->pServer->pJrnlPtr; -} - -/* -** Return the current "safe" TID value. -*/ -SQLITE_PRIVATE u64 sqlite3HctFileSafeTID(HctFile *pFile){ - return sqlite3HctTMapSafeTID(pFile->pTMapClient); -} - -/* -** Allocate a block of nPg physical or logical page ids from the -** end of the current range. -*/ -SQLITE_PRIVATE u32 sqlite3HctFilePageRangeAlloc(HctFile *pFile, int bLogical, int nPg){ - u32 iSlot = HCT_PAGEMAP_PHYSICAL_EOF - bLogical; - u64 iNew = 0; - - assert( bLogical==0 || iSlot==HCT_PAGEMAP_LOGICAL_EOF ); - assert( bLogical!=0 || iSlot==HCT_PAGEMAP_PHYSICAL_EOF ); - - /* Increment the selected slot by nPg. The returned value, iNew, is the - ** new value of the slot - the last page in the range allocated. */ - iNew = hctFilePagemapIncr(pFile, iSlot, nPg); - - /* Return the first page number in the range of nPg allocated */ - return (iNew+1 - nPg); -} - -/* -** This function is called by the upper layer to clear the: -** -** * LOGICAL_IN_USE flag on the specified page id, and the -** * PHYSICAL_IN_USE flag on currently mapped physical page id. -** -** If parameter bReuseNow is true, then the page was never properly linked -** into a list, and so the logical and physical page ids can be reused -** immediately. Otherwise, they are handled as if freed by the current -** transaction. -*/ -SQLITE_PRIVATE int sqlite3HctFileClearInUse(HctFilePage *pPg, int bReuseNow){ - int rc = SQLITE_OK; - if( pPg->pFile ){ - u64 iTid = pPg->pFile->iCurrentTid; - u32 iPhysPg = pPg->iOldPg; - - assert( pPg->iPg>0 ); - assert( pPg->iOldPg>0 ); - -#ifdef SQLITE_DEBUG - if( bReuseNow==0 ){ - u64 iVal = hctFilePagemapGet(pPg->pFile->pMapping, pPg->iPg); - assert( iVal & HCT_PMF_LOGICAL_EVICTED ); - } -#endif - - hctFileClearFlag(pPg->pFile, pPg->iPg, HCT_PMF_LOGICAL_IN_USE); - hctFileClearFlag(pPg->pFile, iPhysPg, HCT_PMF_PHYSICAL_IN_USE); - hctFileFreePg(&rc, pPg->pFile, iTid, pPg->iPg, 1); - hctFileFreePg(&rc, pPg->pFile, iTid, iPhysPg, 0); - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctFileClearPhysInUse(HctFile *pFile, u32 pgno, int bReuseNow){ - u64 iTid = pFile->iCurrentTid; - int rc = SQLITE_OK; - - hctFileClearFlag(pFile, pgno, HCT_PMF_PHYSICAL_IN_USE); - hctFileFreePg(&rc, pFile, iTid, pgno, 0); - return rc; -} - -SQLITE_PRIVATE char *sqlite3HctFileLogFile(HctFile *pFile){ - char *zRet = 0; - HctFileServer *pServer = pFile->pServer; - sqlite3_mutex_enter(pServer->pMutex); - zRet = sqlite3_mprintf("%s-log-%d", pServer->zPath, pFile->iFileId); - sqlite3_mutex_leave(pServer->pMutex); - return zRet; -} - -SQLITE_PRIVATE int sqlite3HctFileStartRecovery(HctFile *pFile, int iStage){ - int bRet = 0; - if( pFile->eInitState==iStage ){ - HctFileServer *pServer = pFile->pServer; - sqlite3_mutex_enter(pServer->pMutex); - if( pServer->eInitState==iStage ){ - bRet = 1; - }else{ - pFile->eInitState = pServer->eInitState; - sqlite3_mutex_leave(pServer->pMutex); - } - } - return bRet; -} - -SQLITE_PRIVATE int sqlite3HctFileFinishRecovery(HctFile *pFile, int iStage, int rc){ - HctFileServer *pServer = pFile->pServer; - if( rc==SQLITE_OK ){ - pFile->eInitState = iStage+1; - pServer->eInitState = iStage+1; - } - sqlite3HctPManClientHandoff(pFile->pPManClient); - sqlite3_mutex_leave(pFile->pServer->pMutex); - return rc; -} - -SQLITE_PRIVATE int sqlite3HctFileRecoverFreelists( - HctFile *pFile, /* File to recover freelists for */ - int nRoot, i64 *aRoot, /* Array of root page numbers */ - int nPhys, i64 *aPhys /* Sorted array of phys. pages to preserve */ -){ - int rc = SQLITE_OK; - HctFileServer *pServer = pFile->pServer; - HctPManServer *pPManServer = pServer->pPManServer; - HctMapping *pMapping = pServer->pMapping; - u64 iSafeTid = hctFilePagemapGet(pMapping, HCT_PAGEMAP_TRANSID_EOF); - u64 nPg1 = hctFilePagemapGet(pMapping, HCT_PAGEMAP_PHYSICAL_EOF); - u64 nPg2 = hctFilePagemapGet(pMapping, HCT_PAGEMAP_LOGICAL_EOF); - u32 iPg; - u32 nPg; - u32 iPhysOff = ((HCT_HEADER_PAGESIZE*2)+pServer->szPage-1)/pServer->szPage; - - int iPhys = 0; - - nPg1 = nPg1 & HCT_PAGEMAP_VMASK; - nPg2 = nPg2 & HCT_PAGEMAP_VMASK; - - /* TODO: Really - page-manager must be empty at this point. Should assert() - ** that instead of making this call. */ - sqlite3HctPManServerReset(pPManServer); - - nPg = MAX((nPg1 & 0xFFFFFFFF), (nPg2 & 0xFFFFFFFF)); - for(iPg=1; iPg<=nPg; iPg++){ - u64 iVal = hctFilePagemapGetSafe(pMapping, iPg); - - if( (iVal & HCT_PMF_LOGICAL_IS_ROOT) && iPg>=3 ){ - int ii; - for(ii=0; iiiPhysOff) - ){ - /* Check if page iPg is one that must be preserved. */ - u64 iTid = iSafeTid; - while( iPhys=HCT_FIRST_LOGICAL - ){ - sqlite3HctPManServerInit(&rc, pPManServer, iSafeTid, iPg, 1); - } - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctFileFindLogs( - HctFile *pFile, - void *pCtx, - int (*xLog)(void*, const char*) -){ - return hctFileFindLogs(pFile->pServer, pCtx, xLog); -} - -SQLITE_PRIVATE int sqlite3HctFileRootArray( - HctFile *pFile, - u32 **paiRoot, - int *pnRoot -){ - int nAlloc = 0; - int nRoot = 0; - u32 *aRoot = 0; - u32 nLogic = 0; - int ii; - int rc; - - rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_LOGICAL_EOF, &nLogic); - for(ii=1; rc==SQLITE_OK && ii<=nLogic; ii++){ - u64 val; - rc = hctFilePagemapGetGrow(pFile, ii, &val); - if( rc==SQLITE_OK && (val & HCT_PMF_LOGICAL_IS_ROOT) ){ - if( nRoot>=nAlloc ){ - int nNew = (nAlloc ? nAlloc*2 : 16); - u32 *aNew = (u32*)sqlite3_realloc(aRoot, nNew*sizeof(u32)); - if( aNew==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - nAlloc = nNew; - aRoot = aNew; - } - } - - if( rc==SQLITE_OK ){ - aRoot[nRoot++] = ii; - } - } - } - - if( rc!=SQLITE_OK ){ - sqlite3_free(aRoot); - aRoot = 0; - nRoot = 0; - } - *paiRoot = aRoot; - *pnRoot = nRoot; - return rc; -} - -SQLITE_PRIVATE u64 sqlite3HctFileWriteCount(HctFile *pFile){ - return pFile->nPageAlloc; -} - -SQLITE_PRIVATE void sqlite3HctFileICArrays( - HctFile *pFile, - u8 **paLogic, u32 *pnLogic, - u8 **paPhys, u32 *pnPhys -){ - int rc = SQLITE_OK; - u32 nLogic = 0; - u32 nPhys = 0; - u8 *aLogic = 0; - u8 *aPhys = 0; - u32 ii; - - rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_LOGICAL_EOF, &nLogic); - if( rc==SQLITE_OK ){ - rc = hctFilePagemapGetGrow32(pFile, HCT_PAGEMAP_PHYSICAL_EOF, &nPhys); - } - - if( rc==SQLITE_OK ){ - aLogic = (u8*)sqlite3HctMalloc(&rc, (nLogic + nPhys) * sizeof(u8)); - if( aLogic ){ - aPhys = &aLogic[nLogic]; - } - } - - for(ii=1; ii<=nLogic && rc==SQLITE_OK; ii++){ - u64 val; - rc = hctFilePagemapGetGrow(pFile, ii, &val); - if( rc==SQLITE_OK && (val & HCT_PMF_LOGICAL_IN_USE)==0 ){ - aLogic[ii-1] = 1; - } - } - for(ii=1; ii<=nPhys && rc==SQLITE_OK; ii++){ - u64 val; - rc = hctFilePagemapGetGrow(pFile, ii, &val); - if( rc==SQLITE_OK && (val & HCT_PMF_PHYSICAL_IN_USE)==0 ){ - aPhys[ii-1] = 1; - } - } - - if( rc!=SQLITE_OK ){ - sqlite3_free(aLogic); - aLogic = aPhys = 0; - nLogic = nPhys = 0; - } - - *paLogic = aLogic; - *paPhys = aPhys; - *pnLogic = nLogic; - *pnPhys = nPhys; -} - -SQLITE_PRIVATE i64 sqlite3HctFileStats(sqlite3 *db, int iStat, const char **pzStat){ - i64 iVal = -1; - HctFile *pFile = sqlite3HctDbFile(sqlite3HctDbFind(db, 0)); - - switch( iStat ){ - case 0: - *pzStat = "cas_attempt"; - iVal = pFile->stats.nCasAttempt; - break; - case 1: - *pzStat = "cas_fail"; - iVal = pFile->stats.nCasFail; - break; - case 2: - *pzStat = "incr_attempt"; - iVal = pFile->stats.nIncrAttempt; - break; - case 3: - *pzStat = "incr_fail"; - iVal = pFile->stats.nIncrFail; - break; - case 4: - *pzStat = "mutex_attempt"; - iVal = pFile->stats.nMutex; - break; - case 5: - *pzStat = "mutex_block"; - iVal = pFile->stats.nMutexBlock; - break; - default: - break; - } - - return iVal; -} - -SQLITE_PRIVATE int sqlite3HctFileNFile(HctFile *pFile, int *pbFixed){ - int iRet = 0; - HctFileServer *p = pFile->pServer; - sqlite3_mutex_enter(p->pMutex); - iRet = p->nFdDb; - *pbFixed = (p->szPage>0); - sqlite3_mutex_leave(p->pMutex); - return iRet; -} - -/************************************************************************* -** Beginning of vtab implemetation. -*************************************************************************/ - -#define HCT_PGMAP_SCHEMA \ -" CREATE TABLE hct_pgmap(" \ -" slot INTEGER," \ -" value INTEGER," \ -" comment TEXT," \ -" physical_in_use BOOLEAN," \ -" logical_in_use BOOLEAN," \ -" logical_evicted BOOLEAN," \ -" logical_irrevicted BOOLEAN,"\ -" logical_is_root BOOLEAN" \ -" );" - -/* -** Virtual table type for "hctpgmap". -*/ -typedef struct pgmap_vtab pgmap_vtab; -struct pgmap_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; - -/* -** Virtual cursor type for "hctpgmap". -*/ -typedef struct pgmap_cursor pgmap_cursor; -struct pgmap_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - HctFile *pFile; /* Database to report on */ - u64 iMaxSlotno; /* Maximum page number for this scan */ - u64 slotno; /* The page-number/rowid value */ - u64 iVal; /* Value read from pagemap */ -}; - -/* -** The pgmapConnect() method is invoked to create a new -** template virtual table. -** -** Think of this routine as the constructor for pgmap_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the pgmap_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against the virtual table will look like. -*/ -static int pgmapConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - pgmap_vtab *pNew; - int rc; - - rc = sqlite3_declare_vtab(db, HCT_PGMAP_SCHEMA); - pNew = (pgmap_vtab*)sqlite3HctMalloc(&rc, sizeof(*pNew)); - if( pNew ){ - pNew->db = db; - } - - *ppVtab = (sqlite3_vtab*)pNew; - return rc; -} - -/* -** This method is the destructor for pgmap_vtab objects. -*/ -static int pgmapDisconnect(sqlite3_vtab *pVtab){ - pgmap_vtab *p = (pgmap_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Constructor for a new pgmap_cursor object. -*/ -static int pgmapOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - pgmap_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a pgmap_cursor. -*/ -static int pgmapClose(sqlite3_vtab_cursor *cur){ - pgmap_cursor *pCur = (pgmap_cursor*)cur; - sqlite3_free(pCur); - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int pgmapEof(sqlite3_vtab_cursor *cur){ - pgmap_cursor *pCur = (pgmap_cursor*)cur; - return pCur->slotno>pCur->iMaxSlotno; -} - -static int pgmapLoadSlot(pgmap_cursor *pCur){ - return hctFilePagemapGetGrow( - pCur->pFile, pCur->slotno, &pCur->iVal - ); -} - -/* -** Advance a hctdb_cursor to its next row of output. -*/ -static int pgmapNext(sqlite3_vtab_cursor *cur){ - pgmap_cursor *pCur = (pgmap_cursor*)cur; - pCur->slotno++; - return pgmapEof(cur) ? SQLITE_OK : pgmapLoadSlot(pCur); -} - -static void pgmapGetComment(sqlite3_context *ctx, i64 iSlot){ - const char *zText = 0; - - switch( iSlot ){ - case HCT_ROOTPAGE_SCHEMA: - zText = "ROOTPAGE_SCHEMA"; - break; - case HCT_ROOTPAGE_META: - zText = "ROOTPAGE_META"; - break; - case HCT_PAGEMAP_LOGICAL_EOF: - zText = "LOGICAL_EOF"; - break; - case HCT_PAGEMAP_PHYSICAL_EOF: - zText = "PHYSICAL_EOF"; - break; - case HCT_PAGEMAP_TRANSID_EOF: - zText = "TRANSID_EOF"; - break; - } - - if( zText ){ - sqlite3_result_text(ctx, zText, -1, SQLITE_TRANSIENT); - } -} - -/* -** Return values of columns for the row at which the pgmap_cursor -** is currently pointing. -*/ -static int pgmapColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - pgmap_cursor *pCur = (pgmap_cursor*)cur; - switch( i ){ - case 0: { /* slotno */ - sqlite3_result_int64(ctx, pCur->slotno); - break; - } - case 1: { /* pgno */ - sqlite3_result_int64(ctx, (pCur->iVal & 0xFFFFFFFF)); - break; - } - case 2: { /* pgno */ - pgmapGetComment(ctx, pCur->slotno); - break; - } - case 3: { /* physical_in_use */ - sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_PHYSICAL_IN_USE)?1:0); - break; - } - case 4: { /* logical_in_use */ - sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IN_USE)?1:0); - break; - } - case 5: { /* logical_evicted */ - sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_EVICTED)?1:0); - break; - } - case 6: { /* logical_irrevicted */ - sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IRREVICTED)?1:0); - break; - } - case 7: { /* logical_is_root */ - sqlite3_result_int64(ctx, (pCur->iVal & HCT_PMF_LOGICAL_IS_ROOT)?1:0); - break; - } - } - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the slotno value. -*/ -static int pgmapRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - pgmap_cursor *pCur = (pgmap_cursor*)cur; - *pRowid = pCur->slotno; - return SQLITE_OK; -} - -/* -** This method is called to "rewind" the pgmap_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to pgmapColumn() or pgmapRowid() or -** pgmapEof(). -*/ -static int pgmapFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - pgmap_cursor *pCur = (pgmap_cursor*)pVtabCursor; - pgmap_vtab *pTab = (pgmap_vtab*)(pCur->base.pVtab); - int rc; - u64 max1; - u64 max2; - - pCur->pFile = sqlite3HctDbFile(sqlite3HctDbFind(pTab->db, 0)); - pCur->slotno = 1; - max1 = hctFilePagemapGet(pCur->pFile->pMapping, HCT_PAGEMAP_PHYSICAL_EOF); - max2 = hctFilePagemapGet(pCur->pFile->pMapping, HCT_PAGEMAP_LOGICAL_EOF); - max1 &= HCT_PGNO_MASK; - max2 &= HCT_PGNO_MASK; - pCur->iMaxSlotno = max1>max2 ? max1 : max2; - rc = pgmapLoadSlot(pCur); - return rc; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -*/ -static int pgmapBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - pIdxInfo->estimatedCost = (double)10; - pIdxInfo->estimatedRows = 10; - return SQLITE_OK; -} - -/* -** This function is the implementation of the xUpdate callback used by -** hctpgmap virtual tables. It is invoked by SQLite each time a row is -** to be inserted, updated or deleted. -** -** A delete specifies a single argument - the rowid of the row to remove. -** -** Update and insert operations pass: -** -** 1. The "old" rowid (for an UPDATE), or NULL (for an INSERT). -** 2. The "new" rowid. -** 3. Values for each of the 6 columns. -** -** Specifically: -** -** apVal[2]: slot -** apVal[3]: value -** apVal[4]: comment -** apVal[5]: physical_in_use -** apVal[6]: logical_in_use -** apVal[7]: logical_evicted -** apVal[8]: logical_irrevicted -** apVal[9]: logical_is_root -*/ -static int pgmapUpdate( - sqlite3_vtab *pVtab, - int nVal, - sqlite3_value **apVal, - sqlite3_int64 *piRowid -){ - pgmap_vtab *p = (pgmap_vtab*)pVtab; - HctFile *pFile = sqlite3HctDbFile(sqlite3HctDbFind(p->db, 0)); - u32 iSlot = 0; - u64 val = 0; - u64 *pPtr = 0; - - i64 iValue = 0; - int bPhysicalInUse = 0; - int bLogicalInUse = 0; - int bLogicalEvicted = 0; - int bLogicalIrrevicted = 0; - int bLogicalIsRoot = 0; - - if( nVal==1 || sqlite3_value_type(apVal[0])!=SQLITE_INTEGER ){ - return SQLITE_CONSTRAINT; - } - iSlot = sqlite3_value_int64(apVal[0]); - - iValue = sqlite3_value_int64(apVal[3]); - bPhysicalInUse = sqlite3_value_int(apVal[5]); - bLogicalInUse = sqlite3_value_int(apVal[6]); - bLogicalEvicted = sqlite3_value_int(apVal[7]); - bLogicalIrrevicted = sqlite3_value_int(apVal[8]); - bLogicalIsRoot = sqlite3_value_int(apVal[9]); - - val = iValue & HCT_PAGEMAP_VMASK; - val |= (bPhysicalInUse ? HCT_PMF_PHYSICAL_IN_USE : 0); - val |= (bLogicalInUse ? HCT_PMF_LOGICAL_IN_USE : 0); - val |= (bLogicalEvicted ? HCT_PMF_LOGICAL_EVICTED : 0); - val |= (bLogicalIrrevicted ? HCT_PMF_LOGICAL_IRREVICTED : 0); - val |= (bLogicalIsRoot ? HCT_PMF_LOGICAL_IS_ROOT : 0); - - pPtr = hctPagemapPtr(pFile->pMapping, iSlot); - AtomicStore(pPtr, val); - - *piRowid = iSlot; - return SQLITE_OK; -} - -SQLITE_PRIVATE int sqlite3HctFileVtabInit(sqlite3 *db){ - static sqlite3_module pgmapModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ pgmapConnect, - /* xBestIndex */ pgmapBestIndex, - /* xDisconnect */ pgmapDisconnect, - /* xDestroy */ 0, - /* xOpen */ pgmapOpen, - /* xClose */ pgmapClose, - /* xFilter */ pgmapFilter, - /* xNext */ pgmapNext, - /* xEof */ pgmapEof, - /* xColumn */ pgmapColumn, - /* xRowid */ pgmapRowid, - /* xUpdate */ pgmapUpdate, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - return sqlite3_create_module(db, "hctpgmap", &pgmapModule, 0); -} - -SQLITE_PRIVATE int sqlite3HctIoerr(int rc){ - sqlite3_log(rc, "sqlite3HctIoerr() - rc=%d errno=%d\n", rc, (int)errno); - assert( 0 ); - abort(); - return rc; -} - - -/************** End of hct_file.c ********************************************/ -/************** Begin file hct_database.c ************************************/ -/* -** 2020 October 13 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -/* #include "hctInt.h" */ -/* #include "vdbeInt.h" */ -/* #include */ -/* #include */ - -typedef struct HctDatabase HctDatabase; -typedef struct HctDbIndexEntry HctDbIndexEntry; -typedef struct HctDbIndexLeaf HctDbIndexLeaf; -typedef struct HctDbIndexNode HctDbIndexNode; -typedef struct HctDbIndexNodeEntry HctDbIndexNodeEntry; -typedef struct HctDbIndexNodeHdr HctDbIndexNodeHdr; -typedef struct HctDbIntkeyEntry HctDbIntkeyEntry; -typedef struct HctDbIntkeyLeaf HctDbIntkeyLeaf; -typedef struct HctDbIntkeyNodeEntry HctDbIntkeyNodeEntry; -typedef struct HctDbIntkeyNode HctDbIntkeyNode; -typedef struct HctDbKey HctDbKey; -typedef struct HctDbLeaf HctDbLeaf; -typedef struct HctDbLeafHdr HctDbLeafHdr; -typedef struct HctDbWriter HctDbWriter; -typedef struct HctDbPageHdr HctDbPageHdr; -typedef struct HctDbHistoryFan HctDbHistoryFan; -typedef struct HctDbRangeCsr HctDbRangeCsr; - -typedef struct HctCsrIntkeyOp HctCsrIntkeyOp; -typedef struct HctCsrIndexOp HctCsrIndexOp; - -typedef struct HctDbPageArray HctDbPageArray; - -struct HctCsrIntkeyOp { - HctCsrIntkeyOp *pNextOp; - i64 iFirst; - i64 iLast; - - u32 iLogical; - u32 iPhysical; -}; - -struct HctCsrIndexOp { - HctCsrIndexOp *pNextOp; - u8 *pFirst; - int nFirst; - u8 *pLast; - int nLast; - - u32 iLogical; - u32 iPhysical; -}; - -struct CsrIntkey { - HctCsrIntkeyOp *pOpList; - HctCsrIntkeyOp *pCurrentOp; -}; -struct CsrIndex { - HctCsrIndexOp *pOpList; - HctCsrIndexOp *pCurrentOp; -}; - -struct HctDbKey { - i64 iKey; /* Integer key value */ - UnpackedRecord *pKey; /* Index key value */ - HctBuffer buf; /* Buffer for pKey data (if required) */ -}; - -/* -** eRange: -** Set to one of the HCT_RANGE_* constants defined below. -*/ -struct HctDbRangeCsr { - HctDbKey lowkey; - HctDbKey highkey; - u64 iRangeTid; /* The range TID that was followed here */ - - int eRange; /* HCT_RANGE_* constant */ - int iCell; - HctFilePage pg; -}; - -#define HCT_RANGE_FOLLOW 0 /* Follow range-pointers only */ -#define HCT_RANGE_MERGE 1 /* Merge in data + follow range-pointers */ -#define HCT_RANGE_FAN 2 /* HctDbRangeCsr.pg is a fan page */ - -#define IS_HCT_MIGRATE(pDb) (pDb->pConfig->db->bHctMigrate) - -/* -** iRoot: -** Logical root page of tree structure that this cursor is open on. -** -** pKeyInfo: -** NULL for cursors open on intkey trees, otherwise points to the -** KeyInfo used to compare keys in the open index tree. For cursors -** opened by the user, this is set when the cursor is opened within -** sqlite3HctDbCsrOpen() and never modified. -** -** pRec: -** UnpackedRecord structure suitable for use with pKeyInfo. This is -** allocated the first time it is required and then retained for -** the lifetime of the HctDbCsr structure. -** -** eDir: -** One of BTREE_DIR_NONE, BTREE_DIR_FORWARD or BTREE_DIR_REVERSE. -** -** pIntkeyOps: -*/ -struct HctDbCsr { - HctDatabase *pDb; /* Database that owns this cursor */ - u32 iRoot; /* Root page cursor is opened on */ - KeyInfo *pKeyInfo; - UnpackedRecord *pRec; - int eDir; /* Direction cursor will step after Seek() */ - int bNosnap; /* The "no-snapshot" flag */ - - u8 *aRecord; /* Record in allocated memory */ - int nRecord; /* Size of aRecord[] in bytes */ - HctBuffer rec; /* Buffer used to manage aRecord[] */ - - struct CsrIntkey intkey; - struct CsrIndex index; - HctDbCsr *pNextScanner; - - int iCell; /* Current cell within page */ - HctFilePage pg; /* Current leaf page */ - - int nRange; - int nRangeAlloc; - HctDbRangeCsr *aRange; -}; - -#define HCTDB_MAX_DIRTY (HCTDB_MAX_PAGEARRAY-2) -// #define HCTDB_MAX_DIRTY (HCTDB_STATIC_PAGEARRAY-2) -#define HCTDB_MAX_PAGEARRAY 2048 -#define HCTDB_STATIC_PAGEARRAY (8+2) - -#define HCTDB_APPEND_MODE_THRESHOLD 5 - - -#define LARGEST_TID ((((u64)1)<<56)-1) -#define HCT_TID_ROLLBACK_OVERRIDE (((u64)0x01) << 56) - - -struct HctDbPageArray { - int nPg; - HctFilePage *aPg; - HctFilePage aStatic[HCTDB_STATIC_PAGEARRAY]; - HctFilePage *aDyn; - int nDyn; -}; - -typedef struct HctDbOverflow HctDbOverflow; -typedef struct HctDbOverflowArray HctDbOverflowArray; - -struct HctDbOverflow { - u32 pgno; - int nOvfl; -}; - -struct HctDbOverflowArray { - int nEntry; - int nAlloc; - HctDbOverflow *aOvfl; -}; - -typedef struct HctDbFPKey HctDbFPKey; -struct HctDbFPKey { - i64 iKey; - u8 *aKey; - HctBuffer buf; -}; - -/* -** -** iHeight: -** The height of the list that this writer is writing to. 0 for leaves, -** 1 for the parents of leaves, etc. -** -** aWritePg/nWritePg: -** -** nWriteKey: -** Number of hctDbInsert() calls since last flush - i.e. how many have to -** be retried if we hit a CAS failure and have to redo this write operation. -** -** iWriteFpKey/aWriteFpKey: -** These two variables store the fence-post key for the peer page of -** the rightmost page in the aWritePg[] array - aWritePg[nWritePg-1]. -** For intkey tables, iWriteFpKey is the 64-bit integer key value. For -** index tables, aWriteFpKey points to a buffer containing the FP key, -** and iWriteFpKey its size in bytes. The buffer is allocated with -** sqlite3_malloc(). -** -** If there is no peer page and writing to an intkey list, iWriteFpKey -** is set to LARGEST_INT64. If writing to an index list, aWriteFpKey is -** set to NULL and iWriteFpKey to 0. -** -** discardpg: -** Pages to the right of writepg[0] that will be removed from the list -** if the CAS instruction for this write succeeds. -** -** bAppend: -** True if the writer is in append mode. -** -** bDoCleanup: -** True if hctDbInsert() has been called since the most recent -** hctDbWriterCleanup(). -*/ -struct HctDbWriter { - int iHeight; /* Height to write at (0==leaves) */ - HctDbPageArray writepg; - int nWriteKey; /* Number of new keys in writepg array */ - - int bAppend; /* Writer is in "append" mode */ - HctDbFPKey fp; /* Fence-Post key. */ - - HctDbCsr writecsr; /* Used to find target page while writing */ - HctDbPageArray discardpg; - HctFilePage fanpg; - - int bDoCleanup; - int nEvictLocked; - u32 iEvictLockedPgno; - - HctDbOverflowArray delOvfl; /* Overflow chains to free on write */ - HctDbOverflowArray insOvfl; /* Overflow chains to free on don't-write */ - - int nOverflow; - - int nMigrateKey; -}; - -/* -** This is used by the rebalance operation implemented by hctDbBalance(). -** The first step of that operation is to assemble an array of these -** structures - one for each cell that will be distributed between the -** output pages. -** -** nByte: -** Total bytes of space required by cell on new page. This includes -** the header entry and the data stored in the cell area. -** -** aEntry: -** Pointer to buffer containing cell entry. Or NULL to indicate that -** the HctDbCellSz structure corresponds to a new cell being written -** (that is not on any input page). -** -** aCell: -** Only valid if (aEntry!=0). Pointer to buffer containing leaf-page -** portion of cell. -*/ -typedef struct HctDbCellSz HctDbCellSz; -struct HctDbCellSz { - int nByte; /* Size of cell in bytes */ - u8 *aEntry; /* Buffer containing cell entry */ - u8 *aCell; /* Buffer containing cell body */ -}; - -typedef struct HctBalance HctBalance; -struct HctBalance { - u8 *aPg[3]; - int nSzAlloc; /* Allocated size of aSz[] array */ - HctDbCellSz *aSz; /* aSz[] array */ -}; - -/* -** Given the database page-size as an argument, the maximum number of cells -** that may fit on any page with variable sized entries (an index leaf or node, -** or intkey leaf page). -*/ -#define MAX_CELLS_PER_PAGE(pgsz) ((pgsz) / 8) - -/* -** This structure, an instance of which is part of each HctDatabase object, -** holds counters collected for the hctstats structure. -*/ -typedef struct HctDatabaseStats HctDatabaseStats; -struct HctDatabaseStats { - i64 nBalanceIntkey; - i64 nBalanceIndex; - i64 nBalanceSingle; - i64 nTMapLookup; - i64 nUpdateInPlace; - i64 nInternalRetry; -}; - -/* -** pScannerList: -** Linked list of cursors used by the current transaction. If this turns -** out to be a write transaction, this list is used to detect read/write -** conflicts. -** -** iJrnlWriteCid: -** This value is set within calls to sqlite3_hct_journal_write(). The CID -** of the journal entry being written to the db. -*/ -struct HctDatabase { - HctFile *pFile; - HctConfig *pConfig; - i64 nCasFail; /* Number cas-collisions so far */ - int pgsz; /* Page size in bytes */ - - u8 *aTmp; /* Temp buffer pgsz bytes in size */ - HctBalance *pBalance; /* Space for hctDbBalance() */ - - HctDbCsr *pScannerList; - - u64 iJrnlWriteCid; - - HctTMap *pTmap; /* Transaction map (non-NULL if trans open) */ - u64 iSnapshotId; /* Snapshot id for reading */ - u64 iLocalMinTid; - HctDbWriter pa; - HctDbCsr rbackcsr; /* Used to find old values during rollback */ - u64 iTid; /* Transaction id for writing */ - u64 nWriteCount; /* Write-count at start of commit */ - - int eMode; /* HCT_MODE_XXX constant */ - int bConcurrent; /* Collect validation information */ - - int (*xSavePhysical)(void*, i64); - void *pSavePhysical; - - HctDatabaseStats stats; -}; - -/* -** Values for HctDatabase.eMode. -*/ -#define HCT_MODE_NORMAL 0 -#define HCT_MODE_ROLLBACK 1 -#define HCT_MODE_VALIDATE 3 - - -/* -** 8-byte database page header. Described in fileformat.wiki. -*/ -struct HctDbPageHdr { - u8 hdrFlags; - u8 nHeight; /* 0 for leaves, 1 for parents etc. */ - u16 nEntry; - u32 iPeerPg; -}; - -/* -** Page types. These are the values that may appear in the page-type -** field of a page header. -*/ -#define HCT_PAGETYPE_INTKEY 0x01 -#define HCT_PAGETYPE_INDEX 0x03 -#define HCT_PAGETYPE_OVERFLOW 0x05 -#define HCT_PAGETYPE_HISTORY 0x06 - -#define HCT_PAGETYPE_MASK 0x07 - -/* -** Page types may be ORed with the following: -*/ -#define HCT_PAGETYPE_LEFTMOST 0x80 - -#define hctPagetype(p) (((HctDbPageHdr*)(p))->hdrFlags&HCT_PAGETYPE_MASK) -#define hctIsLeftmost(p) (((HctDbPageHdr*)(p))->hdrFlags&HCT_PAGETYPE_LEFTMOST) -#define hctPageheight(p) (((HctDbPageHdr*)(p))->nHeight) -#define hctPagenentry(p) (((HctDbPageHdr*)(p))->nEntry) -#define hctPagePeer(p) (((HctDbPageHdr*)(p))->iPeerPg) - -/* -** 16-byte leaf page header. Used by both index and intkey leaf pages. -** Described in fileformat.wiki. -*/ -struct HctDbLeafHdr { - u16 nFreeGap; /* Size of free-space region, in bytes */ - u16 nFreeBytes; /* Total free bytes on page */ - u32 unused; -}; - -struct HctDbLeaf { - HctDbPageHdr pg; - HctDbLeafHdr hdr; -}; - - -struct HctDbIntkeyEntry { - u32 nSize; /* 0: Total size of data (local+overflow) */ - u16 iOff; /* 4: Offset of record within this page */ - u8 flags; /* 6: Flags (see below) */ - u8 unused; /* 7: */ - i64 iKey; /* 8: Integer key value */ -}; - -struct HctDbIndexEntry { - u32 nSize; /* 0: Total size of data (local+overflow) */ - u16 iOff; /* 4: Offset of record within this page */ - u8 flags; /* 6: Flags (see below) */ - u8 unused; /* 7: */ -}; - -struct HctDbIndexNodeEntry { - u32 nSize; - u16 iOff; - u8 flags; - u8 unused; - u32 iChildPg; -}; - -struct HctDbIntkeyNodeEntry { - i64 iKey; /* Value of FP key on page iChild */ - u32 iChildPg; /* Child page */ - u32 unused; -}; - -struct HctDbIntkeyNode { - HctDbPageHdr pg; - HctDbIntkeyNodeEntry aEntry[0]; -}; - -struct HctDbIntkeyLeaf { - HctDbPageHdr pg; - HctDbLeafHdr hdr; - HctDbIntkeyEntry aEntry[0]; -}; - -struct HctDbIndexLeaf { - HctDbPageHdr pg; - HctDbLeafHdr hdr; - HctDbIndexEntry aEntry[0]; -}; - -struct HctDbIndexNodeHdr { - u16 nFreeGap; /* Size of free-space region, in bytes */ - u16 nFreeBytes; /* Total free bytes on page */ -}; - -struct HctDbIndexNode { - HctDbPageHdr pg; - HctDbIndexNodeHdr hdr; - HctDbIndexNodeEntry aEntry[0]; -}; - -/* -** History fanout page. -** -** iSplit0: -** The index of a key in page aPgOld1[0]. This key is the first that -** should be considered in aPgOld1[0]. Implying that no key equal to -** or greater than this from pgOld0 should be considered. -*/ -struct HctDbHistoryFan { - HctDbPageHdr pg; - - u64 iRangeTid0; - u64 iFollowTid0; - u32 pgOld0; - - int iSplit0; - - u64 iRangeTid1; - u32 aPgOld1[0]; -}; - -/* -** Structure for reading/writing cells from and to pages. -*/ -typedef struct HctDbCell HctDbCell; -struct HctDbCell { - u64 iTid; - u64 iRangeTid; - u32 iRangeOld; - u32 iOvfl; - const u8 *aPayload; -}; - -#if 1 -__attribute__ ((noinline)) -static void hctMemcpy(void *a, const void *b, size_t c){ - if( c ) memcpy(a, b, c); -} -#else -# define hctMemcpy memcpy -#endif - - - -/* -** Flags for HctDbIntkeyEntry.flags -*/ -#define HCTDB_HAS_TID 0x01 /* 8 bytes */ -#define HCTDB_HAS_OVFL 0x04 /* 4 bytes */ -#define HCTDB_HAS_RANGETID 0x08 /* 8 bytes */ -#define HCTDB_HAS_RANGEOLD 0x10 /* 4 bytes */ - -#define HCTDB_MAX_EXTRA_CELL_DATA (8+4+8+4) - -SQLITE_PRIVATE int sqlite3HctBufferGrow(HctBuffer *pBuf, int nSize){ - int rc = SQLITE_OK; - if( nSize>pBuf->nAlloc ){ - u8 *aNew = sqlite3_realloc(pBuf->aBuf, nSize); - if( aNew==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pBuf->aBuf = aNew; - pBuf->nAlloc = nSize; - } - } - return rc; -} - -SQLITE_PRIVATE void sqlite3HctBufferFree(HctBuffer *pBuf){ - sqlite3_free(pBuf->aBuf); - memset(pBuf, 0, sizeof(HctBuffer)); -} - -static int hctBufferSet(HctBuffer *pBuf, const u8 *aData, int nData){ - int rc = sqlite3HctBufferGrow(pBuf, nData); - if( rc==SQLITE_OK ){ - hctMemcpy(pBuf->aBuf, aData, nData); - } - return rc; -} - - -#ifdef SQLITE_DEBUG -static int hctSqliteBusy(int iLine){ - return SQLITE_BUSY_SNAPSHOT; -} -# define HCT_SQLITE_BUSY hctSqliteBusy(__LINE__) -#else -# define HCT_SQLITE_BUSY SQLITE_BUSY_SNAPSHOT -#endif /* SQLITE_DEBUG */ - -static u64 hctDbTMapLookup(HctDatabase *pDb, u64 iTid, u64 *peState){ - u64 iVal = 0; - HctTMap *pTmap = pDb->pTmap; - if( iTid==LARGEST_TID ){ - *peState = HCT_TMAP_ROLLBACK; - }else if( iTidiFirstTid ){ - *peState = HCT_TMAP_COMMITTED; - }else{ - int iMap = (iTid - pTmap->iFirstTid) / HCT_TMAP_PAGESIZE; - - if( iMap>=pTmap->nMap ){ - HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); - sqlite3HctTMapUpdate(pTMapClient, &pDb->pTmap); - assert( iTid<(pDb->pTmap->nMap*HCT_TMAP_PAGESIZE)+pDb->pTmap->iFirstTid ); - return hctDbTMapLookup(pDb, iTid, peState); - } - - { - int iOff = (iTid - pTmap->iFirstTid) % HCT_TMAP_PAGESIZE; - iOff = HCT_TMAP_ENTRYSLOT(iOff); - iVal = AtomicLoad(&pTmap->aaMap[iMap][iOff]); - pDb->stats.nTMapLookup++; - } - - *peState = (iVal & HCT_TMAP_STATE_MASK); - } - return (iVal & HCT_TMAP_CID_MASK); -} - - -static void print_out_tmap(HctDatabase *pDb, int nLimit){ - int ii; - - for(ii=0; iipTmap->iFirstTid + ii; - u64 iCid = hctDbTMapLookup(pDb, iTid, &eState); - - printf("tid=%d -> (%s, %d)\n", (int)iTid, - eState==HCT_TMAP_WRITING ? "WRITING" : - eState==HCT_TMAP_VALIDATING ? "VALIDATING" : - eState==HCT_TMAP_ROLLBACK ? "ROLLBACK" : - eState==HCT_TMAP_COMMITTED ? "COMMITTED" : "???", - (int)iCid - ); - } - -} - -static void hctDbPageArrayReset(HctDbPageArray *pArray){ - sqlite3_free(pArray->aDyn); - pArray->nPg = 0; - pArray->aPg = pArray->aStatic; - pArray->aDyn = 0; - pArray->nDyn = 0; -} - -static int hctDbPageArrayGrow(HctDbPageArray *pArray){ - assert( pArray->aDyn==0 ); - pArray->aDyn = sqlite3MallocZero(sizeof(HctFilePage) * HCTDB_MAX_PAGEARRAY); - if( pArray->aDyn==0 ){ - return SQLITE_NOMEM_BKPT; - } - pArray->nDyn = HCTDB_MAX_PAGEARRAY; - pArray->aPg = pArray->aDyn; - hctMemcpy(pArray->aPg, pArray->aStatic, - sizeof(HctFilePage)*HCTDB_STATIC_PAGEARRAY - ); - return SQLITE_OK; -} - -/* -** Grow the dynamic arrays used by the writer, if necessary -*/ -static int hctDbWriterGrow(HctDbWriter *pWriter){ - int rc = SQLITE_OK; - if( pWriter->writepg.aDyn==0 ){ - if( pWriter->writepg.nPg>=(HCTDB_STATIC_PAGEARRAY-2) - || pWriter->discardpg.nPg>=(HCTDB_STATIC_PAGEARRAY-2) - ){ - rc = hctDbPageArrayGrow(&pWriter->writepg); - if( rc==SQLITE_OK ){ - rc = hctDbPageArrayGrow(&pWriter->discardpg); - } - } - } - return rc; -} - -SQLITE_PRIVATE HctDatabase *sqlite3HctDbOpen( - int *pRc, - const char *zFile, - HctConfig *pConfig -){ - int rc = *pRc; - HctDatabase *pNew = 0; - - pNew = (HctDatabase*)sqlite3HctMalloc(&rc, sizeof(*pNew)); - if( pNew ){ - pNew->pFile = sqlite3HctFileOpen(&rc, zFile, pConfig); - pNew->pConfig = pConfig; - if( pNew->pFile ) pNew->pgsz = sqlite3HctFilePgsz(pNew->pFile); - } - - if( rc!=SQLITE_OK ){ - sqlite3HctDbClose(pNew); - pNew = 0; - } - - *pRc = rc; - return pNew; -} - -SQLITE_PRIVATE int sqlite3HctDbPagesize(HctDatabase *pDb){ - return pDb->pgsz; -} - - -SQLITE_PRIVATE void sqlite3HctDbClose(HctDatabase *p){ - if( p ){ - sqlite3_free(p->aTmp); - sqlite3HctFileClose(p->pFile); - p->pFile = 0; - sqlite3_free(p->pBalance); - sqlite3_free(p); - } -} - -SQLITE_PRIVATE HctFile *sqlite3HctDbFile(HctDatabase *pDb){ - return pDb->pFile; -} - -SQLITE_PRIVATE int sqlite3HctDbRootNew(HctDatabase *p, u32 *piRoot){ - return sqlite3HctFileRootPgno(p->pFile, piRoot); -} - -SQLITE_PRIVATE int sqlite3HctDbRootFree(HctDatabase *p, u32 iRoot){ - return sqlite3HctFileRootFree(p->pFile, iRoot); -} - -SQLITE_PRIVATE void sqlite3HctDbRootPageInit( - int bIndex, /* True for an index, false for intkey */ - u8 *aPage, /* Buffer to initialize */ - int szPage /* Size of aPage[] in bytes */ -){ - HctDbLeaf *pLeaf = (HctDbLeaf*)aPage; - memset(aPage, 0, szPage); - if( bIndex ){ - pLeaf->pg.hdrFlags = HCT_PAGETYPE_INDEX | HCT_PAGETYPE_LEFTMOST; - }else{ - pLeaf->pg.hdrFlags = HCT_PAGETYPE_INTKEY | HCT_PAGETYPE_LEFTMOST; - } - pLeaf->hdr.nFreeBytes = szPage - sizeof(HctDbLeaf); - pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; -} - -static void hctDbRootPageInit( - int bIndex, /* True for an index, false for intkey */ - int nHeight, /* Initial height */ - u32 iChildPg, /* Child page number */ - u8 *aPage, /* Buffer to initialize */ - int szPage /* Size of aPage[] in bytes */ -){ - HctDbPageHdr *pPg = (HctDbPageHdr*)aPage; - memset(aPage, 0, szPage); - if( bIndex ){ - pPg->hdrFlags = HCT_PAGETYPE_INDEX | HCT_PAGETYPE_LEFTMOST; - }else{ - pPg->hdrFlags = HCT_PAGETYPE_INTKEY | HCT_PAGETYPE_LEFTMOST; - } - if( nHeight>0 ){ - pPg->nHeight = nHeight; - pPg->nEntry = 1; - if( bIndex ){ - HctDbIndexNode *pNode = (HctDbIndexNode*)pPg; - pNode->aEntry[0].iChildPg = iChildPg; - pNode->hdr.nFreeBytes = - szPage - sizeof(HctDbIndexNode) - sizeof(HctDbIndexNodeEntry); - pNode->hdr.nFreeGap = pNode->hdr.nFreeBytes; - }else{ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pPg; - pNode->aEntry[0].iKey = SMALLEST_INT64; - pNode->aEntry[0].iChildPg = iChildPg; - } - }else{ - HctDbLeaf *pLeaf = (HctDbLeaf*)pPg; - pLeaf->hdr.nFreeBytes = szPage - sizeof(HctDbLeaf); - pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; - } -} - -/* -** Open a read transaction, if one is not already open. -*/ -SQLITE_PRIVATE int sqlite3HctDbStartRead(HctDatabase *pDb, HctJournal *pJrnl){ - int rc = SQLITE_OK; - - assert( (pDb->iSnapshotId==0)==(pDb->pTmap==0) ); - assert( pDb->iSnapshotId!=0 || pDb->bConcurrent==0 ); - if( pDb->iSnapshotId==0 && SQLITE_OK==(rc=sqlite3HctFileNewDb(pDb->pFile)) ){ - if( pDb->aTmp==0 ){ - pDb->pgsz = sqlite3HctFilePgsz(pDb->pFile); - pDb->aTmp = (u8*)sqlite3HctMalloc(&rc, pDb->pgsz); - } - if( rc==SQLITE_OK ){ - u64 iSnapshot = 0; - HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); - - iSnapshot = sqlite3HctJournalSnapshot(pJrnl); - rc = sqlite3HctTMapBegin(pTMapClient, iSnapshot, &pDb->pTmap); - assert( rc==SQLITE_OK ); /* todo */ - - iSnapshot = sqlite3HctJournalSnapshot(pJrnl); - if( iSnapshot==0 ){ - iSnapshot = sqlite3HctFileGetSnapshotid(pDb->pFile); - } - pDb->iSnapshotId = iSnapshot; - pDb->iLocalMinTid = sqlite3HctTMapCommitedTID(pTMapClient); - assert( pDb->iSnapshotId>0 ); - } - } - - return rc; -} - -static u64 hctGetU64(const u8 *a){ - u64 ret; - hctMemcpy(&ret, a, sizeof(u64)); - return ret; -} -static u32 hctGetU32(const u8 *a){ - u32 ret; - hctMemcpy(&ret, a, sizeof(u32)); - return ret; -} - -static void hctPutU32(u8 *a, u32 val){ - hctMemcpy(a, &val, sizeof(u32)); -} - -/* -** Return true if TID iTid maps to a commit-id visible to the current -** client. Or false otherwise. -*/ -static int hctDbTidIsVisible(HctDatabase *pDb, u64 iTid, int bNosnap){ - - if( (iTid & HCT_TID_MASK)<=pDb->iLocalMinTid ) return 1; - while( 1 ){ - u64 eState = 0; - u64 iCid = hctDbTMapLookup(pDb, (iTid & HCT_TID_MASK), &eState); - if( iTid & HCT_TID_ROLLBACK_OVERRIDE ){ - eState = HCT_TMAP_COMMITTED; - } - if( eState==HCT_TMAP_WRITING || eState==HCT_TMAP_ROLLBACK ){ - return 0; - } - if( eState==HCT_TMAP_COMMITTED ){ - if( bNosnap==0 && iCid>pDb->iSnapshotId ){ - return 0; - } - return 1; - } - assert( eState==HCT_TMAP_VALIDATING ); - if( iCid>pDb->iSnapshotId || iTid==pDb->iTid ){ - return 0; - } - } - - assert( 0 ); - return 0; -} - -/* -** This is called when writing keys to the database as part of committing -** a transaction. One of the writes will clobber a key associated with -** transaction-id iTid. This function returns true if this represents -** a write/write conflict and the transaction should be rolled back, or -** false if the write should proceed. -*/ -static int hctDbTidIsConflict(HctDatabase *pDb, u64 iTid){ - if( iTid==pDb->iTid || iTid<=pDb->iLocalMinTid || iTid==LARGEST_TID ){ - return 0; - }else{ - u64 eState = 0; - u64 iCid = hctDbTMapLookup(pDb, iTid & HCT_TID_MASK, &eState); - - /* This should only be called while writing or validating. */ - assert( pDb->iTid ); - if( iTid & HCT_TID_ROLLBACK_OVERRIDE ){ - eState = HCT_TMAP_COMMITTED; - } - - if( eState==HCT_TMAP_COMMITTED && iCid<=pDb->iSnapshotId ) return 0; - if( iCid==pDb->iJrnlWriteCid ) return 0; - return 1; - - if( eState==HCT_TMAP_WRITING || eState==HCT_TMAP_VALIDATING ) return 1; - - /* It's tempting to return 0 here - how can a key that has been rolled - ** back be a conflict? The problem is that the previous version of the - ** key - the one before this rolled back version - may be a write/write - ** conflict. Ideally, this code would check that and return accordingly. */ - if( eState==HCT_TMAP_ROLLBACK ) return 1; - - assert( eState==HCT_TMAP_COMMITTED ); - return (iCid > pDb->iSnapshotId); - } -} - - -static int hctDbOffset(int iOff, int flags){ - static const int aVal[] = { - 0+0+0+0+0, 0+0+0+0+8, 0+0+0+0+0, 0+0+0+0+8, - 0+0+4+0+0, 0+0+4+0+8, 0+0+4+0+0, 0+0+4+0+8, - 0+8+0+0+0, 0+8+0+0+8, 0+8+0+0+0, 0+8+0+0+8, - 0+8+4+0+0, 0+8+4+0+8, 0+8+4+0+0, 0+8+4+0+8, - - 4+0+0+0+0, 4+0+0+0+8, 4+0+0+0+0, 4+0+0+0+8, - 4+0+4+0+0, 4+0+4+0+8, 4+0+4+0+0, 4+0+4+0+8, - 4+8+0+0+0, 4+8+0+0+8, 4+8+0+0+0, 4+8+0+0+8, - 4+8+4+0+0, 4+8+4+0+8, 4+8+4+0+0, 4+8+4+0+8, - }; - - assert( HCTDB_HAS_RANGEOLD==0x10 ); /* +4 */ - assert( HCTDB_HAS_RANGETID==0x08 ); /* +8 */ - assert( HCTDB_HAS_OVFL==0x04 ); /* +4 */ - assert( HCTDB_HAS_TID==0x01 ); /* +8 */ - - assert( aVal[ flags & 0x1F ]==( - ((flags & HCTDB_HAS_TID) ? 8 : 0) - + ((flags & HCTDB_HAS_RANGETID) ? 8 : 0) - + ((flags & HCTDB_HAS_RANGEOLD) ? 4 : 0) - + ((flags & HCTDB_HAS_OVFL) ? 4 : 0) - )); - - return iOff + aVal[ flags&0x1F ]; -} - - -/* -** Wrapper around sqlite3HctFilePageGetPhysical() that also invokes the -** xSavePhysical callback, if one is configured. -*/ -static int hctDbGetPhysical(HctDatabase *pDb, u32 iPg, HctFilePage *pPg){ - int rc = sqlite3HctFilePageGetPhysical(pDb->pFile, iPg, pPg); - if( rc==SQLITE_OK && pDb->xSavePhysical ){ - rc = pDb->xSavePhysical(pDb->pSavePhysical, (i64)iPg); - } - return rc; -} - -/* -** Load the meta-data record from the database and store it in buffer aBuf -** (size nBuf bytes). The meta-data record is stored with rowid=0 int the -** intkey table with root-page=2. -*/ -SQLITE_PRIVATE int sqlite3HctDbGetMeta(HctDatabase *pDb, u8 *aBuf, int nBuf){ - HctFilePage pg; - int rc; - - assert( pDb->iSnapshotId ); - memset(aBuf, 0, nBuf); - rc = sqlite3HctFilePageGet(pDb->pFile, 2, &pg); - while( rc==SQLITE_OK ){ - HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)pg.aOld; - int iOff; - u8 flags; - - if( pLeaf->pg.nEntry==0 ){ - break; - } - - assert( pLeaf->pg.nEntry==1 ); - assert( pLeaf->aEntry[0].iKey==0 ); - assert( pLeaf->aEntry[0].nSize==nBuf ); - iOff = pLeaf->aEntry[0].iOff; - flags = pLeaf->aEntry[0].flags; - - assert( flags==HCTDB_HAS_TID - || flags==(HCTDB_HAS_RANGEOLD|HCTDB_HAS_RANGETID|HCTDB_HAS_TID) - ); - if( (flags & HCTDB_HAS_RANGEOLD) - && 0==hctDbTidIsVisible(pDb, hctGetU64(&pg.aOld[iOff]), 0) - ){ - u32 iOld = hctGetU32(&pg.aOld[iOff+8+8]); - if( iOld==0 ) break; - sqlite3HctFilePageRelease(&pg); - rc = hctDbGetPhysical(pDb, iOld, &pg); - }else{ - iOff = hctDbOffset(iOff, pLeaf->aEntry[0].flags ); - hctMemcpy(aBuf, &pg.aOld[iOff], nBuf); - sqlite3HctFilePageRelease(&pg); - break; - } - } - - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbTransIsConcurrent(HctDatabase *pDb, int eConcurrent){ - pDb->bConcurrent = (eConcurrent!=0); -} - -static int hctDbValidateMeta(HctDatabase *pDb){ - int rc = SQLITE_OK; - HctFilePage pg; - - assert( pDb->iSnapshotId>0 ); - rc = sqlite3HctFilePageGet(pDb->pFile, 2, &pg); - if( rc==SQLITE_OK ){ - HctDbIntkeyEntry *p = &((HctDbIntkeyLeaf*)pg.aOld)->aEntry[0]; - if( p->flags & HCTDB_HAS_TID ){ - u64 iTid = hctGetU64(&pg.aOld[p->iOff]); - if( hctDbTidIsConflict(pDb, iTid) ) rc = HCT_SQLITE_BUSY; - } - sqlite3HctFilePageRelease(&pg); - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbRootInit(HctDatabase *p, int bIndex, u32 iRoot){ - HctFilePage pg; - int rc = SQLITE_OK; - - rc = sqlite3HctFileRootNew(p->pFile, iRoot, &pg); - if( rc==SQLITE_OK ){ - sqlite3HctDbRootPageInit(bIndex, pg.aNew, p->pgsz); - rc = sqlite3HctFilePageRelease(&pg); - } - return rc; -} - -static i64 hctDbIntkeyFPKey(const void *aPg){ - if( ((HctDbPageHdr*)aPg)->nHeight==0 ){ - return ((HctDbIntkeyLeaf*)aPg)->aEntry[0].iKey; - } - return ((HctDbIntkeyNode*)aPg)->aEntry[0].iKey; -} - - -static i64 hctDbGetIntkey(const u8 *aTarget, int iCell){ - assert( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ); - assert( hctPageheight(aTarget)==0 ); - assert( iCell>=0 && iCell<((HctDbIntkeyLeaf*)aTarget)->pg.nEntry ); - - return ((HctDbIntkeyLeaf*)aTarget)->aEntry[iCell].iKey; -} - -#if 0 -static i64 hctDbGetIntkeyFromPhys( - int *pRc, - HctDatabase *pDb, - u32 iPhys, - int iCell -){ - i64 iRet = 0; - int rc = *pRc; - if( rc==SQLITE_OK ){ - HctFilePage pg; - rc = sqlite3HctFilePageGetPhysical(pDb->pFile, iPhys, &pg); - if( rc==SQLITE_OK ){ - iRet = hctDbGetIntkey(pg.aOld, iCell); - sqlite3HctFilePageRelease(&pg); - } - } - *pRc = rc; - return iRet; -} -#endif - - -/* -** Buffer aPg contains an intkey leaf page. -** -** This function searches the leaf page for key iKey. If found, it returns -** the index of the matching key within the page and sets output variable -** (*pbExact) to 1. If there is no match for key iKey, this function returns -** the index of the smallest key on the page that is larger than iKey, or -** (nEntry) if all keys on the page are smaller than iKey. (*pbExact) is -** set to 0 before returning in this case. -*/ -static int hctDbIntkeyLeafSearch( - const u8 *aPg, - i64 iKey, - int *pbExact -){ - const HctDbIntkeyLeaf *pLeaf = (const HctDbIntkeyLeaf*)aPg; - int i1 = 0; - int i2 = pLeaf->pg.nEntry; - - assert( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ); - assert( pLeaf->pg.nHeight==0 ); - while( i2>i1 ){ - int iTest = (i1+i2)/2; - i64 iPgKey = pLeaf->aEntry[iTest].iKey; - if( iPgKey==iKey ){ - *pbExact = 1; - return iTest; - }else if( iPgKey=0 ); - assert( i2==pLeaf->pg.nEntry || iKeyaEntry[i2].iKey ); - assert( i2==0 || iKey>pLeaf->aEntry[i2-1].iKey ); - - *pbExact = 0; - return i2; -} - -static int hctDbIntkeyLocalsize(int pgsz, int nSize){ - const int nMax = ( - pgsz - - sizeof(HctDbIntkeyLeaf) - - sizeof(HctDbIntkeyEntry) - - (HCTDB_MAX_EXTRA_CELL_DATA - sizeof(u32)) - ); - - int nLocal; - if( nSize (nMax-sizeof(u32)) ){ - nLocal = nMin; - } - } - - return nLocal; -} - -static int hctDbIndexLocalsize(int pgsz, int nSize){ - int nLocal; - int nMax = pgsz/4; - if( nSizenMax ){ - nLocal = nMin; - } - } - return nLocal; -} - -static int hctDbLocalsize(const u8 *aPg, int pgsz, int nSize){ - if( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ){ - return hctDbIntkeyLocalsize(pgsz, nSize); - } - return hctDbIndexLocalsize(pgsz, nSize); -} - -static int hctDbIntkeyEntrySize(HctDbIntkeyEntry *pEntry, int pgsz){ - int sz = hctDbIntkeyLocalsize(pgsz, pEntry->nSize) - + hctDbOffset(0, pEntry->flags); - return sz; -} - -static int hctDbIndexEntrySize(HctDbIndexEntry *pEntry, int pgsz){ - int sz = hctDbIndexLocalsize(pgsz, pEntry->nSize) - + hctDbOffset(0, pEntry->flags); - return sz; -} - -static int hctDbIndexNodeEntrySize(HctDbIndexNodeEntry *pEntry, int pgsz){ - return hctDbIndexLocalsize(pgsz, pEntry->nSize) - + ((pEntry->flags & HCTDB_HAS_OVFL) ? 4 : 0); -} - -/* -** The pointer passed as the first argument is a pointer to a buffer -** containing a page that uses variable sized records. That is, an -** intkey leaf page, or an index leaf or node page. This function -** returns the number of bytes of record-area space consumed by -** entry iEntry on the page. -*/ -static int hctDbPageRecordSize(void *aPg, int pgsz, int iEntry){ - int eType = hctPagetype(aPg); - if( eType==HCT_PAGETYPE_INTKEY ){ - assert( hctPageheight(aPg)==0 ); - return hctDbIntkeyEntrySize(&((HctDbIntkeyLeaf*)aPg)->aEntry[iEntry], pgsz); - }else if( hctPageheight(aPg)==0 ){ - return hctDbIndexEntrySize(&((HctDbIndexLeaf*)aPg)->aEntry[iEntry], pgsz); - } - return hctDbIndexNodeEntrySize(&((HctDbIndexNode*)aPg)->aEntry[iEntry], pgsz); -} -static int hctDbPageEntrySize(void *aPg){ - int eType = hctPagetype(aPg); - if( eType==HCT_PAGETYPE_INTKEY ){ - assert( hctPageheight(aPg)==0 ); - return sizeof(HctDbIntkeyEntry); - }else if( hctPageheight(aPg)==0 ){ - return sizeof(HctDbIndexEntry); - } - return sizeof(HctDbIndexNodeEntry); -} - -/* -** The buffer passed as the first argument contains a page that is -** guaranteed to be either an intkey leaf, or an index leaf or node. -** This function returns a pointer to HctDbIndexEntry structure -** associated with page entry iEntry. -*/ -static HctDbIndexEntry *hctDbEntryEntry(const void *aPg, int iEntry){ - int iOff; - - assert( (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) - || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) - ); - - if( hctPagetype(aPg)==HCT_PAGETYPE_INTKEY ){ - iOff = sizeof(HctDbIntkeyLeaf) + iEntry*sizeof(HctDbIntkeyEntry); - }else if( hctPageheight(aPg)==0 ){ - iOff = sizeof(HctDbIndexLeaf) + iEntry*sizeof(HctDbIndexEntry); - }else{ - iOff = sizeof(HctDbIndexNode) + iEntry*sizeof(HctDbIndexNodeEntry); - } - - return (HctDbIndexEntry*)&((u8*)aPg)[iOff]; -} - -/* -** Argument aPg[] is a buffer containing either an index tree page, or an -** intkey leaf page. This function locates the record associated with -** cell iCell on the page, and populates output variables *pnData and -** *paData with the size and a pointer to a buffer containing the record, -** respectively. -** -** If the record in cell iCell does not overflow the page, (*paData) is -** set to point into the body of the page itself. If the record does -** overflow the page, then buffer pBuf is used to store the record and -** (*paData) is set to point to the buffer's allocation. In this case -** it is the responsibility of the caller to eventually release the buffer. -** -** SQLITE_OK is returned if successful, or an SQLite error code otherwise. -*/ -static int hctDbLoadRecord( - HctDatabase *pDb, - HctBuffer *pBuf, - const u8 *aPg, - int iCell, - int *pnData, - const u8 **paData -){ - int rc = SQLITE_OK; - HctDbIndexEntry *p = hctDbEntryEntry(aPg, iCell); - - *pnData = p->nSize; - if( paData ){ - if( p->flags & HCTDB_HAS_OVFL ){ - rc = sqlite3HctBufferGrow(pBuf, p->nSize); - *paData = pBuf->aBuf; - if( rc==SQLITE_OK ){ - u32 pgOvfl; - int nLocal = hctDbLocalsize(aPg, pDb->pgsz, p->nSize); - - int iOff = hctDbOffset(p->iOff, p->flags); - hctMemcpy(pBuf->aBuf, &aPg[iOff], nLocal); - pgOvfl = hctGetU32(&aPg[iOff-sizeof(u32)]); - iOff = nLocal; - - while( rc==SQLITE_OK && iOffnSize ){ - HctFilePage ovfl; - rc = hctDbGetPhysical(pDb, pgOvfl, &ovfl); - if( rc==SQLITE_OK ){ - int nCopy = MIN(pDb->pgsz-8, p->nSize-iOff); - hctMemcpy(&pBuf->aBuf[iOff],&ovfl.aOld[sizeof(HctDbPageHdr)],nCopy); - iOff += nCopy; - pgOvfl = ((HctDbPageHdr*)ovfl.aOld)->iPeerPg; - sqlite3HctFilePageRelease(&ovfl); - } - } - } - }else{ - int iOff = hctDbOffset(p->iOff, p->flags); - *paData = &aPg[iOff]; - } - } - - return rc; -} - -/* -** Buffer aPg[] contains either an index page or an intkey leaf (i.e. a page -** that contains variable length records). This function loads the record -** associated with cell iCell on the page, and populates output object -** pFP with the results. -** -** SQLITE_OK is returned if successful, or an SQLite error code otherwise. -*/ -static int hctDbLoadRecordFP( - HctDatabase *pDb, /* Database handle */ - const u8 *aPg, /* Page to load record from */ - int iCell, /* Cell to load */ - HctDbFPKey *pFP /* Populate this structure with record */ -){ - const u8 *aKey = 0; - int nKey = 0; - int rc = SQLITE_OK; - - rc = hctDbLoadRecord(pDb, &pFP->buf, aPg, iCell, &nKey, &aKey); - if( rc==SQLITE_OK ){ - if( aKey!=pFP->buf.aBuf ){ - rc = sqlite3HctBufferGrow(&pFP->buf, nKey); - if( rc==SQLITE_OK ){ - hctMemcpy(pFP->buf.aBuf, aKey, nKey); - } - } - pFP->iKey = nKey; - pFP->aKey = pFP->buf.aBuf; - } - - return rc; -} - -/* -** Buffer aPg[] contains a history fan page. -** -** This page searches the page, returning the index of the entry that -** points to the page with the largest key that is less than or equal -** to parameter pKey/iKey. -*/ -static int hctDbFanSearch( - int *pRc, - HctDatabase *pDb, - const u8 *aPg, - UnpackedRecord *pKey, - i64 iKey -){ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)aPg; - int rc = *pRc; - int i1 = 0; - int i2 = pFan->pg.nEntry-1; - HctBuffer buf = {0, 0, 0}; - - assert( hctPagetype(aPg)==HCT_PAGETYPE_HISTORY ); - - while( rc==SQLITE_OK && i2>i1 ){ - HctFilePage pg; - int iTest = (i1+i2)/2; - - rc = hctDbGetPhysical(pDb, pFan->aPgOld1[iTest], &pg); - while( rc==SQLITE_OK && hctPagetype(pg.aOld)==HCT_PAGETYPE_HISTORY ){ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aOld; - rc = hctDbGetPhysical(pDb, pFan->pgOld0, &pg); - } - if( rc==SQLITE_OK ){ - int iCell = (iTest==0 ? pFan->iSplit0 : 0); - - assert( pKey || hctPagetype(pg.aOld)==HCT_PAGETYPE_INTKEY ); - assert( pKey==0 || hctPagetype(pg.aOld)==HCT_PAGETYPE_INDEX ); - - if( pKey==0 ){ - i64 iPgKey = hctDbGetIntkey(pg.aOld, iCell); - if( iPgKey==iKey ){ - i1 = i2 = iTest+1; - }else if( iPgKeypKeyInfo->db, pRec); - } -} - -static UnpackedRecord *hctDbAllocateUnpacked(int *pRc, KeyInfo *pKeyInfo){ - UnpackedRecord *pRet = 0; - if( *pRc==SQLITE_OK ){ - pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); - if( pRet==0 ) *pRc = SQLITE_NOMEM_BKPT; - } - return pRet; -} - -SQLITE_PRIVATE void sqlite3HctDbRecordTrim(UnpackedRecord *pRec){ - if( pRec && pRec->pKeyInfo->nUniqField ){ - int ii; - u16 nUniqField = pRec->pKeyInfo->nUniqField; - for(ii=0; iiaMem[ii].flags & MEM_Null ){ - return; - } - } - pRec->nField = nUniqField; - } -} - - -/* -** This function returns the current snapshot-id. It may only be called -** when a read transaction is active. -*/ -SQLITE_PRIVATE i64 sqlite3HctDbSnapshotId(HctDatabase *pDb){ - assert( pDb->iSnapshotId>0 ); - return pDb->iSnapshotId; -} - -/* -** Load the key belonging to cell iCell on page aPg[] into structure (*pKey). -*/ -static void hctDbGetKey( - int *pRc, - HctDatabase *pDb, - KeyInfo *pKeyInfo, - int bDup, - const u8 *aPg, - int iCell, - HctDbKey *pKey -){ - int rc = *pRc; - - if( rc==SQLITE_OK ){ - assert( hctPageheight(aPg)==0 ); - assert( iCell>=0 && iCelliKey = hctDbGetIntkey(aPg, iCell); - }else{ - const u8 *aRec = 0; - int nRec = 0; - rc = hctDbLoadRecord(pDb, &pKey->buf, aPg, iCell, &nRec, &aRec); - if( aRec!=pKey->buf.aBuf && bDup && rc==SQLITE_OK ){ - rc = hctBufferSet(&pKey->buf, aRec, nRec); - aRec = pKey->buf.aBuf; - } - pKey->pKey = hctDbAllocateUnpacked(&rc, pKeyInfo); - if( rc==SQLITE_OK ){ - sqlite3VdbeRecordUnpack(pKeyInfo, nRec, aRec, pKey->pKey); - } - if( rc==SQLITE_OK ){ - sqlite3HctDbRecordTrim(pKey->pKey); - } - } - } - *pRc = rc; -} - -/* -** Retrieve the key from iCell of physical page iPhys. iPhys may be an -** intkey or index leaf page. Populate structure (*pKey) with the key -** value before returning. -*/ -static void hctDbGetKeyFromPage( - int *pRc, - HctDatabase *pDb, - KeyInfo *pKeyInfo, - int bLogical, /* True for logical, false for physical */ - u32 iPg, - int iCell, - HctDbKey *pKey -){ - int rc = *pRc; - - if( rc==SQLITE_OK ){ - HctFilePage pg; - if( bLogical ){ - rc = sqlite3HctFilePageGet(pDb->pFile, iPg, &pg); - }else{ - rc = hctDbGetPhysical(pDb, iPg, &pg); - while( rc==SQLITE_OK && hctPagetype(pg.aOld)==HCT_PAGETYPE_HISTORY ){ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aOld; - rc = hctDbGetPhysical(pDb, pFan->pgOld0, &pg); - } - } - if( rc==SQLITE_OK ){ - hctDbGetKey(&rc, pDb, pKeyInfo, 1, pg.aOld, iCell, pKey); - sqlite3HctFilePageRelease(&pg); - } - } - *pRc = rc; -} - -/* static RecordCompare find_record_compare((UnpackedRecord*, RecordCompare); */ -#define find_record_compare(pRec, xCompare) ( \ - (xCompare) ? (xCompare) : sqlite3VdbeFindCompare(pRec) \ -) - - -static int hctDbIndexSearch( - HctDatabase *pDb, - const u8 *aPg, - RecordCompare xCompare, - UnpackedRecord *pRec, - int *piPos, - int *pbExact -){ - int rc = SQLITE_OK; - HctBuffer buf; - int i1 = 0; - int i2 = ((HctDbPageHdr*)aPg)->nEntry; - - if( pRec ) xCompare = find_record_compare(pRec, xCompare); - memset(&buf, 0, sizeof(buf)); - - while( i2>i1 ){ - int iTest = (i1+i2)/2; - int res; - int nRec = 0; - const u8 *aRec = 0; - - rc = hctDbLoadRecord(pDb, &buf, aPg, iTest, &nRec, &aRec); - if( rc!=SQLITE_OK ) break; - if( nRec==0 ){ - res = -1; - }else{ - res = xCompare(nRec, aRec, pRec); - } - - if( res==0 ){ - *pbExact = 1; - *piPos = iTest; - sqlite3HctBufferFree(&buf); - return SQLITE_OK; - }else if( res<0 ){ - i1 = iTest+1; - }else{ - i2 = iTest; - } - } - - assert( i1==i2 && i2>=0 ); - sqlite3HctBufferFree(&buf); - *pbExact = 0; - *piPos = i2; - return rc; -} - - -/* -** The first argument is a pointer to an intkey internal node page. -** -** This function searches the node page for key iKey. If found, it returns -** the index of the matching key within the page and sets output variable -** (*pbExact) to 1. If there is no match for key iKey, this function returns -** the index of the smallest key on the page that is larger than iKey, or -** (nEntry) if all keys on the page are smaller than iKey. (*pbExact) is -** set to 0 before returning in this case. -*/ -static int hctDbIntkeyNodeSearch( - void *aPg, - i64 iKey, - int *pbExact -){ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPg; - int i1 = 0; - int i2 = pNode->pg.nEntry; - - assert( hctPagetype(pNode)==HCT_PAGETYPE_INTKEY && pNode->pg.nHeight>0 ); - while( i2>i1 ){ - int iTest = (i1+i2)/2; - i64 iPgKey = pNode->aEntry[iTest].iKey; - if( iPgKey==iKey ){ - *pbExact = 1; - return iTest; - }else if( iPgKey=0 ); - assert( i2==pNode->pg.nEntry || iKeyaEntry[i2].iKey ); - assert( i2==0 || iKey>pNode->aEntry[i2-1].iKey ); - - *pbExact = 0; - return i2; -} - -/* -** Set (*bGe) to true if (pRec >= (FP-key for aPg)). -*/ -static int hctDbCompareFPKey( - HctDatabase *pDb, - UnpackedRecord *pRec, - const u8 *aPg, - int *pbGe -){ - const u8 *aFP = 0; - int nFP = 0; - int res; - int rc; - HctBuffer buf = {0,0,0}; - - rc = hctDbLoadRecord(pDb, &buf, aPg, 0, &nFP, &aFP); - if( rc==SQLITE_OK ){ - res = sqlite3VdbeRecordCompare(nFP, aFP, pRec); - sqlite3HctBufferFree(&buf); - *pbGe = (res<=0); - } - return rc; -} - -static int hctDbCsrGoLeft(HctDbCsr*); - -/* -** Seek the cursor within its tree. This only seeks within the tree, it does -** not follow any old-data pointers. -*/ -int hctDbCsrSeek( - HctDbCsr *pCsr, /* Cursor to seek */ - HctDbFPKey *pFP, - int iHeight, /* Height to seek at (0==leaf, 1==parent) */ - RecordCompare xCompare, - UnpackedRecord *pRec, /* Key for index/without rowid tables */ - i64 iKey, /* Key for intkey tables */ - int *pbExact -){ - HctFile *pFile = pCsr->pDb->pFile; - u32 iPg = pCsr->iRoot; - int rc = SQLITE_OK; - - HctFilePage par; - memset(&par, 0, sizeof(par)); - int iPar = 0; - - if( pRec ) xCompare = find_record_compare(pRec, xCompare); - while( rc==SQLITE_OK ){ - if( iPg ) rc = sqlite3HctFilePageGet(pFile, iPg, &pCsr->pg); - if( rc==SQLITE_OK ){ - HctDbPageHdr *pHdr = (HctDbPageHdr*)pCsr->pg.aOld; - int i2 = pHdr->nEntry-1; - int bExact; - if( pHdr->nHeight==0 ){ - if( pRec ){ - rc = hctDbIndexSearch( - pCsr->pDb, pCsr->pg.aOld, xCompare, pRec, &i2, &bExact - ); - }else{ - i2 = hctDbIntkeyLeafSearch(pCsr->pg.aOld, iKey, &bExact); - } - if( bExact==0 ) i2--; - }else{ - if( pRec ){ - HctDbIndexNode *pNode = (HctDbIndexNode*)pCsr->pg.aOld; - rc = hctDbIndexSearch( - pCsr->pDb, pCsr->pg.aOld, xCompare, pRec, &i2, &bExact - ); - i2 -= !bExact; - iPg = pNode->aEntry[i2].iChildPg; - assert( iPg ); - }else{ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pCsr->pg.aOld; - i2 = hctDbIntkeyNodeSearch(pNode, iKey, &bExact); - assert( i2==pHdr->nEntry || iKey<=pNode->aEntry[i2].iKey ); - assert( i2==pHdr->nEntry || bExact==(iKey==pNode->aEntry[i2].iKey) ); - assert( i2nEntry || bExact==0 ); - i2 -= !bExact; - iPg = pNode->aEntry[i2].iChildPg; - assert( iPg ); - } - - /* Avoid following a pointer to an EVICTED page */ - if( pHdr->nHeight!=iHeight ){ - while( sqlite3HctFilePageIsEvicted(pFile, iPg) ){ - i2--; - if( i2<0 ){ - rc = hctDbCsrGoLeft(pCsr); - if( rc!=SQLITE_OK ) break; - i2 = pCsr->iCell; - } - - bExact = 0; - if( pRec ){ - HctDbIndexNode *pNode = (HctDbIndexNode*)pCsr->pg.aOld; - iPg = pNode->aEntry[i2].iChildPg; - }else{ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pCsr->pg.aOld; - iPg = pNode->aEntry[i2].iChildPg; - } - } - } - } - - - /* Test if it is necessary to skip to the peer node. */ - if( i2>=0 && i2==pHdr->nEntry-1 && pHdr->iPeerPg!=0 ){ - HctFilePage peer; - rc = sqlite3HctFilePageGet(pFile, pHdr->iPeerPg, &peer); - if( rc==SQLITE_OK ){ - int bGotoPeer; - if( pRec ){ - rc = hctDbCompareFPKey(pCsr->pDb, pRec, peer.aOld, &bGotoPeer); - }else{ - i64 iFP = hctDbIntkeyFPKey(peer.aOld); - bGotoPeer = (iFP<=iKey); - } - if( bGotoPeer ){ - SWAP(HctFilePage, pCsr->pg, peer); - sqlite3HctFilePageRelease(&peer); - assert( pCsr->pg.aOld ); - iPg = 0; - continue; - } - sqlite3HctFilePageRelease(&peer); - } - } - - if( pHdr->nHeight==iHeight ){ - pCsr->iCell = i2; - if( pbExact ) *pbExact = bExact; - - /* If parameter pFP was not NULL and there is a parent page stored - ** in variable par, try to load the FP key from that page. This - ** is used when seeking a cursor for writing. */ - if( pFP && par.aOld ){ - i64 iPeer = ((HctDbPageHdr*)pCsr->pg.aOld)->iPeerPg; - if( pRec ){ - HctDbIndexNode *pPar = (HctDbIndexNode*)par.aOld; - if( (iPar+1)pg.nEntry - && pPar->aEntry[iPar+1].iChildPg==iPeer - ){ - rc = hctDbLoadRecordFP(pCsr->pDb, par.aOld, iPar+1, pFP); - } - }else{ - HctDbIntkeyNode *pPar = (HctDbIntkeyNode*)par.aOld; - if( (iPar+1)pg.nEntry - && pPar->aEntry[iPar+1].iChildPg==iPeer - ){ - pFP->iKey = pPar->aEntry[iPar+1].iKey; - } - } - } - - break; - } - - if( pFP && pHdr->nHeight==iHeight+1 ){ - par = pCsr->pg; - iPar = i2; - memset(&pCsr->pg, 0, sizeof(HctFilePage)); - }else{ - sqlite3HctFilePageRelease(&pCsr->pg); - } - assert( rc!=SQLITE_OK || iPg!=0 ); - } - } - - if( pFP ) sqlite3HctFilePageRelease(&par); - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbCsrDir(HctDbCsr *pCsr, int eDir){ - pCsr->eDir = eDir; -} - -static int hctDbCellOffset(const u8 *aPage, int iCell, u8 *pFlags){ - HctDbPageHdr *pHdr = (HctDbPageHdr*)aPage; - int iRet; - if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ - HctDbIntkeyEntry *pEntry = &((HctDbIntkeyLeaf*)pHdr)->aEntry[iCell]; - *pFlags = pEntry->flags; - iRet = pEntry->iOff; - }else if( hctPageheight(pHdr)>0 ){ - HctDbIndexNodeEntry *pEntry = &((HctDbIndexNode*)pHdr)->aEntry[iCell]; - *pFlags = pEntry->flags; - iRet = pEntry->iOff; - }else{ - HctDbIndexEntry *pEntry = &((HctDbIndexLeaf*)pHdr)->aEntry[iCell]; - *pFlags = pEntry->flags; - iRet = pEntry->iOff; - } - return iRet; -} - -/* -** If the cursor is open on an index tree, ensure that the UnpackedRecord -** structure is allocated. Return SQLITE_NOMEM if an OOM is encountered -** while attempting to allocate said structure, or SQLITE_OK otherwise. -*/ -static int hctDbCsrAllocateUnpacked(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - if( pCsr->pKeyInfo && pCsr->pRec==0 ){ - pCsr->pRec = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo); - if( pCsr->pRec==0 ){ - rc = SQLITE_NOMEM_BKPT; - } - } - return rc; -} - -static const u8 *hctDbCsrPageAndCellIdx( - HctDbCsr *pCsr, - int iIdx, - int *piCell -){ - const u8 *aPg = 0; - int iCell = 0; - - if( iIdx<0 ){ - aPg = pCsr->pg.aOld; - iCell = pCsr->iCell; - }else{ - aPg = pCsr->aRange[iIdx].pg.aOld; - iCell = pCsr->aRange[iIdx].iCell; - } - *piCell = iCell; - return aPg; -} - -/* -** Return a pointer to the current page accessed by the cursor. Before -** returning, also set output variable (*piCell) to the index of the -** current cell within the page. -*/ -static const u8 *hctDbCsrPageAndCell(HctDbCsr *pCsr, int *piCell){ - const u8 *aPg = 0; - int iCell = 0; - if( pCsr->nRange ){ - aPg = pCsr->aRange[pCsr->nRange-1].pg.aOld; - iCell = pCsr->aRange[pCsr->nRange-1].iCell; - }else{ - aPg = pCsr->pg.aOld; - iCell = pCsr->iCell; - } - - *piCell = iCell; - return aPg; -} - -static void hctDbFreeKeyContents(HctDbKey *pKey){ - hctDbFreeUnpacked(pKey->pKey); - sqlite3HctBufferFree(&pKey->buf); -} - -static void hctDbCsrAscendRange(HctDbCsr *pCsr){ - HctDbRangeCsr *pLast = &pCsr->aRange[--pCsr->nRange]; - assert( pCsr->nRange>=0 ); - hctDbFreeKeyContents(&pLast->highkey); - hctDbFreeKeyContents(&pLast->lowkey); - sqlite3HctFilePageRelease(&pLast->pg); -} - -static void hctDbCsrReset(HctDbCsr *pCsr){ - sqlite3HctFilePageRelease(&pCsr->pg); - pCsr->iCell = -1; - while( pCsr->nRange>0 ){ - hctDbCsrAscendRange(pCsr); - } -} - -static void hctDbFreeCsr(HctDbCsr *pCsr){ - hctDbCsrReset(pCsr); - while( pCsr->intkey.pOpList ){ - HctCsrIntkeyOp *pOp = pCsr->intkey.pOpList; - pCsr->intkey.pOpList = pOp->pNextOp; - sqlite3_free(pOp); - } - while( pCsr->index.pOpList ){ - HctCsrIndexOp *pOp = pCsr->index.pOpList; - pCsr->index.pOpList = pOp->pNextOp; - if( pOp->pLast!=pOp->pFirst ){ - sqlite3_free(pOp->pLast); - } - sqlite3_free(pOp->pFirst); - sqlite3_free(pOp); - } - if( pCsr->pRec ) sqlite3DbFree(pCsr->pKeyInfo->db, pCsr->pRec); - sqlite3KeyInfoUnref(pCsr->pKeyInfo); - sqlite3HctBufferFree(&pCsr->rec); - sqlite3_free(pCsr->aRange); - pCsr->aRange = 0; - pCsr->nRangeAlloc = 0; - sqlite3_free(pCsr); -} - -static void hctDbCsrCleanup(HctDbCsr *pCsr){ - hctDbCsrReset(pCsr); - if( pCsr->pKeyInfo ){ - sqlite3DbFree(pCsr->pKeyInfo->db, pCsr->pRec); - sqlite3KeyInfoUnref(pCsr->pKeyInfo); - pCsr->pKeyInfo = 0; - pCsr->pRec = 0; - } - sqlite3_free(pCsr->aRange); - pCsr->aRange = 0; - pCsr->nRangeAlloc = 0; - sqlite3HctBufferFree(&pCsr->rec); - pCsr->iRoot = 0; -} - -static int hctDbCsrScanStart(HctDbCsr *pCsr, UnpackedRecord *pRec, i64 iKey){ - int rc = SQLITE_OK; - - if( pCsr->pDb->bConcurrent ){ - if( pCsr->pDb->iTid==0 ){ - if( pCsr->pKeyInfo==0 ){ - HctCsrIntkeyOp *pOp = 0; - pOp = sqlite3MallocZero(sizeof(HctCsrIntkeyOp)); - if( pOp==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - assert( pCsr->intkey.pCurrentOp==0 ); - pOp->iFirst = pOp->iLast = iKey; - pCsr->intkey.pCurrentOp = pOp; - pOp->iLogical = pCsr->pg.iPg; - pOp->iPhysical = pCsr->pg.iOldPg; - } - }else{ - HctCsrIndexOp *pOp = 0; - pOp = sqlite3MallocZero(sizeof(HctCsrIndexOp)); - if( pOp==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - if( pRec ){ - rc = sqlite3HctSerializeRecord(pRec, &pOp->pFirst, &pOp->nFirst); - pOp->pLast = pOp->pFirst; - pOp->nLast = pOp->nFirst; - pOp->iLogical = pCsr->pg.iPg; - pOp->iPhysical = pCsr->pg.iOldPg; - } - assert( pCsr->index.pCurrentOp==0 ); - pCsr->index.pCurrentOp = pOp; - } - } - } - } - - return rc; -} - -static int hctDbCsrScanFinish(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - if( pCsr->pDb->bConcurrent ){ - if( pCsr->pKeyInfo==0 ){ - HctCsrIntkeyOp *pOp = pCsr->intkey.pCurrentOp; - pCsr->intkey.pCurrentOp = 0; - if( pOp ){ - HctCsrIntkeyOp *pPrev = pCsr->intkey.pOpList; - - if( pCsr->eDir!=BTREE_DIR_NONE ){ - i64 iVal = 0; - if( sqlite3HctDbCsrEof(pCsr) ){ - if( pCsr->eDir==BTREE_DIR_FORWARD ){ - iVal = LARGEST_INT64; - }else{ - iVal = SMALLEST_INT64; - } - pOp->iLogical = pOp->iPhysical = 0; - }else{ - sqlite3HctDbCsrKey(pCsr, &iVal); - if( pCsr->pg.iPg!=pOp->iLogical ){ - pOp->iLogical = pOp->iPhysical = 0; - } - } - - if( iVal>=pOp->iFirst ){ - pOp->iLast = iVal; - }else{ - pOp->iLast = pOp->iFirst; - pOp->iFirst = iVal; - } - } - - if( pPrev && pOp->iLast<=pPrev->iLast && pOp->iFirst>=pPrev->iFirst ){ - pPrev->iLogical = pPrev->iPhysical = 0; - sqlite3_free(pOp); - }else{ - pOp->pNextOp = pPrev; - pCsr->intkey.pOpList = pOp; - } - } - }else{ - HctCsrIndexOp *pOp = pCsr->index.pCurrentOp; - pCsr->index.pCurrentOp = 0; - if( pOp ){ - if( pCsr->eDir!=BTREE_DIR_NONE ){ - int nKey = 0; - u8 *aCopy = 0; - if( !sqlite3HctDbCsrEof(pCsr) ){ - const u8 *aKey = 0; - rc = sqlite3HctDbCsrData(pCsr, &nKey, &aKey); - if( rc==SQLITE_OK ){ - aCopy = sqlite3_malloc(nKey); - if( aCopy==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - hctMemcpy(aCopy, aKey, nKey); - } - } - if( pCsr->pg.iPg!=pOp->iLogical ){ - pOp->iLogical = pOp->iPhysical = 0; - } - }else{ - pOp->iLogical = pOp->iPhysical = 0; - } - - if( pCsr->eDir==BTREE_DIR_FORWARD ){ - pOp->pLast = aCopy; - pOp->nLast = nKey; - }else{ - pOp->pFirst = aCopy; - pOp->nFirst = nKey; - } - } - - pOp->pNextOp = pCsr->index.pOpList; - pCsr->index.pOpList = pOp; - } - } - } - - return rc; -} - -static int hctDbCsrFirst(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - - /* Starting at the root of the tree structure, follow the left-most - ** pointers to find the left-most node in the list of leaves. */ - u32 iPg = pCsr->iRoot; - HctFile *pFile = pCsr->pDb->pFile; - HctFilePage pg; - while( 1 ){ - HctDbPageHdr *pPg; - rc = sqlite3HctFilePageGet(pFile, iPg, &pg); - if( rc!=SQLITE_OK ) break; - pPg = (HctDbPageHdr*)pg.aOld; - if( pPg->nHeight==0 ){ - break; - }else if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY ){ - iPg = ((HctDbIntkeyNode*)pPg)->aEntry[0].iChildPg; - }else{ - iPg = ((HctDbIndexNode*)pPg)->aEntry[0].iChildPg; - } - sqlite3HctFilePageRelease(&pg); - } - hctMemcpy(&pCsr->pg, &pg, sizeof(pg)); - if( ((HctDbPageHdr*)pCsr->pg.aOld)->nEntry>0 ){ - pCsr->iCell = 0; - }else{ - pCsr->iCell = -1; - } - return rc; -} - -static int hctDbCsrFirstValid(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - - rc = hctDbCsrFirst(pCsr); - - /* Skip forward to the first visible entry, if any. */ - if( rc==SQLITE_OK ){ - pCsr->iCell = -1; - rc = sqlite3HctDbCsrNext(pCsr); - } - - return rc; -} - -static int hctDbCellPut( - u8 *aBuf, - HctDbCell *pCell, - int nLocal -){ - int iOff = 0; - if( pCell->iTid ){ - hctMemcpy(&aBuf[iOff], &pCell->iTid, sizeof(u64)); - iOff += sizeof(u64); - } - if( pCell->iRangeTid ){ - hctMemcpy(&aBuf[iOff], &pCell->iRangeTid, sizeof(u64)); - iOff += sizeof(u64); - } - if( pCell->iRangeOld ){ - hctMemcpy(&aBuf[iOff], &pCell->iRangeOld, sizeof(u32)); - iOff += sizeof(u32); - } - if( pCell->iOvfl ){ - hctMemcpy(&aBuf[iOff], &pCell->iOvfl, sizeof(u32)); - iOff += sizeof(u32); - } - hctMemcpy(&aBuf[iOff], pCell->aPayload, nLocal); - return iOff+nLocal; -} - -static void hctDbCellGet( - HctDatabase *pDb, - const u8 *aBuf, - int flags, - HctDbCell *pCell -){ - int iOff = 0; - memset(pCell, 0, sizeof(HctDbCell)); - - if( flags & HCTDB_HAS_TID ){ - hctMemcpy(&pCell->iTid, &aBuf[iOff], sizeof(u64)); - iOff += sizeof(u64); - } - if( flags & HCTDB_HAS_RANGETID ){ - hctMemcpy(&pCell->iRangeTid, &aBuf[iOff], sizeof(u64)); - iOff += sizeof(u64); - } - if( flags & HCTDB_HAS_RANGEOLD ){ - hctMemcpy(&pCell->iRangeOld, &aBuf[iOff], sizeof(u32)); - iOff += sizeof(u32); - } - if( flags & HCTDB_HAS_OVFL ){ - hctMemcpy(&pCell->iOvfl, &aBuf[iOff], sizeof(u32)); - iOff += sizeof(u32); - } - - pCell->aPayload = &aBuf[iOff]; -} - -static void hctDbCellGetByIdx( - HctDatabase *pDb, - const u8 *aPg, - int iIdx, - HctDbCell *pCell -){ - HctDbIndexEntry *p = hctDbEntryEntry(aPg, iIdx); - hctDbCellGet(pDb, &aPg[p->iOff], p->flags, pCell); -} - -static u8 hctDbCellToFlags(HctDbCell *pCell){ - u8 flags = 0; - if( pCell->iTid ) flags |= HCTDB_HAS_TID; - if( pCell->iOvfl ) flags |= HCTDB_HAS_OVFL; - if( pCell->iRangeTid ) flags |= HCTDB_HAS_RANGETID; - if( pCell->iRangeOld ) flags |= HCTDB_HAS_RANGEOLD; - return flags; -} - -typedef struct HctRangePtr HctRangePtr; -struct HctRangePtr { - u64 iRangeTid; - u64 iFollowTid; - u32 iOld; -}; - -/* -** This function is called when a reader encounters an old-range pointer -** with associated TID value iRangeTid. It returns true if the pointer -** should be followed, or false otherwise. -** -** If the data items on the linked page should be merged in to the cursor -** results, output parameter (*pbMerge) is set to true before returning. -** This happens if the transaction with TID iRangeTid is not visible to -** the reader. Or, if the only reason to follow the pointer is in order -** to follow other pointers on the indicated page, (*pbMerge) is set to -** true. This happens when iRangeTid is included in the transaction, but -** there exists one or more transactions with TID values smaller than iRangeTid -** that are not. -*/ -static int hctDbFollowRangeOld( - HctDatabase *pDb, - HctRangePtr *pPtr, - int *pbMerge -){ - int bRet = 0; - int bMerge = 0; - u64 iRangeTidValue = (pPtr->iRangeTid & HCT_TID_MASK); - - /* HctDatabase.iTid is set when writing, validating or rolling back a - ** transaction. When writing or validating, old-ranges created by this - ** transaction should not be merge in, even if they are followed. But, when - ** doing rollback, they must be merged in (to find the old data). */ - - i64 iDoNotMergeTid = (pDb->eMode==HCT_MODE_VALIDATE) ? 0 : pDb->iTid; - assert( pDb->eMode!=HCT_MODE_ROLLBACK ); - - if( iRangeTidValue>pDb->iLocalMinTid ){ - bRet = 1; - if( iDoNotMergeTid!=iRangeTidValue ){ - bMerge = (0==hctDbTidIsVisible(pDb, pPtr->iRangeTid, 0)); - } - }else if( (pPtr->iFollowTid & HCT_TID_MASK)>pDb->iLocalMinTid ){ - bRet = 1; - assert( bMerge==0 ); - } - - *pbMerge = bMerge; - assert( bRet==0 || iRangeTidValue>0 ); - return bRet; -} - -static int hctDbCsrExtendRange(HctDbCsr *pCsr){ - if( pCsr->nRange==pCsr->nRangeAlloc ){ - int nNew = pCsr->nRangeAlloc ? pCsr->nRangeAlloc*2 : 16; - HctDbRangeCsr *aNew = 0; - - aNew = (HctDbRangeCsr*)sqlite3_realloc( - pCsr->aRange, nNew*sizeof(HctDbRangeCsr) - ); - if( aNew==0 ) return SQLITE_NOMEM_BKPT; - pCsr->nRangeAlloc = nNew; - pCsr->aRange = aNew; - } - - memset(&pCsr->aRange[pCsr->nRange], 0, sizeof(HctDbRangeCsr)); - pCsr->nRange++; - return SQLITE_OK; -} - -static int hctDbCompareKey2( - KeyInfo *pKeyInfo, - UnpackedRecord *pKey1, - i64 iKey1, - HctDbKey *p2 -){ - int ret = 0; - if( pKeyInfo ){ - int ii = 0; - int n1, n2; - - if( pKey1==0 ) return 1; - if( p2->pKey==0 ) return -1; - - n1 = pKey1->nField; - n2 = p2->pKey->nField; - - for(ii=0; ret==0 && iiaColl[ii]; - ret = sqlite3MemCompare(&pKey1->aMem[ii], &p2->pKey->aMem[ii], pColl); - if( pKeyInfo->aSortFlags[ii] & KEYINFO_ORDER_DESC ) ret = -ret; - } - if( ret==0 ){ - /* default_rc==1 if the key has been passed to hctDbDecrementKey() */ - assert( pKey1->default_rc==0 || pKey1->default_rc==1 ); - assert( p2->pKey->default_rc==0 || p2->pKey->default_rc==1 ); - ret = p2->pKey->default_rc - pKey1->default_rc; - } - if( ret==0 ){ - if( n1n2 ){ - ret = +1; - } - } - }else{ - if( iKey1iKey ){ - ret = -1; - }else if( iKey1>p2->iKey ){ - ret = +1; - } - } - return ret; -} - -/* -** Compare the key values in p1 and p2, returning a value less than, equal -** to, or greater than zero if p1 is respectively less than, equal to or -** greater than p2. i.e. -** -** res = (*p1) - (*p2) -*/ -static int hctDbCompareKey(KeyInfo *pKeyInfo, HctDbKey *p1, HctDbKey *p2){ - return hctDbCompareKey2(pKeyInfo, p1->pKey, p1->iKey, p2); -} - -static int hctDbCopyKey(HctDbKey *p1, HctDbKey *p2){ - if( p2->pKey ){ - int ii; - int bNew = 0; - if( p1->pKey==0 || p1->pKey->nFieldpKey->nField ){ - int rc = SQLITE_OK; - hctDbFreeUnpacked(p1->pKey); - p1->pKey = hctDbAllocateUnpacked(&rc, p2->pKey->pKeyInfo); - if( rc!=SQLITE_OK ) return rc; - bNew = 1; - p1->pKey->default_rc = 0; - } - for(ii=0; iipKey->nField; ii++){ - Mem *pFrom = &p2->pKey->aMem[ii]; - Mem *pTo = &p1->pKey->aMem[ii]; - if( bNew ) sqlite3VdbeMemInit(pTo, pFrom->db, 0); - sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Static); - } - p1->pKey->nField = p2->pKey->nField; - p1->pKey->default_rc = p2->pKey->default_rc; - }else{ - p1->iKey = p2->iKey; - } - return SQLITE_OK; -} - -static void hctDbDecrementKey(HctDbKey *pKey){ - if( pKey->pKey ){ - /* TODO: Is this correct? Or should it be +1? Or...? */ - pKey->pKey->default_rc = +1; - }else if( pKey->iKey!=SMALLEST_INT64 ){ - pKey->iKey--; - } -} - -static void hctDbCsrDescendRange( - int *pRc, - HctDbCsr *pCsr, - u64 iRangeTid, - u32 iRangeOld, - int bMerge -){ - int rc = *pRc; - - if( rc==SQLITE_OK ){ - rc = hctDbCsrExtendRange(pCsr); - } - - if( rc==SQLITE_OK ){ - HctDbRangeCsr *pNew = &pCsr->aRange[pCsr->nRange-1]; - assert( bMerge==HCT_RANGE_FOLLOW || bMerge==HCT_RANGE_MERGE ); - - pNew->eRange = bMerge; - pNew->iRangeTid = iRangeTid; - rc = hctDbGetPhysical(pCsr->pDb, iRangeOld, &pNew->pg); - - if( rc==SQLITE_OK ){ - int iPar = pCsr->nRange-2; - int iPCell = 0; - const u8 *aParent = hctDbCsrPageAndCellIdx(pCsr, iPar, &iPCell); - const HctDbPageHdr *pPar = (HctDbPageHdr*)aParent; - int bSeen = 0; - - /* Figure out the upper limit key for the scan of this page */ - if( hctPagetype(aParent)==HCT_PAGETYPE_HISTORY ){ - if( iPCell==0 && pPar->nEntry>1 ){ - const HctDbHistoryFan *pFan = (const HctDbHistoryFan*)aParent; - hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, - 0, pFan->aPgOld1[0], pFan->iSplit0, &pNew->highkey - ); - bSeen = 1; - } - }else{ - if( iPCell==(pPar->nEntry-1) ){ - if( pPar->iPeerPg ){ - hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, - 1, pPar->iPeerPg, 0, &pNew->highkey - ); - bSeen = 1; - } - }else{ - hctDbGetKey(&rc, - pCsr->pDb, pCsr->pKeyInfo, 0, aParent, iPCell+1, &pNew->highkey - ); - bSeen = 1; - } - } - - if( bSeen==0 ){ - if( iPar>=0 ){ - hctDbCopyKey(&pNew->highkey, &pNew[-1].highkey); - }else{ - pNew->highkey.iKey = LARGEST_INT64; - assert( pNew->highkey.pKey==0 ); - } - }else if( iPar>=0 ){ - /* The 'highkey' should be the minimum of pNew->highkey and the - ** parent highkey. highkey = MIN(highkey, parent.highkey); */ - HctDbKey *pPKey = &pNew[-1].highkey; - if( hctDbCompareKey(pCsr->pKeyInfo, &pNew->highkey, pPKey)>0 ){ - hctDbCopyKey(&pNew->highkey, pPKey); - } - } - - /* Figure the lower limit key for the scan of this page */ - pNew->lowkey.iKey = SMALLEST_INT64; - if( hctPagetype(aParent)==HCT_PAGETYPE_HISTORY ){ - if( iPCell>0 ){ - const HctDbHistoryFan *pFan = (const HctDbHistoryFan*)aParent; - hctDbGetKeyFromPage(&rc, pCsr->pDb, pCsr->pKeyInfo, - 0, pFan->aPgOld1[0], pFan->iSplit0, &pNew->lowkey - ); - hctDbDecrementKey(&pNew->lowkey); - }else{ - hctDbCopyKey(&pNew->lowkey, &pNew[-1].lowkey); - } - }else{ - HctDbCell pcell; - hctDbGetKey(&rc, - pCsr->pDb, pCsr->pKeyInfo, 0, aParent, iPCell, &pNew->lowkey - ); - hctDbCellGetByIdx(pCsr->pDb, aParent, iPCell, &pcell); - if( hctDbTidIsVisible(pCsr->pDb, pcell.iTid, 0)==0 ){ - hctDbDecrementKey(&pNew->lowkey); - } - } - if( iPar>=0 ){ - /* The 'lowkey' should be the maximum of pNew->lowkey and the - ** parent lowkey. lowkey = MAX(lowkey, parent.lowkey); */ - HctDbKey *pPKey = &pNew[-1].lowkey; - if( hctDbCompareKey(pCsr->pKeyInfo, &pNew->lowkey, pPKey)<0 ){ - hctDbCopyKey(&pNew->lowkey, pPKey); - } - } - - if( rc==SQLITE_OK && hctPagetype(pNew->pg.aOld)==HCT_PAGETYPE_HISTORY){ - pNew->eRange = HCT_RANGE_FAN; - } - } - } - - *pRc = rc; -} - -static void hctDbGetRange( - const u8 *aPg, - int iCell, - HctRangePtr *pPtr -){ - if( iCell<0 ){ - memset(pPtr, 0, sizeof(*pPtr)); - }else if( hctPagetype(aPg)==HCT_PAGETYPE_HISTORY ){ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)aPg; - if( iCell==0 ){ - pPtr->iRangeTid = pFan->iRangeTid0; - pPtr->iFollowTid = pFan->iFollowTid0; - pPtr->iOld = pFan->pgOld0; - }else{ - pPtr->iFollowTid = pPtr->iRangeTid = pFan->iRangeTid1; - pPtr->iOld = pFan->aPgOld1[iCell-1]; - } - }else{ - HctDbCell cell; - hctDbCellGetByIdx(0, aPg, iCell, &cell); - pPtr->iFollowTid = pPtr->iRangeTid = cell.iRangeTid; - pPtr->iOld = cell.iRangeOld; - } - - assert( (pPtr->iFollowTid & HCT_TID_MASK)>=(pPtr->iRangeTid & HCT_TID_MASK) ); -} - -static void hctDbCsrGetRange( - HctDbCsr *pCsr, - HctRangePtr *pPtr -){ - const u8 *aPg = 0; - int iCell = 0; - aPg = hctDbCsrPageAndCell(pCsr, &iCell); - assert( ((HctDbPageHdr*)aPg)->nEntry>iCell ); - assert( ((HctDbPageHdr*)aPg)->nHeight==0 ); - hctDbGetRange(aPg, iCell, pPtr); -} - -/* -** Return true if the entry that the cursor currently points to is visible -** to the current transaction, or false otherwise. -*/ -static int hctDbCurrentIsVisible(HctDbCsr *pCsr){ - int iCell = 0; - HctDbIndexEntry *p; - const u8 *aPg = hctDbCsrPageAndCell(pCsr, &iCell); - u64 iTid = 0; - - if( pCsr->pKeyInfo ){ - p = &((HctDbIndexLeaf*)aPg)->aEntry[iCell]; - }else{ - p = (HctDbIndexEntry*)&((HctDbIntkeyLeaf*)aPg)->aEntry[iCell]; - } - if( (p->flags & HCTDB_HAS_TID)==0 ) return 1; - hctMemcpy(&iTid, &aPg[p->iOff], sizeof(u64)); - if( pCsr->pDb->iTid==iTid && pCsr->pDb->eMode==HCT_MODE_VALIDATE ) return 1; - - return hctDbTidIsVisible(pCsr->pDb, iTid, pCsr->bNosnap); -} - -/* -** Search leaf page aPg[] for a specified key. -** -** If the key is present in the page, set output variable (*piPos) to -** the index of the key in the page, and (*pbExact) to true. -** -** Or, if the key is not present in the page, set output variable (*piPos) -** to the index of the SMALLEST KEY THAT IS LARGER THAN IKEY/PKEY, and -** set (*pbExact) to false. -*/ -static int hctDbLeafSearch( - HctDatabase *pDb, - const u8 *aPg, - i64 iKey, - UnpackedRecord *pKey, - int *piPos, - int *pbExact -){ - if( hctPagetype(aPg)==HCT_PAGETYPE_INDEX ){ - if( pKey==0 ){ - *piPos = hctPagenentry(aPg); - *pbExact = 0; - }else{ - int rc = hctDbIndexSearch(pDb, aPg, 0, pKey, piPos, pbExact); - if( rc ) return rc; - } - }else{ - *piPos = hctDbIntkeyLeafSearch(aPg, iKey, pbExact); - } - return SQLITE_OK; -} - -static int hctDbCsrRollbackDescend( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index/without rowid tables */ - i64 iKey, /* Key for intkey tables */ - int *pbExact -){ - HctDatabase *pDb = pCsr->pDb; - int bExact = 0; - int rc = SQLITE_OK; - - assert( pDb->eMode==HCT_MODE_ROLLBACK ); - while( 1 ){ - HctRangePtr ptr; - HctDbRangeCsr *p = 0; - - hctDbCsrGetRange(pCsr, &ptr); - - if( (ptr.iFollowTid & HCT_TID_MASK)pDb->iTid ) break; - - rc = hctDbCsrExtendRange(pCsr); - if( rc==SQLITE_OK ){ - p = &pCsr->aRange[pCsr->nRange-1]; - rc = hctDbGetPhysical(pDb, ptr.iOld, &p->pg); - } - if( rc==SQLITE_OK ){ - p->iRangeTid = ptr.iRangeTid & HCT_TID_MASK; - if( hctPagetype(p->pg.aOld)==HCT_PAGETYPE_HISTORY ){ - p->eRange = HCT_RANGE_FAN; - p->iCell = hctDbFanSearch(&rc, pCsr->pDb, p->pg.aOld, pRec, iKey); - bExact = 0; - }else{ - p->eRange = HCT_RANGE_MERGE; - rc = hctDbLeafSearch( - pCsr->pDb, p->pg.aOld, iKey, pRec, &p->iCell, &bExact - ); - if( rc!=SQLITE_OK || bExact ) break; - p->iCell--; - if( p->iCell<0 ) break; - } - } - } - - *pbExact = bExact; - return rc; -} - -static int hctDbCsrSeekAndDescend( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index/without rowid tables */ - i64 iKey, /* Key for intkey tables */ - int bStopOnExact, /* Stop on exact match, even if not visible */ - int *pbExact -){ - int rc = SQLITE_OK; - int bExact = 0; - - /* This function is never called when writing to the database. Or while - ** doing rollback. But it is called during transaction preparation (iTid==0), - ** and validation (eMode==HCT_MODE_VALIDATE). */ - assert( pCsr->pDb->eMode==HCT_MODE_VALIDATE || pCsr->pDb->iTid==0 ); - - rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, iKey, &bExact); - if( bExact && bStopOnExact ){ - *pbExact = 1; - return rc; - } - - while( rc==SQLITE_OK && (0==bExact || 0==hctDbCurrentIsVisible(pCsr)) ){ - HctRangePtr ptr; - int bMerge = 0; - - /* Check if there is a range pointer that we should follow */ - hctDbCsrGetRange(pCsr, &ptr); - if( hctDbFollowRangeOld(pCsr->pDb, &ptr, &bMerge) ){ - hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); - if( rc==SQLITE_OK ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - - assert( hctDbCompareKey2(pCsr->pKeyInfo, pRec, iKey, &p->lowkey)>=0 ); - if( hctDbCompareKey2(pCsr->pKeyInfo, pRec, iKey, &p->lowkey)<=0 ){ - p->iCell = -1; - break; - } - - if( p->eRange==HCT_RANGE_FAN ){ - p->iCell = hctDbFanSearch(&rc, pCsr->pDb, p->pg.aOld, pRec, iKey); - bExact = 0; - }else{ - rc = hctDbLeafSearch( - pCsr->pDb, p->pg.aOld, iKey, pRec, &p->iCell, &bExact - ); - if( rc!=SQLITE_OK ) break; - if( bExact==0 ){ - p->iCell--; - }else if( bStopOnExact ){ - *pbExact = 1; - return SQLITE_OK; - } - if( p->iCell<0 ) break; - if( p->eRange==HCT_RANGE_FOLLOW ) bExact = 0; - } - } - }else{ - break; - } - } - - while( rc==SQLITE_OK && pCsr->nRange>0 ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - if( p->eRange==HCT_RANGE_MERGE && p->iCell>=0 ) break; - hctDbCsrAscendRange(pCsr); - } - - *pbExact = bExact; - return rc; -} - -/* -** Find the CID of the last transaction to write to a specified key. -** -** This must be called from within a transaction. -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrFindLastWrite( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index/without rowid tables */ - i64 iKey, /* Key for intkey tables */ - u64 *piCid /* Last CID to write to this key */ -){ - int rc = SQLITE_OK; - u64 iCid = 0; - int bExact = 0; - - rc = hctDbCsrSeekAndDescend(pCsr, pRec, iKey, 1, &bExact); - if( rc==SQLITE_OK && bExact ){ - u64 iTid = 0; - if( pCsr->nRange>1 ){ - /* In this case the key has been deleted. Find the TID of the - ** transaction that deleted it. */ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-2]; - HctRangePtr ptr; - hctDbGetRange(p->pg.aOld, p->iCell, &ptr); - iTid = ptr.iRangeTid; - }else{ - HctDbCell cell; - hctDbCellGetByIdx(pCsr->pDb, pCsr->pg.aOld, pCsr->iCell, &cell); - if( pCsr->nRange ){ - assert( pCsr->nRange==1 ); - iTid = cell.iRangeTid; - }else{ - iTid = cell.iTid; - } - } - - if( iTid ){ - u64 dummy = 0; - iTid = (iTid & HCT_TID_MASK); - iCid = hctDbTMapLookup(pCsr->pDb, iTid, &dummy); - }else{ - iCid = 1; - } - } - - *piCid = iCid; - return rc; -} - -/* -** An integer is written into *pRes which is the result of -** comparing the key with the entry to which the cursor is -** pointing. The meaning of the integer written into -** *pRes is as follows: -** -** *pRes<0 The cursor is left pointing at an entry that -** is smaller than iKey/pRec or if the table is empty -** and the cursor is therefore left point to nothing. -** -** *pRes==0 The cursor is left pointing at an entry that -** exactly matches iKey/pRec. -** -** *pRes>0 The cursor is left pointing at an entry that -** is larger than iKey/pRec. -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrSeek( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index tables */ - i64 iKey, /* Key for intkey tables */ - int *pRes /* Result of seek (see above) */ -){ - int rc = SQLITE_OK; - int bExact; - - /* Should not be called while committing, validating or during rollback. */ - assert( pCsr->pDb->eMode==HCT_MODE_NORMAL ); - assert( pCsr->pDb->iTid==0 ); - - rc = hctDbCsrScanFinish(pCsr); - hctDbCsrReset(pCsr); - - if( rc==SQLITE_OK ){ - rc = hctDbCsrSeekAndDescend(pCsr, pRec, iKey, 0, &bExact); - } - if( rc==SQLITE_OK ){ - rc = hctDbCsrScanStart(pCsr, pRec, iKey); - } - - /* The main cursor now points to the largest entry less than or equal - ** to the supplied key (pRec or iKey). If the supplied key is smaller - ** than all entries in the table, then pCsr->iCell is set to -1. */ - if( rc==SQLITE_OK ){ - if( pCsr->iCell<0 ){ - /* The supplied key is smaller than all keys in the table. If the cursor - ** is BTREE_DIR_REVERSE or NONE, then leave it as it is at EOF. - ** Otherwise, if the cursor is BTREE_DIR_FORWARD, attempt to move - ** it to the first valid entry. */ - if( pCsr->eDir==BTREE_DIR_FORWARD ){ - rc = hctDbCsrFirstValid(pCsr); - *pRes = sqlite3HctDbCsrEof(pCsr) ? -1 : +1; - }else{ - *pRes = -1; - } - }else{ - - if( rc==SQLITE_OK && 0==hctDbCurrentIsVisible(pCsr) ){ - switch( pCsr->eDir ){ - case BTREE_DIR_FORWARD: - *pRes = 1; - rc = sqlite3HctDbCsrNext(pCsr); - *pRes = sqlite3HctDbCsrEof(pCsr) ? -1 : +1; - break; - case BTREE_DIR_REVERSE: - rc = sqlite3HctDbCsrPrev(pCsr); - /* Either the cursor is is now at EOF or it points to a key - ** smaller than iKey/pRec. Either way, set (*pRes) to -ve. */ - *pRes = -1; - break; - default: assert( pCsr->eDir==BTREE_DIR_NONE ); - hctDbCsrReset(pCsr); - *pRes = -1; - break; - } - }else{ - *pRes = (bExact ? 0 : -1); - } - } - } - - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbSetSavePhysical( - HctDatabase *pDb, - int (*xSave)(void*, i64 iPhys), - void *pSave -){ - pDb->xSavePhysical = xSave; - pDb->pSavePhysical = pSave; -} - -SQLITE_PRIVATE int sqlite3HctDbCsrRollbackSeek( - HctDbCsr *pCsr, /* Cursor to seek */ - UnpackedRecord *pRec, /* Key for index tables */ - i64 iKey, /* Key for intkey tables */ - int *pOp /* Required rollback op */ -){ - HctDatabase *pDb = pCsr->pDb; - int rc = SQLITE_OK; - int bExact = 0; - int op = 0; - - hctDbCsrReset(pCsr); - - /* At this point pDb->bRollback is set and pDb->iTid is set to the TID - ** of the transaction being rolled back. There are four possibilities: - ** - ** 1) The key was written by transaction pDb->iTid and there was no - ** previous entry. - ** - ** 2) The key was written by transaction pDb->iTid and there is a - ** previous entry to restore. - ** - ** 3) The key was deleted by transaction pDb->iTid. - ** - ** 4) None of the above. No rollback required. - */ - - rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, iKey, &bExact); - if( rc==SQLITE_OK && bExact==0 ){ - rc = hctDbCsrRollbackDescend(pCsr, pRec, iKey, &bExact); - } - - if( rc==SQLITE_OK && bExact ){ - HctDbCell cell; - int iCell = 0; - const u8 *aPg = hctDbCsrPageAndCell(pCsr, &iCell); - - memset(&cell, 0, sizeof(cell)); - hctDbCellGetByIdx(pDb, aPg, iCell, &cell); - if( cell.iTid==pDb->iTid ){ - op = -1; - rc = hctDbCsrRollbackDescend(pCsr, pRec, iKey, &bExact); - } - - if( rc==SQLITE_OK - && bExact - && pCsr->nRange && pDb->iTid==pCsr->aRange[pCsr->nRange-1].iRangeTid - ){ - op = +1; - } - } - - *pOp = op; - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbIsIndex(HctDatabase *pDb, u32 iRoot, int *pbIndex){ - HctFilePage pg; - int rc = sqlite3HctFilePageGet(pDb->pFile, iRoot, &pg); - if( rc==SQLITE_OK ){ - *pbIndex = (hctPagetype(pg.aOld)==HCT_PAGETYPE_INDEX); - sqlite3HctFilePageRelease(&pg); - } - return rc; -} - -SQLITE_PRIVATE char *sqlite3HctDbLogFile(HctDatabase *pDb){ - return sqlite3HctFileLogFile(pDb->pFile); -} - -static void hctDbCsrInit( - HctDatabase *pDb, - u32 iRoot, - KeyInfo *pKeyInfo, - HctDbCsr *pCsr -){ - memset(pCsr, 0, sizeof(HctDbCsr)); - pCsr->pDb = pDb; - pCsr->iRoot = iRoot; - if( pKeyInfo ){ - pCsr->pKeyInfo = sqlite3KeyInfoRef(pKeyInfo); - } -} - - - -/* -** Return the size of the local part of a nData byte record stored on -** an intkey leaf page. -*/ -#if 0 -static int hctDbLocalSize(HctDatabase *pDb, int nData){ - int nOther = sizeof(HctDbIntkeyLeaf) + sizeof(HctDbIntkeyEntry) + 12; - if( nData<=(pDb->pgsz-nOther) ){ - return nData; - } - assert( !"todo" ); - return 0; -} -#endif - -#if 0 -static i64 hctDbIntkeyGetKey(u8 *aPg, int ii){ - HctDbIntkeyLeaf *p = (HctDbIntkeyLeaf*)aPg; - return p->aEntry[ii].iKey; -} -#endif - - - -/* -** Return the maximum number of entries that fit on an intkey internal -** node if the database page size is as specified by the only parameter. -*/ -static int hctDbMaxCellsPerIntkeyNode(int pgsz){ - return (pgsz - sizeof(HctDbIntkeyNode)) / sizeof(HctDbIntkeyNodeEntry); -} -static int hctDbMinCellsPerIntkeyNode(int pgsz){ - return (pgsz - sizeof(HctDbIntkeyNode)) / (3*sizeof(HctDbIntkeyNodeEntry)); -} - -static void hctDbIrrevocablyEvictPage(HctDatabase *pDb, HctDbWriter *p); - -static int hctDbOverflowArrayFree(HctDatabase *pDb, HctDbOverflowArray *p){ - int ii = 0; - int rc = SQLITE_OK; - - for(ii=0; rc==SQLITE_OK && iinEntry; ii++){ - u32 pgno = p->aOvfl[ii].pgno; - int nRem = p->aOvfl[ii].nOvfl; - while( 1 ){ - HctFilePage pg; - sqlite3HctFileClearPhysInUse(pDb->pFile, pgno, 0); - nRem--; - if( nRem==0 ) break; - rc = hctDbGetPhysical(pDb, pgno, &pg); - assert( rc==SQLITE_OK ); - pgno = ((HctDbPageHdr*)pg.aOld)->iPeerPg; - sqlite3HctFilePageRelease(&pg); - } - } - - return rc; -} - -#ifdef SQLITE_DEBUG -/* -** Do some assert() statements to check that: -** -** * the pages in discardpg[] are sorted according to key. -*/ -static void assert_writer_is_ok(HctDatabase *pDb, HctDbWriter *p){ - int ii; - HctBuffer buf = {0,0,0}; - UnpackedRecord *pRec = 0; - - for(ii=1; iidiscardpg.nPg; ii++){ - u8 *a1 = p->discardpg.aPg[ii-1].aOld; - u8 *a2 = p->discardpg.aPg[ii].aOld; - - if( hctPagetype(a1)==HCT_PAGETYPE_INTKEY ){ - i64 i1 = hctDbIntkeyFPKey(a1); - i64 i2 = hctDbIntkeyFPKey(a2); - assert( i2>i1 ); - }else{ - int nData = 0; - const u8 *aData = 0; - int rc = hctDbLoadRecord(pDb, &buf, a1, 0, &nData, &aData); - if( rc==SQLITE_OK && pRec==0 ){ - pRec = sqlite3VdbeAllocUnpackedRecord(p->writecsr.pKeyInfo); - if( pRec==0 ){ - rc = SQLITE_NOMEM; - } - } - if( rc==SQLITE_OK ){ - int bGe = 555; - sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nData, aData, pRec); - rc = hctDbCompareFPKey(pDb, pRec, a2, &bGe); - assert( rc!=SQLITE_OK || bGe==0 ); - } - } - } - - sqlite3HctBufferFree(&buf); - hctDbFreeUnpacked(pRec); -} -#else /* if !SQLITE_DEBUG */ -# define assert_writer_is_ok(pDb, p) -#endif - -/* -** Cleanup the writer object passed as the first argument. -*/ -static void hctDbWriterCleanup(HctDatabase *pDb, HctDbWriter *p, int bRevert){ - - if( p->bDoCleanup ){ - int ii; - - sqlite3HctFileDebugPrint(pDb->pFile, - "writer cleanup height=%d bRevert=%d\n", p->iHeight, bRevert - ); - - assert_writer_is_ok(pDb, p); - - sqlite3HctBufferFree(&p->fp.buf); - memset(&p->fp, 0, sizeof(p->fp)); - - /* sqlite3HctFilePageUnwrite(&p->fanpg); */ - sqlite3HctFilePageRelease(&p->fanpg); - - /* If not reverting, mark the overflow chains in p->delOvfl as free */ - if( bRevert==0 ){ - hctDbOverflowArrayFree(pDb, &p->delOvfl); - }else{ - hctDbOverflowArrayFree(pDb, &p->insOvfl); - } - sqlite3_free(p->delOvfl.aOvfl); - sqlite3_free(p->insOvfl.aOvfl); - memset(&p->delOvfl, 0, sizeof(p->delOvfl)); - memset(&p->insOvfl, 0, sizeof(p->insOvfl)); - - for(ii=0; iiwritepg.nPg; ii++){ - HctFilePage *pPg = &p->writepg.aPg[ii]; - if( bRevert ){ - if( pPg->aNew ){ - sqlite3HctFilePageUnwrite(pPg); - }else if( ii>0 ){ - sqlite3HctFileClearInUse(pPg, 1); - } - } - sqlite3HctFilePageRelease(pPg); - } - hctDbPageArrayReset(&p->writepg); - - for(ii=0; iidiscardpg.nPg; ii++){ - if( bRevert && pDb->pConfig->nTryBeforeUnevict>1 ){ - sqlite3HctFilePageUnevict(&p->discardpg.aPg[ii]); - } - sqlite3HctFilePageRelease(&p->discardpg.aPg[ii]); - } - - hctDbPageArrayReset(&p->discardpg); - p->fp.iKey = 0; - p->fp.aKey = 0; - - if( p->iEvictLockedPgno ){ - assert( p->writecsr.iRoot ); - p->nEvictLocked++; - if( p->nEvictLocked>=pDb->pConfig->nTryBeforeUnevict ){ - p->nEvictLocked = -1; - hctDbIrrevocablyEvictPage(pDb, p); - p->nEvictLocked = 0; - } - }else{ - p->nEvictLocked = 0; - } - p->iEvictLockedPgno = 0; - p->bAppend = 0; - - /* Free/zero various buffers and caches */ - hctDbCsrCleanup(&p->writecsr); - hctDbCsrCleanup(&pDb->rbackcsr); - p->bDoCleanup = 0; - } -} - -static int hctDbInsert( - HctDatabase *pDb, - HctDbWriter *p, - u32 iRoot, - UnpackedRecord *pRec, /* The key value for index tables */ - i64 iKey, /* For intkey tables, the key value */ - u32 iChildPg, /* For internal node ops, the child pgno */ - int bDel, /* True for a delete operation */ - int nData, const u8 *aData /* Record/key to insert */ -); - -typedef struct HctDbWriterOrigin HctDbWriterOrigin; -struct HctDbWriterOrigin { - u8 bDiscard; /* 1 for aDiscard[], 0 for aWritePg[] */ - i16 iPg; /* Index of page in array*/ -}; - -static int hctdbWriterSortFPKeys( - HctDatabase *pDb, - int eType, - HctDbWriter *p, - HctDbWriterOrigin *aOrigin /* Populate this array */ -){ - int iDiscard = 0; - int iWP = 1; - int iOut = 0; - int rc = SQLITE_OK; - - assert( eType==HCT_PAGETYPE_INDEX || eType==HCT_PAGETYPE_INTKEY ); - - while( iDiscarddiscardpg.nPg || iWPwritepg.nPg ){ - if( iDiscard>=p->discardpg.nPg ){ - aOrigin[iOut].bDiscard = 0; - aOrigin[iOut].iPg = iWP++; - iOut++; - } - else if( iWP>=p->writepg.nPg ){ - aOrigin[iOut].bDiscard = 1; - aOrigin[iOut].iPg = iDiscard++; - iOut++; - }else{ - int bDiscard = 0; - const u8 *aD = p->discardpg.aPg[iDiscard].aOld; - const u8 *aW = p->writepg.aPg[iWP].aOld; - - if( eType==HCT_PAGETYPE_INTKEY ){ - i64 i1 = hctDbIntkeyFPKey(aD); - i64 i2 = hctDbIntkeyFPKey(aW); - bDiscard = (i1<=i2); - }else{ - int nFP = 0; - const u8 *aFP = 0; - UnpackedRecord *pRec = p->writecsr.pRec; - rc = hctDbLoadRecord(pDb, &p->writecsr.rec, aW, 0, &nFP, &aFP); - if( rc!=SQLITE_OK ) break; - sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nFP, aFP, pRec); - rc = hctDbCompareFPKey(pDb, pRec, aD, &bDiscard); - if( rc!=SQLITE_OK ) break; - } - - aOrigin[iOut].bDiscard = bDiscard; - if( bDiscard ){ - aOrigin[iOut].iPg = iDiscard++; - }else{ - aOrigin[iOut].iPg = iWP++; - } - iOut++; - } - } - - return rc; -} - -#if 0 -/* -** -*/ -static int hctDbTruncateRecord( - HctBuffer *pBuf, /* Buffer to use for storage space */ - KeyInfo *pKeyInfo, /* Description of index */ - int *pnFP, /* IN/OUT: Size of record */ - const u8 **aFP /* IN/OUT: Pointer to record */ -){ -} -#endif - -/* -** This is a wrapper around: -** -** sqlite3HctFilePageEvict(pPg, 0); -** -** If the call fails with SQLITE_LOCKED because page pPg has been evicted, -** HctDbWriter.iEvictLockedPgno is set to the logical page number of pPg. -*/ -static int hctDbFilePageEvict(HctDbWriter *p, HctFilePage *pPg){ - int rc = sqlite3HctFilePageEvict(pPg, 0); - if( rc==SQLITE_LOCKED && sqlite3HctFilePageIsEvicted(pPg->pFile, pPg->iPg) ){ - p->iEvictLockedPgno = pPg->iPg; - } - return rc; -} - -static int hctDbFilePageCommit(HctDbWriter *p, HctFilePage *pPg){ - int rc = sqlite3HctFilePageCommit(pPg); - if( rc==SQLITE_LOCKED && sqlite3HctFilePageIsEvicted(pPg->pFile, pPg->iPg) ){ - p->iEvictLockedPgno = pPg->iPg; - } - return rc; -} - -static int hctDbMigrateReinsertKeys(HctDatabase *pDb, HctDbWriter *p); - -static int hctDbInsertFlushWrite(HctDatabase *pDb, HctDbWriter *p){ - int rc = SQLITE_OK; - int ii; - int eType = hctPagetype(p->writepg.aPg[0].aNew); - HctFilePage root; - int bUnevict = 0; - - memset(&root, 0, sizeof(root)); - - rc = hctDbMigrateReinsertKeys(pDb, p); - -#ifdef SQLITE_DEBUG - for(ii=1; rc==SQLITE_OK && iiwritepg.nPg; ii++){ - u32 iPeer = ((HctDbPageHdr*)p->writepg.aPg[ii-1].aNew)->iPeerPg; - assert( p->writepg.aPg[ii].iPg==iPeer ); - } -#endif - - /* Test if this is a split of a root page of the tree. */ - if( rc==SQLITE_OK - && p->writepg.nPg>1 - && p->writepg.aPg[0].iPg==p->writecsr.iRoot - ){ - HctFilePage *pPg0 = &p->writepg.aPg[0]; - hctMemcpy(&root, pPg0, sizeof(HctFilePage)); - memset(pPg0, 0, sizeof(HctFilePage)); - rc = sqlite3HctFilePageNew(pDb->pFile, pPg0); - if( rc==SQLITE_OK ){ - hctMemcpy(pPg0->aNew, root.aNew, pDb->pgsz); - hctDbRootPageInit(eType==HCT_PAGETYPE_INDEX, - hctPageheight(root.aNew)+1, pPg0->iPg, root.aNew, pDb->pgsz - ); - } - } - - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageRelease(&p->fanpg); - } - - /* Loop through the set of pages to write out. They must be - ** written in reverse order - so that page aWritePg[0] is written - ** last. */ - assert( p->writepg.nPg>0 ); - for(ii=p->writepg.nPg-1; rc==SQLITE_OK && ii>=0; ii--){ - rc = hctDbFilePageCommit(p, &p->writepg.aPg[ii]); - } - - /* If there is one, write the new root page to disk */ - if( rc==SQLITE_OK && root.iPg ){ - rc = hctDbFilePageCommit(p, &root); - sqlite3HctFilePageRelease(&root); - } - - if( rc!=SQLITE_OK ){ - bUnevict = 1; - } - - /* If there is more than one page in the writepg array, or more than - ** zero in the discardpg array, then the parent list must be updated. - ** This block does that. */ - if( (p->writepg.nPg>1 || p->discardpg.nPg>0) && rc==SQLITE_OK ){ - const u32 iRoot = p->writecsr.iRoot; - const int nOrig = p->discardpg.nPg + p->writepg.nPg - 1; - HctDbWriterOrigin aStatic[6]; - HctDbWriterOrigin *aDyn = 0; - HctDbWriterOrigin *aOrig = aStatic; - HctBuffer buf; - HctDbWriter wr; - int iOrig = 0; - - memset(&buf, 0, sizeof(buf)); - memset(&wr, 0, sizeof(wr)); - hctDbPageArrayReset(&wr.writepg); - hctDbPageArrayReset(&wr.discardpg); - - if( nOrig>ArraySize(aStatic) ){ - int nByte = sizeof(HctDbWriterOrigin) * nOrig; - aOrig = aDyn = (HctDbWriterOrigin*)sqlite3HctMalloc(&rc, nByte); - } - - if( rc==SQLITE_OK ){ - wr.iHeight = p->iHeight + 1; - rc = hctDbCsrAllocateUnpacked(&p->writecsr); - } - - if( rc==SQLITE_OK ){ - rc = hctdbWriterSortFPKeys(pDb, eType, p, aOrig); - } - - if( rc==SQLITE_OK ){ - do { - assert( rc==SQLITE_OK || rc==SQLITE_LOCKED ); - rc = SQLITE_OK; - - while( iOrigbDiscard; - - pPg = &(bDel ? p->discardpg.aPg : p->writepg.aPg)[pOrig->iPg]; - if( eType==HCT_PAGETYPE_INTKEY ){ - iKey = hctDbIntkeyFPKey(pPg->aOld); - }else{ - rc = hctDbLoadRecord(pDb, &buf, pPg->aOld, 0, &nFP, &aFP); - if( rc!=SQLITE_OK ) break; - pRec = p->writecsr.pRec; - sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nFP, aFP, pRec); - sqlite3HctDbRecordTrim(pRec); - } - - rc = hctDbInsert( - pDb, &wr, iRoot, pRec, iKey, pPg->iPg, bDel, nFP, aFP - ); - } - - if( rc==SQLITE_OK ){ - rc = hctDbInsertFlushWrite(pDb, &wr); - } - if( rc==SQLITE_LOCKED ){ - assert( iOrig>=wr.nWriteKey ); - iOrig -= wr.nWriteKey; - pDb->nCasFail++; - pDb->stats.nInternalRetry++; - } - hctDbWriterCleanup(pDb, &wr, (rc!=SQLITE_OK)); - wr.nWriteKey = 0; - - }while( rc==SQLITE_LOCKED ); - } - - sqlite3HctBufferFree(&buf); - sqlite3_free(aDyn); - } - - if( rc==SQLITE_OK ){ - for(ii=0; iidiscardpg.nPg; ii++){ - sqlite3HctFileClearInUse(&p->discardpg.aPg[ii], 0); - } - } - - /* Clean up the Writer object */ - hctDbWriterCleanup(pDb, p, bUnevict); - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbRollbackMode(HctDatabase *pDb, int eRollback){ - assert( eRollback==0 || pDb->eMode==HCT_MODE_NORMAL ); - pDb->pa.nWriteKey = 0; - pDb->eMode = eRollback ? HCT_MODE_ROLLBACK : HCT_MODE_NORMAL; - if( eRollback>1 ){ - memset(&pDb->pa, 0, sizeof(pDb->pa)); - hctDbPageArrayReset(&pDb->pa.writepg); - hctDbPageArrayReset(&pDb->pa.discardpg); - - /* During recovery rollback the connection should read the latest - ** version of the db - no exceptions. Set these two to the largest - ** possible values to ensure that this happens. */ - pDb->iSnapshotId = LARGEST_TID-1; - pDb->iLocalMinTid = LARGEST_TID-1; - } -} - -SQLITE_PRIVATE i64 sqlite3HctDbNCasFail(HctDatabase *pDb){ - return pDb->nCasFail; -} - -#if 0 -static HctDbIntkeyEntry *hctDbIntkeyEntry(u8 *aPg, int iCell){ - return iCell<0 ? 0 : (&((HctDbIntkeyLeaf*)aPg)->aEntry[iCell]); -} -#endif - -SQLITE_PRIVATE int sqlite3HctDbInsertFlush(HctDatabase *pDb, int *pnRetry){ - int rc = SQLITE_OK; - if( pDb->pa.writepg.nPg ){ - rc = hctDbInsertFlushWrite(pDb, &pDb->pa); - if( rc==SQLITE_LOCKED ){ - *pnRetry = pDb->pa.nWriteKey; - rc = SQLITE_OK; - pDb->nCasFail++; - }else{ - *pnRetry = 0; - } -#if 0 - { - sqlite3HctFileDebugPrint(pDb->pFile, - "%p: %s sqlite3HctDbInsertFlush() -> %d (nRetry=%d)\n", - pDb, (pDb->eMode==HCT_MODE_ROLLBACK ? "RB" : " "), rc, *pnRetry - ); - fflush(stdout); - } -#endif - pDb->pa.nWriteKey = 0; - } - return rc; -} - -/* -** If pRec is not NULL, it contains an unpacked index key. Compare this key -** with the write-fp-key in pDb->pa.aWriteFpKey. Return true if pRec is greater -** than or equal to the write-fp-key. -** -** Or, if pRec is NULL, iKey is the key and it is compared to -** pDb->iWriteFpKey. -*/ -static int hctDbTestWriteFpKey( - HctDbWriter *p, - RecordCompare xCompare, - UnpackedRecord *pRec, - i64 iKey -){ - if( pRec ){ - int r; - if( p->fp.aKey==0 ){ - r = 1; - }else{ - r = xCompare(p->fp.iKey, p->fp.aKey, pRec); - } - return (r <= 0); - } - return iKey>=p->fp.iKey; -} - -static int hctDbSetWriteFpKey(HctDatabase *pDb, HctDbWriter *p){ - int rc = SQLITE_OK; - HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[p->writepg.nPg-1].aNew; - - p->fp.aKey = 0; - p->fp.iKey = 0; - - if( pHdr->iPeerPg==0 ){ - if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ - p->fp.iKey = LARGEST_INT64; - } - }else{ - HctFilePage pg; - rc = sqlite3HctFilePageGet(pDb->pFile, pHdr->iPeerPg, &pg); - if( rc==SQLITE_OK ){ - if( hctPagetype(pHdr)==HCT_PAGETYPE_INTKEY ){ - p->fp.iKey = hctDbIntkeyFPKey(pg.aOld); - }else{ - rc = hctDbLoadRecordFP(pDb, pg.aOld, 0, &p->fp); - } - sqlite3HctFilePageRelease(&pg); - } - } - - return rc; -} - -/* -** Buffer aTarget[] contains a page that contains variable length keys -** (i.e. an intkey leaf or an index leaf or node). This function returns -** the offset of the aEntry[] array in aTarget. Before doing so, it sets -** output variable (*pszEntry) to the sizeof(aEntry[0]). -*/ -static int hctDbEntryArrayDim(const u8 *aTarget, int *pszEntry){ - int eType = hctPagetype(aTarget); - int nHeight = hctPageheight(aTarget); - int nRet; - - assert( eType==HCT_PAGETYPE_INTKEY || eType==HCT_PAGETYPE_INDEX ); - assert( eType==HCT_PAGETYPE_INDEX || nHeight==0 ); - if( eType==HCT_PAGETYPE_INTKEY ){ - *pszEntry = sizeof(HctDbIntkeyEntry); - nRet = sizeof(HctDbIntkeyLeaf); - }else if( nHeight==0 ){ - *pszEntry = sizeof(HctDbIndexEntry); - nRet = sizeof(HctDbIndexLeaf); - }else{ - *pszEntry = sizeof(HctDbIndexNodeEntry); - nRet = sizeof(HctDbIndexNode); - } - - return nRet; -} - -static int hctIsVarRecords(const u8 *aTarget){ - int eType = hctPagetype(aTarget); - int nHeight = hctPageheight(aTarget); - return (nHeight==0 || eType==HCT_PAGETYPE_INDEX); -} - -#ifdef SQLITE_DEBUG - -static void print_out_page(const char *zCaption, const u8 *aData, int nData){ - HctDbPageHdr *pPg = (HctDbPageHdr*)aData; - - if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY && pPg->nHeight==0 ){ - HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)pPg; - char *zPrint = 0; - const char *zSep = ""; - int ii; - - for(ii=0; iipg.nEntry; ii++){ - HctDbIntkeyEntry *pEntry = &pLeaf->aEntry[ii]; - zPrint = sqlite3_mprintf("%z%s(k=%lld f=%.2x %d..%d)", zPrint, zSep, - pEntry->iKey, pEntry->flags, - pEntry->iOff, pEntry->iOff+ hctDbIntkeyEntrySize(pEntry, nData) - ); - zSep = ","; - } - - printf("%s: nFreeGap=%d nFreeBytes=%d (intkey leaf)\n", zCaption, - pLeaf->hdr.nFreeGap, - pLeaf->hdr.nFreeBytes - ); - printf("%s: %s\n", zCaption, zPrint); - sqlite3_free(zPrint); - } - - if( hctPagetype(pPg)==HCT_PAGETYPE_INDEX && pPg->nHeight==0 ){ - HctDbIndexLeaf *pLeaf = (HctDbIndexLeaf*)pPg; - char *zPrint = 0; - const char *zSep = ""; - int ii; - - for(ii=0; iipg.nEntry; ii++){ - HctDbIndexEntry *pEntry = &pLeaf->aEntry[ii]; - zPrint = sqlite3_mprintf("%z%s(%d..%d)", zPrint, zSep, - pEntry->iOff, pEntry->iOff + hctDbIndexEntrySize(pEntry, nData) - ); - zSep = ","; - } - - printf("%s: nFreeGap=%d nFreeBytes=%d (index leaf)\n", zCaption, - pLeaf->hdr.nFreeGap, - pLeaf->hdr.nFreeBytes - ); - printf("%s: %s\n", zCaption, zPrint); - fflush(stdout); - sqlite3_free(zPrint); - } - - -} - -#define assert_or_print(E) \ - if( !(E) ){ \ - print_out_page("page", aData, nData); \ - assert( E ); \ - } - -typedef struct VarCellReader VarCellReader; -struct VarCellReader { - const u8 *aData; - int nData; - int szEntry; - int iEntry0; -}; - -static void hctVCRInit(VarCellReader *p, const u8 *aData, int nData){ - p->aData = aData; - p->nData = nData; - p->iEntry0 = hctDbEntryArrayDim(aData, &p->szEntry); -} - -static int hctVCRFindCell(VarCellReader *p, int iCell, int *pnByte){ - HctDbIndexNodeEntry *pEntry; - - pEntry = (HctDbIndexNodeEntry*)&p->aData[p->iEntry0 + iCell*p->szEntry]; - *pnByte = hctDbLocalsize(p->aData, p->nData, pEntry->nSize) - + hctDbOffset(0, pEntry->flags); - - return pEntry->iOff; -} - -static void assert_page_is_ok(const u8 *aData, int nData){ - - if( aData && hctIsVarRecords(aData) ){ - HctDbIndexNode *p = (HctDbIndexNode*)aData; - VarCellReader vcr; - int iEnd = nData; - int iStart = 0; - int nRecTotal = 0; - int ii = 0; - int nFreeExpect; - - hctVCRInit(&vcr, aData, nData); - for(ii=0; iipg.nEntry; ii++){ - int sz = 0; - int iOff = hctVCRFindCell(&vcr, ii, &sz); - if( iOff ){ - assert_or_print( (iOff+sz)<=nData ); - iEnd = MIN(iEnd, iOff); - nRecTotal += sz; - }else{ - assert( sz==0 && ii==0 ); - } - } - - iStart = vcr.iEntry0 + vcr.szEntry * p->pg.nEntry; - nFreeExpect = nData - (iStart + nRecTotal); - - assert_or_print( p->hdr.nFreeGap==(iEnd - iStart) ); - assert_or_print( p->hdr.nFreeBytes==nFreeExpect); - } - -} -#else -# define assert_page_is_ok(x,y) -#endif - -#ifdef SQLITE_DEBUG -static void assert_all_pages_ok(HctDatabase *pDb, HctDbWriter *p){ - int ii; - return; - for(ii=0; iiwritepg.nPg; ii++){ - u8 *aPg = p->writepg.aPg[ii].aNew; - assert( aPg[0]!=0x00 ); - assert( hctIsVarRecords(aPg) ); - assert_page_is_ok(aPg, pDb->pgsz); - assert( ii==p->writepg.nPg-1 - || ((HctDbPageHdr*)aPg)->iPeerPg==p->writepg.aPg[ii+1].iPg - ); - } -} -static void assert_all_pages_nonempty(HctDatabase *pDb, HctDbWriter *p){ - return; - if( p->writepg.nPg>1 ){ - int ii; - for(ii=0; iiwritepg.nPg; ii++){ - HctDbPageHdr *pPg = (HctDbPageHdr*)p->writepg.aPg[ii].aNew; - assert( pPg->nEntry>0 ); - } - } -} -#else -# define assert_all_pages_ok(x,y) -# define assert_all_pages_nonempty(x,y) -#endif - - -/* -** HOW INSERT/DELETE OPERATIONS WORK: -** -** 1. If the page array is not empty, flush it to disk if required. It -** should be flushed to disk if either: -** -** a) the key being written (specified by iKey/pRec) is greater or -** equal to the FP key to the right of the page array (stored -** in HctDbWriter.iWriteFpKey/aWriteFpKey). -** -** b) there are more than HCTDB_MAX_DIRTY pages in the array. -** -** 2. If the page array is empty, either because it was flushed to disk -** in (1) or because it was empty when this function was called, seek -** the write-cursor (HctDbWriter.writecsr) to the key being written. -** The page the cursor seeks to becomes the first page of the page -** array. -** -** 3. Locate within the page array the page into which the new key -** or delete-key should be inserted. There are three possible outcomes: -** -** i) the new key may just be written to the page. -** -** ii) the new key fits on the page, but leaves it underfull. In this -** context, "underfull" means that the total amount of free space -** on the page is less than or equal to (pgsz*2/3). -** -** iii) the new key does not fit on the page. -** -** In cases (ii) or (iii), first ensure that that the page has two peers in -** the page array (unless there are fewer than three pages in the list, in -** which case the entire list should be loaded). Then redistribute the keys -** between the minimum number of pages, discarding or adding nodes as -** required. -*/ - -/* -** Insert nPg new pages at index iPg into the write-array of the HctDbWriter -** passed as the second argument and link them into the list. -*/ -static int hctDbExtendWriteArray( - HctDatabase *pDb, - HctDbWriter *p, - int iPg, - int nPg -){ - int rc = SQLITE_OK; - int ii; - - assert( iPg>0 ); - assert( (p->writepg.nPg+nPg)>0 ); - assert( p->writepg.nPg>0 ); - - /* Add any new pages required */ - for(ii=iPg; rc==SQLITE_OK && iiwritepg.nPgwritepg.aPg) ); - assert( ii>0 ); - if( iiwritepg.nPg ){ - int nByte = sizeof(HctFilePage) * (p->writepg.nPg-ii); - memmove(&p->writepg.aPg[ii+1], &p->writepg.aPg[ii], nByte); - } - p->writepg.nPg++; - memset(&p->writepg.aPg[ii], 0, sizeof(HctFilePage)); - rc = sqlite3HctFilePageNew(pDb->pFile, &p->writepg.aPg[ii]); - if( rc==SQLITE_OK ){ - HctDbPageHdr *pNew = (HctDbPageHdr*)p->writepg.aPg[ii].aNew; - HctDbPageHdr *pPrev = (HctDbPageHdr*)p->writepg.aPg[ii-1].aNew; - memset(pNew, 0, sizeof(HctDbPageHdr)); - pNew->hdrFlags = hctPagetype(pPrev); - pNew->nHeight = pPrev->nHeight; - pNew->iPeerPg = pPrev->iPeerPg; - pPrev->iPeerPg = p->writepg.aPg[ii].iPg; - } - } - - /* Remove pages that are not required */ - for(ii=nPg; ii<0; ii++){ - HctDbPageHdr *pPrev = (HctDbPageHdr*)(p->writepg.aPg[iPg-1].aNew); - HctDbPageHdr *pRem = (HctDbPageHdr*)(p->writepg.aPg[iPg].aNew); - pPrev->iPeerPg = pRem->iPeerPg; - assert( p->writepg.nPg>1 ); - p->writepg.nPg--; - - assert( iPg!=0 ); - assert( p->writepg.aPg[iPg].aOld==0 ); - sqlite3HctFilePageUnwrite(&p->writepg.aPg[iPg]); - - if( iPg!=p->writepg.nPg ){ - int nByte = sizeof(HctFilePage) * (p->writepg.nPg-iPg); - assert( nByte>0 ); - memmove(&p->writepg.aPg[iPg], &p->writepg.aPg[iPg+1], nByte); - } - } - - return rc; -} - -static int hctDbCsrLoadAndDecode( - HctDbCsr *pCsr, - int iCell, - UnpackedRecord **ppRec -){ - const u8 *aPg = pCsr->pg.aNew ? pCsr->pg.aNew : pCsr->pg.aOld; - int nData = 0; - const u8 *aData = 0; - int rc; - - rc = hctDbLoadRecord(pCsr->pDb, &pCsr->rec, aPg, iCell, &nData, &aData); - if( rc==SQLITE_OK ){ - rc = hctDbCsrAllocateUnpacked(pCsr); - } - if( rc==SQLITE_OK ){ - *ppRec = pCsr->pRec; - sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, nData, aData, pCsr->pRec); - assert( pCsr->pRec->nField>0 ); - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbCsrLoadAndDecode(HctDbCsr *pCsr, UnpackedRecord **ppRec){ - return hctDbCsrLoadAndDecode(pCsr, pCsr->iCell, ppRec); -} - -/* -** -*/ -static int hctDbFindLhsPeer( - HctDatabase *pDb, - HctDbWriter *p, - HctFilePage *pPg, - HctFilePage *pOut -){ - HctDbCsr csr; - u8 *aLeft = pPg->aNew ? pPg->aNew : pPg->aOld; - int rc = SQLITE_OK; - - hctDbCsrInit(pDb, p->writecsr.iRoot, 0, &csr); - csr.pKeyInfo = p->writecsr.pKeyInfo; - if( hctPagetype(aLeft)==HCT_PAGETYPE_INTKEY ){ - i64 iKey = hctDbIntkeyFPKey(aLeft); - assert( iKey!=SMALLEST_INT64 ); - rc = hctDbCsrSeek(&csr, 0, p->iHeight, 0, 0, iKey-1, 0); - }else{ - UnpackedRecord *pRec = 0; - HctBuffer buf; - int nData = 0; - const u8 *aData = 0; - memset(&buf, 0, sizeof(buf)); - rc = hctDbLoadRecord(pDb, &buf, aLeft, 0, &nData, &aData); - if( rc==SQLITE_OK ){ - rc = hctDbCsrAllocateUnpacked(&p->writecsr); - } - if( rc==SQLITE_OK ){ - pRec = p->writecsr.pRec; - sqlite3VdbeRecordUnpack(p->writecsr.pKeyInfo, nData, aData, pRec); - sqlite3HctDbRecordTrim(pRec); - pRec->default_rc = 1; - rc = hctDbCsrSeek(&csr, 0, p->iHeight, 0, pRec, 0, 0); - pRec->default_rc = 0; - - assert( csr.pg.iPg!=pPg->iPg ); - } - sqlite3HctBufferFree(&buf); - } - - if( rc==SQLITE_OK - && ((HctDbPageHdr*)csr.pg.aOld)->iPeerPg==pPg->iPg - ){ - *pOut = csr.pg; - }else{ - memset(pOut, 0, sizeof(HctFilePage)); - rc = SQLITE_LOCKED_ERR(pPg->iPg, "peer"); - } - - return rc; -} - -static void hctDbIrrevocablyEvictPage(HctDatabase *pDb, HctDbWriter *p){ - int rc = SQLITE_OK; - u32 iLocked = p->iEvictLockedPgno; - int bDone = 0; - - KeyInfo *pKeyInfo = sqlite3KeyInfoRef(p->writecsr.pKeyInfo); - u32 iRoot = p->writecsr.iRoot; - - sqlite3HctFileDebugPrint(pDb->pFile,"BEGIN forced eviction of %d\n", iLocked); - - do { - HctFilePage pg1; - HctFilePage pg0; - memset(&pg1, 0, sizeof(pg1)); - if( p->writecsr.iRoot==0 ){ - hctDbCsrInit(pDb, iRoot, pKeyInfo, &p->writecsr); - } - rc = sqlite3HctFilePageGet(pDb->pFile, iLocked, &pg1); - while( rc==SQLITE_OK ){ - memset(&pg0, 0, sizeof(pg0)); - rc = hctDbFindLhsPeer(pDb, p, &pg1, &pg0); - if( rc ) break; - if( 0==sqlite3HctFilePageIsEvicted(pg0.pFile, pg0.iPg) ) break; - sqlite3HctFilePageRelease(&pg1); - pg1 = pg0; - memset(&pg0, 0, sizeof(pg0)); - } - - if( rc==SQLITE_OK ){ - bDone = (pg1.iPg==iLocked); - sqlite3HctFileDebugPrint( - pDb->pFile, "forcing write of %d->%d\n", pg0.iPg, pg1.iPg - ); - - rc = sqlite3HctFilePageEvict(&pg1, 1); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageWrite(&pg0); - } - if( rc==SQLITE_OK ){ - hctMemcpy(pg0.aNew, pg0.aOld, pDb->pgsz); - } - if( rc==SQLITE_OK ){ - p->writepg.aPg[0] = pg0; - p->writepg.nPg = 1; - rc = hctDbExtendWriteArray(pDb, p, 1, 1); - } - if( rc==SQLITE_OK ){ - hctMemcpy(p->writepg.aPg[1].aNew, pg1.aOld, pDb->pgsz); - p->discardpg.aPg[0] = pg1; - p->discardpg.nPg = 1; - } - - p->bDoCleanup = 1; - if( rc==SQLITE_OK ){ - rc = hctDbInsertFlushWrite(pDb, p); - }else{ - hctDbWriterCleanup(pDb, p, 1); - } - - }else{ - sqlite3HctFilePageRelease(&pg0); - sqlite3HctFilePageRelease(&pg1); - } - }while( rc==SQLITE_OK && bDone==0 ); - - sqlite3KeyInfoUnref(pKeyInfo); - sqlite3HctFileDebugPrint(pDb->pFile,"END forced eviction of %d\n", iLocked); -} - -/* -** -*/ -static int hctDbLoadPeers(HctDatabase *pDb, HctDbWriter *p, int *piPg){ - int rc = SQLITE_OK; - int iPg = *piPg; - - if( p->writepg.nPg<3 ){ - HctFilePage *pLeft = &p->writepg.aPg[0]; - - if( p->writepg.nPg==1 && 0==hctIsLeftmost(pLeft->aNew) ){ - HctFilePage *pCopy = 0; - assert( iPg==0 ); - - /* First, evict the page currently in p->writepg.aPg[0]. If we - ** successfully evict the page here, then of course no other thread - ** can - which guarantees that the seek operation below really does - ** find the left-hand peer (assuming the db is not corrupt). */ - rc = hctDbFilePageEvict(p, pLeft); - - /* Assuming the LOGICAL_EVICTED flag was successfully set, seek - ** cursor csr to the leaf page immediately to the left of pLeft. */ - if( rc==SQLITE_OK ){ - if( p->discardpg.nPg>0 ){ - int nMove = p->discardpg.nPg * sizeof(HctFilePage); - memmove(&p->discardpg.aPg[1], &p->discardpg.aPg[0], nMove); - } - pCopy = &p->discardpg.aPg[0]; - p->discardpg.nPg++; - *pCopy = *pLeft; - rc = hctDbFindLhsPeer(pDb, p, pCopy, pLeft); - } - if( rc==SQLITE_OK ){ - assert( ((HctDbPageHdr*)pLeft->aOld)->iPeerPg==pCopy->iPg ); - rc = sqlite3HctFilePageWrite(pLeft); - } - - if( rc==SQLITE_OK ){ - hctMemcpy(pLeft->aNew, pLeft->aOld, pDb->pgsz); - rc = hctDbExtendWriteArray(pDb, p, 1, 1); - } - if( rc==SQLITE_OK ){ - hctMemcpy(p->writepg.aPg[1].aNew, pCopy->aNew, pDb->pgsz); - sqlite3HctFilePageUnwrite(pCopy); - *piPg = 1; - } - } - - if( rc==SQLITE_OK ){ - HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[p->writepg.nPg-1].aNew; - if( pHdr->iPeerPg ){ - HctFilePage *pCopy = &p->discardpg.aPg[p->discardpg.nPg]; - - rc = sqlite3HctFilePageGet(pDb->pFile, pHdr->iPeerPg, pCopy); - if( rc==SQLITE_OK ){ - /* Evict the page immediately */ - rc = hctDbFilePageEvict(p, pCopy); - if( rc!=SQLITE_OK ){ - sqlite3HctFilePageRelease(pCopy); - }else{ - p->discardpg.nPg++; - } - } - - if( rc==SQLITE_OK ){ - rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); - } - if( rc==SQLITE_OK ){ - HctFilePage *pPg = &p->writepg.aPg[p->writepg.nPg-1]; - hctMemcpy(pPg->aNew, pCopy->aOld, pDb->pgsz); - rc = hctDbSetWriteFpKey(pDb, p); - } - } - } - } - - return rc; -} - -static int hctDbOverflowArrayAppend(HctDbOverflowArray *p, u32 ovfl, int nOvfl){ - assert( p->nAlloc>=p->nEntry ); - assert( ovfl>0 && nOvfl>0 ); - - if( p->nAlloc==p->nEntry ){ - int nNew = p->nAlloc ? p->nAlloc*2 : 16; - int nByte = nNew*sizeof(HctDbOverflow); - HctDbOverflow *aNew = (HctDbOverflow*)sqlite3_realloc(p->aOvfl, nByte); - - if( aNew==0 ){ - return SQLITE_NOMEM_BKPT; - } - p->aOvfl = aNew; - p->nAlloc = nNew; - } - - p->aOvfl[p->nEntry].pgno = ovfl; - p->aOvfl[p->nEntry].nOvfl = nOvfl; - p->nEntry++; - - return SQLITE_OK; -} - - -/* -** Buffer aTarget[] must contain a page with variable sized records - an -** index leaf or node, or an intkey leaf. This function returns the offset -** of the record for entry iEntry, and populates output variable *pFlags -** with the entry flags. -*/ -static int hctDbFindEntry(u8 *aTarget, int iEntry, u8 *pFlags, int *pnSize){ - int iRet; - if( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ){ - iRet = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].iOff; - *pFlags = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].flags; - *pnSize = ((HctDbIntkeyLeaf*)aTarget)->aEntry[iEntry].nSize; - }else if( hctPageheight(aTarget)==0 ){ - iRet = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].iOff; - *pFlags = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].flags; - *pnSize = ((HctDbIndexLeaf*)aTarget)->aEntry[iEntry].nSize; - }else{ - iRet = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].iOff; - *pFlags = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].flags; - *pnSize = ((HctDbIndexNode*)aTarget)->aEntry[iEntry].nSize; - } - return iRet; -} - -static int hctDbRemoveOverflow( - HctDatabase *pDb, - HctDbWriter *p, - u8 *aPage, - int iCell -){ - int rc = SQLITE_OK; - - int nSize = 0; - u8 flags = 0; - int iOff = hctDbFindEntry(aPage, iCell, &flags, &nSize); - if( flags & HCTDB_HAS_OVFL ){ - u32 ovfl = 0; - int nOvfl = 0; - const int nBytePerOvfl = pDb->pgsz - sizeof(HctDbPageHdr); - int nLocal = hctDbLocalsize(aPage, pDb->pgsz, nSize); - - if( flags & HCTDB_HAS_TID ) iOff += 8; - if( flags & HCTDB_HAS_RANGETID ) iOff += 8; - if( flags & HCTDB_HAS_RANGEOLD ) iOff += 4; - - ovfl = hctGetU32(&aPage[iOff]); - nOvfl = ((nSize - nLocal) + nBytePerOvfl - 1) / nBytePerOvfl; - - rc = hctDbOverflowArrayAppend(&p->delOvfl, ovfl, nOvfl); - } - - return rc; -} - -static void hctDbRemoveTids( - HctDbIndexNodeEntry *p, - u8 *aPg, - u64 iSafeTid -){ - if( (p->flags & HCTDB_HAS_TID)==HCTDB_HAS_TID ){ - u64 iTid; - memcpy(&iTid, &aPg[p->iOff], sizeof(u64)); - if( (iTid & HCT_TID_MASK)<=iSafeTid ){ - p->flags &= ~HCTDB_HAS_TID; - p->iOff += sizeof(u64); - } - } - if( (p->flags & (HCTDB_HAS_TID|HCTDB_HAS_RANGETID))==HCTDB_HAS_RANGETID ){ - u64 iTid; - assert( p->flags & HCTDB_HAS_RANGEOLD ); - memcpy(&iTid, &aPg[p->iOff], sizeof(u64)); - if( (iTid & HCT_TID_MASK)<=iSafeTid ){ - p->flags &= ~(HCTDB_HAS_RANGETID|HCTDB_HAS_RANGEOLD); - p->iOff += (sizeof(u64) + sizeof(u32)); - } - } -} - -/* -** Populate the aSz[] array with the sizes and locations of each cell -** -** (bClobber && nNewCell==0) -> full-delete -** (bClobber) -> clobber -** (bClobber==0) -> insert of new key -*/ -static void hctDbBalanceGetCellSz( - HctDatabase *pDb, - HctDbWriter *pWriter, - int iInsert, - int bClobber, - int nNewCell, /* Bytes stored on page for new cell */ - u8 *aPg, - HctDbCellSz *aSz, - int *pnSz /* OUT: number of entries in aSz[] */ -){ - HctDbPageHdr *pPg = (HctDbPageHdr*)aPg; - u64 iSafeTid = sqlite3HctFileSafeTID(pDb->pFile); - int szEntry; - int i0 = hctDbEntryArrayDim(aPg, &szEntry); - int iCell = 0; /* Current cell of aPgCopy[ii] */ - int iSz = 0; /* Current populated size of aSz[] */ - int iIns = iInsert; - - for(iSz=0; iCellnEntry || iCell==iIns; iSz++){ - HctDbCellSz *pSz = &aSz[iSz]; - - assert( pPg->nEntrypgsz ); - if( iCell==iIns ){ - assert( nNewCell>0 || bClobber ); - if( nNewCell ){ - pSz->nByte = szEntry + nNewCell; - pSz->aEntry = 0; - pSz->aCell = 0; - }else{ - iSz--; - } - if( bClobber ){ - iCell++; - } - iIns = -1; - }else{ - HctDbIndexNodeEntry *pE = (HctDbIndexNodeEntry*)&aPg[i0+iCell*szEntry]; - hctDbRemoveTids(pE, aPg, iSafeTid); - - pSz->nByte = szEntry + hctDbPageRecordSize(pPg, pDb->pgsz, iCell); - pSz->aEntry = (u8*)pE; - pSz->aCell = &aPg[pE->iOff]; - assert( pSz->nByte>0 ); - iCell++; - } - } - if( pnSz ) *pnSz = iSz; -} - -typedef struct HctDbInsertOp HctDbInsertOp; -struct HctDbInsertOp { - u8 entryFlags; /* Flags for page entry added by this call */ - u8 *aEntry; /* Buffer containing formatted entry */ - int nEntry; /* Size of aEntry[] */ - int nEntrySize; /* Value for page header nSize field */ - - int iPg; /* Index in HctDbWriter.writepg.aPg */ - int iInsert; /* Index in page to write to */ - - i64 iIntkey; /* Key to insert (if intkey page) */ - - int eBalance; /* True if balance routine must be called */ - int bFullDel; /* True to skip insert */ - - u32 iOldPg; - const u8 *aOldPg; -}; - -/* -** Values for HctDbInsertOp.eBalance -*/ -#define BALANCE_NONE 0 -#define BALANCE_OPTIONAL 1 -#define BALANCE_REQUIRED 2 - - -static int hctDbBalanceAppend( - HctDatabase *pDb, - HctDbWriter *p, - HctDbInsertOp *pOp -){ - int rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); - if( rc==SQLITE_OK ){ - HctDbLeaf *pLeaf = (HctDbLeaf*)p->writepg.aPg[p->writepg.nPg-1].aNew; - pLeaf->hdr.nFreeBytes = pDb->pgsz - sizeof(HctDbLeaf); - pLeaf->hdr.nFreeGap = pLeaf->hdr.nFreeBytes; - assert( p->iHeight==0 ); - assert_all_pages_ok(pDb, p); - pOp->iPg = p->writepg.nPg-1; - pOp->iInsert = 0; - } - return rc; -} - -static HctBalance *hctDbBalanceSpace(int *pRc, HctDatabase *pDb){ - if( pDb->pBalance==0 ){ - HctBalance *p = 0; - int nPg = ArraySize(p->aPg); - int nSzAlloc = (nPg * 2 * MAX_CELLS_PER_PAGE(pDb->pgsz)) + 1; - - pDb->pBalance = p = (HctBalance*)sqlite3HctMalloc(pRc, - sizeof(HctBalance) + - nPg * pDb->pgsz + - sizeof(HctDbCellSz) * nSzAlloc - ); - if( p ){ - u8 *aCsr = (u8*)&p[1]; - int ii; - for(ii=0; iiaPg[ii] = aCsr; - aCsr += pDb->pgsz; - } - p->aSz = (HctDbCellSz*)aCsr; - p->nSzAlloc = nSzAlloc; - } - } - return pDb->pBalance; -} - -/* -** Rebalance routine for pages with variably-sized records - intkey leaves, -** index leaves and index nodes. -*/ -static int hctDbBalance( - HctDatabase *pDb, - HctDbWriter *p, - HctDbInsertOp *pOp, - int bClobber -){ - int rc = SQLITE_OK; /* Return code */ - int iPg = pOp->iPg; - int iIns = pOp->iInsert; - - int iLeftPg; /* Index of leftmost page used in balance */ - int nIn = 1; /* Number of input peers for balance */ - int ii; /* Iterator used for various things */ - int nOut = 0; /* Number of output peers */ - int szEntry = 0; - int iEntry0 = 0; - HctDbCellSz *aSz = 0; - int nSz = 0; - u8 **aPgCopy = 0; - - int nRem; - - int aPgRem[5]; - int aPgFirst[6]; - - /* Grab the temporary space used by balance operations. */ - HctBalance *pBal = 0; - pBal = hctDbBalanceSpace(&rc, pDb); - if( pBal==0 ) return rc; - - /* Populate the aSz[] and aPgCopy[] arrays as if this were a single-page - ** rebalance only. */ - aSz = &pBal->aSz[MAX_CELLS_PER_PAGE(pDb->pgsz) * 2]; - aPgCopy = pBal->aPg; - hctMemcpy(aPgCopy[0], p->writepg.aPg[iPg].aNew, pDb->pgsz); - hctDbBalanceGetCellSz(pDb, p, iIns, bClobber,pOp->nEntry,aPgCopy[0],aSz,&nSz); - - if( pOp->eBalance==BALANCE_OPTIONAL ){ - int nTotal = 0; - for(ii=0; iipgsz - sizeof(HctDbIntkeyLeaf)) ){ - /* This is a single page balance */ - nIn = 1; - nOut = 1; - iLeftPg = iPg; - } - } - - if( nOut==0 ){ - HctDbPageHdr *pHdr = (HctDbPageHdr*)p->writepg.aPg[iPg].aNew; - if( p->iHeight==0 - && bClobber==0 && pOp->nEntry>0 - && pHdr->iPeerPg==0 && pHdr->nEntry==iIns - ){ - p->bAppend = 1; - rc = hctDbBalanceAppend(pDb, p, pOp); - return rc; - } - - /* If the HctDbWriter.writepg.aPg[] array still contains a single page, - ** load some peer pages into it. */ - assert( p->discardpg.nPg>=0 ); - if( IS_HCT_MIGRATE(pDb)==0 ){ - rc = hctDbLoadPeers(pDb, p, &iPg); - if( rc!=SQLITE_OK ){ - return rc; - } - } - assert_all_pages_ok(pDb, p); - - /* Determine the subset of HctDbWriter.writepg.aPg[] pages that will be - ** rebalanced. Variable nIn is set to the number of input pages, and - ** iLeftPg to the index of the leftmost of them. */ - iLeftPg = iPg; - if( iPg==0 ){ - nIn = MIN(p->writepg.nPg, 3); - }else{ - if( iPg==p->writepg.nPg-1 ){ - nIn = MIN(p->writepg.nPg, 3); - iLeftPg -= (nIn-1); - }else{ - nIn = 3; - iLeftPg--; - } - SWAP(u8*, aPgCopy[0], aPgCopy[iPg-iLeftPg]); - } - - /* aPgCopy[iPg-iLeftPg] already contains a copy of page iPg at this - ** point. This loop takes copies of the other pages involved in the - ** balance operation. */ - for(ii=0; iiwritepg.aPg[iLeftPg+ii].aNew, pDb->pgsz); - } - - for(ii=(iPg-iLeftPg)-1; ii>=0; ii--){ - int nCell = hctPagenentry(aPgCopy[ii]); - aSz -= nCell; - nSz += nCell; - hctDbBalanceGetCellSz(pDb, p, -1, 0, 0, aPgCopy[ii], aSz, 0); - } - for(ii=(iPg-iLeftPg)+1; iiwritecsr.pKeyInfo==0 ){ - pDb->stats.nBalanceIntkey++; - }else{ - pDb->stats.nBalanceIndex++; - } - if( nIn==1 ){ - pDb->stats.nBalanceSingle++; - } - - /* Figure out how many output pages will be required. This loop calculates - ** a mapping heavily biased to the left. */ - aPgFirst[0] = 0; - if( nOut==0 ){ - assert( sizeof(HctDbIntkeyLeaf)==sizeof(HctDbIndexLeaf) ); - nRem = pDb->pgsz - sizeof(HctDbIntkeyLeaf); - nOut = 1; - for(ii=0; iinRem ){ - aPgRem[nOut-1] = nRem; - aPgFirst[nOut] = ii; - nOut++; - nRem = pDb->pgsz - sizeof(HctDbIntkeyLeaf); - assert( nOut<=ArraySize(aPgRem) ); - } - nRem -= aSz[ii].nByte; - } - aPgRem[nOut-1] = nRem; - } - aPgFirst[nOut] = nSz; - - /* Adjust the packing calculated by the previous loop. */ - for(ii=nOut-1; ii>0; ii--){ - /* Try to shift cells from output page (ii-1) to output page (ii). Shift - ** cells for as long as (a) there is more free space on page (ii) than on - ** page (ii-1), and (b) there is enough free space on page (ii) to fit - ** the last cell from page (ii-1). */ - while( aPgRem[ii]>aPgRem[ii-1] ){ /* condition (a) */ - HctDbCellSz *pLast = &aSz[aPgFirst[ii]-1]; - if( pLast->nByte>aPgRem[ii] ) break; /* condition (b) */ - aPgRem[ii] -= pLast->nByte; - aPgRem[ii-1] += pLast->nByte; - aPgFirst[ii] = (pLast - aSz); - } - } - - /* Allocate any required new pages and link them into the list. */ - rc = hctDbExtendWriteArray(pDb, p, iLeftPg+1, nOut-nIn); - - /* Populate the output pages */ - iEntry0 = hctDbEntryArrayDim(aPgCopy[0], &szEntry); - for(ii=0; iiwritepg.aPg[iIdx].aNew; - HctDbIndexLeaf *pLeaf = (HctDbIndexLeaf*)aTarget; - int iOff = pDb->pgsz; /* Start of data area in aTarget[] */ - int iLast = (ii==(nOut-1) ? nSz : aPgFirst[ii+1]); - int nNewEntry = 0; /* Number of entries on this output page */ - int i2; - - for(i2=0; i2<(iLast - aPgFirst[ii]); i2++){ - HctDbCellSz *pSz = &aSz[aPgFirst[ii] + i2]; - if( pSz->aEntry ){ - u8 *aETo = &aTarget[iEntry0 + nNewEntry*szEntry]; - int nCopy = pSz->nByte - szEntry; - hctMemcpy(aETo, pSz->aEntry, szEntry); - iOff -= nCopy; - ((HctDbIndexEntry*)aETo)->iOff = iOff; - hctMemcpy(&aTarget[iOff], pSz->aCell, nCopy); - nNewEntry++; - }else{ - pOp->iPg = iIdx; - pOp->iInsert = i2; - } - } - - pLeaf->pg.nEntry = nNewEntry; - pLeaf->hdr.nFreeBytes = iOff - (iEntry0 + nNewEntry*szEntry); - pLeaf->hdr.nFreeGap = iOff - (iEntry0 + nNewEntry*szEntry); - } - - return rc; -} - - -static int hctDbBalanceIntkeyNode( - HctDatabase *pDb, - HctDbWriter *p, - int iPg, - int iInsert, /* Index in iPg for new key, if any */ - i64 iKey, /* Integer key value */ - u32 iChildPg /* The child pgno */ -){ - int nMax = hctDbMaxCellsPerIntkeyNode(pDb->pgsz); - int rc = SQLITE_OK; - int nIn; /* Number of input pages */ - int nOut; /* Number of output pages */ - int iLeftPg; /* Index of left-most page in balance */ - int ii; /* Iterator variable */ - int nTotal = 0; /* Total number of keys for balance */ - u8 *aPgCopy[3]; - u8 *pFree = 0; - - assert( p->writepg.aPg[p->writepg.nPg-1].aNew ); - if( IS_HCT_MIGRATE(pDb)==0 ){ - rc = hctDbLoadPeers(pDb, p, &iPg); - if( rc!=SQLITE_OK ){ - return rc; - } - } - - iLeftPg = iPg; - if( iPg==0 ){ - nIn = MIN(p->writepg.nPg, 3); - }else if( iPg==p->writepg.nPg-1 ){ - nIn = MIN(p->writepg.nPg, 3); - iLeftPg -= (nIn-1); - }else{ - nIn = MIN(p->writepg.nPg, 3); - iLeftPg--; - assert( iLeftPg+nIn<=p->writepg.nPg ); - } - - /* Take a copy of each input page. Make the buffer used to store each - ** copy larger than required by the size of one entry. Then, there is - ** a new entry to add in stack variables (iKey/iChildPg), add it to the - ** copy of its page. This is to make the loop that populates the output - ** pages below easier to write. A real candidate for optimization, this. */ - pFree = (u8*)sqlite3Malloc(nIn*(pDb->pgsz+sizeof(HctDbIntkeyNodeEntry))); - if( pFree==0 ) return SQLITE_NOMEM; - for(ii=0; iipgsz + sizeof(HctDbIntkeyNodeEntry)) * ii]; - hctMemcpy(aPgCopy[ii], p->writepg.aPg[iLeftPg+ii].aNew, pDb->pgsz); - } - if( iInsert>=0 ){ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPgCopy[iPg-iLeftPg]; - if( iInsertpg.nEntry ){ - int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-iInsert); - memmove(&pNode->aEntry[iInsert+1], &pNode->aEntry[iInsert], nByte); - } - pNode->pg.nEntry++; - pNode->aEntry[iInsert].iKey = iKey; - pNode->aEntry[iInsert].iChildPg = iChildPg; - } - - /* Figure out how many entries there are, in total */ - for(ii=0; iipg.nEntry; - } - - /* Figure out how many output pages are required */ - nOut = (nTotal + (nMax-1)) / nMax; - rc = hctDbExtendWriteArray(pDb, p, iLeftPg+1, nOut-nIn); - assert( rc==SQLITE_OK ); /* todo */ - - /* Populate the output pages */ - if( rc==SQLITE_OK ){ - int nRem = nTotal; - int iIn = 0; - int iInEntry = 0; - - for(ii=0; iiwritepg.aPg[ii+iLeftPg].aNew; - for(pEntry=pNode->aEntry; pEntry<&pNode->aEntry[nCell]; pEntry++){ - HctDbIntkeyNode *pIn = (HctDbIntkeyNode*)aPgCopy[iIn]; - *pEntry = pIn->aEntry[iInEntry++]; - if( iInEntry>=pIn->pg.nEntry ){ - iInEntry = 0; - iIn++; - } - } - pNode->pg.nEntry = nCell; - nRem -= nCell; - } - } - - sqlite3_free(pFree); - return rc; -} - -/* -** This function handles the second part of an insert or delete operation -** on an internal intkey node key. The implementation is separate from the -** usual insert/delete routine because internal intkey nodes use fixed size -** records. The other three types of pages found in lists - intkey leaves, -** index leaves and index nodes - all use variable sized entries. -*/ -static int hctDbInsertIntkeyNode( - HctDatabase *pDb, - HctDbWriter *p, - int iPg, - int iInsert, - i64 iKey, /* Integer key value */ - u32 iChildPg, /* The child pgno */ - int bClobber, /* True to clobber entry iInsert */ - int bDel /* True for a delete operation */ -){ - int nMax = hctDbMaxCellsPerIntkeyNode(pDb->pgsz); - int nMin = hctDbMinCellsPerIntkeyNode(pDb->pgsz); - HctDbIntkeyNode *pNode; - int rc = SQLITE_OK; - - /* If bDel is set, then bClobber must also be set. */ - assert( bDel==0 || bClobber ); - - pNode = (HctDbIntkeyNode*)p->writepg.aPg[iPg].aNew; - if( (pNode->pg.nEntry>=nMax && bClobber==0 && bDel==0 ) ){ - /* Need to do a balance operation to make room for the new entry */ - rc = hctDbBalanceIntkeyNode(pDb, p, iPg, iInsert, iKey, iChildPg); - }else if( bDel ){ - assert( iInsertpg.nEntry ); - if( iInsert==0 ){ - rc = hctDbLoadPeers(pDb, p, &iPg); - pNode = (HctDbIntkeyNode*)p->writepg.aPg[iPg].aNew; - } - if( rc==SQLITE_OK ){ - if( iInsert<(pNode->pg.nEntry-1) ){ - int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-1-iInsert); - memmove(&pNode->aEntry[iInsert], &pNode->aEntry[iInsert+1], nByte); - } - pNode->pg.nEntry--; - if( iInsert==0 || pNode->pg.nEntrypg.nEntry ){ - int nByte = sizeof(HctDbIntkeyNodeEntry) * (pNode->pg.nEntry-iInsert); - memmove(&pNode->aEntry[iInsert+1], &pNode->aEntry[iInsert], nByte); - } - pNode->pg.nEntry++; - } - pNode->aEntry[iInsert].iKey = iKey; - pNode->aEntry[iInsert].iChildPg = iChildPg; - pNode->aEntry[iInsert].unused = 0; - } - - return rc; -} - - -/* -** The buffer passed as the first -*/ -static int hctDbFreegap(void *aPg){ - assert( - (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) - || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) - ); - return ((HctDbIndexNode*)aPg)->hdr.nFreeGap; -} - -static int hctDbFreebytes(void *aPg){ - assert( - (hctPagetype(aPg)==HCT_PAGETYPE_INTKEY && hctPageheight(aPg)==0) - || (hctPagetype(aPg)==HCT_PAGETYPE_INDEX) - ); - return ((HctDbIndexNode*)aPg)->hdr.nFreeBytes; -} - -static int hctDbInsertOverflow( - HctDatabase *pDb, - HctDbWriter *pWriter, - u8 *aTarget, - int nData, - const u8 *aData, - int *pnWrite, - u32 *ppgOvfl -){ - int rc = SQLITE_OK; - int nLocal = hctDbLocalsize(aTarget, pDb->pgsz, nData); - - if( nLocal==nData ){ - *pnWrite = nData; - *ppgOvfl = 0; - }else{ - const int sz = (pDb->pgsz - sizeof(HctDbPageHdr)); - int nRem; - int nCopy; - u32 iPg = 0; - int nOvfl = 0; - - nRem = nData; - nCopy = (nRem-nLocal) % sz; - if( nCopy==0 ) nCopy = sz; - while( rc==SQLITE_OK && nRem>nLocal ){ - HctFilePage pg; - nOvfl++; - rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &pg); - if( rc==SQLITE_OK ){ - HctDbPageHdr *pPg = (HctDbPageHdr*)pg.aNew; - memset(pPg, 0, sizeof(HctDbPageHdr)); - pPg->iPeerPg = iPg; - pPg->nEntry = nCopy; - hctMemcpy(&pPg[1], &aData[nRem-nCopy], nCopy); - iPg = pg.iNewPg; - sqlite3HctFilePageRelease(&pg); - } - nRem -= nCopy; - nCopy = sz; - } - - *ppgOvfl = iPg; - *pnWrite = nLocal; - - if( rc==SQLITE_OK ){ - rc = hctDbOverflowArrayAppend(&pWriter->insOvfl, iPg, nOvfl); - } - } - - return rc; -} - -static void hctDbRemoveCell( - HctDatabase *pDb, - HctDbWriter *pWriter, - u8 *aTarget, - int iRem -){ - HctDbIndexNode *p = (HctDbIndexNode*)aTarget; - const int eType = hctPagetype(aTarget); - const int nHeight = hctPageheight(aTarget); - const int pgsz = pDb->pgsz; - - int szEntry = 0; /* Size of each entry in aEntry[] array */ - int iArrayOff = 0; /* Offset of aEntry array in aTarget */ - int iData = 0; /* Offset of cell in aTarget[] */ - int nData = 0; /* Local size of cell to remove */ - - /* Populate stack variables szEntry, iArrayOff, iData and nData. */ - assert( eType==HCT_PAGETYPE_INTKEY || eType==HCT_PAGETYPE_INDEX ); - assert( eType==HCT_PAGETYPE_INDEX || nHeight==0 ); - if( eType==HCT_PAGETYPE_INTKEY ){ - HctDbIntkeyEntry *pEntry = &((HctDbIntkeyLeaf*)aTarget)->aEntry[iRem]; - iData = pEntry->iOff; - nData = hctDbIntkeyEntrySize(pEntry, pgsz); - szEntry = sizeof(*pEntry); - iArrayOff = sizeof(HctDbIntkeyLeaf); - }else if( nHeight==0 ){ - HctDbIndexEntry *pEntry = &((HctDbIndexLeaf*)aTarget)->aEntry[iRem]; - iData = pEntry->iOff; - nData = hctDbIndexEntrySize(pEntry, pgsz); - szEntry = sizeof(*pEntry); - iArrayOff = sizeof(HctDbIndexLeaf); - }else{ - HctDbIndexNodeEntry *pEntry = &((HctDbIndexNode*)aTarget)->aEntry[iRem]; - iData = pEntry->iOff; - nData = hctDbIndexNodeEntrySize(pEntry, pgsz); - szEntry = sizeof(*pEntry); - iArrayOff = sizeof(HctDbIndexNode); - } - - /* Remove the aEntry[] array entry */ - if( iRempg.nEntry-1 ){ - u8 *aTo = &aTarget[iArrayOff + iRem*szEntry]; - memmove(aTo, &aTo[szEntry], (p->pg.nEntry-iRem-1) * szEntry); - } - p->pg.nEntry--; - p->hdr.nFreeBytes += szEntry; - p->hdr.nFreeGap += szEntry; - - /* Remove the cell from the data area */ - if( iData==(iArrayOff + szEntry*p->pg.nEntry + p->hdr.nFreeGap) ){ - int ii; - int iFirst = pDb->pgsz; - p->hdr.nFreeGap += nData; - for(ii=0; iipg.nEntry; ii++){ - int iOff = ((HctDbIndexEntry*)&aTarget[iArrayOff + szEntry*ii])->iOff; - if( iOff && iOffhdr.nFreeGap = iFirst - (iArrayOff + szEntry*p->pg.nEntry); - } - p->hdr.nFreeBytes += nData; - -} - - -/* -** This is called as part of a bulk insert of contiguous keys. At present -** this only occurs as part of a migrate, but in the future it could be -** auto-detected. -*/ -static int hctDbBalanceMigrate( - HctDatabase *pDb, - HctDbWriter *p, - HctDbInsertOp *pOp -){ - HctDbLeaf *pLeaf = (HctDbLeaf*)p->writepg.aPg[0].aNew; - int ii = 0; - - assert( p->writepg.nPg==1 ); - assert( p->bAppend==0 ); - assert( p->iHeight==0 ); - assert( pOp->iInsert<=pLeaf->pg.nEntry ); - assert( pOp->eBalance==BALANCE_REQUIRED || pOp->eBalance==BALANCE_OPTIONAL ); - - /* Set nMigrateKey to the number of keys to copy from p->writepg.aPg[0].aOld - ** before flushing the current array of pages to disk. */ - p->nMigrateKey = pLeaf->pg.nEntry - pOp->iInsert; - - /* Remove the last nMigrateKey cells from the page. */ - for(ii=0; iinMigrateKey; ii++){ - hctDbRemoveCell(pDb, 0, (u8*)pLeaf, pLeaf->pg.nEntry-1); - } - p->bAppend = 1; - - /* Use a regular balance to make space for the new key */ - pOp->eBalance = BALANCE_REQUIRED; - return hctDbBalance(pDb, p, pOp, 0); -} - -/* -** Buffer aTarget must contain the image of a page that uses variable -** length records - an intkey leaf, or an index leaf or node. This -** function does part of the job of inserting a new record into the -** page. -** -** Buffer aEntry[], size nEntry bytes, contains the sequence of bytes that -** will be stored in the data area of the page (i.e. any serialized -** tids, the old page number if any, any overflow page number and the -** portion of the database record that will be stored on the main -** page. Parameter iIns specifies the index within the page at which -** the new entry will be inserted. -*/ -static void hctDbInsertEntry( - HctDatabase *pDb, - u8 *aTarget, - int iIns, - const u8 *aEntry, - int nEntry -){ - HctDbIndexNode *p = (HctDbIndexNode*)aTarget; - int szEntry = 0; /* Size of each entry in aEntry[] array */ - int iEntry0 = 0; /* Offset of aEntry array in aTarget */ - int iOff = 0; /* Offset of new cell data in aTarget */ - u8 *aFrom = 0; - - iEntry0 = hctDbEntryArrayDim(aTarget, &szEntry); - - /* This might fail if the db is corrupt */ - assert( p->hdr.nFreeGap>=(nEntry + szEntry) ); - - /* Insert the new zeroed entry into the aEntry[] array */ - aFrom = &aTarget[iEntry0 + szEntry*iIns]; - if( iInspg.nEntry ){ - memmove(&aFrom[szEntry], aFrom, (p->pg.nEntry-iIns) * szEntry); - } - memset(aFrom, 0, szEntry); - p->hdr.nFreeBytes -= szEntry; - p->hdr.nFreeGap -= szEntry; - p->pg.nEntry++; - - /* Insert the cell into the data area */ - iOff = iEntry0 + p->pg.nEntry*szEntry + p->hdr.nFreeGap - nEntry; - hctMemcpy(&aTarget[iOff], aEntry, nEntry); - p->hdr.nFreeBytes -= nEntry; - p->hdr.nFreeGap -= nEntry; - - /* Set the aEntry[].iOff field */ - ((HctDbIndexEntry*)aFrom)->iOff = iOff; -} - - -static int hctDbMigrateReinsertKeys(HctDatabase *pDb, HctDbWriter *p){ - int rc = SQLITE_OK; - if( p->nMigrateKey>0 ){ - assert( p->iHeight==0 ); - - /* Append a page to the write-array */ - rc = hctDbExtendWriteArray(pDb, p, p->writepg.nPg, 1); - - - if( rc==SQLITE_OK ){ - int ii = 0; - HctDbInsertOp op; - HctDbLeaf *pOld = (HctDbLeaf*)p->writepg.aPg[0].aOld; - HctDbLeaf *pNew = (HctDbLeaf*)p->writepg.aPg[p->writepg.nPg-1].aNew; - - /* TODO: Might this not be a part of ExtendWriteArray() ? */ - pNew->hdr.nFreeBytes = pDb->pgsz - sizeof(HctDbLeaf); - pNew->hdr.nFreeGap = pNew->hdr.nFreeBytes; - - /* Loop through the last nMigrateKey on the old page, copying them - ** to the new page. */ - for(ii=0; iinMigrateKey; ii++){ - int iOld = (pOld->pg.nEntry - p->nMigrateKey) + ii; - HctDbIndexEntry *pOldE = 0; - HctDbIndexEntry *pNewE = 0; - int nEntry = 0; - - pOldE = hctDbEntryEntry(pOld, iOld); - nEntry = hctDbPageRecordSize(pOld, pDb->pgsz, iOld); - hctDbInsertEntry(pDb, (u8*)pNew, ii, &((u8*)pOld)[pOldE->iOff], nEntry); - - pNewE = hctDbEntryEntry(pNew, ii); - pNewE->nSize = pOldE->nSize; - pNewE->flags = pOldE->flags; - if( hctPagetype(pOld)==HCT_PAGETYPE_INTKEY ){ - ((HctDbIntkeyEntry*)pNewE)->iKey = ((HctDbIntkeyEntry*)pOldE)->iKey; - } - } - - memset(&op, 0, sizeof(op)); - op.iPg = p->writepg.nPg-1; - op.iInsert = -1; - op.eBalance = BALANCE_OPTIONAL; - rc = hctDbBalance(pDb, p, &op, 0); - } - } - - return rc; -} - -/* -** Parameter aTarget points to a buffer containing an intkey or index -** internal node. Return the child-page number for entry iInsert on -** that page. -*/ -u32 hctDbGetChildPage(u8 *aTarget, int iInsert){ - const int eType = hctPagetype(aTarget); - u32 iChildPg; - if( eType==HCT_PAGETYPE_INTKEY ){ - iChildPg = ((HctDbIntkeyNode*)aTarget)->aEntry[iInsert].iChildPg; - }else{ - assert( eType==HCT_PAGETYPE_INDEX ); - iChildPg = ((HctDbIndexNode*)aTarget)->aEntry[iInsert].iChildPg; - } - return iChildPg; -} - -static void hctDbClobberEntry( - HctDatabase *pDb, - u8 *aTarget, - HctDbInsertOp *pOp -){ - HctDbIndexEntry *pEntry; /* Entry being clobbered */ - int nOld = hctDbPageRecordSize(aTarget, pDb->pgsz, pOp->iInsert); - - pEntry = hctDbEntryEntry(aTarget, pOp->iInsert); - pEntry->nSize = pOp->nEntrySize; - pEntry->flags = pOp->entryFlags; - - memcpy(&aTarget[pEntry->iOff], pOp->aEntry, pOp->nEntry); - ((HctDbIndexNode*)aTarget)->hdr.nFreeBytes += (nOld - pOp->nEntry); - - pDb->stats.nUpdateInPlace++; -} - -static int hctDbFindOldPage( - HctDatabase *pDb, - HctDbWriter *p, - UnpackedRecord *pKey, - i64 iKey, - u32 *piOld, - const u8 **paOld -){ - HctFilePage *pPg = 0; - int rc = SQLITE_OK; - int iTest; - - for(iTest=p->discardpg.nPg-1; iTest>=0; iTest--){ - pPg = &p->discardpg.aPg[iTest]; - if( pKey ){ - int bGe = 0; - rc = hctDbCompareFPKey(pDb, pKey, pPg->aOld, &bGe); - if( bGe || rc!=SQLITE_OK ) break; - }else{ - i64 iFP = hctDbIntkeyFPKey(pPg->aOld); - if( iKey>=iFP ) break; - } - pPg = 0; - } - - if( pPg==0 ){ - pPg = &p->writepg.aPg[0]; - } - assert( pPg->iOldPg!=0 ); - *piOld = pPg->iOldPg; - *paOld = pPg->aOld; - - return rc; -} - -static u64 hctDbGetRangeTidByIdx(HctDatabase *pDb, u8 *aTarget, int iIdx){ - HctDbCell cell; - hctDbCellGetByIdx(pDb, aTarget, iIdx, &cell); - return cell.iRangeTid; -} - -static u32 hctDbMakeFollowPtr( - int *pRc, - HctDatabase *pDb, - u64 iFollowTid, - u32 iPg -){ - int rc = *pRc; - HctFilePage pg; - u32 iRet = 0; - - memset(&pg, 0, sizeof(pg)); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &pg); - iRet = pg.iNewPg; - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctFileClearPhysInUse(pDb->pFile, iRet, 0); - } - if( rc==SQLITE_OK ){ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)pg.aNew; - memset(pFan, 0, sizeof(*pFan)); - pFan->pg.hdrFlags = HCT_PAGETYPE_HISTORY; - pFan->pg.nEntry = 1; - pFan->iRangeTid0 = pDb->iTid; - pFan->iFollowTid0 = iFollowTid; - pFan->pgOld0 = iPg; - rc = sqlite3HctFilePageRelease(&pg); - }else{ - sqlite3HctFilePageUnwrite(&pg); - sqlite3HctFilePageRelease(&pg); - } - - *pRc = rc; - return iRet; -} - -static int hctDbDelete( - HctDatabase *pDb, - HctDbWriter *p, - UnpackedRecord *pRec, - HctDbInsertOp *pOp -){ - u64 iTidOr = (pDb->eMode==HCT_MODE_ROLLBACK ? HCT_TID_ROLLBACK_OVERRIDE : 0); - u64 iSafeTid = sqlite3HctFileSafeTID(pDb->pFile); - u64 iTidValue = pDb->iTid | iTidOr; - u64 iDelRangeTid = 0; - int rc = SQLITE_OK; - u8 *aNull = 0; - int prevFlags = 0; - int nLocalSz = 0; - u8 *aTarget = p->writepg.aPg[pOp->iPg].aNew; - int bLeftmost = (hctIsLeftmost(aTarget) && pOp->iInsert==0); - - HctDbCell prev; /* Previous cell on page */ - - assert( pOp->bFullDel==0 ); - - if( pOp->iInsert==0 && !bLeftmost ){ - /* If deleting the first key on the first page, set the eBalance flag (as - ** deleting a FP key means the parent list must be adjusted) and load peer - ** pages into memory. */ - pOp->eBalance = BALANCE_REQUIRED; - if( pOp->iPg==0 ){ - rc = hctDbLoadPeers(pDb, p, &pOp->iPg); - if( rc!=SQLITE_OK ) return rc; - aTarget = p->writepg.aPg[pOp->iPg].aNew; - } - } - assert_page_is_ok(aTarget, pDb->pgsz); - - /* Deal with the case where the cell we are about to remove (cell iInsert) - ** has a range-tid greater than that of the current transaction (iTid) */ - iDelRangeTid = hctDbGetRangeTidByIdx(pDb, aTarget, pOp->iInsert); - if( (iDelRangeTid & HCT_TID_MASK)>pDb->iTid ){ - iTidValue = iDelRangeTid; - pOp->iOldPg = hctDbMakeFollowPtr(&rc, pDb, iDelRangeTid, pOp->iOldPg); - sqlite3HctFilePageRelease(&p->fanpg); - } - - if( bLeftmost ){ - int nNull = 0; - - memset(&prev, 0, sizeof(prev)); - prev.iTid = LARGEST_TID; - prevFlags |= HCTDB_HAS_TID; - - assert( pOp->iPg==0 ); - if( hctPagetype(aTarget)==HCT_PAGETYPE_INDEX ){ - int nField = p->writecsr.pKeyInfo->nAllField; - int nByte = nField + 9; - aNull = sqlite3HctMalloc(&rc, nByte); - if( rc!=SQLITE_OK ) return rc; - if( nField<=126 ){ - aNull[0] = nField+1; - nNull = nField+1; - } - else if( nField<=16382 ){ - sqlite3PutVarint(aNull, nField+2); - nNull = nField+2; - }else{ - assert( sqlite3VarintLen(nField+3)==3 ); - sqlite3PutVarint(aNull, nField+3); - nNull = nField+3; - } - prev.aPayload = aNull; - } - prev.iTid = LARGEST_TID; - prevFlags |= HCTDB_HAS_TID; - pOp->nEntrySize = nNull; - nLocalSz = hctDbLocalsize(aTarget, pDb->pgsz, pOp->nEntrySize); - - }else{ - HctDbIndexEntry *pPrev = 0; - - /* Remove the cell being deleted from the target page. This must be done - ** after hctDbLoadPeers() is called (if it is called). */ - assert_page_is_ok(aTarget, pDb->pgsz); - hctDbRemoveCell(pDb, p, aTarget, pOp->iInsert); - assert_page_is_ok(aTarget, pDb->pgsz); - if( pOp->iInsert==0 ){ - assert( pOp->iPg>0 ); - pOp->iPg--; - aTarget = p->writepg.aPg[pOp->iPg].aNew; - assert( hctPagenentry(aTarget)>0 ); - pOp->iInsert = ((HctDbPageHdr*)aTarget)->nEntry - 1; - }else{ - pOp->iInsert--; - } - - /* Load the cell immediately before the one just removed */ - pPrev = hctDbEntryEntry(aTarget, pOp->iInsert); - pOp->nEntrySize = pPrev->nSize; - prevFlags = pPrev->flags; - - hctDbCellGet(pDb, &aTarget[pPrev->iOff], pPrev->flags, &prev); - nLocalSz = hctDbLocalsize(aTarget, pDb->pgsz, pOp->nEntrySize); - } - - /* Update the range-tid and range-oldpg fields. There are several - ** possibilities: - ** - ** 1) The left-hand-cell already has the desired range-pointer values - ** (both TID and old-page-number). - ** - ** 2) The left-hand-cell does not have a range-pointer. Or else - ** has a range-pointer so old it can be overwritten with impunity. - ** - ** 3) The left-hand-cell has a range-pointer to a fan-page that was - ** created by the current HctDbWriter batch, and that fan-page - ** is not already full. - ** - ** 4) None of the above are true. A new fan-page must be created. - */ - if( prev.iRangeTid==iTidValue && prev.iRangeOld==pOp->iOldPg ){ - /* Possibility (1) */ - pOp->bFullDel = 1; - pOp->iInsert = -1; - } - else if( prev.iRangeTid==0 || (prev.iRangeTid & HCT_TID_MASK)<=iSafeTid ){ - /* Possibility (2) */ - prev.iRangeTid = iTidValue; - prev.iRangeOld = pOp->iOldPg; - }else if( prev.iRangeOld==p->fanpg.iNewPg ){ - /* Possibility (3) */ - HctDbHistoryFan *pFan = (HctDbHistoryFan*)p->fanpg.aNew; - assert( pFan->iRangeTid1==iTidValue ); - if( pFan->aPgOld1[pFan->pg.nEntry-2]!=pOp->iOldPg ){ - const int nMax = ((pDb->pgsz - sizeof(HctDbHistoryFan))/sizeof(u32)); - assert( pFan->pg.nEntryaPgOld1[pFan->pg.nEntry-1] = pOp->iOldPg; - pFan->pg.nEntry++; - if( pFan->pg.nEntry==nMax ){ - rc = sqlite3HctFilePageRelease(&p->fanpg); - } - } - pOp->bFullDel = 1; - pOp->iInsert = -1; - }else{ - /* Possibility (4) */ - rc = sqlite3HctFilePageRelease(&p->fanpg); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageNewPhysical(pDb->pFile, &p->fanpg); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctFileClearPhysInUse(pDb->pFile, p->fanpg.iNewPg, 0); - } - if( rc==SQLITE_OK ){ - int bDummy = 0; - HctDbHistoryFan *pFan = (HctDbHistoryFan*)p->fanpg.aNew; - memset(pFan, 0, pDb->pgsz); - pFan->pg.hdrFlags = HCT_PAGETYPE_HISTORY; - pFan->pg.nEntry = 2; - pFan->iRangeTid0 = prev.iRangeTid; - pFan->iFollowTid0 = prev.iRangeTid; - pFan->pgOld0 = prev.iRangeOld; - rc = hctDbLeafSearch( - pDb, pOp->aOldPg, pOp->iIntkey, pRec, &pFan->iSplit0, &bDummy - ); - assert( bDummy ); - pFan->iRangeTid1 = iTidValue; - pFan->aPgOld1[0] = pOp->iOldPg; - prev.iRangeOld = p->fanpg.iNewPg; - if( (prev.iRangeTid & HCT_TID_MASK)<(iTidValue & HCT_TID_MASK) ){ - prev.iRangeTid = iTidValue; - } - } - } - - if( rc==SQLITE_OK && pOp->bFullDel==0 ){ - prev.iRangeTid |= iTidOr; - pOp->aEntry = pDb->aTmp; - pOp->nEntry = hctDbCellPut(pOp->aEntry, &prev, nLocalSz); - pOp->entryFlags = prevFlags | HCTDB_HAS_RANGETID | HCTDB_HAS_RANGEOLD; - if( hctPagetype(aTarget)==HCT_PAGETYPE_INTKEY ){ - if( bLeftmost ){ - pOp->iIntkey = SMALLEST_INT64; - }else{ - pOp->iIntkey = ((HctDbIntkeyLeaf*)aTarget)->aEntry[pOp->iInsert].iKey; - } - } - } - - assert_page_is_ok(aTarget, pDb->pgsz); - if( aNull ) sqlite3_free(aNull); - return rc; -} - -static int hctDbInsertFindPosition( - HctDatabase *pDb, - HctDbWriter *p, - u32 iRoot, - UnpackedRecord *pRec, - i64 iKey, - HctDbInsertOp *pOp, - int *pbClobber -){ - const RecordCompare xCompare = pRec ? sqlite3VdbeFindCompare(pRec) : 0; - int rc = SQLITE_OK; - - if( p->writepg.nPg==0 ){ - if( p->writecsr.iRoot!=iRoot ){ - hctDbCsrInit(pDb, iRoot, 0, &p->writecsr); - }else{ - hctDbCsrReset(&p->writecsr); - } - if( pRec ){ - p->writecsr.pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); - } - rc = hctDbCsrSeek( - &p->writecsr, &p->fp, p->iHeight, xCompare, pRec, iKey, pbClobber - ); - if( rc ) return rc; - pOp->iInsert = p->writecsr.iCell; - if( *pbClobber==0 ) pOp->iInsert++; - - p->writepg.aPg[0] = p->writecsr.pg; - memset(&p->writecsr.pg, 0, sizeof(HctFilePage)); - - assert( p->bDoCleanup ); - p->writepg.nPg = 1; - rc = sqlite3HctFilePageWrite(&p->writepg.aPg[0]); - if( rc ) return rc; - hctMemcpy(p->writepg.aPg[0].aNew, p->writepg.aPg[0].aOld, pDb->pgsz); - if( p->fp.iKey==0 ){ - rc = hctDbSetWriteFpKey(pDb, p); - } - if( rc ) return rc; - }else if( pRec ){ - HctBuffer buf = {0,0,0}; - for(pOp->iPg=p->writepg.nPg-1; pOp->iPg>0; pOp->iPg--){ - const u8 *aK; - int nK; - rc = hctDbLoadRecord( - pDb, &buf, p->writepg.aPg[pOp->iPg].aNew, 0, &nK, &aK - ); - if( rc!=SQLITE_OK ){ - sqlite3HctBufferFree(&buf); - return rc; - } - if( xCompare(nK, aK, pRec)<=0 ) break; - } - sqlite3HctBufferFree(&buf); - rc = hctDbIndexSearch(pDb, - p->writepg.aPg[pOp->iPg].aNew, xCompare, pRec, &pOp->iInsert, pbClobber - ); - if( rc!=SQLITE_OK ) return rc; - }else{ - for(pOp->iPg=p->writepg.nPg-1; pOp->iPg>0; pOp->iPg--){ - if( hctDbIntkeyFPKey(p->writepg.aPg[pOp->iPg].aNew)<=iKey ) break; - } - if( p->iHeight==0 ){ - pOp->iInsert = hctDbIntkeyLeafSearch( - p->writepg.aPg[pOp->iPg].aNew, iKey, pbClobber - ); - }else{ - pOp->iInsert = hctDbIntkeyNodeSearch( - p->writepg.aPg[pOp->iPg].aNew, iKey, pbClobber - ); - } - } - - return rc; -} - -static int hctDbWriteWriteConflict( - HctDatabase *pDb, - HctDbWriter *p, - HctDbInsertOp *pOp, - UnpackedRecord *pKey, - i64 iKey, - int bClobber -){ - int rc = SQLITE_OK; - const u8 *aTarget = p->writepg.aPg[pOp->iPg].aNew; - - assert( p->iHeight==0 && pDb->eMode==HCT_MODE_NORMAL ); - - if( bClobber ){ - HctDbIndexEntry *pE; - if( pKey ){ - pE = &((HctDbIndexLeaf*)aTarget)->aEntry[pOp->iInsert]; - }else{ - pE = (HctDbIndexEntry*)&((HctDbIntkeyLeaf*)aTarget)->aEntry[pOp->iInsert]; - } - if( pE->flags & HCTDB_HAS_TID ){ - u64 iTid; - hctMemcpy(&iTid, &aTarget[pE->iOff], sizeof(u64)); - if( hctDbTidIsConflict(pDb, iTid) ){ - rc = HCT_SQLITE_BUSY; - } - } - }else if( pOp->iInsert>0 ){ - int iCell = 0; - int bMerge = 0; - HctRangePtr ptr; - - iCell = (pOp->iInsert - 1); - hctDbGetRange(aTarget, iCell, &ptr); - while( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ - HctFilePage pg; - const u8 *aOld = 0; - - if( ptr.iOld==pDb->pa.fanpg.iNewPg ){ - aOld = pDb->pa.fanpg.aNew; - memset(&pg, 0, sizeof(pg)); - }else{ - rc = hctDbGetPhysical(pDb, ptr.iOld, &pg); - aOld = pg.aOld; - } - - /* assert( bMerge==0 || iRangeTid!=pDb->iTid ); */ - if( rc==SQLITE_OK ){ - int iCell = 0; - if( hctPagetype(aOld)==HCT_PAGETYPE_HISTORY ){ - iCell = hctDbFanSearch(&rc, pDb, aOld, pKey, iKey); - }else{ - int bExact = 0; - rc = hctDbLeafSearch(pDb, aOld, iKey, pKey, &iCell, &bExact); - if( rc==SQLITE_OK && bExact ){ - if( bMerge ){ - HctDbCell cell; - hctDbCellGetByIdx(pDb, aOld, iCell, &cell); - if( hctDbTidIsVisible(pDb, cell.iTid, 0) ) rc = HCT_SQLITE_BUSY; - } - sqlite3HctFilePageRelease(&pg); - break; - }else{ - iCell--; - } - if( rc ){ - sqlite3HctFilePageRelease(&pg); - break; - } - } - - hctDbGetRange(aOld, iCell, &ptr); - sqlite3HctFilePageRelease(&pg); - }else{ - break; - } - } - } - - return rc; -} - -static int hctDbInsert( - HctDatabase *pDb, - HctDbWriter *p, - u32 iRoot, - UnpackedRecord *pRec, /* The key value for index tables */ - i64 iKey, /* For intkey tables, the key value */ - u32 iChildPg, /* For internal node ops, the child pgno */ - int bDel, /* True for a delete operation */ - int nData, const u8 *aData /* Record/key to insert */ -){ - const RecordCompare xCompare = pRec ? sqlite3VdbeFindCompare(pRec) : 0; - int rc = SQLITE_OK; - int bClobber = 0; - u8 *aTarget; /* Page to write new entry to */ - HctDbInsertOp op = {0,0,0,0,0,0,0,0,0,0,0}; - int bUpdateInPlace = 0; - - p->nWriteKey++; - - assert( pDb->eMode==HCT_MODE_NORMAL || pDb->eMode==HCT_MODE_ROLLBACK ); - - /* Check if any existing dirty pages need to be flushed to disk before - ** this key can be inserted. If they do, flush them. */ - assert( p->writepg.nPg==0 || iRoot==p->writecsr.iRoot ); - assert( p->writepg.nPg>0 || p->bAppend==0 ); - if( p->writepg.nPg ){ - assert( p->bDoCleanup ); - if( p->writepg.nPg>HCTDB_MAX_DIRTY - || p->discardpg.nPg>=HCTDB_MAX_DIRTY - || hctDbTestWriteFpKey(p, xCompare, pRec, iKey) - ){ - rc = hctDbInsertFlushWrite(pDb, p); - if( rc ) return rc; - p->nWriteKey = 1; - } - } - - p->bDoCleanup = 1; - rc = hctDbWriterGrow(p); - if( rc ) return rc; - - /* This block sets stack variables: - ** - ** op.iPg: Index of page in HctDbWriter.writepg.aPg[] to write to. - ** op.iInsert: The index of the new, overwritten, or deleted entry - ** within the page. - ** bClobber: True if this write clobbers (or deletes, if bDel) an - ** existing entry. - ** aTarget: The aNew[] buffer of the page that will be written. - ** - ** It also checks if the current key is a write-write conflict. And - ** returns early if so. - */ - if( p->bAppend ){ - assert( bClobber==0 ); - assert( p->writepg.nPg>0 ); - op.iPg = p->writepg.nPg-1; - aTarget = p->writepg.aPg[op.iPg].aNew; - op.iInsert = hctPagenentry(aTarget); - }else{ - /* If the page array is empty, seek the write cursor to find the leaf - ** page on which to insert this new entry or delete key. - ** - ** Otherwise, figure out which page in the HctDbWriter.aWritePg[] array the - ** new entry belongs on. */ - rc = hctDbInsertFindPosition(pDb, p, iRoot, pRec, iKey, &op, &bClobber); - if( rc ) return rc; - aTarget = p->writepg.aPg[op.iPg].aNew; - assert( aTarget ); - - /* If this is a write to a leaf page, and not part of a rollback, - ** check for a write-write conflict here. */ - if( 0==p->iHeight - && pDb->eMode==HCT_MODE_NORMAL - && (rc=hctDbWriteWriteConflict(pDb, p, &op, pRec, iKey, bClobber)) - ){ - return rc; - } - } - - if( bClobber==0 && bDel ){ - return SQLITE_OK; - } - - /* At this point, once the page that will be modified has been loaded - ** and marked as writable, if the operation is on an internal list: - ** - ** 1) For an insert, check if the child page has already been marked - ** as EVICTED by some other client. If so, return early. - ** - ** 2) For a delete, check that there is an entry to delete. And if so, - ** that the value of its child-page field matches iChildPg. If - ** not, return early. Note that the page marked as writable will - ** still be flushed to disk in this case - even though it may be - ** unmodified. - ** - ** This resolves a race condition that may occur if client B starts - ** removing page X from a list before client A has finished inserting - ** the corresponding entry into the parent list. Specifically: - ** - ** + when client A gets here, if the EVICTED flag is not set on page X, - ** then client B will try to delete the corresponding entry from - ** the parent list at some point in the future. This will either - ** occur after client A has updated the list, in which case no - ** problem, or it will cause client A's attempt to flush the modified - ** page to disk to fail. Client A will retry, see the EVICTED flag - ** is set, and continue. - ** - ** + or, if EVICTED is set, then there is no point in writing the - ** entry into the parent list. - */ - assert( rc==SQLITE_OK ); - if( p->iHeight>0 ){ - if( bDel==0 && sqlite3HctFilePageIsEvicted(pDb->pFile, iChildPg) ){ - return SQLITE_OK; - } - if( bDel ){ - u32 iChild = hctDbGetChildPage(aTarget, op.iInsert); - if( iChild!=iChildPg ) return SQLITE_OK; - } - } - - /* Writes to an intkey internal node are handled separately. They are - ** different because they used fixed size key/data pairs. All other types - ** of page use variably sized key/data entries. */ - if( pRec==0 && p->iHeight>0 ){ - return hctDbInsertIntkeyNode( - pDb, p, op.iPg, op.iInsert, iKey, iChildPg, bClobber, bDel - ); - } - - if( p->iHeight>0 ){ - op.bFullDel = bDel; - } - - if( rc ){ - assert( !"is this really possible?" ); - return rc; - } - - /* If this is a clobber or delete operation and the entry being removed - ** has an overflow chain, add an entry to HctDbWriter.delOvfl. */ - if( bClobber ){ - hctDbRemoveOverflow(pDb, p, aTarget, op.iInsert); - } - - /* Populate the following variables: - ** - ** entryFlags - ** aEntry - ** nEntry - ** nEntrySize - ** - ** This block populates the above variables. It also inserts overflow pages. - */ - op.iIntkey = iKey; - if( op.bFullDel==0 ){ - - if( p->iHeight==0 && (bClobber || bDel) ){ - rc = hctDbFindOldPage(pDb, p, pRec, iKey, &op.iOldPg, &op.aOldPg); - if( rc!=SQLITE_OK ) goto insert_out; - assert( op.iOldPg!=0 ); - } - - if( bDel && p->iHeight==0 ){ - assert( bClobber ); - rc = hctDbDelete(pDb, p, pRec, &op); - aTarget = p->writepg.aPg[op.iPg].aNew; - assert_page_is_ok(aTarget, pDb->pgsz); - if( op.bFullDel ) bClobber = 0; - }else{ - HctDbCell cell; - int nLocal = 0; - memset(&cell, 0, sizeof(cell)); - - if( p->iHeight==0 ){ - - /* There should never be a rollback operation while migrating a - ** database. */ - assert( IS_HCT_MIGRATE(pDb)==0 || pDb->eMode!=HCT_MODE_ROLLBACK ); - - if( IS_HCT_MIGRATE(pDb)==0 ){ - cell.iTid = pDb->iTid; - if( pDb->eMode==HCT_MODE_ROLLBACK ){ - cell.iTid |= HCT_TID_ROLLBACK_OVERRIDE; - } - } - - if( bClobber ){ - u64 iOldRangeTid = hctDbGetRangeTidByIdx(pDb, aTarget, op.iInsert); - if( (iOldRangeTid & HCT_TID_MASK)>pDb->iTid ){ - cell.iRangeOld = hctDbMakeFollowPtr(&rc,pDb,iOldRangeTid,op.iOldPg); - cell.iRangeTid = iOldRangeTid; - }else{ - cell.iRangeTid = pDb->iTid; - cell.iRangeOld = op.iOldPg; - } - }else if( op.iInsert>0 ){ - HctDbCell prev; - hctDbCellGetByIdx(pDb, aTarget, op.iInsert-1, &prev); - cell.iRangeTid = prev.iRangeTid; - cell.iRangeOld = prev.iRangeOld; - assert( cell.iRangeTid==0 || cell.iRangeOld!=0 ); - } - } - rc = hctDbInsertOverflow( - pDb, p, aTarget, nData, aData, &nLocal, &cell.iOvfl - ); - cell.aPayload = aData; - - op.aEntry = pDb->aTmp; - op.nEntry = hctDbCellPut(op.aEntry, &cell, nLocal); - op.nEntrySize = nData; - op.entryFlags = hctDbCellToFlags(&cell); - } - - assert( rc!=SQLITE_OK || op.bFullDel || op.aEntry==pDb->aTmp ); - if( rc!=SQLITE_OK ) goto insert_out; - } - - assert( op.aEntry==0 || op.aEntry==pDb->aTmp ); - - /* There are now two choices - either the aTarget[] page can be updated - ** directly (if the new entry fits on the page), or the balance-tree() - ** routine runs to redistribute cells between aTarget[] and its peers, - ** writing the new entry at the same time. A balance is required if: - ** - ** 1) there is insufficient space in the free-gap for any new - ** cell and array entry, or - ** - ** 2) this is a full-delete of the fpkey of the page (iInsert==0), or - ** - ** 3) this operation would leave the page underfull, and it is not - ** the only page in its list. - */ - if( op.eBalance==BALANCE_NONE ){ - int szEntry = hctDbPageEntrySize(aTarget); - int nFree = hctDbFreebytes(aTarget); - int nReq = 0; - int nSpace = 0; /* Space freed by removing cell */ - - if( bClobber ){ - nSpace = hctDbPageRecordSize(aTarget, pDb->pgsz, op.iInsert); - nFree += szEntry; - nFree += nSpace; - } - - if( op.bFullDel==0 ){ - if( nSpace>=op.nEntry ) bUpdateInPlace = 1; - nFree -= op.nEntry; - nFree -= szEntry; - nReq = op.nEntry + (bClobber ? 0 : szEntry); - } - - /* If (a) this is a clobber operation, and (b) either the first - ** key on the page is being deleted or else the page will be less - ** than 1/3 full following the update, and (c) the page is not - ** the only page in its linked list, rebalance! */ - if( (bClobber || bDel) /* (a) */ - && ((op.iInsert==0 && op.bFullDel) || (nFree>(2*pDb->pgsz/3))) /* (b) */ - && (hctIsLeftmost(aTarget)==0 || hctPagePeer(aTarget)!=0) /* (c) */ - ){ - /* Target page will be underfull following this op. Rebalance! */ - op.eBalance = BALANCE_REQUIRED; - bUpdateInPlace = 0; - }else if( hctDbFreegap(aTarget)bAppend ){ - rc = hctDbBalanceAppend(pDb, p, &op); - }else if( IS_HCT_MIGRATE(pDb) && p->iHeight==0 ){ - rc = hctDbBalanceMigrate(pDb, p, &op); - }else{ - rc = hctDbBalance(pDb, p, &op, bClobber); - } - if( rc==SQLITE_OK ) assert_all_pages_ok(pDb, p); - aTarget = p->writepg.aPg[op.iPg].aNew; - }else if( bUpdateInPlace ){ - assert_page_is_ok(aTarget, pDb->pgsz); - hctDbClobberEntry(pDb, aTarget, &op); - assert_page_is_ok(aTarget, pDb->pgsz); - }else if( bClobber ){ - assert_page_is_ok(aTarget, pDb->pgsz); - hctDbRemoveCell(pDb, p, aTarget, op.iInsert); - assert_page_is_ok(aTarget, pDb->pgsz); - } - - /* Unless this is a full-delete operation, update rest of the aEntry[] - ** entry fields for the new cell. */ - if( rc==SQLITE_OK && op.bFullDel==0 ){ - int eType = hctPagetype(aTarget); - assert_page_is_ok(aTarget, pDb->pgsz); - assert( op.iInsert>=0 ); - - /* print_out_page("1", aTarget, pDb->pgsz); */ - if( bUpdateInPlace==0 ){ - hctDbInsertEntry(pDb, aTarget, op.iInsert, op.aEntry, op.nEntry); - } - - assert( (pRec==0)==(eType==HCT_PAGETYPE_INTKEY) ); - if( eType==HCT_PAGETYPE_INTKEY ){ - HctDbIntkeyEntry *pE = &((HctDbIntkeyLeaf*)aTarget)->aEntry[op.iInsert]; - pE->iKey = op.iIntkey; - pE->nSize = op.nEntrySize; - pE->flags = op.entryFlags; - }else if( p->iHeight==0 ){ - HctDbIndexEntry *pE = &((HctDbIndexLeaf*)aTarget)->aEntry[op.iInsert]; - pE->nSize = op.nEntrySize; - pE->flags = op.entryFlags; - }else{ - HctDbIndexNodeEntry *pE = &((HctDbIndexNode*)aTarget)->aEntry[op.iInsert]; - pE->nSize = op.nEntrySize; - pE->flags = op.entryFlags; - pE->iChildPg = iChildPg; - } - - /* print_out_page("2", aTarget, pDb->pgsz); */ - assert_page_is_ok(aTarget, pDb->pgsz); - } - - insert_out: - if( rc==SQLITE_OK ){ - assert_all_pages_ok(pDb, p); - assert_all_pages_nonempty(pDb, p); - } - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbInsert( - HctDatabase *pDb, /* Database to insert into or delete from */ - u32 iRoot, /* Root page of table to modify */ - UnpackedRecord *pRec, /* The key value for index tables */ - i64 iKey, /* For intkey tables, the key value */ - int bDel, /* True for a delete, false for insert */ - int nData, const u8 *aData, /* Record/key to insert */ - int *pnRetry /* OUT: number of operations to retry */ -){ - int rc = SQLITE_OK; - int nRecField = pRec ? pRec->nField : 0; - - /* If this operation is inserting an index entry, figure out how many of - ** the record fields to consider when determining if a potential write - ** collision is found in the data structure. */ - sqlite3HctDbRecordTrim(pRec); - -#if 0 - { - char *zText = sqlite3HctDbRecordToText(0, aData, nData); - sqlite3HctFileDebugPrint(pDb->pFile, - "%p: %s sqlite3HctDbInsert(bDel=%d, iKey=%lld, aData={%s}) iTid=%lld\n", - pDb, - (pDb->eMode==HCT_MODE_ROLLBACK ? "RB" : " "), - bDel, iKey, zText, (i64)pDb->iTid - ); - fflush(stdout); - } -#endif - - assert( pDb->eMode==HCT_MODE_NORMAL - || pDb->eMode==HCT_MODE_ROLLBACK - ); - if( pDb->eMode==HCT_MODE_ROLLBACK ){ - int op = 0; - - pDb->pa.bDoCleanup = 1; - if( pDb->rbackcsr.iRoot!=iRoot ){ - hctDbCsrInit(pDb, iRoot, 0, &pDb->rbackcsr); - if( pRec ){ - pDb->rbackcsr.pKeyInfo = sqlite3KeyInfoRef(pRec->pKeyInfo); - } - }else{ - hctDbCsrReset(&pDb->rbackcsr); - } - - rc = sqlite3HctDbCsrRollbackSeek(&pDb->rbackcsr, pRec, iKey, &op); - if( rc==SQLITE_OK ){ - if( op<0 ){ - bDel = 1; - aData = 0; - nData = 0; - }else if( op>0 ){ - rc = sqlite3HctDbCsrData(&pDb->rbackcsr, &nData, &aData); - bDel = 0; - }else{ - /* TODO: It would be nice to assert( op!=0 ) here, but this fails - ** if the original op being rolled back was a no-op delete. If - ** we could note these as they occur, we could bring a form - ** of this assert() back. */ - /* assert( op!=0 ); */ - goto insert_done; - } - } - } - - if( rc==SQLITE_OK ){ - rc = hctDbInsert(pDb, &pDb->pa, iRoot, pRec, iKey, 0, bDel, nData, aData); - if( rc!=SQLITE_OK ){ - hctDbWriterCleanup(pDb, &pDb->pa, 1); - } - } - if( rc==SQLITE_LOCKED || (rc&0xFF)==SQLITE_BUSY ){ - if( rc==SQLITE_LOCKED ){ - rc = SQLITE_OK; - pDb->nCasFail++; - } - *pnRetry = pDb->pa.nWriteKey; - pDb->pa.nWriteKey = 0; - }else{ - *pnRetry = 0; - } - - insert_done: - if( pRec ) pRec->nField = nRecField; - return rc; -} - -/* -** Start the write-phase of a transaction. -*/ -SQLITE_PRIVATE int sqlite3HctDbStartWrite(HctDatabase *p, u64 *piTid){ - int rc = SQLITE_OK; - HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(p->pFile); - - assert( p->iTid==0 ); - assert( p->eMode==HCT_MODE_NORMAL ); - memset(&p->pa, 0, sizeof(p->pa)); - hctDbPageArrayReset(&p->pa.writepg); - hctDbPageArrayReset(&p->pa.discardpg); - - p->nWriteCount = sqlite3HctFileWriteCount(p->pFile); - p->iTid = sqlite3HctFileAllocateTransid(p->pFile); - rc = sqlite3HctTMapNewTID(pTMapClient, p->iTid, &p->pTmap); - *piTid = p->iTid; - return rc; -} - -SQLITE_PRIVATE i64 sqlite3HctDbTid(HctDatabase *p){ - return p->iTid; -} - -/* -** Set HctDatabase.iJrnlWriteCid. -*/ -SQLITE_PRIVATE void sqlite3HctDbJrnlWriteCid(HctDatabase *pDb, u64 iVal){ - pDb->iJrnlWriteCid = iVal; -} - -static u64 *hctDbFindTMapEntry(HctTMap *pTmap, u64 iTid){ - int iMap, iEntry; - assert( pTmap->iFirstTid<=iTid ); - assert( pTmap->iFirstTid+(pTmap->nMap*HCT_TMAP_PAGESIZE)>iTid ); - iMap = (iTid - pTmap->iFirstTid) / HCT_TMAP_PAGESIZE; - iEntry = (iTid - pTmap->iFirstTid) % HCT_TMAP_PAGESIZE; - - iEntry = HCT_TMAP_ENTRYSLOT(iEntry); - return &pTmap->aaMap[iMap][iEntry]; -} - -/* -** This is called once the current transaction has been completely -** written to disk and validated. The CID is passed as the second argument. -** Or, if the transaction was abandoned and rolled back, iCid is passed -** zero. -*/ -SQLITE_PRIVATE int sqlite3HctDbEndWrite(HctDatabase *p, u64 iCid, int bRollback){ - int rc = SQLITE_OK; - u64 *pEntry = hctDbFindTMapEntry(p->pTmap, p->iTid); - - assert( p->eMode==HCT_MODE_NORMAL ); - assert( p->pa.writepg.nPg==0 ); - - HctAtomicStore(pEntry, iCid|(bRollback?HCT_TMAP_ROLLBACK:HCT_TMAP_COMMITTED)); - p->iTid = 0; - return rc; -} - -static void hctDbFreeCsrList(HctDbCsr *pList){ - HctDbCsr *pNext = pList; - while( pNext ){ - HctDbCsr *pDel = pNext; - pNext = pNext->pNextScanner; - hctDbFreeCsr(pDel); - } -} - -SQLITE_PRIVATE int sqlite3HctDbEndRead(HctDatabase *pDb){ - HctTMapClient *pTMapClient = sqlite3HctFileTMapClient(pDb->pFile); - // assert( (pDb->iSnapshotId==0)==(pDb->pTmap==0) ); - hctDbFreeCsrList(pDb->pScannerList); - pDb->pScannerList = 0; - if( pDb->pTmap ){ - sqlite3HctTMapEnd(pTMapClient, pDb->iSnapshotId); - pDb->pTmap = 0; - pDb->iSnapshotId = 0; - pDb->bConcurrent = 0; - } - return SQLITE_OK; -} - -/* -** If recovery is still required, this function grabs the file-server -** mutex and returns non-zero. Or, if recovery is not required, returns -** zero without grabbing the mutex. -*/ -SQLITE_PRIVATE int sqlite3HctDbStartRecovery(HctDatabase *pDb, int iStage){ - assert( iStage==0 || iStage==1 ); - assert( pDb->eMode==HCT_MODE_NORMAL ); - if( sqlite3HctFileStartRecovery(pDb->pFile, iStage) ){ - memset(&pDb->pa, 0, sizeof(pDb->pa)); - hctDbPageArrayReset(&pDb->pa.writepg); - hctDbPageArrayReset(&pDb->pa.discardpg); - pDb->eMode = HCT_MODE_ROLLBACK; - - /* During recovery the connection should read the latest version of - ** the db - no exceptions. Set these two to the largest possible - ** values to ensure that this happens. */ - pDb->iSnapshotId = LARGEST_TID-1; - pDb->iLocalMinTid = LARGEST_TID-1; - } - return (pDb->eMode==HCT_MODE_ROLLBACK); -} - -SQLITE_PRIVATE void sqlite3HctDbRecoverTid(HctDatabase *pDb, u64 iTid){ - pDb->iTid = iTid; - pDb->iLocalMinTid = iTid ? iTid-1 : 0; -} - -SQLITE_PRIVATE int sqlite3HctDbFinishRecovery(HctDatabase *pDb, int iStage, int rc){ - /* assert( pDb->eMode==HCT_MODE_ROLLBACK ); */ - assert( iStage==0 || iStage==1 ); - assert( pDb->iSnapshotId>0 ); - - pDb->iTid = 0; - pDb->eMode = HCT_MODE_NORMAL; - pDb->iSnapshotId = 0; - pDb->iLocalMinTid = 0; - return sqlite3HctFileFinishRecovery(pDb->pFile, iStage, rc); -} - -/* -** Open a cursor. -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrOpen( - HctDatabase *pDb, - KeyInfo *pKeyInfo, - u32 iRoot, - HctDbCsr **ppCsr -){ - int rc = SQLITE_OK; - HctDbCsr *p; - - assert( pDb->iSnapshotId!=0 ); - - /* Search for an existing cursor that can be reused. */ - HctDbCsr **pp; - for(pp=&pDb->pScannerList; *pp; pp=&(*pp)->pNextScanner){ - if( (*pp)->iRoot==iRoot ){ - *ppCsr = *pp; - *pp = (*pp)->pNextScanner; - return SQLITE_OK; - } - } - - /* If no existing cursor was found, allocate a new one */ - p = (HctDbCsr*)sqlite3MallocZero(sizeof(HctDbCsr)); - if( p==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - p->pDb = pDb; - p->iRoot = iRoot; - p->iCell = -1; - p->pKeyInfo = pKeyInfo; - sqlite3KeyInfoRef(pKeyInfo); - } - *ppCsr = p; - return rc; -} - -/* -** Set the "no-snapshot" flag on the cursor passed as the first argument. -*/ -SQLITE_PRIVATE void sqlite3HctDbCsrNosnap(HctDbCsr *pCsr, int bNosnap){ - if( pCsr ) pCsr->bNosnap = bNosnap; -} - -/* -** Close a cursor opened with sqlite3HctDbCsrOpen(). -*/ -SQLITE_PRIVATE void sqlite3HctDbCsrClose(HctDbCsr *pCsr){ - if( pCsr ){ - HctDatabase *pDb = pCsr->pDb; - hctDbCsrScanFinish(pCsr); - hctDbCsrReset(pCsr); - if( pDb->bConcurrent && pDb->iTid==0 ){ - pCsr->pNextScanner = pDb->pScannerList; - pDb->pScannerList = pCsr; - }else{ - hctDbFreeCsr(pCsr); - } - } -} - -/* -** The cursor passed as the first argument must be open on an intkey -** table and pointed at a valid entry. This function sets output variable -** (*piKey) to the integer key value associated with that entry before -** returning. -*/ -SQLITE_PRIVATE void sqlite3HctDbCsrKey(HctDbCsr *pCsr, i64 *piKey){ - int iCell = 0; - const u8 *aPg = 0; - - aPg = hctDbCsrPageAndCell(pCsr, &iCell); - *piKey = hctDbGetIntkey(aPg, iCell); -} - -/* -** Return true if the cursor is at EOF. Otherwise false. -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrEof(HctDbCsr *pCsr){ - return pCsr==0 || pCsr->iCell<0; -} - -/* -** Set the cursor to point to the first entry in its table. If it is -** stepped, this cursor will be stepped with sqlite3HctDbCsrNext(). -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrFirst(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - - rc = hctDbCsrScanFinish(pCsr); - if( rc==SQLITE_OK ){ - hctDbCsrReset(pCsr); - pCsr->eDir = BTREE_DIR_FORWARD; - rc = hctDbCsrScanStart(pCsr, 0, SMALLEST_INT64); - } - pCsr->eDir = BTREE_DIR_FORWARD; - - if( rc==SQLITE_OK ){ - rc = hctDbCsrFirstValid(pCsr); - } - - return rc; -} - -/* -** Set the cursor to point to the last entry in its table. If it is -** stepped, this cursor will be stepped with sqlite3HctDbCsrPrev(). -*/ -SQLITE_PRIVATE int sqlite3HctDbCsrLast(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - HctFile *pFile = pCsr->pDb->pFile; - u32 iPg = pCsr->iRoot; - HctDbPageHdr *pPg = 0; - HctFilePage pg; - - rc = hctDbCsrScanFinish(pCsr); - if( rc==SQLITE_OK ){ - hctDbCsrReset(pCsr); - pCsr->eDir = BTREE_DIR_REVERSE; - rc = hctDbCsrScanStart(pCsr, 0, LARGEST_INT64); - } - - /* Find the last page in the leaf page list. */ - while( 1 ){ - rc = sqlite3HctFilePageGet(pFile, iPg, &pg); - if( rc!=SQLITE_OK ) break; - - pPg = (HctDbPageHdr*)pg.aOld; - if( pPg->iPeerPg ){ - iPg = pPg->iPeerPg; - }else if( pPg->nHeight==0 ){ - break; - }else if( hctPagetype(pPg)==HCT_PAGETYPE_INTKEY ){ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)pPg; - iPg = pNode->aEntry[pPg->nEntry-1].iChildPg; - }else{ - HctDbIndexNode *pNode = (HctDbIndexNode*)pPg; - iPg = pNode->aEntry[pPg->nEntry-1].iChildPg; - } - sqlite3HctFilePageRelease(&pg); - } - - /* Set the cursor to point to one position past the last entry on the - ** page located above. Then call sqlite3HctDbCsrPrev() to step back to - ** the first entry visible to the current transaction. */ - if( rc==SQLITE_OK ){ - assert( pPg->nHeight==0 && pPg->iPeerPg==0 ); - hctMemcpy(&pCsr->pg, &pg, sizeof(pg)); - if( pPg->nEntry==0 ){ - pCsr->iCell = -1; - }else{ - pCsr->iCell = pPg->nEntry; - rc = sqlite3HctDbCsrPrev(pCsr); - } - } - - return rc; -} - -/* -** Load the key associated with cell iCell1 on page aPg1[] and compare -** it to pKey2. Return an integer less than, equal to or greater than -** zero if the loaded key is less than, equal to or greater than pKey2, -** respectively. i.e. -** -** ret = key(aPg1, iCell1) - (*pKey2) -*/ -static int hctDbCompareCellKey( - int *pRc, - HctDatabase *pDb, - const u8 *aPg1, - int iCell1, - HctDbKey *pKey2 -){ - int ret = 0; - if( *pRc==SQLITE_OK ){ - - assert( hctPagetype(aPg1)==HCT_PAGETYPE_INTKEY - || hctPagetype(aPg1)==HCT_PAGETYPE_INDEX - ); - if( hctPagetype(aPg1)==HCT_PAGETYPE_INTKEY ){ - i64 iKey = hctDbGetIntkey(aPg1, iCell1); - if( iKeyiKey ){ - ret = -1; - }else if( iKey>pKey2->iKey ){ - ret = +1; - } - }else if( pKey2->pKey==0 ){ - ret = -1; - }else{ - int nRec = 0; - const u8 *aRec = 0; - HctBuffer buf = {0,0,0}; - int rc = hctDbLoadRecord(pDb, &buf, aPg1, iCell1, &nRec, &aRec); - if( rc!=SQLITE_OK ){ - *pRc = rc; - }else{ - ret = sqlite3VdbeRecordCompare(nRec, aRec, pKey2->pKey); - } - sqlite3HctBufferFree(&buf); - } - } - - return ret; -} - - -static int hctDbCsrNext(HctDbCsr *pCsr){ - HctDatabase *pDb = pCsr->pDb; - HctDbPageHdr *pPg = 0; - int rc = SQLITE_OK; - - /* Check if the current cell, be it on the linked list of leaves, or - ** on a history page, has an old-data pointer that should be followed. - ** - ** Except, don't do this if pCsr->iCell is less than zero. In that - ** case this call is supposed to jump to the first cell on the main - ** page. */ - if( pCsr->iCell>=0 ){ - do { - int bMerge = 0; - HctRangePtr ptr; - - hctDbCsrGetRange(pCsr, &ptr); - if( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ - hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); - if( rc==SQLITE_OK ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - if( p->eRange==HCT_RANGE_FAN ){ - p->iCell = -1; - }else{ - int bExact = 0; - hctDbLeafSearch(pDb, - p->pg.aOld, p->lowkey.iKey, p->lowkey.pKey, &p->iCell, &bExact - ); - if( bExact==0 ) p->iCell--; - } - } - } - - while( pCsr->nRange ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - - p->iCell++; - if( p->iCellpg.aOld) && ( - p->eRange==HCT_RANGE_FAN - || hctDbCompareCellKey(&rc, pDb, p->pg.aOld, p->iCell, &p->highkey)<0 - )){ - if( p->eRange==HCT_RANGE_MERGE ){ - return SQLITE_OK; - } - break; - } - sqlite3HctFilePageRelease(&p->pg); - hctDbCsrAscendRange(pCsr); - } - - }while( pCsr->nRange ); - - } - - pPg = (HctDbPageHdr*)pCsr->pg.aOld; - assert( pCsr->iCell>=-1 && pCsr->iCellnEntry ); - assert( pPg->nHeight==0 ); - - pCsr->iCell++; - if( pCsr->iCell==pPg->nEntry ){ - u32 iPeerPg = pPg->iPeerPg; - if( iPeerPg==0 ){ - /* Main cursor is now at EOF */ - pCsr->iCell = -1; - sqlite3HctFilePageRelease(&pCsr->pg); - }else{ - /* Jump to peer page */ - rc = sqlite3HctFilePageRelease(&pCsr->pg); - if( rc==SQLITE_OK ){ - rc = sqlite3HctFilePageGet(pDb->pFile, iPeerPg, &pCsr->pg); - pCsr->iCell = 0; - } - } - } - - return rc; -} - -static int hctDbCsrGoLeft(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - int nHeight = ((HctDbPageHdr*)pCsr->pg.aOld)->nHeight; - - if( pCsr->pKeyInfo ){ - UnpackedRecord *pRec = 0; - rc = hctDbCsrLoadAndDecode(pCsr, 0, &pRec); - if( rc==SQLITE_OK ){ - int bDummy; - HctFilePage pg = pCsr->pg; - memset(&pCsr->pg, 0, sizeof(HctFilePage)); - pRec->default_rc = 1; - hctDbCsrSeek(pCsr, 0, nHeight, 0, pRec, 0, &bDummy); - pRec->default_rc = 0; - sqlite3HctFilePageRelease(&pg); - } - }else if( hctIsLeftmost(pCsr->pg.aOld)==0 ){ - i64 iKey = hctDbIntkeyFPKey(pCsr->pg.aOld); - sqlite3HctFilePageRelease(&pCsr->pg); - rc = hctDbCsrSeek(pCsr, 0, nHeight, 0, 0, iKey-1, 0); - } - - return rc; -} - -static int hctDbCsrPrev(HctDbCsr *pCsr){ - HctDatabase *pDb = pCsr->pDb; - int rc = SQLITE_OK; - /* Advance the cursor */ - - if( pCsr->nRange ){ - HctDbRangeCsr *pRange = &pCsr->aRange[pCsr->nRange-1]; - pRange->iCell--; - }else{ - pCsr->iCell--; - if( pCsr->iCell<0 ){ - rc = hctDbCsrGoLeft(pCsr); - } - } - - if( pCsr->iCell>=0 ){ - do { - HctRangePtr ptr; - int bMerge = 0; - - hctDbCsrGetRange(pCsr, &ptr); - if( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ){ - do { - hctDbCsrDescendRange(&rc, pCsr, ptr.iRangeTid, ptr.iOld, bMerge); - memset(&ptr, 0, sizeof(ptr)); - if( rc==SQLITE_OK ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - if( p->eRange==HCT_RANGE_FAN ){ - p->iCell = ((HctDbPageHdr*)p->pg.aOld)->nEntry-1; - }else{ - int bExact; - hctDbLeafSearch(pDb, p->pg.aOld, - p->highkey.iKey, p->highkey.pKey, &p->iCell, &bExact - ); - p->iCell--; - } - - if( p->iCell>=0 ){ - hctDbCsrGetRange(pCsr, &ptr); - } - } - }while( hctDbFollowRangeOld(pDb, &ptr, &bMerge) ); - } - - while( pCsr->nRange>0 ){ - HctDbRangeCsr *p = &pCsr->aRange[pCsr->nRange-1]; - if( p->iCell>=0 && ( - p->eRange==HCT_RANGE_FAN - || hctDbCompareCellKey(&rc, pDb, p->pg.aOld, p->iCell, &p->lowkey)>0 - )){ - if( p->eRange==HCT_RANGE_MERGE ){ - return SQLITE_OK; - } - p->iCell--; - break; - } - sqlite3HctFilePageRelease(&p->pg); - hctDbCsrAscendRange(pCsr); - } - }while( pCsr->nRange ); - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbCsrNext(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - - /* Should not be called while committing, validating or doing rollback. */ - assert( pCsr->pDb->iTid==0 && pCsr->pDb->eMode==HCT_MODE_NORMAL ); - - do { - rc = hctDbCsrNext(pCsr); - }while( rc==SQLITE_OK && pCsr->iCell>=0 && hctDbCurrentIsVisible(pCsr)==0 ); - return rc; -} - -SQLITE_PRIVATE int sqlite3HctDbCsrPrev(HctDbCsr *pCsr){ - int rc = SQLITE_OK; - - assert( pCsr->pDb->eMode==HCT_MODE_NORMAL ); - do { - rc = hctDbCsrPrev(pCsr); - }while( rc==SQLITE_OK && pCsr->iCell>=0 && hctDbCurrentIsVisible(pCsr)==0 ); - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbCsrClear(HctDbCsr *pCsr){ - hctDbCsrScanFinish(pCsr); - hctDbCsrReset(pCsr); -} - - -SQLITE_PRIVATE int sqlite3HctDbCsrData(HctDbCsr *pCsr, int *pnData, const u8 **paData){ - const u8 *pPg; - int iCell; - - pPg = hctDbCsrPageAndCell(pCsr, &iCell); - assert( hctPageheight(pPg)==0 ); - -#if 0 - if( pCsr->nRange ){ - printf("%p: data from range page %d (from %d) (snapshotid=%lld)\n", - pCsr->pDb, - (int)pCsr->aRange[pCsr->nRange-1].pg.iOldPg, - (int)pCsr->pg.iOldPg, pCsr->pDb->iSnapshotId - ); - }else{ - printf("%p: data from page %d (snapshotid=%lld)\n", - pCsr->pDb, - (int)pCsr->pg.iOldPg, pCsr->pDb->iSnapshotId - ); - } - fflush(stdout); -#endif - - return hctDbLoadRecord(pCsr->pDb, &pCsr->rec, pPg, iCell, pnData, paData); -} - -static int hctDbValidateEntry(HctDatabase *pDb, HctDbCsr *pCsr){ - int rc = SQLITE_OK; - u8 flags; - - if( pCsr->nRange ){ - /* If the current entry is on a history page, it is not valid (as - ** it has already been deleted). Later: unless of course it was this - ** transaction that deleted it! */ - if( pCsr->aRange[pCsr->nRange-1].iRangeTid!=pDb->iTid ){ - rc = HCT_SQLITE_BUSY; - } - }else{ - int iOff = hctDbCellOffset(pCsr->pg.aOld, pCsr->iCell, &flags); - if( flags & HCTDB_HAS_TID ){ - u64 iTid = hctGetU64(&pCsr->pg.aOld[iOff]); - if( hctDbTidIsConflict(pCsr->pDb, iTid) ){ - rc = HCT_SQLITE_BUSY; - } - } - } - return rc; -} - -static int hctDbValidateIntkey(HctDatabase *pDb, HctDbCsr *pCsr){ - int rc = SQLITE_OK; - HctCsrIntkeyOp *pOpList = pCsr->intkey.pOpList; - HctCsrIntkeyOp *pOp; - - pCsr->intkey.pOpList = 0; - assert( pCsr->intkey.pCurrentOp==0 ); - for(pOp=pOpList; pOp && rc==SQLITE_OK; pOp=pOp->pNextOp){ - int bDum = 0; - assert( pOp->iFirst<=pOp->iLast ); - - if( pOp->iLogical ){ - int bEvict = 0; - - /* If the physical page associated with the logical page containing - ** the current key has not changed, and the logical page has not been - ** evicted, then the current key itself may not have been modified. - ** Jump to the next iteration of the loop in this case. */ - u32 iPhys = sqlite3HctFilePageMapping(pDb->pFile, pOp->iLogical, &bEvict); - if( pOp->iPhysical==iPhys && bEvict==0 ) continue; - - /* Alternatively, if the logical page has not been evicted, load it - ** and seek to the desired key. If the key is found, or if it is not - ** found but the key would reside on the current page, then load - ** the page into the cursor. This is faster than the hctDbCsrSeek() - ** call below. */ - if( bEvict==0 && pOp->iLogical!=pCsr->iRoot ){ - rc = hctDbGetPhysical(pDb, iPhys, &pCsr->pg); - if( rc==SQLITE_OK ){ - pCsr->eDir = BTREE_DIR_FORWARD; - pCsr->iCell = hctDbIntkeyLeafSearch(pCsr->pg.aOld, pOp->iFirst,&bDum); - if( pCsr->iCell>=((HctDbIntkeyLeaf*)pCsr->pg.aOld)->pg.nEntry ){ - hctDbCsrReset(pCsr); - } - } - } - } - - if( pCsr->pg.aOld==0 ){ - if( pOp->iFirst==SMALLEST_INT64 ){ - pCsr->eDir = BTREE_DIR_FORWARD; - rc = hctDbCsrFirst(pCsr); - }else{ - if( pOp->iFirst==pOp->iLast ){ - pCsr->eDir = BTREE_DIR_NONE; - }else{ - pCsr->eDir = BTREE_DIR_FORWARD; - } - rc = hctDbCsrSeekAndDescend(pCsr, 0, pOp->iFirst, 0, &bDum); - } - } - - while( rc==SQLITE_OK && !sqlite3HctDbCsrEof(pCsr) ){ - i64 iKey = 0; - sqlite3HctDbCsrKey(pCsr, &iKey); - if( iKey>=pOp->iFirst && iKey<=pOp->iLast ){ - rc = hctDbValidateEntry(pDb, pCsr); - } - if( rc!=SQLITE_OK || iKey>=pOp->iLast ) break; - rc = hctDbCsrNext(pCsr); - } - hctDbCsrReset(pCsr); - } - assert( pCsr->intkey.pOpList==0 && pCsr->intkey.pCurrentOp==0 ); - pCsr->intkey.pOpList = pOpList; - - return rc; -} - -static int hctDbValidateIndex(HctDatabase *pDb, HctDbCsr *pCsr){ - int rc = SQLITE_OK; - HctCsrIndexOp *pOpList = pCsr->index.pOpList; - HctCsrIndexOp *pOp; - - pCsr->index.pOpList = 0; - assert( pCsr->index.pCurrentOp==0 ); - rc = hctDbCsrAllocateUnpacked(pCsr); - for(pOp=pOpList; pOp && rc==SQLITE_OK; pOp=pOp->pNextOp){ - UnpackedRecord *pRec = pCsr->pRec; - int bDummy = 0; - - if( pOp->iLogical - && pOp->iPhysical==sqlite3HctFilePageMapping(pDb->pFile, pOp->iLogical, &bDummy) - ){ - continue; - } - - hctDbCsrReset(pCsr); - pCsr->eDir = (pOp->pFirst==pOp->pLast) ? BTREE_DIR_NONE : BTREE_DIR_FORWARD; - if( pOp->pFirst==0 ){ - rc = hctDbCsrFirst(pCsr); - }else{ - int bExact = 0; - sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, pOp->nFirst, pOp->pFirst, pRec); - rc = hctDbCsrSeek(pCsr, 0, 0, 0, pRec, 0, &bExact); - if( rc==SQLITE_OK && bExact==0 ){ - rc = hctDbCsrNext(pCsr); - } - } - if( pOp->pLast && pOp->pLast!=pOp->pFirst ){ - sqlite3VdbeRecordUnpack(pCsr->pKeyInfo, pOp->nLast, pOp->pLast, pRec); - }else{ - pRec = 0; - } - if( rc!=SQLITE_OK ) break; - - if( pOp->pLast==pOp->pFirst ){ - assert( !sqlite3HctDbCsrEof(pCsr) ); - rc = hctDbValidateEntry(pDb, pCsr); - }else{ - while( !sqlite3HctDbCsrEof(pCsr) ){ - int res = -1; - if( pRec ){ - const u8 *aKey = 0; - int nKey = 0; - rc = sqlite3HctDbCsrData(pCsr, &nKey, &aKey); - if( rc!=SQLITE_OK ) break; - res = sqlite3VdbeRecordCompare(nKey, aKey, pRec); - if( res<0 ) break; - } - rc = hctDbValidateEntry(pDb, pCsr); - if( res==0 || rc!=SQLITE_OK ) break; - rc = hctDbCsrNext(pCsr); - if( rc!=SQLITE_OK ) break; - } - } - } - - assert( pCsr->index.pOpList==0 && pCsr->index.pCurrentOp==0 ); - pCsr->index.pOpList = pOpList; - return rc; -} - -SQLITE_PRIVATE void sqlite3HctDbTMapScan(HctDatabase *pDb){ - sqlite3HctTMapScan(sqlite3HctFileTMapClient(pDb->pFile)); -} - -int -__attribute__ ((noinline)) -sqlite3HctDbValidate( - sqlite3 *db, - HctDatabase *pDb, - u64 *piCid, - int *pbTmapscan -){ - HctDbCsr *pCsr = 0; - u64 *pEntry = hctDbFindTMapEntry(pDb->pTmap, pDb->iTid); - u64 iCid = *piCid; - u64 nFinalWrite = 0; - int rc = SQLITE_OK; - int nPageScan = pDb->pConfig->nPageScan; - - /* Set nWrite to the number of pages written by this transaction. This - ** is used for scheduling tmap scans only, so it doesn't matter if it - ** is slightly inaccurate in some cases. */ - int nWrite = sqlite3HctFileWriteCount(pDb->pFile) - pDb->nWriteCount; - assert( nWrite>=0 ); - if( nWrite==0 ) nWrite = 1; - - assert( *pEntry==0 ); - if( iCid==0 ){ - HctAtomicStore(pEntry, HCT_TMAP_VALIDATING); - iCid = sqlite3HctFileAllocateCID(pDb->pFile, 1); - } - HctAtomicStore(pEntry, HCT_TMAP_VALIDATING | iCid); - - nFinalWrite = sqlite3HctFileIncrWriteCount(pDb->pFile, nWrite); - if( (nFinalWrite / nPageScan)!=((nFinalWrite-nWrite) / nPageScan) ){ - *pbTmapscan = 1; - } - - assert( pDb->eMode==HCT_MODE_NORMAL ); - - /* Invoke the SQLITE_TESTCTRL_HCT_MTCOMMIT hook, if applicable */ - if( db->xMtCommit ) db->xMtCommit(db->pMtCommitCtx, 2); - - /* If iCid is one more than pDb->iSnapshotId, then this transaction is - ** being applied against the snapshot that it was run against. In this - ** case we can skip validation entirely. */ - if( iCid!=pDb->iSnapshotId+1 ){ - if( pDb->bConcurrent ){ - pDb->eMode = HCT_MODE_VALIDATE; - if( hctDbValidateMeta(pDb) ){ - rc = HCT_SQLITE_BUSY; - }else{ - for(pCsr=pDb->pScannerList; pCsr; pCsr=pCsr->pNextScanner){ - if( pCsr->pKeyInfo==0 ){ - rc = hctDbValidateIntkey(pDb, pCsr); - }else{ - rc = hctDbValidateIndex(pDb, pCsr); - } - if( rc ) break; - } - } - pDb->eMode = HCT_MODE_NORMAL; - }else{ - rc = HCT_SQLITE_BUSY; - } - } - - *piCid = iCid; - return rc; -} - -/************************************************************************* -************************************************************************** -** Start of integrity-check implementation. -** -** The code here assumes that the database is quiescent. If it is invoked -** concurrently with database writers, false-positive errors may be reported. -*/ - -/* -** Walk the tree structure with logical root page iRoot, visiting every -** page and overflow page currently linked in. -** -** For each page in the tree, the supplied callback is invoked. The first -** argument passed to the callback is a copy of the fourth argument to -** this function. The second and third arguments are the logical and -** physical page number, respectively. If there is no logical page number, -** as for overflow pages, the second parameter is passed zero. -** -** It (presumably) makes little sense to call this function without -** somehow guaranteeing that the tree is not being currently written to. -*/ -SQLITE_PRIVATE int sqlite3HctDbWalkTree( - HctFile *pFile, /* File tree resides in */ - u32 iRoot, /* Root page of tree */ - int (*x)(void*, u32, u32), /* Callback function */ - void *pCtx /* First argument to pass to x() */ -){ - int rc = SQLITE_OK; - u32 pgno = iRoot; - - u32 iPhys = 0; - int dummy = 0; - - /* Special case - the root page is not mapped to any physical page. */ - iPhys = sqlite3HctFilePageMapping(pFile, iRoot, &dummy); - if( iPhys==0 ){ - return x(pCtx, iRoot, 0); - } - - /* This outer loop runs once for each list in the tree structure - once - ** for the list of leaves, once for the list of parent, and so on. - ** Starting from the root page and descending towards the leaves. */ - do { - HctFilePage pg; - int nHeight = 0; - int eType = 0; - u32 pgnoChild = 0; - - /* Load up page pgno - the leftmost of its list. Then, unless this - ** is the list of leaves, set pgnoChild to the leftmost child of - ** the page. Or, if this is a list of leaves, leave pgnoChild set - ** to zero. */ - rc = sqlite3HctFilePageGet(pFile, pgno, &pg); - if( rc!=SQLITE_OK ){ - break; - }else{ - nHeight = hctPageheight(pg.aOld); - eType = hctPagetype(pg.aOld); - if( eType!=HCT_PAGETYPE_INTKEY && eType!=HCT_PAGETYPE_INDEX ){ - rc = SQLITE_CORRUPT_BKPT; - break; - } - else if( nHeight>0 ){ - if( eType==HCT_PAGETYPE_INTKEY ){ - pgnoChild = ((HctDbIntkeyNode*)pg.aOld)->aEntry[0].iChildPg; - }else{ - pgnoChild = ((HctDbIndexNode*)pg.aOld)->aEntry[0].iChildPg; - } - } - } - - while( pg.aOld ){ - u32 iPeerPg = ((HctDbPageHdr*)pg.aOld)->iPeerPg; - u32 iLogic = pg.iPg; - u32 iPhys = pg.iOldPg; - - rc = x(pCtx, iLogic, iPhys); - if( rc!=SQLITE_OK ) break; - - if( nHeight==0 || eType==HCT_PAGETYPE_INDEX ){ - int iCell = 0; - int nEntry = ((HctDbPageHdr*)pg.aOld)->nEntry; - for(iCell=0; iCelliPeerPg; - sqlite3HctFilePageRelease(&ov); - } - } - } - } - - sqlite3HctFilePageRelease(&pg); - if( iPeerPg ){ - rc = sqlite3HctFilePageGet(pFile, iPeerPg, &pg); - if( rc!=SQLITE_OK ) break; - } - } - - pgno = pgnoChild; - }while( rc==SQLITE_OK && pgno!=0 ); - - return rc; -} - -typedef struct IntCheckCtx IntCheckCtx; -struct IntCheckCtx { - u32 nLogic; /* Number of logical pages in db */ - u32 nPhys; /* Number of physical pages in db */ - u8 *aLogic; - u8 *aPhys; - int nErr; - int nMaxErr; - char *zErr; - i64 nEntry; /* Number of entries in table */ -}; - -static void hctDbICError( - IntCheckCtx *p, - char *zFmt, - ... -){ - va_list ap; - char *zErr; - va_start(ap, zFmt); - zErr = sqlite3_vmprintf(zFmt, ap); - p->zErr = sqlite3_mprintf("%z%s%z", p->zErr, (p->zErr ? "\n" : ""), zErr); - p->nErr++; - va_end(ap); -} - -static int hctDbIntegrityCheckCb( - void *pCtx, - u32 iLogic, - u32 iPhys -){ - IntCheckCtx *p = (IntCheckCtx*)pCtx; - if( iLogic ){ - if( p->aLogic[iLogic-1] ){ - hctDbICError(p, "multiple refs to logical page %d", (int)iLogic); - } - p->aLogic[iLogic-1] = 1; - } - if( iPhys ){ - if( p->aPhys[iPhys-1] ){ - hctDbICError(p, "multiple refs to physical page %d", (int)iPhys); - } - p->aPhys[iPhys-1] = 1; - } - - return (p->nErr>=p->nMaxErr) ? -1 : 0; -} - - -SQLITE_PRIVATE char *sqlite3HctDbIntegrityCheck( - HctDatabase *pDb, - u32 *aRoot, - Mem *aCnt, - int nRoot, - int *pnErr -){ - HctFile *pFile = pDb->pFile; - IntCheckCtx c; - u32 *aFileRoot = 0; - int nFileRoot = 0; - - int rc = sqlite3HctFileRootArray(pFile, &aFileRoot, &nFileRoot); - memset(&c, 0, sizeof(c)); - if( rc==SQLITE_OK ){ - c.nErr = *pnErr; - c.nMaxErr = 100; - sqlite3HctFileICArrays(pFile, &c.aLogic, &c.nLogic, &c.aPhys, &c.nPhys); - } - if( !c.aLogic ){ - c.nErr++; - }else{ - int ii; - - for(ii=0; c.nErr==0 && iistats.nBalanceIntkey; - break; - case 1: - *pzStat = "balance_index"; - iVal = pDb->stats.nBalanceIndex; - break; - case 2: - *pzStat = "balance_single"; - iVal = pDb->stats.nBalanceSingle; - break; - case 3: - *pzStat = "tmap_lookup"; - iVal = pDb->stats.nTMapLookup; - break; - case 4: - *pzStat = "update_in_place"; - iVal = pDb->stats.nUpdateInPlace; - break; - case 5: - *pzStat = "internal_retry"; - iVal = pDb->stats.nInternalRetry; - break; - default: - break; - } - - return iVal; -} - -/************************************************************************* -************************************************************************** -** Below are the virtual table implementations. These are debugging -** aids only. -*/ - -typedef struct hctdb_vtab hctdb_vtab; -struct hctdb_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; - -/* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will -** serve as the underlying representation of a cursor that scans -** over rows of the result -*/ -typedef struct hctdb_cursor hctdb_cursor; -struct hctdb_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - HctDatabase *pDb; /* Database to report on */ - u64 iMaxPgno; /* Maximum page number for this scan */ - - u64 pgno; /* The page-number/rowid value */ - const char *zPgtype; - u32 iPeerPg; - u32 nEntry; - u32 nHeight; - u32 nFree; - char *zFpKey; -}; - -/* -** The hctdbConnect() method is invoked to create a new -** template virtual table. -** -** Think of this routine as the constructor for hctdb_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the hctdb_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against the virtual table will look like. -*/ -static int hctdbConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - hctdb_vtab *pNew; - int rc; - - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(" - "pgno INTEGER, pgtype TEXT, nheight INTEGER, " - "peer INTEGER, nentry INTEGER, nfree INTEGER, fpkey TEXT" - ")" - ); - - if( rc==SQLITE_OK ){ - pNew = sqlite3MallocZero( sizeof(*pNew) ); - *ppVtab = (sqlite3_vtab*)pNew; - if( pNew==0 ) return SQLITE_NOMEM; - pNew->db = db; - } - return rc; -} - -/* -** This method is the destructor for hctdb_vtab objects. -*/ -static int hctdbDisconnect(sqlite3_vtab *pVtab){ - hctdb_vtab *p = (hctdb_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Constructor for a new hctdb_cursor object. -*/ -static int hctdbOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - hctdb_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a hctdb_cursor. -*/ -static int hctdbClose(sqlite3_vtab_cursor *cur){ - hctdb_cursor *pCur = (hctdb_cursor*)cur; - sqlite3_free(pCur->zFpKey); - sqlite3_free(pCur); - return SQLITE_OK; -} - -static char *hex_encode(const u8 *aIn, int nIn){ - char *zRet = sqlite3MallocZero(nIn*2+1); - if( zRet ){ - static const char aDigit[] = "0123456789ABCDEF"; - int i; - for(i=0; i> 4) ]; - zRet[i*2+1] = aDigit[ (aIn[i] & 0xF) ]; - } - } - return zRet; -} - - -SQLITE_PRIVATE char *sqlite3HctDbRecordToText(sqlite3 *db, const u8 *aRec, int nRec){ - char *zRet = 0; - const char *zSep = ""; - const u8 *pEndHdr; /* Points to one byte past record header */ - const u8 *pHdr; /* Current point in record header */ - const u8 *pBody; /* Current point in record data */ - u64 nHdr; /* Bytes in record header */ - - if( nRec==0 ){ - return sqlite3_mprintf(""); - } - - pHdr = aRec + sqlite3GetVarint(aRec, &nHdr); - pBody = pEndHdr = &aRec[nHdr]; - while( pHdrbase.pVtab)->db; - int eType; - - assert( 0==sqlite3_stricmp("intkey", azType[HCT_PAGETYPE_INTKEY]) ); - assert( 0==sqlite3_stricmp("index", azType[HCT_PAGETYPE_INDEX]) ); - assert( 0==sqlite3_stricmp("overflow", azType[HCT_PAGETYPE_OVERFLOW]) ); - - sqlite3_free(pCur->zFpKey); - pCur->zFpKey = 0; - - eType = hctPagetype(pHdr); - if( eTypezPgtype = azType[hctPagetype(pHdr)]; - }else{ - pCur->zPgtype = "!INVALID!"; - } - pCur->iPeerPg = pHdr->iPeerPg; - pCur->nEntry = pHdr->nEntry; - pCur->nHeight = pHdr->nHeight; - - if( eType==HCT_PAGETYPE_INTKEY ){ - if( pHdr->nHeight==0 ){ - HctDbIntkeyLeaf *pLeaf = (HctDbIntkeyLeaf*)aPg; - char *zFpKey = sqlite3_mprintf("%lld", pLeaf->aEntry[0].iKey); - if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; - pCur->zFpKey = zFpKey; - pCur->nFree = (int)pLeaf->hdr.nFreeBytes; - }else{ - HctDbIntkeyNode *pNode = (HctDbIntkeyNode*)aPg; - char *zFpKey = sqlite3_mprintf("%lld", pNode->aEntry[0].iKey); - if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; - pCur->zFpKey = zFpKey; - pCur->nFree = ( - hctDbMaxCellsPerIntkeyNode(pCur->pDb->pgsz) - pNode->pg.nEntry - ) * sizeof(HctDbIntkeyNodeEntry); - } - - }else if( eType==HCT_PAGETYPE_INDEX ){ - HctBuffer buf = {0,0,0}; - const u8 *aRec = 0; - int nRec = 0; - - rc = hctDbLoadRecord(pCur->pDb, &buf, aPg, 0, &nRec, &aRec); - if( rc==SQLITE_OK ){ - char *zFpKey = sqlite3HctDbRecordToText(db, aRec, nRec); - if( zFpKey==0 ) rc = SQLITE_NOMEM_BKPT; - pCur->zFpKey = zFpKey; - } - - pCur->nFree = (int)(((HctDbIndexNode*)pHdr)->hdr.nFreeBytes); - sqlite3HctBufferFree(&buf); - } - return rc; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int hctdbEof(sqlite3_vtab_cursor *cur){ - hctdb_cursor *pCur = (hctdb_cursor*)cur; - return pCur->pgno>pCur->iMaxPgno; -} - -/* -** Advance a hctdb_cursor to its next row of output. -*/ -static int hctdbNext(sqlite3_vtab_cursor *cur){ - hctdb_cursor *pCur = (hctdb_cursor*)cur; - int rc = SQLITE_OK; - HctFilePage pg; - - memset(&pg, 0, sizeof(pg)); - do { - sqlite3HctFilePageRelease(&pg); - pCur->pgno++; - if( hctdbEof(cur) ) return SQLITE_OK; - rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->pgno, &pg); - }while( rc==SQLITE_OK && pg.aOld==0 ); - - if( pg.aOld ){ - rc = hctdbLoadPage(pCur, pg.aOld); - } - return rc; -} - -/* -** Return values of columns for the row at which the hctdb_cursor -** is currently pointing. -*/ -static int hctdbColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - hctdb_cursor *pCur = (hctdb_cursor*)cur; - assert( i>=0 && i<=5 ); - switch( i ){ - case 0: /* pgno */ - sqlite3_result_int64(ctx, (i64)pCur->pgno); - break; - case 1: /* pgtype */ - sqlite3_result_text(ctx, pCur->zPgtype, -1, SQLITE_TRANSIENT); - break; - case 2: /* nHeight */ - sqlite3_result_int64(ctx, (i64)pCur->nHeight); - break; - case 3: /* peer */ - sqlite3_result_int64(ctx, (i64)pCur->iPeerPg); - break; - case 4: /* nEntry */ - sqlite3_result_int64(ctx, (i64)pCur->nEntry); - break; - case 5: /* nfree */ - sqlite3_result_int64(ctx, (i64)pCur->nFree); - break; - case 6: /* fpkey */ - sqlite3_result_text(ctx, pCur->zFpKey, -1, SQLITE_TRANSIENT); - break; - } - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the output value. -*/ -static int hctdbRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - hctdb_cursor *pCur = (hctdb_cursor*)cur; - *pRowid = pCur->pgno; - return SQLITE_OK; -} - -/* -** This method is called to "rewind" the hctdb_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to hctdbColumn() or hctdbRowid() or -** hctdbEof(). -*/ -static int hctdbFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - hctdb_cursor *pCur = (hctdb_cursor*)pVtabCursor; - hctdb_vtab *pTab = (hctdb_vtab*)(pCur->base.pVtab); - - pCur->pDb = sqlite3HctDbFind(pTab->db, 0); - if( argc==1 ){ - u32 iVal = (u32)sqlite3_value_int64(argv[0]); - pCur->iMaxPgno = iVal; - pCur->pgno = iVal-1; - }else{ - pCur->pgno = 0; - pCur->iMaxPgno = sqlite3HctFileMaxpage(pCur->pDb->pFile); - } - return hctdbNext(pVtabCursor); -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -*/ -static int hctdbBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - int i; - pIdxInfo->estimatedCost = (double)10000; - pIdxInfo->estimatedRows = 10000; - - for(i=0; inConstraint; i++){ - struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; - if( p->iColumn!=0 ) continue; - if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - if( !p->usable ) continue; - pIdxInfo->aConstraintUsage[i].argvIndex = 1; - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = (double)10; - pIdxInfo->estimatedRows = 10; - break; - } - - return SQLITE_OK; -} - -typedef struct hctentry_vtab hctentry_vtab; -struct hctentry_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; - -/* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will -** serve as the underlying representation of a cursor that scans -** over rows of the result -*/ -typedef struct hctentry_cursor hctentry_cursor; -struct hctentry_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - HctDatabase *pDb; /* Database to report on */ - int iEntry; - HctFilePage pg; - u32 iPg; /* Current physical page number */ - u32 iLastPg; /* Last physical page to report on */ -}; - -/* -** The hctentryConnect() method is invoked to create a new -** template virtual table. -** -** Think of this routine as the constructor for hctentry_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the hctentry_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against the virtual table will look like. -*/ -static int hctentryConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - hctentry_vtab *pNew; - int rc; - - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(" - "pgno INTEGER, entry INTEGER, " - "ikey INTEGER, size INTEGER, offset INTEGER, " - "child INTEGER, " - "tid INTEGER, rangetid INTEGER, " - /* "oldpg INTEGER, " */ - "rangeoldpg INTEGER, ovfl INTEGER, record TEXT" - ")" - ); - - if( rc==SQLITE_OK ){ - pNew = sqlite3MallocZero( sizeof(*pNew) ); - *ppVtab = (sqlite3_vtab*)pNew; - if( pNew==0 ) return SQLITE_NOMEM; - pNew->db = db; - } - return rc; -} - -/* -** This method is the destructor for hctentry_vtab objects. -*/ -static int hctentryDisconnect(sqlite3_vtab *pVtab){ - hctentry_vtab *p = (hctentry_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Constructor for a new hctentry_cursor object. -*/ -static int hctentryOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - hctentry_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a hctentry_cursor. -*/ -static int hctentryClose(sqlite3_vtab_cursor *cur){ - hctentry_cursor *pCur = (hctentry_cursor*)cur; - sqlite3HctFilePageRelease(&pCur->pg); - sqlite3_free(pCur); - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int hctentryEof(sqlite3_vtab_cursor *cur){ - hctentry_cursor *pCur = (hctentry_cursor*)cur; - return pCur->pg.aOld==0; -} - -/* -** Advance a hctentry_cursor to its next row of output. -*/ -static int hctentryNext(sqlite3_vtab_cursor *cur){ - int rc = SQLITE_OK; - hctentry_cursor *pCur = (hctentry_cursor*)cur; - - while( rc==SQLITE_OK ){ - HctDbPageHdr *pPg = (HctDbPageHdr*)pCur->pg.aOld; - int eType = hctPagetype(pPg); - if( eType==HCT_PAGETYPE_INTKEY - || eType==HCT_PAGETYPE_INDEX - || eType==HCT_PAGETYPE_HISTORY - ){ - pCur->iEntry++; - if( pCur->iEntrynEntry ) break; - } - pCur->iEntry = -1; - pCur->iPg++; - sqlite3HctFilePageRelease(&pCur->pg); - if( pCur->iPg>pCur->iLastPg ) break; - rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->iPg, &pCur->pg); - } - - return rc; -} - -/* -** Return values of columns for the row at which the hctentry_cursor -** is currently pointing. -*/ -static int hctentryColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - hctentry_cursor *pCur = (hctentry_cursor*)cur; - int eType = hctPagetype(pCur->pg.aOld); - int nHeight = hctPageheight(pCur->pg.aOld); - - HctDbIntkeyEntry *pIntkey = 0; - HctDbIntkeyNodeEntry *pIntkeyNode = 0; - HctDbIndexEntry *pIndex = 0; - HctDbIndexNodeEntry *pIndexNode = 0; - HctDbHistoryFan *pFan = 0; - - switch( eType ){ - case HCT_PAGETYPE_INTKEY: - if( nHeight==0 ){ - pIntkey = &((HctDbIntkeyLeaf*)pCur->pg.aOld)->aEntry[pCur->iEntry]; - }else{ - pIntkeyNode = &((HctDbIntkeyNode*)pCur->pg.aOld)->aEntry[pCur->iEntry]; - } - break; - - case HCT_PAGETYPE_INDEX: - if( nHeight==0 ){ - pIndex = &((HctDbIndexLeaf*)pCur->pg.aOld)->aEntry[pCur->iEntry]; - }else{ - pIndexNode = &((HctDbIndexNode*)pCur->pg.aOld)->aEntry[pCur->iEntry]; - } - break; - - case HCT_PAGETYPE_HISTORY: - pFan = (HctDbHistoryFan*)pCur->pg.aOld; - break; - - } - - switch( i ){ - case 0: /* pgno */ - sqlite3_result_int64(ctx, (i64)pCur->iPg); - break; - case 1: /* iEntry */ - sqlite3_result_int64(ctx, (i64)pCur->iEntry); - break; - case 2: /* ikey */ - if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->iKey); - if( pIntkeyNode ) sqlite3_result_int64(ctx, pIntkeyNode->iKey); - break; - case 3: /* size */ - if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->nSize); - if( pIndex ) sqlite3_result_int64(ctx, pIndex->nSize); - if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->nSize); - break; - case 4: /* offset */ - if( pIntkey ) sqlite3_result_int64(ctx, pIntkey->iOff); - if( pIndex ) sqlite3_result_int64(ctx, pIndex->iOff); - if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->iOff); - break; - case 5: /* child */ - if( pIndexNode ) sqlite3_result_int64(ctx, pIndexNode->iChildPg); - if( pIntkeyNode ) sqlite3_result_int64(ctx, pIntkeyNode->iChildPg); - break; - - case 6: /* tid */ - case 7: /* rangetid */ - case 8: /* rangeoldpg */ - case 9: /* ovfl */ - if( pIntkey || pIndex || pIndexNode ){ - u8 *aPg = pCur->pg.aOld; - HctDbCell cell; - HctDbIndexEntry *p = hctDbEntryEntry(aPg, pCur->iEntry); - hctDbCellGet(pCur->pDb, &aPg[p->iOff], p->flags, &cell); - - if( i==6 && cell.iTid ){ - i64 iVal = (cell.iTid & HCT_TID_MASK); - if( cell.iTid & HCT_TID_ROLLBACK_OVERRIDE ) iVal = iVal*-1; - sqlite3_result_int64(ctx, iVal); - } - if( i==7 && cell.iRangeTid ){ - i64 iVal = (cell.iRangeTid & HCT_TID_MASK); - if( cell.iRangeTid & HCT_TID_ROLLBACK_OVERRIDE ) iVal = iVal*-1; - sqlite3_result_int64(ctx, iVal); - } - if( i==8 && cell.iRangeOld ){ - sqlite3_result_int64(ctx, (i64)cell.iRangeOld); - } - if( i==9 && cell.iOvfl ){ - sqlite3_result_int64(ctx, (i64)cell.iOvfl); - } - }else if( pFan ){ - if( i==7 ){ /* rangetid */ - u64 iVal = ((pCur->iEntry==0) ? pFan->iRangeTid0 : pFan->iRangeTid1); - if( iVal & HCT_TID_ROLLBACK_OVERRIDE ){ - sqlite3_result_int64(ctx, ((i64)(iVal & HCT_TID_MASK)) * -1); - }else{ - sqlite3_result_int64(ctx, (i64)iVal); - } - }else if( i==8 ){ /* rangeoldpg */ - u32 iRangeOldPg = - ((pCur->iEntry==0) ? pFan->pgOld0 : pFan->aPgOld1[pCur->iEntry-1]); - sqlite3_result_int64(ctx, (i64)iRangeOldPg); - } - } - break; - case 10: /* record */ - if( pIntkey || pIndex || pIndexNode ){ - sqlite3 *db = sqlite3_context_db_handle(ctx); - u8 *aPg = pCur->pg.aOld; - char *zRec; - int sz; - const u8 *aRec = 0; - HctBuffer buf = {0,0,0}; - - hctDbLoadRecord(pCur->pDb, &buf, aPg, pCur->iEntry, &sz, &aRec); - - zRec = sqlite3HctDbRecordToText(db, aRec, sz); - if( zRec ){ - sqlite3_result_text(ctx, zRec, -1, SQLITE_TRANSIENT); - sqlite3_free(zRec); - } - sqlite3HctBufferFree(&buf); - }else if( pFan ){ - char *zRec = sqlite3_mprintf("iSplit0=%d", pFan->iSplit0); - if( zRec ){ - sqlite3_result_text(ctx, zRec, -1, SQLITE_TRANSIENT); - sqlite3_free(zRec); - } - } - break; - } - - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the output value. -*/ -static int hctentryRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - hctentry_cursor *pCur = (hctentry_cursor*)cur; - *pRowid = (((i64)pCur->iPg) << 32) + pCur->iEntry; - return SQLITE_OK; -} - -/* -** This method is called to "rewind" the hctentry_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to hctentryColumn() or hctentryRowid() or -** hctentryEof(). -*/ -static int hctentryFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - int rc; - hctentry_cursor *pCur = (hctentry_cursor*)pVtabCursor; - hctentry_vtab *pTab = (hctentry_vtab*)(pCur->base.pVtab); - u32 iLastPg; - - pCur->pDb = sqlite3HctDbFind(pTab->db, 0); - pCur->iEntry = -1; - iLastPg = sqlite3HctFileMaxpage(pCur->pDb->pFile); - - if( idxNum==1 ){ - u32 iPg = (u32)sqlite3_value_int64(argv[0]); - assert( argc==1 ); - if( iPg<1 || iPg>iLastPg ) return SQLITE_OK; - pCur->iPg = pCur->iLastPg = iPg; - }else{ - pCur->iPg = 1; - pCur->iLastPg = iLastPg; - } - - rc = sqlite3HctFilePageGetPhysical(pCur->pDb->pFile, pCur->iPg, &pCur->pg); - if( rc!=SQLITE_OK ){ - return rc; - } - return hctentryNext(pVtabCursor); -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -*/ -static int hctentryBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - int i; - int iPgnoEq = -1; - - pIdxInfo->estimatedCost = (double)1000000; - pIdxInfo->estimatedRows = 1000000; - - /* Search for a pgno=? constraint */ - for(i=0; inConstraint; i++){ - struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; - if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ - iPgnoEq = i; - } - } - - if( iPgnoEq>=0 ){ - pIdxInfo->aConstraintUsage[iPgnoEq].argvIndex = 1; - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = (double)1000; - pIdxInfo->estimatedRows = 1000; - } - - return SQLITE_OK; -} - -typedef struct hctvalid_vtab hctvalid_vtab; -typedef struct hctvalid_cursor hctvalid_cursor; -struct hctvalid_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; -struct hctvalid_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - HctDatabase *pDb; /* Database to report on */ - int iEntry; /* Current entry (i.e. rowid) */ - - u32 rootpgno; /* Value of rootpgno column */ - char *zFirst; - char *zLast; - char *zPglist; -}; -static int hctvalidConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - hctvalid_vtab *pNew = 0; - int rc = SQLITE_OK; - - *ppVtab = 0; - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(rootpgno, first, last, pglist)" - ); - - if( rc==SQLITE_OK ){ - pNew = sqlite3MallocZero( sizeof(*pNew) ); - *ppVtab = (sqlite3_vtab*)pNew; - if( pNew==0 ) return SQLITE_NOMEM; - pNew->db = db; - } - return rc; -} -static int hctvalidBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - pIdxInfo->estimatedCost = (double)10000; - pIdxInfo->estimatedRows = 10000; - return SQLITE_OK; -} -static int hctvalidDisconnect(sqlite3_vtab *pVtab){ - hctvalid_vtab *p = (hctvalid_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} -static int hctvalidOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - hctvalid_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} -static int hctvalidClose(sqlite3_vtab_cursor *cur){ - hctvalid_cursor *pCur = (hctvalid_cursor*)cur; - sqlite3_free(pCur); - return SQLITE_OK; -} -static int hctvalidNext(sqlite3_vtab_cursor *cur){ - hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; - hctvalid_vtab *pTab = (hctvalid_vtab*)(pCsr->base.pVtab); - int ii; - HctDbCsr *pDbCsr = 0; - HctCsrIntkeyOp *pIntkeyOp = 0; - HctCsrIndexOp *pIndexOp = 0; - - sqlite3_free(pCsr->zFirst); - sqlite3_free(pCsr->zLast); - sqlite3_free(pCsr->zPglist); - pCsr->zFirst = 0; - pCsr->zLast = 0; - pCsr->zPglist = 0; - pCsr->rootpgno = 0; - pCsr->iEntry++; - pDbCsr = pCsr->pDb->pScannerList; - pIntkeyOp = pDbCsr->intkey.pOpList; - pIndexOp = pDbCsr->index.pOpList; - ii = 0; - if( pIntkeyOp==0 && pIndexOp==0 ) ii--; - for(/*noop*/; pDbCsr && iiiEntry; ii++){ - if( pIntkeyOp ) pIntkeyOp = pIntkeyOp->pNextOp; - if( pIndexOp ) pIndexOp = pIndexOp->pNextOp; - if( pIntkeyOp==0 && pIndexOp==0 ){ - pDbCsr = pDbCsr->pNextScanner; - if( pDbCsr ){ - pIntkeyOp = pDbCsr->intkey.pOpList; - pIndexOp = pDbCsr->index.pOpList; - if( pIntkeyOp==0 && pIndexOp==0 ) ii--; - } - } - } - - if( pDbCsr ){ - pCsr->rootpgno = pDbCsr->iRoot; - if( pIntkeyOp ){ - if( pIntkeyOp->iFirst!=SMALLEST_INT64 ){ - pCsr->zFirst = sqlite3_mprintf("%lld", pIntkeyOp->iFirst); - } - if( pIntkeyOp->iFirst!=LARGEST_INT64 ){ - pCsr->zLast = sqlite3_mprintf("%lld", pIntkeyOp->iLast); - } - if( pIntkeyOp->iLogical ){ - pCsr->zPglist = sqlite3_mprintf( - "%lld/%lld", pIntkeyOp->iLogical, pIntkeyOp->iPhysical - ); - } - }else{ - if( pIndexOp->pFirst ){ - pCsr->zFirst = sqlite3HctDbRecordToText( - pTab->db, pIndexOp->pFirst, pIndexOp->nFirst - ); - } - if( pIndexOp->pLast ){ - pCsr->zLast = sqlite3HctDbRecordToText( - pTab->db, pIndexOp->pLast, pIndexOp->nLast - ); - } - if( pIndexOp->iLogical ){ - pCsr->zPglist = sqlite3_mprintf( - "%lld/%lld", pIndexOp->iLogical, pIndexOp->iPhysical - ); - } - } - } - - return SQLITE_OK; -} -static int hctvalidFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; - hctvalid_vtab *pTab = (hctvalid_vtab*)(pCsr->base.pVtab); - - pCsr->pDb = sqlite3HctDbFind(pTab->db, 0); - pCsr->iEntry = -1; - return hctvalidNext(cur); -} -static int hctvalidEof(sqlite3_vtab_cursor *cur){ - hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; - return (pCsr->rootpgno==0); -} -static int hctvalidColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; - switch( i ){ - case 0: - sqlite3_result_int64(ctx, (i64)pCsr->rootpgno); - break; - case 1: - sqlite3_result_text(ctx, pCsr->zFirst, -1, SQLITE_TRANSIENT); - break; - case 2: - sqlite3_result_text(ctx, pCsr->zLast, -1, SQLITE_TRANSIENT); - break; - case 3: - sqlite3_result_text(ctx, pCsr->zPglist, -1, SQLITE_TRANSIENT); - break; - } - return SQLITE_OK; -} -static int hctvalidRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - hctvalid_cursor *pCsr = (hctvalid_cursor*)cur; - *pRowid = pCsr->iEntry; - return SQLITE_OK; -} - - - -SQLITE_PRIVATE int sqlite3HctVtabInit(sqlite3 *db){ - static sqlite3_module hctdbModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ hctdbConnect, - /* xBestIndex */ hctdbBestIndex, - /* xDisconnect */ hctdbDisconnect, - /* xDestroy */ 0, - /* xOpen */ hctdbOpen, - /* xClose */ hctdbClose, - /* xFilter */ hctdbFilter, - /* xNext */ hctdbNext, - /* xEof */ hctdbEof, - /* xColumn */ hctdbColumn, - /* xRowid */ hctdbRowid, - /* xUpdate */ 0, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - static sqlite3_module hctentryModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ hctentryConnect, - /* xBestIndex */ hctentryBestIndex, - /* xDisconnect */ hctentryDisconnect, - /* xDestroy */ 0, - /* xOpen */ hctentryOpen, - /* xClose */ hctentryClose, - /* xFilter */ hctentryFilter, - /* xNext */ hctentryNext, - /* xEof */ hctentryEof, - /* xColumn */ hctentryColumn, - /* xRowid */ hctentryRowid, - /* xUpdate */ 0, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - static sqlite3_module hctvalidModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ hctvalidConnect, - /* xBestIndex */ hctvalidBestIndex, - /* xDisconnect */ hctvalidDisconnect, - /* xDestroy */ 0, - /* xOpen */ hctvalidOpen, - /* xClose */ hctvalidClose, - /* xFilter */ hctvalidFilter, - /* xNext */ hctvalidNext, - /* xEof */ hctvalidEof, - /* xColumn */ hctvalidColumn, - /* xRowid */ hctvalidRowid, - /* xUpdate */ 0, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - int rc; - - rc = sqlite3_create_module(db, "hctdb", &hctdbModule, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_module(db, "hctentry", &hctentryModule, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_module(db, "hctvalid", &hctvalidModule, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctFileVtabInit(db); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctPManVtabInit(db); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctStatsInit(db); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctJrnlInit(db); - } - return rc; -} - -/************** End of hct_database.c ****************************************/ -/************** Begin file hct_tmap.c ****************************************/ -/* -** 2021 February 28 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -/* -** NOTES ON LOCKING -** -** Each time a new HctTMap object is allocated, the locking related -** variables are set: -** -** HctTMap.iMinTid -** HctTMap.iMinCid -** -** New HctTMap objects are always allocated by writers during the -** WRITING phase of a transaction. The iMinCid variable is set to -** the CID value associated with the snapshot on which the writer -** based its transaction. The iMinTid value is set to the largest -** TID value for which it and all smaller TID values map to fully -** committed transactions with CID values smaller than or equal -** to iMinCid. This means that: -** -** * The new object may be used by any client accessing a snapshot -** with a snapshot-id >= iMinCid. -** -** * So long as this object exists, it is not safe to reuse any -** page ids (logical or physical) freed by transactions with -** TID values > iMinTid. -** -** The HctTMap object may then be used to access any snapshot with -** a CID value greater than or equal to iMinCid. While the HctTMap -** is still in use, it is not safe to reuse any logical or physical -** page id freed by a transaction with a TID value greater than -** iMinTid. -** -** A new HctTMap object is created by a writer after it is allocated -** its TID iff: -** -** TODO: This all needs updating!!! -** -** * The expression (iNewTid % HctTMapServer.nTidStep)==0 is true, or -** * The existing transaction map is too small to contain an entry -** for iNewTid. -** -** The first time a client obtains a new HctTMap object, it remembers -** the CID of the first snapshot it accesses using it. The HctTMap -** is released at the end of the first transaction for which the CID is -** greater than or equal to (iFirstCid + HctTMapServer.nTidStep). This -** happens even if a new HctTMap has been obtained since then. TODO: There -** is probably a role for some randomness here. -** -** The above creates a problem - a single dormant connection can prevent -** all reuse of freed logical and physical pages. This is addressed by -** using smart reference objects of type HctTMapRef that support the -** reference being revoked by the server at any time. See comments above -** struct HctTMapRef for details. -*/ - -/* #include "hctInt.h" */ - -typedef struct HctTMapFull HctTMapFull; -typedef struct HctTMapRef HctTMapRef; - -/* -** The following object type represents a reference to an HctTMapFull -** object. The reference is taken and released under the cover of the -** associated HctTMapServer.mutex mutex. -** -** pRefNext/pRefPrev: -** These are used to link this object into the linked list at -** HctTMapFull.pRefList. They may only be accessed under the cover -** of the associated HctTMapServer.mutex mutex. -** -** pMap: -** Pointer to the HctTMapFull object, if any, that this reference -** currently points to. -** -** refMask: -** This may be set to one of four values. It is always modified using -** CAS instructions. -** -** Zero: -** HctTMapRef.pMap is not valid (always NULL). -** -** HCT_TMAPREF_SERVER: -** When the reference is first taken, under cover of the server mutex, -** refMask is set to this value. -** -** HCT_TMAPREF_SERVER|HCT_TMAPREF_CLIENT: -** When a client actually wishes to use the tmap indicated by this -** reference, it uses a CAS instruction to set refMask to this value. -** It may then use the tmap object. This does not require the mutex. -** -** If the client finds that refMask is not HCT_TMAPREF_SERVER, but -** has been set to 0, then the reference has been revoked. In this -** case it is not safe for the client to touch pMap. It must -** reinitialize the HctTmapRef object (under cover of the server -** mutex). -** -** When the read transaction is over, and the client does not need -** need the tmap object, it uses a CAS instruction to set refMask -** back to HCT_TMAPREF_SERVER. If, when doing so, it finds that the -** HCT_TMAPREF_SERVER bit has already been cleared, then it must -** release the reference immediately (under cover of the server -** mutex). -** -** HCT_TMAPREF_CLIENT: -*/ -struct HctTMapRef { - u32 refMask; - HctTMapFull *pMap; - HctTMapRef *pRefNext; - HctTMapRef *pRefPrev; -}; - -/* -** Bits from HctTMapRef.refMask. -*/ -#define HCT_TMAPREF_CLIENT 0x01 -#define HCT_TMAPREF_SERVER 0x02 -#define HCT_TMAPREF_BOTH 0x03 - -/* -** Event counters used by the hctstats virtual table. -*/ -typedef struct HctTMapStats HctTMapStats; -struct HctTMapStats { - i64 nMutex; - i64 nMutexBlock; -}; - - -/* -** iLockValue: -** This field contains two things - a flag and a safe-tid value. The flag -** is set whenever a read transaction is active, and clear otherwise. -** The safe-tid value is set to a TID value for which itself an all smaller -** TID values are included in the connection's transactions - current and -** future. -** -** Pages freed by the transaction with the safe-tid value may be reused -** without disturbing this client. -** -** pNextClient: -** Linked list of all clients associated with pServer. -** -** pBuild: -** This is used by the sqlite3HctTMapRecoveryXXX() API when constructing -** a new tmap object as part of sqlite_hct_journal recovery. -*/ -struct HctTMapClient { - HctTMapServer *pServer; - HctConfig *pConfig; - u64 iLockValue; - HctTMapClient *pNextClient; - HctTMapFull *pMap; - HctTMapStats stats; - - HctTMapFull *pBuild; - u64 iBuildMin; /* Min TID value explicitly set in pBuild */ -}; - -#define HCT_LOCKVALUE_ACTIVE (((u64)0x01) << 56) - -/* -** Values for HctTMapClient.eState -*/ -#define HCT_CLIENT_NONE 0 -#define HCT_CLIENT_OPEN 1 -#define HCT_CLIENT_UP 2 - -/* -** iMinMinTid: -** This value is set only when the mutex is held, using HctAtomicStore(). -** It may be read, using HctAtomicLoad(), at any time. -*/ -struct HctTMapServer { - sqlite3_mutex *pMutex; /* Mutex to protect this object */ - int nClient; /* Number of connected clients */ - u64 iMinMinTid; /* Smallest iMinTid value in pList */ - HctTMapFull *pList; /* List of tmaps. Newest first */ - HctTMapClient *pClientList; /* List of clients */ -}; - -/* -** nRef: -** Number of clients that hold a pointer to this object. -*/ -struct HctTMapFull { - HctTMap m; - int nRef; /* Number of pointers to this object */ - HctTMapFull *pNext; /* Next entry in HctTMapServer.pList */ -}; - -/* -** ENTER_TMAP_MUTEX(pClient) implementation. -** -** Grab the server mutex. And update client-stats as required at the same -** time. -*/ -static void hctTMapMutexEnter(HctTMapClient *pClient){ - sqlite3_mutex *pMutex = pClient->pServer->pMutex; - pClient->stats.nMutex++; - if( sqlite3_mutex_try(pMutex)!=SQLITE_OK ){ - pClient->stats.nMutexBlock++; - sqlite3_mutex_enter(pMutex); - } -} - -#if 0 -#define ENTER_TMAP_MUTEX(pClient) sqlite3_mutex_enter(pClient->pServer->pMutex) -#endif -#define ENTER_TMAP_MUTEX(pClient) hctTMapMutexEnter(pClient) -#define LEAVE_TMAP_MUTEX(pClient) sqlite3_mutex_leave(pClient->pServer->pMutex) - -/* -** Atomic version of: -** -** if( *pPtr!=iOld ){ -** return 0; -** } -** *pPtr = iNew; -** return 1; -*/ -#if 0 -static int hctTMapBoolCAS32(u32 *pPtr, u32 iOld, u32 iNew){ - return HctCASBool(pPtr, iOld, iNew); -} -#endif -static int hctTMapBoolCAS64(u64 *pPtr, u64 iOld, u64 iNew){ - return HctCASBool(pPtr, iOld, iNew); -} - -/* -** Return a pointer to the slot in pMap associated with TID iTid. -*/ -static u64 *hctTMapFind(HctTMapFull *pMap, u64 iTid){ - int iOff = iTid - pMap->m.iFirstTid; - int iMap = iOff / HCT_TMAP_PAGESIZE; - iOff = HCT_TMAP_ENTRYSLOT( (iOff % HCT_TMAP_PAGESIZE) ); - return &pMap->m.aaMap[iMap][iOff % HCT_TMAP_PAGESIZE]; -} - -/* -** Allocate the initial HctTMapFull object for the server passed as the -** only argument. This is called as part of sqlite3HctTMapServerNew(). -*/ -static int hctTMapInit(HctTMapServer *p, u64 iFirstTid, u64 iLastTid){ - int rc = SQLITE_OK; - int nMap = 0; - int nByte = 0; - u64 iFirst = (iFirstTid / HCT_TMAP_PAGESIZE) * HCT_TMAP_PAGESIZE; - HctTMapFull *pNew = 0; - - assert( p->pList==0 ); - assert( (iFirstTid & HCT_TMAP_CID_MASK)==iFirstTid ); - - nMap = (iLastTid / HCT_TMAP_PAGESIZE) - (iFirst / HCT_TMAP_PAGESIZE) + 3; - nByte = sizeof(HctTMapFull) + sizeof(u64*)*nMap; - pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, nByte); - if( pNew ){ - int i; - pNew->m.iFirstTid = iFirst; - pNew->m.nMap = nMap; - pNew->m.aaMap = (u64**)&pNew[1]; - for(i=0; im.nMap; i++){ - u64 *a = (u64*)sqlite3HctMalloc(&rc, sizeof(u64)*HCT_TMAP_PAGESIZE); - pNew->m.aaMap[i] = a; - } - - if( rc!=SQLITE_OK ){ - assert( 0 ); /* OOM case */ - for(i=0; im.nMap; i++){ - sqlite3_free(pNew->m.aaMap[i]); - } - sqlite3_free(pNew); - }else{ - u64 t; - for(t=iFirst; tpList = pNew; - pNew->nRef = 1; /* Server reference */ - } - } - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTMapServerNew(u64 iFirstTid, u64 iLastTid, HctTMapServer **pp){ - int rc = SQLITE_OK; - HctTMapServer *pNew; - - pNew = sqlite3MallocZero(sizeof(HctTMapServer)); - if( pNew==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pNew->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pNew->pMutex==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pNew->iMinMinTid = iFirstTid-1; - rc = hctTMapInit(pNew, iFirstTid, iLastTid); - } - } - - if( rc!=SQLITE_OK ){ - sqlite3HctTMapServerFree(pNew); - pNew = 0; - } - - *pp = pNew; - return rc; -} - -SQLITE_PRIVATE int sqlite3HctTMapServerSet(HctTMapServer *pServer, u64 iTid, u64 iCid){ - u64 *pEntry = hctTMapFind(pServer->pList, iTid); - *pEntry = iCid; - return SQLITE_OK; -} - -/* -** Argument pMap is an HctTMapFull object that is currently linked -** into the list at HctTMapServer.pList. This function removes pMap -** from that list and frees all associated allocations. -*/ -static void hctTMapFreeMap(HctTMapServer *p, HctTMapFull *pMap){ - int iFirst = 0; /* First in pMap->m.aaMap[] to free */ - int iSave = 0; /* First in pMap->m.aaMap[] to preserve */ - int ii; - - assert( pMap && pMap->nRef==0 ); - if( pMap==p->pList ){ - if( pMap->pNext==0 ) iSave = pMap->m.nMap; - p->pList = pMap->pNext; - }else{ - HctTMapFull *pPrev; - HctTMapFull *pNext = pMap->pNext; - - for(pPrev=p->pList; pPrev->pNext!=pMap; pPrev=pPrev->pNext); - for(iSave=0; iSavem.nMap; iSave++){ - if( pMap->m.aaMap[iSave]==pPrev->m.aaMap[0] ) break; - } - - if( pNext ){ - u64 *aDoNotDel = pNext->m.aaMap[pNext->m.nMap-1]; - for(iFirst=pMap->m.nMap; iFirst>0; iFirst--){ - if( pMap->m.aaMap[iFirst-1]==aDoNotDel ) break; - } - } - - pPrev->pNext = pMap->pNext; - } - - for(ii=iFirst; iim.aaMap[ii]); - } - sqlite3_free(pMap); - -} - -/* -** Free a tmap-server object. -*/ -SQLITE_PRIVATE void sqlite3HctTMapServerFree(HctTMapServer *p){ - if( p ){ - assert( p->pClientList==0 ); - sqlite3_mutex_free(p->pMutex); - - assert( p->pList==0 || p->pList->nRef==1 ); - if( p->pList ) p->pList->nRef--; - while( p->pList ){ - HctTMapFull *pMap = p->pList; - while( pMap->pNext ) pMap = pMap->pNext; - hctTMapFreeMap(p, pMap); - } - - sqlite3_free(p); - } -} - -SQLITE_PRIVATE int sqlite3HctTMapClientNew( - HctTMapServer *p, - HctConfig *pConfig, - HctTMapClient **ppClient -){ - int rc = SQLITE_OK; - HctTMapClient *pNew; - - pNew = (HctTMapClient*)sqlite3HctMalloc(&rc, sizeof(HctTMapClient)); - if( pNew ){ - pNew->pServer = p; - pNew->pConfig = pConfig; - ENTER_TMAP_MUTEX(pNew); - /* Under cover of the server mutex, link this new client into the - ** list of clients associated with the server. The minimum TID value - ** for the client is set to the current global minimum. */ - pNew->iLockValue = p->iMinMinTid; - pNew->pNextClient = p->pClientList; - pNew->pMap = p->pList; - pNew->pMap->nRef++; - p->pClientList = pNew; - LEAVE_TMAP_MUTEX(pNew); - } - *ppClient = pNew; - return rc; -} - -SQLITE_PRIVATE void sqlite3HctTMapClientFree(HctTMapClient *pClient){ - if( pClient ){ - HctTMapClient **pp; - ENTER_TMAP_MUTEX(pClient); - - pClient->pMap->nRef--; - if( pClient->pMap->nRef==0 ){ - hctTMapFreeMap(pClient->pServer, pClient->pMap); - } - - /* Remove this client from the HctTMapServer.pClientList list */ - for(pp=&pClient->pServer->pClientList;*pp!=pClient;pp=&(*pp)->pNextClient); - *pp = pClient->pNextClient; - - LEAVE_TMAP_MUTEX(pClient); - sqlite3_free(pClient); - } -} - - -SQLITE_PRIVATE int sqlite3HctTMapBegin(HctTMapClient *pClient, u64 iSnapshot, HctTMap **ppMap){ - HctTMapFull *pMap = pClient->pMap; - u64 iEof = pMap->m.iFirstTid + pMap->m.nMap*HCT_TMAP_PAGESIZE; - - while( 1 ){ - u64 iOrigLockValue = HctAtomicLoad(&pClient->iLockValue); - u64 iLockValue; - - /* Find the new "safe-tid" value */ - u64 iSafe = (iOrigLockValue & HCT_TMAP_CID_MASK); - u64 iMinMinTid = HctAtomicLoad(&pClient->pServer->iMinMinTid); - if( iSafeiSnapshot ) break; - iSafe++; - } - - /* Set the lock-value. If this fails, it means some writer process - ** has increased the safe-tid value for us. */ - assert( (iOrigLockValue & HCT_LOCKVALUE_ACTIVE)==0 ); - iLockValue = iSafe | HCT_LOCKVALUE_ACTIVE; - if( hctTMapBoolCAS64(&pClient->iLockValue, iOrigLockValue, iLockValue) ){ - break; - } - } - - *ppMap = (HctTMap*)pMap; - return SQLITE_OK; -} - -SQLITE_PRIVATE u64 sqlite3HctTMapCommitedTID(HctTMapClient *pClient){ - return (pClient->iLockValue & HCT_TMAP_CID_MASK); -} - -static void hctTMapUpdateSafe(HctTMapClient *pClient){ - assert( sqlite3_mutex_held(pClient->pServer->pMutex) ); - if( pClient->pMap!=pClient->pServer->pList ){ - pClient->pMap->nRef--; - if( pClient->pMap->nRef==0 ){ - hctTMapFreeMap(pClient->pServer, pClient->pMap); - } - pClient->pMap = pClient->pServer->pList; - pClient->pMap->nRef++; - } -} - -/* -** This is called by a reader if it needs to look-up a TID for which its -** current HctTMap object is not large enough. This function sets output -** parameter (*ppMap) to point to the latest HctTMap object, which, -** unless the db is corrupt, is guaranteed to be large enough. -** -** SQLITE_OK is returned if successful. -*/ -SQLITE_PRIVATE int sqlite3HctTMapUpdate(HctTMapClient *pClient, HctTMap **ppMap){ - ENTER_TMAP_MUTEX(pClient); - hctTMapUpdateSafe(pClient); - LEAVE_TMAP_MUTEX(pClient); - *ppMap = (HctTMap*)pClient->pMap; - return SQLITE_OK; -} - -/* -** Called to signal the end of a read or write a transaction. Parameter -** iCID is passed the CID of the snapshot on which the transaction was -** based. -*/ -SQLITE_PRIVATE int sqlite3HctTMapEnd(HctTMapClient *pClient, u64 iCID){ - while( 1 ){ - u64 iOrigLockValue = pClient->iLockValue; - u64 iLockValue; - - assert( (iOrigLockValue & HCT_LOCKVALUE_ACTIVE)!=0 ); - iLockValue = (iOrigLockValue & ~HCT_LOCKVALUE_ACTIVE); - if( hctTMapBoolCAS64(&pClient->iLockValue, iOrigLockValue, iLockValue) ){ - break; - } - } - return SQLITE_OK; -} - -/* -** Allocate a new HctTMapFull object and link it into the list -** belonging to server pServer. The new map object is based on -** the server's current newest - pServer->pList. Relative to this -** object, the new map: -** -** * appends one mapping page to the end of the map, and -** -** * may remove one or more mapping pages from the start of the -** map, based on the current value of HctTMapServer.iMinMinTid. -** -** The server mutex must be held to call this function. -*/ -static int hctTMapNewObject(HctTMapServer *pServer){ - u64 iFirst = (pServer->iMinMinTid / HCT_TMAP_PAGESIZE) * HCT_TMAP_PAGESIZE; - HctTMapFull *pOld = pServer->pList; - HctTMapFull *pNew = 0; - int nMap = 0; - int nDiscard = 0; - int nByte = 0; - int rc = SQLITE_OK; - - assert( sqlite3_mutex_held(pServer->pMutex) ); - assert( (iFirst % HCT_TMAP_PAGESIZE)==0 ); - assert( (pOld->m.iFirstTid % HCT_TMAP_PAGESIZE)==0 ); - assert( (pServer->iMinMinTid & HCT_TMAP_CID_MASK)==pServer->iMinMinTid ); - assert( (iFirst & HCT_TMAP_CID_MASK)==iFirst ); - - nDiscard = (iFirst - pOld->m.iFirstTid) / HCT_TMAP_PAGESIZE; - nMap = pOld->m.nMap + 1 - nDiscard; - nByte = sizeof(HctTMapFull) + nMap*sizeof(u64*); - pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, nByte); - - if( pNew ){ - int ii; - pNew->m.iFirstTid = iFirst; - pNew->m.nMap = nMap; - pNew->m.aaMap = (u64**)&pNew[1]; - pNew->nRef = 1; - for(ii=0; ii<(nMap-1); ii++){ - pNew->m.aaMap[ii] = pOld->m.aaMap[ii+nDiscard]; - } - pNew->m.aaMap[ii] = (u64*)sqlite3HctMalloc( - &rc, sizeof(u64)*HCT_TMAP_PAGESIZE - ); - - pServer->pList->nRef--; - if( pServer->pList->nRef==0 ){ - hctTMapFreeMap(pServer, pServer->pList); - } - pNew->pNext = pServer->pList; - pServer->pList = pNew; - } - - return rc; -} - -/* -** Return the largest TID for which it is safe to reuse freed pages. -*/ -SQLITE_PRIVATE u64 sqlite3HctTMapSafeTID(HctTMapClient *p){ - /* TODO: -1? */ - return HctAtomicLoad(&p->pServer->iMinMinTid); -} - -/* -** This is called by write transactions immediately after obtaining -** the transaction's TID value (at the start of the commit process). -*/ -SQLITE_PRIVATE int sqlite3HctTMapNewTID( - HctTMapClient *p, /* Transaction map client */ - u64 iTid, /* TID for write transaction */ - HctTMap **ppMap /* OUT: (possibly) new transaction map */ -){ - int rc = SQLITE_OK; - HctTMapFull *pMap = p->pMap; - u64 iEof = pMap->m.iFirstTid + ((u64)pMap->m.nMap*HCT_TMAP_PAGESIZE); - - /* If it is time to do so, allocate a new transaction-map */ - if( iTid>=iEof || iTid==(iEof - HCT_TMAP_PAGESIZE/2) ){ - ENTER_TMAP_MUTEX(p); - hctTMapUpdateSafe(p); - pMap = p->pMap; - iEof = pMap->m.iFirstTid + ((u64)pMap->m.nMap*HCT_TMAP_PAGESIZE); - if( iTid>=iEof || iTid==(iEof - HCT_TMAP_PAGESIZE/2) ){ - hctTMapNewObject(p->pServer); - hctTMapUpdateSafe(p); - } - LEAVE_TMAP_MUTEX(p); - } - - *ppMap = (HctTMap*)p->pMap; - return rc; -} - -SQLITE_PRIVATE void sqlite3HctTMapScan(HctTMapClient *p){ - HctTMapClient *pClient = 0; - u64 iSafe = p->iLockValue & HCT_TMAP_CID_MASK; - - ENTER_TMAP_MUTEX(p); - for(pClient=p->pServer->pClientList; pClient; pClient=pClient->pNextClient){ - u64 iVal = HctAtomicLoad(&pClient->iLockValue); - u64 iTid = (iVal & HCT_TMAP_CID_MASK); - - if( (iVal & HCT_LOCKVALUE_ACTIVE)==0 && iTidiLockValue, iVal, iSafe); - iVal = HctAtomicLoad(&pClient->iLockValue); - iTid = (iVal & HCT_TMAP_CID_MASK); - } - - iSafe = MIN(iSafe, iTid); - } - HctAtomicStore(&p->pServer->iMinMinTid, iSafe); - LEAVE_TMAP_MUTEX(p); -} - -SQLITE_PRIVATE i64 sqlite3HctTMapStats(sqlite3 *db, int iStat, const char **pzStat){ - HctTMapClient *pClient = 0; - i64 iVal = -1; - - pClient = sqlite3HctFileTMapClient(sqlite3HctDbFile(sqlite3HctDbFind(db, 0))); - switch( iStat ){ - case 0: - *pzStat = "mutex_attempt"; - iVal = pClient->stats.nMutex; - break; - case 1: - *pzStat = "mutex_block"; - iVal = pClient->stats.nMutexBlock; - break; - default: - break; - } - - return iVal; -} - -SQLITE_PRIVATE int sqlite3HctTMapRecoverySet(HctTMapClient *p, u64 iTid, u64 iCid){ - int rc = SQLITE_OK; - HctTMapFull *pNew = p->pBuild; - if( pNew==0 ){ - u64 iFirst = 1; - u64 iEof = p->pServer->pList->m.iFirstTid; - u64 iLast = iEof + (HCT_TMAP_PAGESIZE*2); - int nMap = 0; - if( iTid>=HCT_TMAP_PAGESIZE ){ - iFirst = 1 + ((iTid / HCT_TMAP_PAGESIZE) - 1) * HCT_TMAP_PAGESIZE; - } - nMap = ((iLast - iFirst) + HCT_TMAP_PAGESIZE-1) / HCT_TMAP_PAGESIZE; - assert( nMap>0 ); - - p->pBuild = pNew = (HctTMapFull*)sqlite3HctMalloc(&rc, - sizeof(HctTMapFull) + nMap*sizeof(u64*) - ); - p->iBuildMin = iTid; - if( pNew ){ - int ii; - pNew->m.iFirstTid = iFirst; - pNew->m.nMap = nMap; - pNew->m.aaMap = (u64**)&pNew[1]; - pNew->nRef = 1; - for(ii=0; iim.aaMap[ii] = aMap; - } - if( rc==SQLITE_OK ){ - u64 ee; - for(ee=iFirst; eem.aaMap[iMap][iOff] = ((u64)1 | HCT_TMAP_COMMITTED); - } - } - } - } - p->iBuildMin = MIN(p->iBuildMin, iTid); - - while( rc==SQLITE_OK && pNew->m.iFirstTid>iTid ){ - int ii; - HctTMapFull *pAlloc = 0; - int nMap = pNew->m.nMap + 1; - - pAlloc = (HctTMapFull*)sqlite3HctMalloc(&rc, - sizeof(HctTMapFull) + nMap*sizeof(u64*) - ); - pAlloc->nRef = 1; - pAlloc->m.nMap = nMap; - pAlloc->m.aaMap = (u64**)&pAlloc[1]; - pAlloc->m.iFirstTid = pNew->m.iFirstTid - HCT_TMAP_PAGESIZE; - memcpy(&pAlloc->m.aaMap[1], pNew->m.aaMap, pNew->m.nMap*sizeof(u64*)); - pAlloc->m.aaMap[0] = (u64*)sqlite3HctMalloc(&rc, - sizeof(u64) * HCT_TMAP_PAGESIZE - ); - for(ii=0; iim.aaMap[0][ii] = ((u64)1 | HCT_TMAP_COMMITTED); - } - - assert( pNew->nRef==1 ); - sqlite3_free(pNew); - p->pBuild = pNew = pAlloc; - } - - if( rc==SQLITE_OK ){ - int iMap = (iTid - pNew->m.iFirstTid) / HCT_TMAP_PAGESIZE; - int iOff = (iTid - pNew->m.iFirstTid) % HCT_TMAP_PAGESIZE; - pNew->m.aaMap[iMap][iOff] = (iCid | HCT_TMAP_COMMITTED); - } - - return rc; -} - -SQLITE_PRIVATE void sqlite3HctTMapRecoveryFinish(HctTMapClient *p, int rc){ - HctTMapFull *pNew = p->pBuild; - if( pNew ){ - p->pBuild = 0; - if( rc==SQLITE_OK ){ - pNew->pNext = p->pServer->pList; - p->pServer->pList = pNew; - p->pServer->iMinMinTid = p->iBuildMin; - if( pNew->pNext ){ - pNew->pNext->nRef--; - if( pNew->pNext->nRef==0 ){ - hctTMapFreeMap(p->pServer, pNew->pNext); - } - } - }else{ - int ii; - for(ii=0; iim.nMap; ii++){ - sqlite3_free(pNew->m.aaMap[ii]); - } - sqlite3_free(pNew); - } - p->iBuildMin = 0; - } -} - - -/************** End of hct_tmap.c ********************************************/ -/************** Begin file hct_record.c **************************************/ -/* -** 2022 May 19 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -/* #include "hctInt.h" */ -/* #include "sqliteInt.h" */ -/* #include "vdbeInt.h" */ - -/* #include */ -/* #include */ - -/* -** Write the serialized data blob for the value stored in pMem into -** buf. It is assumed that the caller has allocated sufficient space. -** Return the number of bytes written. -** -** nBuf is the amount of space left in buf[]. The caller is responsible -** for allocating enough space to buf[] to hold the entire field, exclusive -** of the pMem->u.nZero bytes for a MEM_Zero value. -** -** Return the number of bytes actually written into buf[]. The number -** of bytes in the zero-filled tail is included in the return value only -** if those bytes were zeroed in buf[]. -*/ -static u32 hctRecordSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ - u32 len; - - /* Integer and Real */ - if( serial_type<=7 && serial_type>0 ){ - u64 v; - u32 i; - if( serial_type==7 ){ - assert( sizeof(v)==sizeof(pMem->u.r) ); - memcpy(&v, &pMem->u.r, sizeof(v)); - swapMixedEndianFloat(v); - }else{ - v = pMem->u.i; - } - len = i = sqlite3SmallTypeSizes[serial_type]; - assert( i>0 ); - do{ - buf[--i] = (u8)(v&0xFF); - v >>= 8; - }while( i ); - return len; - } - - /* String or blob */ - if( serial_type>=12 ){ - assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0) - == (int)sqlite3VdbeSerialTypeLen(serial_type) ); - len = pMem->n; - if( len>0 ) memcpy(buf, pMem->z, len); - return len; - } - - /* NULL or constants 0 or 1 */ - return 0; -} - -/* -** Return the serial-type for the value stored in pMem. -** -** This routine might convert a large MEM_IntReal value into MEM_Real. -*/ -static u32 hctRecordSerialType(Mem *pMem, u32 *pLen){ - int flags = pMem->flags; - u32 n; - - assert( pLen!=0 ); - if( flags&MEM_Null ){ - *pLen = 0; - return 0; - } - if( flags&(MEM_Int|MEM_IntReal) ){ - /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ -# define MAX_6BYTE ((((i64)0x00008000)<<32)-1) - i64 i = pMem->u.i; - u64 u; - testcase( flags & MEM_Int ); - testcase( flags & MEM_IntReal ); - if( i<0 ){ - u = ~i; - }else{ - u = i; - } - if( u<=127 ){ - if( (i&1)==i ){ - *pLen = 0; - return 8+(u32)u; - }else{ - *pLen = 1; - return 1; - } - } - if( u<=32767 ){ *pLen = 2; return 2; } - if( u<=8388607 ){ *pLen = 3; return 3; } - if( u<=2147483647 ){ *pLen = 4; return 4; } - if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } - *pLen = 8; - if( flags&MEM_IntReal ){ - /* If the value is IntReal and is going to take up 8 bytes to store - ** as an integer, then we might as well make it an 8-byte floating - ** point value */ - pMem->u.r = (double)pMem->u.i; - pMem->flags &= ~MEM_IntReal; - pMem->flags |= MEM_Real; - return 7; - } - return 6; - } - if( flags&MEM_Real ){ - *pLen = 8; - return 7; - } - assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); - assert( pMem->n>=0 ); - n = (u32)pMem->n; - if( flags & MEM_Zero ){ - n += pMem->u.nZero; - } - *pLen = n; - return ((n*2) + 12 + ((flags&MEM_Str)!=0)); -} - - -/* -** -*/ -SQLITE_PRIVATE int sqlite3HctSerializeRecord( - UnpackedRecord *pRec, /* Record to serialize */ - u8 **ppRec, /* OUT: buffer containing serialization */ - int *pnRec /* OUT: size of (*ppRec) in bytes */ -){ - int ii; - int nData = 0; - int nHdr = 0; - u8 *pOut = 0; - int iOffHdr = 0; - int iOffData = 0; - - for(ii=0; iinField; ii++){ - u32 n; - u32 stype = hctRecordSerialType(&pRec->aMem[ii], &n); - nData += n; - nHdr += sqlite3VarintLen(stype); - pRec->aMem[ii].uTemp = stype; - } - - if( nHdr<=126 ){ - /* The common case */ - nHdr += 1; - }else{ - /* Rare case of a really large header */ - int nVarint = sqlite3VarintLen(nHdr); - nHdr += nVarint; - if( nVarintnField; ii++){ - u32 stype = pRec->aMem[ii].uTemp; - iOffHdr += putVarint32(&pOut[iOffHdr], stype); - iOffData += hctRecordSerialPut(&pOut[iOffData], &pRec->aMem[ii], stype); - } - assert( iOffData==(nHdr+nData) ); - - *ppRec = pOut; - *pnRec = iOffData; - - return SQLITE_OK; -} - - -/************** End of hct_record.c ******************************************/ -/************** Begin file hct_stats.c ***************************************/ -/* -** 2022 September 28 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - - -/* #include "hctInt.h" */ - -typedef struct hctstats_vtab hctstats_vtab; -typedef struct hctstats_cursor hctstats_cursor; -struct hctstats_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; -}; -struct hctstats_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - int iSubsys; - int iStat; - - i64 iRowid; - const char *zStat; /* Value for "stat" column. NULL for EOF. */ - i64 iVal; /* Value for "val" column. */ -}; - -typedef struct HctStatsSubsys HctStatsSubsys; -struct HctStatsSubsys { - const char *zSubsys; - i64 (*xStat)(sqlite3*, int iStat, const char **pzStat); -}; - -static HctStatsSubsys aHctStatGlobal[] = { - { "file", sqlite3HctFileStats }, - { "db", sqlite3HctDbStats }, - { "tmap", sqlite3HctTMapStats }, - { "pman", sqlite3HctPManStats }, - { "hct", sqlite3HctMainStats } -}; - -#define HCTSTATS_SCHEMA "CREATE TABLE x(subsys, stat, val)" - -/* -** xConnect() callback for hctstats table. -*/ -static int hctstatsConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - hctstats_vtab *pNew = 0; - int rc = SQLITE_OK; - - *ppVtab = 0; - rc = sqlite3_declare_vtab(db, HCTSTATS_SCHEMA); - - if( rc==SQLITE_OK ){ - pNew = sqlite3MallocZero( sizeof(*pNew) ); - *ppVtab = (sqlite3_vtab*)pNew; - if( pNew==0 ) return SQLITE_NOMEM; - pNew->db = db; - } - return rc; -} - -/* -** xBestIndex() callback for hctstats table. -*/ -static int hctstatsBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - pIdxInfo->estimatedCost = (double)10000; - pIdxInfo->estimatedRows = 10000; - return SQLITE_OK; -} - -/* -** xDisconnect() callback for hctstats table. Free the vtab handle. -*/ -static int hctstatsDisconnect(sqlite3_vtab *pVtab){ - hctstats_vtab *p = (hctstats_vtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** xOpen() callback for hctstats table. Free the vtab handle. -*/ -static int hctstatsOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - hctstats_cursor *pCur; - pCur = sqlite3MallocZero(sizeof(*pCur)); - if( pCur==0 ) return SQLITE_NOMEM; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** xClose() callback for hctstats table. Free the vtab handle. -*/ -static int hctstatsClose(sqlite3_vtab_cursor *cur){ - hctstats_cursor *pCur = (hctstats_cursor*)cur; - sqlite3_free(pCur); - return SQLITE_OK; -} - -static int hctstatsNext(sqlite3_vtab_cursor *cur){ - hctstats_cursor *pCsr = (hctstats_cursor*)cur; - hctstats_vtab *pTab = (hctstats_vtab*)(pCsr->base.pVtab); - - pCsr->zStat = 0; - pCsr->iStat++; - - while( pCsr->zStat==0 && pCsr->iSubsysiSubsys]; - pCsr->iVal = p->xStat(pTab->db, pCsr->iStat, &pCsr->zStat); - if( pCsr->zStat==0 ){ - pCsr->iStat = 0; - pCsr->iSubsys++; - } - } - - return SQLITE_OK; -} - -static int hctstatsFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - hctstats_cursor *pCsr = (hctstats_cursor*)cur; - - if( sqlite3HctDbFind(((hctstats_vtab*)cur->pVtab)->db, 0)==0 ){ - /* Main database is not an hctree db */ - return SQLITE_OK; - } - - pCsr->iStat = -1; - pCsr->iSubsys = 0; - pCsr->iRowid = 0; - return hctstatsNext(cur); -} - -static int hctstatsEof(sqlite3_vtab_cursor *cur){ - hctstats_cursor *pCsr = (hctstats_cursor*)cur; - return (pCsr->zStat==0); -} - -static int hctstatsColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - hctstats_cursor *pCsr = (hctstats_cursor*)cur; - - assert( i==0 || i==1 || i==2 ); - switch( i ){ - case 0: { - HctStatsSubsys *p = &aHctStatGlobal[pCsr->iSubsys]; - sqlite3_result_text(ctx, p->zSubsys, -1, SQLITE_STATIC); - break; - } - - case 1: - sqlite3_result_text(ctx, pCsr->zStat, -1, SQLITE_STATIC); - break; - - default: - assert( i==2 ); - sqlite3_result_int64(ctx, pCsr->iVal); - break; - } - return SQLITE_OK; -} - -static int hctstatsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - hctstats_cursor *pCsr = (hctstats_cursor*)cur; - *pRowid = pCsr->iRowid; - return SQLITE_OK; -} - - -/* -** Register the hct_stats virtual table module with the supplied -** SQLite database handle. -*/ -SQLITE_PRIVATE int sqlite3HctStatsInit(sqlite3 *db){ - static sqlite3_module hctstatsModule = { - /* iVersion */ 0, - /* xCreate */ 0, - /* xConnect */ hctstatsConnect, - /* xBestIndex */ hctstatsBestIndex, - /* xDisconnect */ hctstatsDisconnect, - /* xDestroy */ 0, - /* xOpen */ hctstatsOpen, - /* xClose */ hctstatsClose, - /* xFilter */ hctstatsFilter, - /* xNext */ hctstatsNext, - /* xEof */ hctstatsEof, - /* xColumn */ hctstatsColumn, - /* xRowid */ hctstatsRowid, - /* xUpdate */ 0, - /* xBegin */ 0, - /* xSync */ 0, - /* xCommit */ 0, - /* xRollback */ 0, - /* xFindMethod */ 0, - /* xRename */ 0, - /* xSavepoint */ 0, - /* xRelease */ 0, - /* xRollbackTo */ 0, - /* xShadowName */ 0 - }; - - return sqlite3_create_module(db, "hctstats", &hctstatsModule, 0); -} - - - -/************** End of hct_stats.c *******************************************/ -/************** Begin file hct_journal.c *************************************/ -/* -** 2020 October 13 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -/* #include "hctInt.h" */ -/* #include "vdbeInt.h" */ - -#define HCT_JOURNAL_SCHEMA \ -"CREATE TABLE sqlite_hct_journal(" \ - "cid INTEGER PRIMARY KEY," \ - "schema TEXT," \ - "data BLOB," \ - "schemacid INTEGER," \ - "hash BLOB," \ - "tid INTEGER," \ - "validcid INTEGER" \ -");" - - -#define HCT_BASELINE_SCHEMA \ -"CREATE TABLE sqlite_hct_baseline(" \ - "cid INTEGER," \ - "schemacid INTEGER," \ - "hash BLOB" \ -");" - -/* -** In follower mode, it is not possible to call sqlite3_hct_journal_write() -** for the transaction with CID (N + HCT_MAX_LEADING_WRITE) until all -** transactions with CID values of N or less have been committed. -*/ -#define HCT_MAX_LEADING_WRITE (8*1024) - -typedef struct HctJrnlServer HctJrnlServer; -typedef struct HctJrnlPendingHook HctJrnlPendingHook; - -/* -** One object of this type is shared by all connections to the same -** database. Managed by the HctFileServer object (see functions -** sqlite3HctFileGetJrnlPtr() and SetJrnlPtr()). -** -** iSchemaCid: -** This contains the current schema version of the database. Even though -** this value may be concurrently accessed, there is no need for an -** advanced or versioned data structure. Because: -** -** 1) In LEADER mode, this value is only accessed when writing an entry -** to the journal table, from within sqlite3HctJrnlLog(). It is only -** written to if the transaction has modified the database schema. -** -** The call to sqlite3HctJrnlLog() comes after the transaction has been -** successfully validated. And a transaction that modifies the schema -** only passes validation if there have been no writes at all to the -** the database since its snapshot was opened - i.e. if the CID for the -** transaction is one greater than the CID of its snapshot. This -** guarantees that there are no transactions with CID values less than -** that of the schema transaction concurrently accessing iSchemaCid. -** -** Also, since schema transactions modify the schema cookie, and all other -** transactions check the schema cookie during validation, it is -** guaranteed that no transaction started before the schema transaction -** is committed may successfully validate with a CID value greater than -** that of the schema transaction. -** -** Therefore, if a schema transaction has passed validation, it is -** guaranteed exclusive access to the iSchemaCid variable. -** -** 2) In FOLLOWER mode, the value is: -** -** * read from within sqlite3_hct_journal_write(), just after opening -** a snapshot, and -** -** * written from within the same call, following successful validation -** of a schema transaction. -** -** A schema transaction is only started once all transactions with CID -** values less than that of the schema transaction have finished -** committing. This alone ensures that there is at most a single -** writer to the iSchemaCid variable at any one time. -** -** eMode: -** The current database mode - either SQLITE_HCT_JOURNAL_MODE_FOLLOWER or -** SQLITE_HCT_JOURNAL_MODE_LEADER. -** -** iSnapshot: -** This is meaningful in FOLLOWER mode only. -** -** This is set to a CID value for which it and all prior transactions are -** committed. It may be written by any client using an atomic CAS operation, -** but may only be increased, never decreased. No transaction with a CID -** greater than (iSnapshot + HCT_MAX_LEADING_WRITE) may be started - -** iSnapshot must be increased first. -** -** nCommit: -** Size of aCommit[] array. -** -** aCommit: -** This array is only populated if the object is in FOLLOWER mode. -** -** Say the size of the array is N (actually HctJrnlServer.nCommit). Then, -** when transaction X is committed, slot aCommit[X % N] is set to X. Or, -** if transaction X is committed but no snapshot is valid until Y (for Y>X), -** then instead slot aCommit[X % N] is set to Y. -*/ -struct HctJrnlServer { - u64 iSchemaCid; - int eMode; - u64 iSnapshot; - int nSchemaVersionIncr; - int nCommit; - u64 *aCommit; /* Array of size nCommit */ -}; - -struct HctJrnlPendingHook { - u64 iCid; - u64 iSCid; - HctBuffer data; - HctBuffer schema; -}; - -/* -** There is one instance of this structure for each database handle (HBtree*) -** open on a replication-enabled hctree database. -** -** eInWrite: -** Set to true while the database connection is in a call to -** sqlite3_hct_journal_write(). -*/ -struct HctJournal { - u64 iJrnlRoot; /* Root page of journal table */ - u64 iBaseRoot; /* Root page of base table */ - int eInWrite; - u64 iWriteTid; - u64 iWriteCid; - u64 iRollbackSnapshot; - HctDatabase *pDb; - HctTree *pTree; - HctJrnlServer *pServer; - HctJrnlPendingHook pending; -}; - -#define HCT_JOURNAL_NONE 0 -#define HCT_JOURNAL_INWRITE 1 -#define HCT_JOURNAL_INROLLBACK 2 - -static void hctJournalSetDbError( - sqlite3 *db, /* Database on which to set error */ - int rc, /* Error code */ - const char *zFormat, ... /* Printf() error string and arguments */ -){ - char *zErr = 0; - sqlite3_mutex_enter( sqlite3_db_mutex(db) ); - if( zFormat ){ - va_list ap; - va_start(ap, zFormat); - zErr = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - } - if( zErr ){ - sqlite3ErrorWithMsg(db, rc, "%s", zErr); - sqlite3_free(zErr); - }else{ - sqlite3ErrorWithMsg(db, rc, 0, 0); - } - sqlite3_mutex_leave( sqlite3_db_mutex(db) ); -} - -/* -** Initialize the main database for replication. -*/ -SQLITE_API int sqlite3_hct_journal_init(sqlite3 *db){ - const char *zTest1 = "PRAGMA hct_ndbfile"; - const char *zTest2 = "SELECT 1 WHERE (SELECT count(*) FROM sqlite_schema)=0"; - sqlite3_stmt *pTest = 0; - int rc = SQLITE_OK; - - /* Test that there is not already an open transaction on this database. */ - if( sqlite3_get_autocommit(db)==0 ){ - hctJournalSetDbError(db, SQLITE_ERROR, "open transaction on database"); - return SQLITE_ERROR; - } - - /* Test that the main db really is an hct database. Leave rc set to - ** something other than SQLITE_OK and an error message in the database - ** handle if it is not. */ - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, zTest1, -1, &pTest, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_step(pTest); - sqlite3_finalize(pTest); - if( rc==SQLITE_DONE ){ - hctJournalSetDbError(db, SQLITE_ERROR, "not an hct database"); - }else if( rc==SQLITE_ROW ){ - rc = SQLITE_OK; - } - } - - /* Open a transaction on the db */ - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); - } - - /* Test that the main db really is empty */ - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, zTest2, -1, &pTest, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_step(pTest); - sqlite3_finalize(pTest); - if( rc==SQLITE_DONE ){ - hctJournalSetDbError(db, SQLITE_ERROR, "not an empty database"); - rc = SQLITE_ERROR; - }else if( rc==SQLITE_ROW ){ - rc = SQLITE_OK; - } - } - - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, - "PRAGMA writable_schema = 1;" - HCT_JOURNAL_SCHEMA ";" - HCT_BASELINE_SCHEMA ";" - "INSERT INTO sqlite_hct_baseline VALUES(6, 0, zeroblob(16));" - "PRAGMA writable_schema = 0;" - ,0 ,0 ,0 - ); - } - - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); - } - if( rc!=SQLITE_OK ){ - char *zErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); - sqlite3_exec(db, "ROLLBACK", 0, 0, 0); - hctJournalSetDbError(db, rc, "%s", zErr); - sqlite3_free(zErr); - }else{ - rc = sqlite3HctDetectJournals(db); - } - - return rc; -} - -/* -** Register a custom validation callback with the database handle. -*/ -SQLITE_API int sqlite3_hct_journal_hook( - sqlite3 *db, - void *pArg, - int(*xValidate)( - void *pCopyOfArg, - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid - ) -){ - db->xValidate = xValidate; - db->pValidateArg = pArg; - return SQLITE_OK; -} - -SQLITE_API void sqlite3_hct_migrate_mode(sqlite3 *db, int bActivate){ - db->bHctMigrate = bActivate; -} - -/* -** Value iVal is to be stored as an integer in an SQLite record. This -** function returns the number of bytes that it will use for storage. -*/ -static int hctJrnlIntSize(u64 iVal){ -#define MAX_6BYTE ((((i64)0x00008000)<<32)-1) - if( iVal<=127 ) return 1; - if( iVal<=32767 ) return 2; - if( iVal<=8388607 ) return 3; - if( iVal<=2147483647 ) return 4; - if( iVal<=MAX_6BYTE ) return 6; - return 8; -} - -/* -** Store an (nByte*8) bit big-endian integer, value iVal, in buffer a[]. -*/ -static void hctJrnlIntPut(u8 *a, u64 iVal, int nByte){ - int i; - for(i=1; i<=nByte; i++){ - a[nByte-i] = (iVal & 0xFF); - iVal = (iVal >> 8); - } -} - -/* -** Return the byte value that should be stored in the SQLite record -** header for an nSize byte integer field. -*/ -static u8 hctJrnlIntHdr(int nSize){ - if( nSize==8 ) return 6; - if( nSize==6 ) return 5; - return nSize; -} - -/* -** Compose an SQLite record suitable for the sqlite_hct_journal table. -*/ -static u8 *hctJrnlComposeRecord( - u64 iCid, - const char *zSchema, - const u8 *pData, int nData, - u64 iSchemaCid, - u64 iTid, - u64 iValidCid, - int *pnRec -){ - u8 *pRec = 0; - int nRec = 0; - int nHdr = 0; - int nBody = 0; - int nSchema = 0; /* Length of zSchema, in bytes */ - int nTidByte = 0; - int nSchemaCidByte = 0; - int nValidCidByte = 0; - u8 aHash[SQLITE_HCT_JOURNAL_HASHSIZE]; - - nSchema = sqlite3Strlen30(zSchema); - nTidByte = hctJrnlIntSize(iTid); - nSchemaCidByte = hctJrnlIntSize(iSchemaCid); - nValidCidByte = hctJrnlIntSize(iValidCid); - - sqlite3_hct_journal_hashentry( - aHash, iCid, zSchema, pData, nData, iSchemaCid - ); - - /* First figure out how large the eventual record will be */ - nHdr = 1 /* size of header varint */ - + 1 /* "cid" - always NULL */ - + sqlite3VarintLen((nSchema * 2) + 13) /* "schema" - TEXT */ - + sqlite3VarintLen((nData * 2) + 12) /* "data" - BLOB */ - + 1 /* "schemacid" - INTEGER */ - + 1 /* "hash" - BLOB */ - + 1 /* "tid" - INTEGER */ - + 1; /* "validcid" - INTEGER */ - - nBody = 0 /* "cid" - always NULL */ - + nSchema /* "schema" - TEXT */ - + nData /* "data" - BLOB */ - + nSchemaCidByte /* "schemacid" - INTEGER */ - + SQLITE_HCT_JOURNAL_HASHSIZE /* "hash" - BLOB */ - + nTidByte /* "tid" - INTEGER */ - + nValidCidByte; /* "validcid" - INTEGER */ - - nRec = nBody+nHdr; - pRec = (u8*)sqlite3_malloc(nRec); - if( pRec ){ - u8 *pHdr = pRec; - u8 *pBody = &pRec[nHdr]; - - *pHdr++ = (u8)nHdr; /* size-of-header varint */ - *pHdr++ = 0x00; /* "cid" - NULL */ - - /* "schema" field - TEXT */ - pHdr += sqlite3PutVarint(pHdr, (nSchema*2) + 13); - if( nSchema>0 ){ - memcpy(pBody, zSchema, nSchema); - pBody += nSchema; - } - - /* "data" field - BLOB */ - pHdr += sqlite3PutVarint(pHdr, (nData*2) + 12); - if( nData>0 ){ - memcpy(pBody, pData, nData); - pBody += nData; - } - - /* "schemacid" field - INTEGER */ - *pHdr++ = hctJrnlIntHdr(nSchemaCidByte); - hctJrnlIntPut(pBody, iSchemaCid, nSchemaCidByte); - pBody += nSchemaCidByte; - - /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ - *pHdr++ = (u8)((SQLITE_HCT_JOURNAL_HASHSIZE * 2) + 12); - memcpy(pBody, aHash, SQLITE_HCT_JOURNAL_HASHSIZE); - pBody += SQLITE_HCT_JOURNAL_HASHSIZE; - - /* "tid" field - INTEGER */ - *pHdr++ = hctJrnlIntHdr(nTidByte); - hctJrnlIntPut(pBody, iTid, nTidByte); - pBody += nTidByte; - - /* "validcid" field - INTEGER */ - *pHdr++ = hctJrnlIntHdr(nValidCidByte); - hctJrnlIntPut(pBody, iValidCid, nValidCidByte); - pBody += nValidCidByte; - - assert( pHdr==&pRec[nHdr] ); - assert( pBody==&pRec[nRec] ); - }else{ - nRec = 0; - } - - *pnRec = nRec; - return pRec; -} - -typedef struct JrnlCtx JrnlCtx; -struct JrnlCtx { - Schema *pSchema; - HctTree *pTree; - HctBuffer *pBuf; - HctBuffer *pSchemaSql; -}; - -typedef struct JrnlTree JrnlTree; -struct JrnlTree { - const char *zName; -}; - -static int hctJrnlFindTree(Schema *pSchema, u32 iRoot, JrnlTree *pJTree){ - HashElem *k; - if( iRoot==1 ) return 0; - for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ - Table *pTab = (Table*)sqliteHashData(k); - if( pTab->tnum==iRoot ){ - pJTree->zName = pTab->zName; - return 1; - } - } - return 0; -} - -static void hctJrnlRecordPrefix( - HctBuffer *pBuf, - int nData, /* Size of buffer aData[] in bytes */ - const u8 *aData, /* Buffer containing SQLite record */ - int nField /* Number of prefix fields requested */ -){ - int iHdr = 0; - int iBody = 0; - int ii = 0; - int szHdr = 0; /* Size of output header */ - int szBody = 0; /* Size of output record body */ - u8 *aHdrOut = 0; - u8 *aBodyOut = 0; - - iHdr = getVarint32(aData, iBody); - - /* Figure out the aggregate sizes of the header and body fields for the - ** required number of prefix fields. */ - for(ii=0; ii126 ){ - int nVarint = sqlite3VarintLen(szHdr); - szHdr += nVarint; - if( sqlite3VarintLen(szHdr)!=nVarint ) szHdr++; - } - - /* Size of record field */ - pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], szHdr+szBody); - - aHdrOut = &pBuf->aBuf[pBuf->nBuf]; - aBodyOut = &aHdrOut[szHdr]; - - /* Write the size-of-header field for the output record */ - aHdrOut += sqlite3PutVarint(aHdrOut, szHdr); - - /* Write the other fields to both the header and body of the output record */ - for(ii=0; ii0 ){ - memcpy(aBodyOut, &aData[iBody], nBody); - iBody += nBody; - aBodyOut += nBody; - } - } - - pBuf->nBuf = (aBodyOut - pBuf->aBuf); -} - -static int hctBufferExtend(HctBuffer *pBuf, int nExtend){ - i64 nDesire = pBuf->nBuf + nExtend; - if( pBuf->nAllocaBuf[pBuf->nBuf], zApp, nApp+1); - pBuf->nBuf += nApp; - sqlite3_free(zApp); - return SQLITE_OK; -} - - -static int hctJrnlLogTree(void *pCtx, u32 iRoot, KeyInfo *pKeyInfo){ - int rc = SQLITE_OK; - JrnlCtx *pJrnl = (JrnlCtx*)pCtx; - HctBuffer *pBuf = pJrnl->pBuf; - - if( iRoot==HCT_TREE_SCHEMAOP_ROOT ){ - HctTreeCsr *pCsr = 0; - rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, iRoot, &pCsr); - if( rc==SQLITE_OK ){ - for(rc=sqlite3HctTreeCsrFirst(pCsr); - rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; - rc=sqlite3HctTreeCsrNext(pCsr) - ){ - int nData = 0; - const u8 *aData = 0; - sqlite3HctTreeCsrData(pCsr, &nData, &aData); - rc = hctBufferAppend(pJrnl->pSchemaSql, "%s%.*s", - (pJrnl->pSchemaSql->nBuf>0 ? ";" : ""), nData, (const char*)aData - ); - } - sqlite3HctTreeCsrClose(pCsr); - } - }else{ - JrnlTree jrnltree; - memset(&jrnltree, 0, sizeof(jrnltree)); - if( hctJrnlFindTree(pJrnl->pSchema, iRoot, &jrnltree) ){ - int nName = sqlite3Strlen30(jrnltree.zName); - - rc = hctBufferExtend(pBuf, 1+nName+1); - if( rc==SQLITE_OK ){ - HctTreeCsr *pCsr = 0; - - pBuf->aBuf[pBuf->nBuf++] = 'T'; - memcpy(&pBuf->aBuf[pBuf->nBuf], jrnltree.zName, nName+1); - pBuf->nBuf += nName+1; - rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, iRoot, &pCsr); - - if( rc==SQLITE_OK ){ - for(rc=sqlite3HctTreeCsrFirst(pCsr); - rc==SQLITE_OK && sqlite3HctTreeCsrEof(pCsr)==0; - rc=sqlite3HctTreeCsrNext(pCsr) - ){ - i64 iKey = 0; - int nData = 0; - const u8 *aData = 0; - int bDel = 0; - - sqlite3HctTreeCsrKey(pCsr, &iKey); - sqlite3HctTreeCsrData(pCsr, &nData, &aData); - bDel = sqlite3HctTreeCsrIsDelete(pCsr); - - rc = hctBufferExtend(pBuf, 1+9+9+nData); - if( rc!=SQLITE_OK ) break; - - if( pKeyInfo==0 ){ - pBuf->aBuf[pBuf->nBuf++] = bDel ? 'd' : 'i'; - pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], iKey); - }else{ - pBuf->aBuf[pBuf->nBuf++] = bDel ? 'D' : 'I'; - if( bDel ){ - hctJrnlRecordPrefix(pBuf, nData, aData, pKeyInfo->nUniqField); - } - } - if( bDel==0 ){ - pBuf->nBuf += sqlite3PutVarint(&pBuf->aBuf[pBuf->nBuf], nData); - memcpy(&pBuf->aBuf[pBuf->nBuf], aData, nData); - pBuf->nBuf += nData; - } - } - } - - sqlite3HctTreeCsrClose(pCsr); - } - } - } - - return rc; -} - -static int hctJrnlWriteRecord( - HctJournal *pJrnl, - u64 iCid, - const char *zSchema, - const void *pData, int nData, - u64 iSchemaCid, - u64 iTid -){ - int rc = SQLITE_OK; - u8 *pRec = 0; - int nRec = 0; - - pRec = hctJrnlComposeRecord( - iCid, zSchema, pData, nData, iSchemaCid, iTid, 0, &nRec - ); - if( pRec==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - int nRetry = 0; - do { - nRetry = 0; - rc = sqlite3HctDbInsert( - pJrnl->pDb, (u32)pJrnl->iJrnlRoot, 0, iCid, 0, nRec, pRec, &nRetry - ); - if( rc!=SQLITE_OK ) break; - assert( nRetry==0 || nRetry==1 ); - if( nRetry==0 ){ - rc = sqlite3HctDbInsertFlush(pJrnl->pDb, &nRetry); - if( rc!=SQLITE_OK ) break; - } - }while( nRetry ); - } - sqlite3_free(pRec); - - return rc; -} - -SQLITE_PRIVATE int sqlite3HctJrnlWriteEmpty( - HctJournal *pJrnl, - u64 iCid, - u64 iTid, - sqlite3 *db /* If non-NULL, invoke custom validation */ -){ - int rc = SQLITE_OK; - if( pJrnl->eInWrite==HCT_JOURNAL_NONE ){ - rc = hctJrnlWriteRecord(pJrnl, iCid, "", 0, 0, 0, iTid); - - /* If argument db is not NULL and there is a custom validation hook - ** configured, invoke it now. This is just to propagate the empty - ** transaction to any follower databases, not to actually validate - ** an empty transaction - the return code is ignored. */ - if( rc==SQLITE_OK && db && db->xValidate ){ - // (void)db->xValidate(db->pValidateArg, iCid, "", 0, 0, 0); - pJrnl->pending.iCid = iCid; - pJrnl->pending.iSCid = 0; - pJrnl->pending.data.nBuf = 0; - pJrnl->pending.schema.nBuf = 0; - } - } - return rc; -} - -SQLITE_PRIVATE void sqlite3HctJrnlInvokeHook(HctJournal *pJrnl, sqlite3 *db){ - if( pJrnl ){ - HctJrnlPendingHook *pPending = &pJrnl->pending; - if( pPending->iCid>0 ){ - if( db->xValidate ){ - const char *zSchema = ""; - if( pJrnl->pending.schema.nBuf>0 ){ - zSchema = (const char*)pJrnl->pending.schema.aBuf; - } - (void)db->xValidate( - db->pValidateArg, pPending->iCid, - zSchema, pPending->data.aBuf, pPending->data.nBuf, - pPending->iSCid - ); - } - - pPending->iCid = 0; - } - } -} - -SQLITE_PRIVATE int sqlite3HctJrnlLog( - HctJournal *pJrnl, - sqlite3 *db, - Schema *pSchema, - u64 iCid, - u64 iTid, - int *pbValidateCalled -){ - int rc = SQLITE_OK; - JrnlCtx jrnlctx; - const char *zSchema = ""; - u64 iSchemaCid = HctAtomicLoad(&pJrnl->pServer->iSchemaCid); - - assert( *pbValidateCalled==0 ); - if( pJrnl->eInWrite!=HCT_JOURNAL_NONE ) return SQLITE_OK; - - memset(&jrnlctx, 0, sizeof(jrnlctx)); - jrnlctx.pSchema = pSchema; - jrnlctx.pTree = pJrnl->pTree; - jrnlctx.pBuf = &pJrnl->pending.data; - jrnlctx.pSchemaSql = &pJrnl->pending.schema; - - jrnlctx.pBuf->nBuf = 0; - jrnlctx.pSchemaSql->nBuf = 0; - - rc = sqlite3HctTreeForeach(pJrnl->pTree, 1, (void*)&jrnlctx, hctJrnlLogTree); - if( jrnlctx.pSchemaSql->nBuf ){ - zSchema =(const char*)jrnlctx.pSchemaSql->aBuf; - } - - if( rc==SQLITE_OK ){ - rc = hctJrnlWriteRecord(pJrnl, iCid, zSchema, - jrnlctx.pBuf->aBuf, jrnlctx.pBuf->nBuf, iSchemaCid, iTid - ); - } - - /* If one is registered, invoke the validation hook */ - if( rc==SQLITE_OK && db->xValidate ){ -#if 0 - int res = db->xValidate(db->pValidateArg, iCid, zSchema, - jrnlctx.buf.aBuf, jrnlctx.buf.nBuf, iSchemaCid - ); - if( res!=0 ){ - rc = SQLITE_BUSY_SNAPSHOT; - } - *pbValidateCalled = 1; -#endif - pJrnl->pending.iCid = iCid; - pJrnl->pending.iSCid = iSchemaCid; - } - - if( zSchema[0] && rc==SQLITE_OK ){ - HctAtomicStore(&pJrnl->pServer->iSchemaCid, iCid); - } - - return rc; -} - -static void hctJrnlDelServer(void *p){ - if( p ){ - HctJrnlServer *pServer = (HctJrnlServer*)p; - sqlite3_free(pServer->aCommit); - sqlite3_free(pServer); - } -} - -typedef struct HctJournalRecord HctJournalRecord; -struct HctJournalRecord { - i64 iCid; - const char *zSchema; int nSchema; - const void *pData; int nData; - i64 iSchemaCid; - const void *pHash; - i64 iTid; - i64 iValidCid; -}; - -/* -** Structure containing values read from the sqlite_hct_baseline table. -*/ -typedef struct HctBaselineRecord HctBaselineRecord; -struct HctBaselineRecord { - i64 iCid; - u8 aHash[SQLITE_HCT_JOURNAL_HASHSIZE]; - i64 iSchemaCid; -}; - - -typedef struct HctRecordReader HctRecordReader; -struct HctRecordReader { - const u8 *aRec; - int nRec; - int nHdr; - const u8 *pHdr; - const u8 *pBody; -}; - -static void hctJrnlReadInit( - HctRecordReader *p, - int nRec, - const u8 *aRec -){ - memset(p, 0, sizeof(*p)); - p->aRec = aRec; - p->nRec = nRec; - p->pHdr = p->aRec + getVarint32(aRec, p->nHdr); - p->pBody = &p->aRec[p->nHdr]; -} - -static const u8 *hctJrnlReadBlobText( - int *pRc, - HctRecordReader *p, - int bText, - int *pnData -){ - const u8 *pRet = 0; - if( *pRc==SQLITE_OK ){ - u64 iType = 0; - p->pHdr += sqlite3GetVarint(p->pHdr, &iType); - if( iType<12 || (iType % 2)!=bText ){ - *pRc = SQLITE_CORRUPT_BKPT; - }else{ - *pnData = (iType - 12) / 2; - pRet = p->pBody; - p->pBody += (*pnData); - } - } - return pRet; -} - -static const char *hctJrnlReadText( - int *pRc, - HctRecordReader *p, - int *pnText -){ - return (const char*)hctJrnlReadBlobText(pRc, p, 1, pnText); -} -static const u8 *hctJrnlReadBlob( - int *pRc, - HctRecordReader *p, - int *pnText -){ - return hctJrnlReadBlobText(pRc, p, 0, pnText); -} - -static i64 hctJrnlReadInteger(int *pRc, HctRecordReader *p){ - i64 iRet = 0; - if( *pRc==SQLITE_OK ){ - u64 iType = 0; - p->pHdr += sqlite3GetVarint(p->pHdr, &iType); - switch( iType ){ - case 1: - iRet = p->pBody[0]; - p->pBody++; - break; - case 2: - iRet = ((u64)p->pBody[0] << 8) - + ((u64)p->pBody[1] << 0); - p->pBody += 2; - break; - case 3: - iRet = ((u64)p->pBody[0] << 16) - + ((u64)p->pBody[1] << 8) - + ((u64)p->pBody[2] << 0); - p->pBody += 3; - break; - case 4: - iRet = ((u64)p->pBody[0] << 24) - + ((u64)p->pBody[1] << 16) - + ((u64)p->pBody[2] << 8) - + ((u64)p->pBody[3] << 0); - p->pBody += 4; - break; - case 5: - iRet = ((u64)p->pBody[0] << 40) - + ((u64)p->pBody[1] << 32) - + ((u64)p->pBody[2] << 24) - + ((u64)p->pBody[3] << 16) - + ((u64)p->pBody[4] << 8) - + ((u64)p->pBody[5] << 0); - p->pBody += 6; - break; - case 6: - iRet = ((u64)p->pBody[0] << 56) - + ((u64)p->pBody[1] << 48) - + ((u64)p->pBody[2] << 40) - + ((u64)p->pBody[3] << 32) - + ((u64)p->pBody[4] << 24) - + ((u64)p->pBody[5] << 16) - + ((u64)p->pBody[6] << 8) - + ((u64)p->pBody[7] << 0); - p->pBody += 6; - break; - case 8: - iRet = 0; - break; - case 9: - iRet = 1; - break; - default: - *pRc = SQLITE_CORRUPT_BKPT; - break; - } - } - - return iRet; -} - -static void hctJrnlReadHash( - int *pRc, /* IN/OUT: Error code */ - HctRecordReader *p, /* Record reader */ - u8 *aHash /* Pointer to buffer to populate */ -){ - int nHash = 0; - const u8 *a = 0; - a = hctJrnlReadBlob(pRc, p, &nHash); - if( *pRc==SQLITE_OK && nHash!=SQLITE_HCT_JOURNAL_HASHSIZE ){ - *pRc = SQLITE_CORRUPT_BKPT; - } - if( *pRc==SQLITE_OK ){ - memcpy(aHash, a, SQLITE_HCT_JOURNAL_HASHSIZE); - } -} - -static int hctJrnlReadJournalRecord(HctDbCsr *pCsr, HctJournalRecord *pRec){ - int rc = SQLITE_OK; - int nData = 0; - const u8 *aData = 0; - - memset(pRec, 0, sizeof(*pRec)); - - sqlite3HctDbCsrKey(pCsr, (i64*)&pRec->iCid); - rc = sqlite3HctDbCsrData(pCsr, &nData, &aData); - if( rc==SQLITE_OK ){ - int nHash = 0; - HctRecordReader rdr; - hctJrnlReadInit(&rdr, nData, aData); - - /* "cid" field - always NULL */ - if( *rdr.pHdr++!=0 ) return SQLITE_CORRUPT_BKPT; - - /* "schema" field - always TEXT. */ - pRec->zSchema = hctJrnlReadText(&rc, &rdr, &pRec->nSchema); - - /* "data" field - always BLOB */ - pRec->pData = hctJrnlReadBlob(&rc, &rdr, &pRec->nData); - - /* "schemacid" field - always INTEGER */ - pRec->iSchemaCid = hctJrnlReadInteger(&rc, &rdr); - - /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ - pRec->pHash = (const void*)hctJrnlReadBlob(&rc, &rdr, &nHash); - if( nHash!=SQLITE_HCT_JOURNAL_HASHSIZE ) rc = SQLITE_CORRUPT_BKPT; - - /* "tid" field - an INTEGER */ - pRec->iTid = hctJrnlReadInteger(&rc, &rdr); - - /* "valid_cid" field - an INTEGER */ - pRec->iValidCid = hctJrnlReadInteger(&rc, &rdr); - } - return rc; -} - -/* -** Read the contents of the sqlite_hct_baseline table into structure -** (*pRec). Return SQLITE_OK if successful, or an SQLite error code -** otherwise. -*/ -static int hctJrnlReadBaseline( - HctJournal *pJrnl, /* Database to read from */ - HctBaselineRecord *pRec /* Populate this structure before returning */ -){ - HctDbCsr *pCsr = 0; - int rc = SQLITE_OK; - - memset(pRec, 0, sizeof(HctBaselineRecord)); - - /* Open a cursor on the baseline table */ - rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, (u32)pJrnl->iBaseRoot, &pCsr); - - /* Move the cursor to the first record in the table. */ - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrFirst(pCsr); - } - if( rc==SQLITE_OK && sqlite3HctDbCsrEof(pCsr) ){ - rc = SQLITE_CORRUPT_BKPT; - } - - if( rc==SQLITE_OK ){ - int nData = 0; - const u8 *aData = 0; - - rc = sqlite3HctDbCsrData(pCsr, &nData, &aData); - if( rc==SQLITE_OK ){ - HctRecordReader rdr; - hctJrnlReadInit(&rdr, nData, aData); - - /* "cid" field - an INTEGER */ - pRec->iCid = hctJrnlReadInteger(&rc, &rdr); - - /* "schemacid" field - an INTEGER */ - pRec->iSchemaCid = hctJrnlReadInteger(&rc, &rdr); - - /* "hash" field - SQLITE_HCT_JOURNAL_HASHSIZE byte BLOB */ - hctJrnlReadHash(&rc, &rdr, pRec->aHash); - } - } - sqlite3HctDbCsrClose(pCsr); - - return rc; -} - -static int hctJrnlGetJrnlShape( - sqlite3 *db, - i64 *piLast, /* Out: Last entry in journal */ - i64 *piLastCont /* Out: Last contiguous entry in journal */ -){ - const char *z1 = "SELECT max(cid) FROM sqlite_hct_journal"; - const char *z2 = "SELECT cid FROM sqlite_hct_journal ORDER BY 1 DESC"; - - int rc = SQLITE_OK; - sqlite3_stmt *pStmt = 0; - i64 iLast = 0; - i64 iLastCont = 0; - - rc = sqlite3_prepare_v2(db, z1, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - iLast = sqlite3_column_int64(pStmt, 0); - } - rc = sqlite3_finalize(pStmt); - } - - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, z2, -1, &pStmt, 0); - } - if( rc==SQLITE_OK ){ - i64 iPrev = iLast; - iLastCont = iLast; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - i64 iThis = sqlite3_column_int64(pStmt, 0); - if( iThis!=iPrev-1 ){ - iLastCont = iThis; - } - if( (iLast-iThis)>HCT_MAX_LEADING_WRITE*2 ) break; - iPrev = iThis; - } - rc = sqlite3_finalize(pStmt); - } - - *piLast = iLast; - *piLastCont = iLastCont; - return rc; -} - -static sqlite3_stmt *hctPreparePrintf( - int *pRc, - sqlite3 *db, - const char *zFmt, ... -){ - sqlite3_stmt *pRet = 0; - va_list ap; - char *zSql = 0; - - va_start(ap, zFmt); - zSql = sqlite3_vmprintf(zFmt, ap); - va_end(ap); - - if( *pRc==SQLITE_OK ){ - if( zSql==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - *pRc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0); - } - } - sqlite3_free(zSql); - return pRet; -} - -/* -** Iterator for reading a blob from the "data" column of a journal entry. -*/ -typedef struct HctDataReader HctDataReader; -struct HctDataReader { - const u8 *aData; - int nData; - int iData; - - int bEof; - char eType; - - /* Valid for all values of eType */ - const char *zTab; - - /* For eType==HCT_TYPE_INSERT_ROWID, HCT_TYPE_DELETE_ROWID */ - i64 iRowid; - - /* For eType==HCT_TYPE_INSERT_ROWID */ - int nRecord; - const u8 *aRecord; -}; - -#define HCT_TYPE_TABLE 'T' -#define HCT_TYPE_INSERT_ROWID 'i' -#define HCT_TYPE_DELETE_ROWID 'd' - -static int hctDataReaderNext(HctDataReader *p){ - if( p->iData>=p->nData ){ - p->bEof = 1; - }else{ - p->eType = (char)(p->aData[p->iData++]); - switch( p->eType ){ - case 'T': { - p->zTab = (const char*)&p->aData[p->iData]; - p->iData += sqlite3Strlen30(p->zTab) + 1; - break; - } - - case 'd': { - p->iData += sqlite3GetVarint(&p->aData[p->iData], (u64*)&p->iRowid); - break; - } - - case 'i': { - p->iData += sqlite3GetVarint(&p->aData[p->iData], (u64*)&p->iRowid); - p->iData += getVarint32(&p->aData[p->iData], p->nRecord); - p->aRecord = &p->aData[p->iData]; - p->iData += p->nRecord; - break; - } - - default: { - return SQLITE_CORRUPT_BKPT; - } - } - } - - return SQLITE_OK; -} - -/* -** Initialize an HctDataReader object to iterate through the nData byte -** 'data' blob in buffer pData. Leave the iterator pointing at the first -** entry in the blob. -*/ -static int hctDataReaderInit(const void *pData, int nData, HctDataReader *pRdr){ - memset(pRdr, 0, sizeof(*pRdr)); - pRdr->aData = (const u8*)pData; - pRdr->nData = nData; - return hctDataReaderNext(pRdr); -} - -SQLITE_PRIVATE int sqlite3HctJrnlSavePhysical( - sqlite3 *db, - HctJournal *pJrnl, - int (*xSave)(void*, i64 iPhys), - void *pSave -){ - const char *zSql = "SELECT data FROM sqlite_hct_journal WHERE cid>?"; - int rc = SQLITE_OK; - i64 iLast = 0; - i64 iLastCont = 0; - sqlite3_stmt *pStmt = 0; - - rc = hctJrnlGetJrnlShape(db, &iLast, &iLastCont); - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - } - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, iLastCont); - while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - const void *pData = sqlite3_column_blob(pStmt, 0); - int nData = sqlite3_column_bytes(pStmt, 0); - sqlite3_stmt *pQuery = 0; - HctDataReader rdr; - - sqlite3HctDbSetSavePhysical(pJrnl->pDb, xSave, pSave); - for(rc=hctDataReaderInit(pData, nData, &rdr); - rc==SQLITE_OK && rdr.bEof==0; - rc=hctDataReaderNext(&rdr) - ){ - switch( rdr.eType ){ - case HCT_TYPE_TABLE: { - rc = sqlite3_finalize(pQuery); - pQuery = hctPreparePrintf( - &rc, db, "SELECT * FROM %Q WHERE _rowid_=?", rdr.zTab - ); - break; - } - - case HCT_TYPE_INSERT_ROWID: - case HCT_TYPE_DELETE_ROWID: { - sqlite3_bind_int64(pQuery, 1, rdr.iRowid); - sqlite3_step(pQuery); - rc = sqlite3_reset(pQuery); - break; - } - - default: assert( 0 ); - } - if( rc ) break; - } - sqlite3HctDbSetSavePhysical(pJrnl->pDb, 0, 0); - sqlite3_finalize(pQuery); - } - rc = sqlite3_finalize(pStmt); - } - - return rc; -} - -/* -** Do special recovery (startup) processing for replication-enabled databases. -** This function is called during stage 1 recovery - after any log files have -** been processed (and the database schema + contents restored), but before the -** free-page-lists are recovered. -*/ -SQLITE_PRIVATE int sqlite3HctJrnlRecovery(HctJournal *pJrnl, HctDatabase *pDb){ - HctBaselineRecord base; /* sqlite_hct_baseline data */ - HctJrnlServer *pServer = 0; - HctFile *pFile = sqlite3HctDbFile(pDb); - int rc = SQLITE_OK; - HctDbCsr *pCsr = 0; - - i64 iMaxCid = 0; - i64 iSchemaCid = 0; - - /* Read the contents of the sqlite_hct_baseline table. */ - rc = hctJrnlReadBaseline(pJrnl, &base); - - /* Allocate the new HctJrnlServer structure */ - pServer = (HctJrnlServer*)sqlite3HctMalloc(&rc, sizeof(HctJrnlServer)); - - /* Read the last record of the sqlite_hct_journal table. Specifically, - ** the value of fields "cid" and "schema_version". Store these values - ** in stack variables iMaxCid and aSchema, respectively. Or, if the - ** sqlite_hct_journal table is empty, populate iMaxCid and aSchema[] with - ** values from the baseline table. */ - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrOpen(pDb, 0, (u32)pJrnl->iJrnlRoot, &pCsr); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrLast(pCsr); - } - if( rc==SQLITE_OK ){ - if( sqlite3HctDbCsrEof(pCsr)==0 ){ - HctJournalRecord rec; - rc = hctJrnlReadJournalRecord(pCsr, &rec); - if( rc==SQLITE_OK ){ - iMaxCid = rec.iCid; - iSchemaCid = (rec.zSchema[0] ? rec.iCid : rec.iSchemaCid); - } - }else{ - iMaxCid = base.iCid; - iSchemaCid = base.iSchemaCid; - } - } - - /* Scan the sqlite_hct_journal table from beginning to end. When - ** the first missing entry is found, calculate the size of the - ** HctJrnlServer.aCommit[] API and allocate it. Then continue - ** scanning the sqlite_hct_journal table, populating aCommit[] along - ** the way. */ - if( rc==SQLITE_OK ){ - HctTMapClient *pTClient = sqlite3HctFileTMapClient(pFile); - i64 iPrev = base.iCid; - int nTrans = 0; - u64 *aCommit = 0; - - /* Scan until the first missing entry. Set nTrans to the number of - ** number of entries between the first missing one and the last - ** present, or to HCT_MAX_LEADING_WRITE, whichever is greater. - ** Set iPrev to the largest CID value for which it and all previous - ** CIDs have been written into the journal table. */ - for(rc = sqlite3HctDbCsrFirst(pCsr); - rc==SQLITE_OK && 0==sqlite3HctDbCsrEof(pCsr); - rc = sqlite3HctDbCsrNext(pCsr) - ){ - i64 iCid = 0; - sqlite3HctDbCsrKey(pCsr, &iCid); - if( iPrev!=0 && iCid!=iPrev+1 ){ - nTrans = iMaxCid - iPrev; - break; - } - iPrev = iCid; - } - nTrans = MAX(HCT_MAX_LEADING_WRITE, nTrans); - - pServer->nCommit = nTrans*2; - aCommit = (u64*)sqlite3HctMalloc(&rc, pServer->nCommit*sizeof(u64)); - pServer->aCommit = aCommit; - pServer->iSnapshot = iPrev; - - /* Scan through whatever is left of the sqlite_hct_journal table, - ** populating the aCommit[] array and the transaction-map (hct_tmap.c) - ** along the way. */ - while( rc==SQLITE_OK && 0==sqlite3HctDbCsrEof(pCsr) ){ - HctJournalRecord rec; - rc = hctJrnlReadJournalRecord(pCsr, &rec); - if( rc==SQLITE_OK ){ - i64 iVal = rec.iValidCid ? rec.iValidCid : rec.iCid; - pServer->aCommit[rec.iCid % pServer->nCommit] = iVal; - rc = sqlite3HctTMapRecoverySet(pTClient, rec.iTid, rec.iCid); - } - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrNext(pCsr); - } - } - sqlite3HctTMapRecoveryFinish(pTClient, rc); - } - - if( rc==SQLITE_OK ){ - HctAtomicStore(&pServer->iSchemaCid, iSchemaCid); - pJrnl->pServer = pServer; - sqlite3HctFileSetJrnlPtr(pFile, (void*)pServer, hctJrnlDelServer); - if( iMaxCid>0 ) sqlite3HctFileSetCID(pFile, iMaxCid); - }else{ - hctJrnlDelServer((void*)pServer); - } - - sqlite3HctDbCsrClose(pCsr); - return rc; -} - -static u64 hctFindRootByName(Schema *pSchema, const char *zName){ - u64 iRet = 0; - Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zName); - if( pTab ){ - iRet = pTab->tnum; - } - return iRet; -} - -SQLITE_PRIVATE int sqlite3HctJournalNewIf( - Schema *pSchema, - HctTree *pTree, - HctDatabase *pDb, - HctJournal **pp -){ - int rc = SQLITE_OK; - u64 iJrnlRoot = hctFindRootByName(pSchema, "sqlite_hct_journal"); - u64 iBaseRoot = hctFindRootByName(pSchema, "sqlite_hct_baseline"); - - assert( *pp==0 ); - - if( (iJrnlRoot==0)!=(iBaseRoot==0) ){ - return SQLITE_CORRUPT_BKPT; - } - if( iJrnlRoot ){ - HctJournal *pNew = sqlite3HctMalloc(&rc, sizeof(HctJournal)); - if( pNew ){ - HctFile *pFile = sqlite3HctDbFile(pDb); - pNew->iJrnlRoot = iJrnlRoot; - pNew->iBaseRoot = iBaseRoot; - pNew->pDb = pDb; - pNew->pTree = pTree; - pNew->pServer = (HctJrnlServer*)sqlite3HctFileGetJrnlPtr(pFile); - *pp = pNew; - } - } - - return rc; -} - -SQLITE_PRIVATE void sqlite3HctJournalClose(HctJournal *pJrnl){ - sqlite3_free(pJrnl); -} - -/* -** See description in hctJrnlInt.h. -*/ -SQLITE_PRIVATE int sqlite3HctJournalIsReadonly( - HctJournal *pJrnl, - u64 iTable, - int *pbNosnap -){ - if( pJrnl ){ - HctJrnlServer *p = pJrnl->pServer; - int bNosnap = (pJrnl->iJrnlRoot==iTable || pJrnl->iBaseRoot==iTable); - *pbNosnap = bNosnap; - return (pJrnl->eInWrite==HCT_JOURNAL_NONE && ( - bNosnap || !p || p->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER - )); - } - return 0; -} - -/* -** Called during log file recovery to remove the entry with "tid" (not CID!) -** value iTid from the sqlite_hct_journal table. -*/ -SQLITE_PRIVATE int sqlite3HctJrnlRollbackEntry(HctJournal *pJrnl, i64 iTid){ - i64 iDel = 0; - HctDbCsr *pCsr = 0; - int rc = SQLITE_OK; - - rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, (u32)pJrnl->iJrnlRoot, &pCsr); - if( rc==SQLITE_OK ){ - HctJournalRecord rec; - sqlite3HctDbCsrNosnap(pCsr, 1); - for(rc=sqlite3HctDbCsrLast(pCsr); - iDel==0 && rc==SQLITE_OK && sqlite3HctDbCsrEof(pCsr)==0; - rc=sqlite3HctDbCsrPrev(pCsr) - ){ - hctJrnlReadJournalRecord(pCsr, &rec); - if( rec.iTid==iTid ) iDel = rec.iCid; - } - - if( iDel!=0 && rc==SQLITE_OK ){ - rc = hctJrnlWriteRecord(pJrnl, iDel, "", 0, 0, 0, iTid); - } - - sqlite3HctDbCsrClose(pCsr); - } - - return rc; -} - -/* -** Find the HctJournal object associated with the "main" database of the -** connection passed as the only argument. If successful, set (*ppJrnl) -** to point to said object and return SQLITE_OK. Or, if the database is -** not a replication-enabled db, set (*ppJrnl) to NULL and return SQLITE_OK. -** Or, if an error occurs, return an SQLite error code. The final value -** of (*ppJrnl) is undefined in this case. -*/ -static int hctJrnlFind(sqlite3 *db, HctJournal **ppJrnl){ - int rc = SQLITE_OK; - HctJournal *pJrnl = sqlite3HctJrnlFind(db); - - if( pJrnl==0 ){ - /* If the journal was not found, it might be because the database is - ** not yet initialized. Run a query to ensure it is, then try to retrieve - ** the journal object again. */ - rc = sqlite3_exec(db, "SELECT 1 FROM sqlite_schema LIMIT 1", 0, 0, 0); - if( rc==SQLITE_OK ){ - pJrnl = sqlite3HctJrnlFind(db); - } - } - - if( rc==SQLITE_OK && pJrnl==0 ){ - hctJournalSetDbError(db, SQLITE_ERROR, "not a journaled hct database"); - rc = SQLITE_ERROR; - } - - *ppJrnl = pJrnl; - return rc; -} - - -/* -** Return the current journal mode - SQLITE_HCT_JOURNAL_MODE_FOLLOWER or -** SQLITE_HCT_JOURNAL_MODE_LEADER - for the main database of the connection -** passed as the only argument. Or, if the main database is not a -** replication-enabled hct database, return -1; -*/ -SQLITE_API int sqlite3_hct_journal_mode(sqlite3 *db){ - int eRet = -1; - HctJournal *pJrnl = sqlite3HctJrnlFind(db); - if( pJrnl ){ - eRet = pJrnl->pServer->eMode; - } - return eRet; -} - -/* -** Return true if the journal is complete - contains no holes. Or false -** otherwise. This function is not threadsafe. Results are undefined -** if there are concurrent transactions running on the database. -*/ -static int hctJrnlIsComplete(HctJournal *pJrnl){ - HctJrnlServer *pServer = pJrnl->pServer; - u64 iSnapshot = pServer->iSnapshot; - int ii; - - assert( pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ); - - /* Set iSnapshot to the CID of the last contiguous commit */ - while( 1 ){ - int iNext = (iSnapshot+1) % pServer->nCommit; - u64 iVal = HctAtomicLoad(&pServer->aCommit[iNext]); - if( iVal<=iSnapshot ) break; - iSnapshot++; - } - - /* See if there are any transactions yet committed with CID values greater - ** than iSnapshot. If there are, then the journal is not complete. */ - for(ii=0; iinCommit; ii++){ - u64 iVal = HctAtomicLoad(&pServer->aCommit[ii]); - if( iVal>iSnapshot ){ - return 0; - } - } - - return 1; -} - -/* -** Set the LEADER/FOLLOWER setting of the main database of the connection -** passed as the first argument. -*/ -SQLITE_API int sqlite3_hct_journal_setmode(sqlite3 *db, int eMode){ - int rc = SQLITE_OK; - HctJournal *pJrnl = sqlite3HctJrnlFind(db); - - if( pJrnl==0 ){ - rc = sqlite3_exec(db, "SELECT 1 FROM sqlite_schema LIMIT 1", 0, 0, 0); - if( rc==SQLITE_OK ){ - pJrnl = sqlite3HctJrnlFind(db); - } - } - - if( rc==SQLITE_OK ){ - if( eMode!=SQLITE_HCT_JOURNAL_MODE_LEADER - && eMode!=SQLITE_HCT_JOURNAL_MODE_FOLLOWER - ){ - return SQLITE_MISUSE_BKPT; - }else if( pJrnl==0 ){ - hctJournalSetDbError(db, SQLITE_ERROR, "not a journaled hct database"); - rc = SQLITE_ERROR; - }else{ - HctFile *pFile = sqlite3HctDbFile(pJrnl->pDb); - HctJrnlServer *pServer = pJrnl->pServer; - if( eMode!=pServer->eMode ){ - if( eMode==SQLITE_HCT_JOURNAL_MODE_LEADER ){ - /* Switch from FOLLOWER to LEADER mode. This is only allowed if - ** there are no holes in the journal. */ - if( hctJrnlIsComplete(pJrnl)==0 ){ - hctJournalSetDbError(db, SQLITE_ERROR, "incomplete journal"); - rc = SQLITE_ERROR; - }else{ - u64 iCid = sqlite3HctJournalSnapshot(pJrnl); - pServer->eMode = SQLITE_HCT_JOURNAL_MODE_LEADER; - if( iCid>0 ){ - sqlite3HctFileSetCID(sqlite3HctDbFile(pJrnl->pDb), iCid); - } - } - pServer->nSchemaVersionIncr++; - }else{ - /* Switch from LEADER to FOLLOWER mode. This is always possible. */ - void *pSchema = sqlite3HctBtreeSchema(db->aDb[0].pBt, 0, 0); - u64 iSnapshotId = sqlite3HctFileGetSnapshotid(pFile); - memset(pServer->aCommit, 0, pServer->nCommit*sizeof(u64)); - pServer->iSnapshot = iSnapshotId; - pServer->eMode = SQLITE_HCT_JOURNAL_MODE_FOLLOWER; - sqlite3HctJournalFixSchema(pJrnl, db, pSchema); - } - } - } - } - - return rc; -} - -static void hctJrnlFixTable(Table *pTab){ - Index *pIdx; - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->idxType==SQLITE_IDXTYPE_UNIQUE - || pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY - ){ - pIdx->idxType = SQLITE_IDXTYPE_APPDEF; - } - pIdx->uniqNotNull = 0; - pIdx->onError = OE_None; - } - - -} - -/* -** This function is used to "fix" a schema so that it can be used in -** a FOLLOWER mode database. Specifically: -** -** * All UNIQUE indexes are marked as not-unique. -** * All triggers are removed from the schema. -** * All FK definitions are removed from the schema. -*/ -SQLITE_PRIVATE void sqlite3HctJournalFixSchema(HctJournal *pJrnl, sqlite3 *db, void *pS){ - HctJrnlServer *pServer = pJrnl->pServer; - if( pServer==0 || pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ - Schema *pSchema = (Schema*)pS; - HashElem *k; - - for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ - Table *pTab = (Table*)sqliteHashData(k); - hctJrnlFixTable(pTab); - while( pTab->pTrigger ){ - Trigger *pTrig = pTab->pTrigger; - pTab->pTrigger = pTrig->pNext; - sqlite3DeleteTrigger(db, pTrig); - } - if( IsOrdinaryTable(pTab) ){ - sqlite3FkDelete(db, pTab); - } - } - sqlite3HashClear(&pSchema->trigHash); - } -} - -SQLITE_PRIVATE void sqlite3HctJournalSchemaVersion(HctJournal *pJrnl, u32 *pSchemaVersion){ - if( pJrnl && pJrnl->pServer ){ - *pSchemaVersion += HctAtomicLoad(&pJrnl->pServer->nSchemaVersionIncr); - } -} - -#ifdef SQLITE_DEBUG -/* -** assert() that the schema associated with table pTab has been "fixed", -** according to the definition used by sqlite3HctJournalFixSchema(). -*/ -static void assert_schema_is_fixed(Table *pTab){ - Index *pIdx; - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - assert( pIdx->idxType==SQLITE_IDXTYPE_APPDEF ); - assert( pIdx->uniqNotNull==0 ); - assert( pIdx->onError==OE_None ); - } - assert( pTab->pTrigger==0 ); - assert( pTab->u.tab.pFKey==0 ); -} -#else -# define assert_schema_is_fixed(x) -#endif - -static int hctJrnlGetInsertStmt( - sqlite3 *db, - const char *zTab, - int *piPk, - sqlite3_stmt **ppStmt -){ - sqlite3_str *pStr; - Schema *pSchema = db->aDb[0].pSchema; - Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zTab); - char *zSql = 0; - int rc = SQLITE_OK; - int ii; - - assert( pTab ); - assert_schema_is_fixed(pTab); - - *ppStmt = 0; - pStr = sqlite3_str_new(0); - sqlite3_str_appendf(pStr, "REPLACE INTO main.%Q(", zTab); - if( pTab->iPKey<0 ){ - sqlite3_str_appendf(pStr, "_rowid_, "); - } - for(ii=0; iinCol; ii++){ - const char *zSep = (ii==pTab->nCol-1) ? ") VALUES (" : ","; - sqlite3_str_appendf(pStr, "%Q%s ", pTab->aCol[ii].zCnName, zSep); - } - if( pTab->iPKey<0 ){ - sqlite3_str_appendf(pStr, "?%d, ", pTab->nCol+1); - *piPk = pTab->nCol+1; - }else{ - *piPk = pTab->iPKey+1; - } - for(ii=0; iinCol; ii++){ - const char *zSep = (ii==pTab->nCol-1) ? ")" : ", "; - sqlite3_str_appendf(pStr, "?%d%s", ii+1, zSep); - } - - zSql = sqlite3_str_finish(pStr); - if( zSql==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); - sqlite3_free(zSql); - } - - return rc; -} - -static int hctJrnlGetDeleteStmt( - sqlite3 *db, - const char *zTab, - sqlite3_stmt **ppStmt -){ - Schema *pSchema = db->aDb[0].pSchema; - Table *pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, zTab); - int rc = SQLITE_OK; - char *zSql = 0; - const char *zRowid = "_rowid_"; - - assert( pTab ); - assert_schema_is_fixed(pTab); - - if( pTab->iPKey>=0 ){ - zRowid = pTab->aCol[pTab->iPKey].zCnName; - } - - *ppStmt = 0; - zSql = sqlite3_mprintf( - "DELETE FROM main.%Q WHERE main.%Q.%Q = ?", - pTab->zName, pTab->zName, zRowid - ); - if( zSql==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); - sqlite3_free(zSql); - } - - return rc; -} - -/* -** Parameter aData[] points to a record encoded in SQLite format. Bind -** each value in the record to the statement passed as the second argument. -*/ -static int hctJrnlBindRecord(int *pRc, sqlite3_stmt *pStmt, const u8 *aData){ - int rc = *pRc; - int ret = 0; - if( rc==SQLITE_OK ){ - const u8 *pHdr = aData; - const u8 *pData = 0; - int nHdr; - int iBind; - - pHdr += getVarint32(pHdr, nHdr); - pData = &aData[nHdr]; - for(iBind=1; pHdr<&aData[nHdr]; iBind++){ - u32 t; - pHdr += getVarint32(pHdr, t); - switch( t ){ - case 10: - case 11: - case 0: /* NULL */ - sqlite3_bind_null(pStmt, iBind); - break; - - case 1: { /* 1 byte integer */ - i64 iVal = pData[0]; - pData += 1; - sqlite3_bind_int64(pStmt, iBind, iVal); - break; - } - case 2: { /* 2 byte integer */ - i64 iVal = ((i64)pData[0]<<8) + (i64)pData[1]; - pData += 2; - sqlite3_bind_int64(pStmt, iBind, iVal); - break; - } - case 3: { /* 3 byte integer */ - i64 iVal = ((i64)pData[0]<<16) + ((i64)pData[1]<<8) + (i64)pData[2]; - pData += 3; - sqlite3_bind_int64(pStmt, iBind, iVal); - break; - } - case 4: { /* 4 byte integer */ - i64 iVal = ((i64)pData[0]<<24) - + ((i64)pData[1]<<16) - + ((i64)pData[2]<<8) - + (i64)pData[3]; - pData += 4; - sqlite3_bind_int64(pStmt, iBind, iVal); - break; - } - case 5: { /* 6 byte integer */ - i64 iVal = ((i64)pData[0]<<40) - + ((i64)pData[1]<<32) - + ((i64)pData[2]<<24) - + ((i64)pData[3]<<16) - + ((i64)pData[4]<<8) - + (i64)pData[5]; - pData += 6; - sqlite3_bind_int64(pStmt, iBind, iVal); - break; - } - - case 6: case 7: { /* 8 byte integer, 8 byte real value */ - u64 iVal = ((u64)pData[0]<<56) - + ((u64)pData[1]<<48) - + ((u64)pData[2]<<40) - + ((u64)pData[3]<<32) - + ((u64)pData[4]<<24) - + ((u64)pData[5]<<16) - + ((u64)pData[6]<<8) - + (u64)pData[7]; - pData += 8; - if( t==6 ){ - i64 iVal2; - memcpy(&iVal2, &iVal, sizeof(iVal)); - sqlite3_bind_int64(pStmt, iBind, iVal2); - }else{ - double rVal2; - memcpy(&rVal2, &iVal, sizeof(iVal)); - sqlite3_bind_double(pStmt, iBind, rVal2); - } - break; - } - - case 8: /* integer value 0 */ - sqlite3_bind_int(pStmt, iBind, 0); - break; - - case 9: /* integer value 1 */ - sqlite3_bind_int(pStmt, iBind, 1); - break; - - default: { - int nByte = (t - 12) / 2; - if( t & 0x01 ){ - sqlite3_bind_text( - pStmt, iBind, (const char*)pData, nByte, SQLITE_TRANSIENT - ); - }else{ - sqlite3_bind_blob( - pStmt, iBind, (const void*)pData, nByte, SQLITE_TRANSIENT - ); - } - pData += nByte; - break; - }; - } - } - - ret = pData - aData; - } - return ret; -} - -SQLITE_PRIVATE u64 sqlite3HctJrnlWriteTid(HctJournal *pJrnl, u64 *piCid){ - u64 iRet = 0; - assert( *piCid==0 ); - if( pJrnl && pJrnl->eInWrite!=HCT_JOURNAL_NONE ){ - iRet = pJrnl->iWriteTid; - *piCid = pJrnl->iWriteCid; - } - return iRet; -} - -SQLITE_PRIVATE u64 sqlite3HctJournalSnapshot(HctJournal *pJrnl){ - u64 iRet = 0; - if( pJrnl ){ - if( pJrnl->eInWrite==HCT_JOURNAL_INROLLBACK ){ - return pJrnl->iRollbackSnapshot; - } - HctJrnlServer *pServer = pJrnl->pServer; - if( pServer && pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ - u64 iTest = 0; - u64 iValid = 0; - u64 iSnap = HctAtomicLoad(&pServer->iSnapshot); - iRet = iSnap; - for(iTest=iRet+1; 1; iTest++){ - u64 iVal = HctAtomicLoad(&pServer->aCommit[iTest % pServer->nCommit]); - if( iVal=iValid ) iRet = iTest; - }else{ - iValid = MAX(iVal, iValid); - } - } - - /* Update HctJrnlServer.iSnapshot if required */ - if( iRet>=iSnap+16 ){ - (void)HctCASBool(&pServer->iSnapshot, iSnap, iRet); - } - - /* If we are in an sqlite3_hct_journal_write() call, it is fine (and - ** necessary) to read snapshots that are invalid to the application. - ** So ignore any entries in the aCommit[] array that indicate such. */ - if( pJrnl->eInWrite==HCT_JOURNAL_INWRITE ){ - assert( (iTest-1)>=iRet ); - iRet = (iTest-1); - } - } - } - return iRet; -} - -/* -** Set output variable (*piCid) to the CID of the newest available -** database snapshot. Return SQLITE_OK if successful, or an SQLite -** error code if something goes wrong. -*/ -SQLITE_API int sqlite3_hct_journal_snapshot(sqlite3 *db, sqlite3_int64 *piCid){ - int rc = SQLITE_OK; - HctJournal *pJrnl = 0; - - rc = hctJrnlFind(db, &pJrnl); - if( rc==SQLITE_OK ){ - *piCid = (i64)sqlite3HctJournalSnapshot(pJrnl); - }else{ - *piCid = 0; - } - return rc; -} - -static sqlite3_stmt *hctJrnlPrepare(int *pRc, sqlite3 *db, const char *zSql){ - sqlite3_stmt *pStmt = 0; - if( *pRc==SQLITE_OK ){ - *pRc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - } - return pStmt; -} - -static void hctJrnlFinalize(int *pRc, sqlite3_stmt *pStmt){ - int rc = sqlite3_finalize(pStmt); - if( *pRc==SQLITE_OK ){ - *pRc = rc; - } -} - -SQLITE_API int sqlite3_hct_journal_truncate(sqlite3 *db, i64 iMinCid){ - int rc = SQLITE_OK; - HctJournal *pJrnl = 0; - sqlite3_stmt *pSelJrnl = 0; - sqlite3_stmt *pSelBaseline = 0; - sqlite3_stmt *pDelete = 0; - sqlite3_stmt *pUpdate = 0; - - if( 0==sqlite3_get_autocommit(db) ){ - hctJournalSetDbError(db, SQLITE_ERROR, - "cannot truncate journal from within a transaction" - ); - return SQLITE_ERROR; - } - - rc = hctJrnlFind(db, &pJrnl); - if( rc==SQLITE_OK - && pJrnl->pServer->eMode==SQLITE_HCT_JOURNAL_MODE_FOLLOWER - ){ - u64 iCid = sqlite3HctJournalSnapshot(pJrnl); - if( iCideInWrite = HCT_JOURNAL_INWRITE; - rc = sqlite3_exec(db, "BEGIN CONCURRENT", 0, 0, 0); - } - - pSelBaseline = hctJrnlPrepare(&rc, db, - "SELECT cid, schemacid, hash FROM sqlite_hct_baseline" - ); - pSelJrnl = hctJrnlPrepare(&rc, db, - "SELECT cid, schemacid, hash FROM sqlite_hct_journal WHERE cidpDb, &pJrnl->iWriteTid); - pJrnl->iWriteCid = 1; - } - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); - } - if( rc!=SQLITE_OK ){ - sqlite3_exec(db, "ROLLBACK", 0, 0, 0); - } - } - - hctJrnlFinalize(&rc, pSelJrnl); - hctJrnlFinalize(&rc, pSelBaseline); - hctJrnlFinalize(&rc, pDelete); - hctJrnlFinalize(&rc, pUpdate); - pJrnl->eInWrite = HCT_JOURNAL_NONE; - pJrnl->iWriteTid = 0; - pJrnl->iWriteCid = 0; - return rc; -} - -static int hctBufferAppendInsert( - HctBuffer *pBuf, - i64 iRowid, - Table *pTab, - sqlite3_stmt *pQuery -){ - int ii; - int rc = SQLITE_OK; - - rc = hctBufferAppend(pBuf, "REPLACE INTO %Q(_rowid_", pTab->zName); - for(ii=0; rc==SQLITE_OK && iinCol; ii++){ - if( ii!=pTab->iPKey ){ - rc = hctBufferAppend(pBuf, ", %Q", pTab->aCol[ii].zCnName); - } - } - - if( rc==SQLITE_OK ){ - rc = hctBufferAppend(pBuf, ") VALUES(%lld", iRowid); - } - - for(ii=0; rc==SQLITE_OK && iinCol; ii++){ - if( ii!=pTab->iPKey ){ - rc = hctBufferAppend(&buf, "%squote(x.%Q)", zSep, pTab->aCol[ii].zCnName); - zSep = ", "; - } - } - if( rc==SQLITE_OK ){ - rc = hctBufferAppend(&buf, "FROM %Q AS x WHERE _rowid_=?", pTab->zName); - } - - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (const char*)buf.aBuf, -1, &pRet, 0); - } - sqlite3_free(buf.aBuf); - - *pRc = rc; - return pRet; -} - -/* -** Rollback transactions that follow the first hole in the journal. -*/ -SQLITE_API int sqlite3_hct_journal_rollback(sqlite3 *db, sqlite3_int64 iCid){ - int rc = SQLITE_OK; - HctJournal *pJrnl = 0; - i64 iLast = 0; - i64 iLastCont = 0; - sqlite3_stmt *pStmt = 0; - Schema *pSchema = 0; - - rc = hctJrnlFind(db, &pJrnl); - if( rc!=SQLITE_OK ) return rc; - pSchema = db->aDb[0].pSchema; - - /* - ** 1. Find the location of the first hole in the journal. - ** - ** 2. Loop through journal entries, from the newest back to the - ** first hole in the journal. - ** - ** 3. Work through each of the transactions identified in step (1). - ** For each, write a log file, make the required modifications to - ** the db and journal file, then delete the log file. - */ - - /* Cannot call this with an open transaction. */ - if( 0==sqlite3_get_autocommit(db) ){ - hctJournalSetDbError(db, SQLITE_ERROR, - "cannot rollback journal from within a transaction" - ); - return SQLITE_ERROR; - } - - /* Cannot call this in LEADER mode. */ - if( pJrnl->pServer->eMode==SQLITE_HCT_JOURNAL_MODE_LEADER ){ - hctJournalSetDbError(db, SQLITE_ERROR, - "cannot rollback journal in leader database" - ); - return SQLITE_ERROR; - } - - /* Find the location of the first hole in the journal. If there are no - ** holes in the journal, this call is a no-op. */ - rc = hctJrnlGetJrnlShape(db, &iLast, &iLastCont); - assert( iLastCont<=iLast ); - if( rc!=SQLITE_OK || iLastCont>=iLast ) return rc; - - /* Loop through all of the journal entries that will be rolled back. - ** For each, extract the primary keys from the "data" blob. Query the - ** current database snapshot for each of these keys, generating an SQL - ** script with a "REPLACE INTO" for each row present in the db and a - ** "DELETE" for each not. */ - rc = sqlite3_prepare_v2(db, - "SELECT data FROM sqlite_hct_journal WHERE cid>?", -1, &pStmt, 0 - ); - if( rc==SQLITE_OK ){ - HctBuffer sql = {0, 0, 0}; - sqlite3_bind_int64(pStmt, 1, iLastCont); - - rc = hctBufferAppend(&sql, "BEGIN CONCURRENT;\n"); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - const void *pData = sqlite3_column_blob(pStmt, 0); - int nData = sqlite3_column_bytes(pStmt, 0); - sqlite3_stmt *pQuery = 0; - Table *pTab = 0; - HctDataReader rdr; - - for(rc=hctDataReaderInit(pData, nData, &rdr); - rc==SQLITE_OK && rdr.bEof==0; - rc=hctDataReaderNext(&rdr) - ){ - switch( rdr.eType ){ - case HCT_TYPE_TABLE: { - pTab = (Table*)sqlite3HashFind(&pSchema->tblHash, rdr.zTab); - if( pTab==0 ){ - rc = SQLITE_CORRUPT_BKPT; - }else{ - rc = sqlite3_finalize(pQuery); - pQuery = hctGetQuoteQuery(&rc, db, pTab); - } - break; - } - - case HCT_TYPE_INSERT_ROWID: - case HCT_TYPE_DELETE_ROWID: { - sqlite3_bind_int64(pQuery, 1, rdr.iRowid); - if( SQLITE_ROW==sqlite3_step(pQuery) ){ - rc = hctBufferAppendInsert(&sql, rdr.iRowid, pTab, pQuery); - }else{ - rc = hctBufferAppend(&sql, - "DELETE FROM %Q WHERE _rowid_=%lld;\n", rdr.zTab, rdr.iRowid - ); - } - rc = sqlite3_reset(pQuery); - break; - } - - default: assert( 0 ); - } - if( rc ) break; - } - sqlite3_finalize(pQuery); - } - if( rc==SQLITE_OK ){ - rc = hctBufferAppend(&sql, - "DELETE FROM sqlite_hct_journal WHERE cid>%lld;\n", iLastCont - ); - } - - if( rc==SQLITE_OK ){ - assert( pJrnl->eInWrite==HCT_JOURNAL_NONE ); - pJrnl->eInWrite = HCT_JOURNAL_INROLLBACK; - rc = sqlite3_exec(db, (const char*)sql.aBuf, 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbStartWrite(pJrnl->pDb, &pJrnl->iWriteTid); - } - if( rc==SQLITE_OK ){ - pJrnl->iWriteCid = iLastCont; - pJrnl->iRollbackSnapshot = iLast; - rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); - } - if( rc!=SQLITE_OK ){ - sqlite3_exec(db, "ROLLBACK", 0, 0, 0); - } - pJrnl->eInWrite = HCT_JOURNAL_NONE; - } - - sqlite3_free(sql.aBuf); - sqlite3_finalize(pStmt); - } - - return rc; -} - -static u64 hctJournalFindLastWrite( - int *pRc, /* IN/OUT: Error code */ - HctJournal *pJrnl, /* Journal object */ - u64 iRoot, /* Root page of table */ - i64 iRowid /* Key (for rowid tables) */ -){ - int rc = *pRc; - u64 iRet = 0; - if( rc==SQLITE_OK ){ - HctDbCsr *pCsr = 0; - rc = sqlite3HctDbCsrOpen(pJrnl->pDb, 0, iRoot, &pCsr); - if( rc==SQLITE_OK ){ - rc = sqlite3HctDbCsrFindLastWrite(pCsr, 0, iRowid, &iRet); - sqlite3HctDbCsrClose(pCsr); - } - *pRc = rc; - } - return iRet; -} - -/* -** Write a transaction into the database. -*/ -SQLITE_API int sqlite3_hct_journal_write( - sqlite3 *db, /* Write to "main" db of this handle */ - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid -){ - int rc = SQLITE_OK; - char *zErr = 0; /* Error message, if any */ - HctJournal *pJrnl = 0; - u64 iValidCid = 0; - u64 iSnapshotId = 0; - Btree *pBt = db->aDb[0].pBt; - Schema *pSchema = db->aDb[0].pSchema; - u64 iRoot = 0; /* Root page of zTab */ - HctJrnlServer *pServer = 0; - - HctDataReader rdr; /* For iterating through pData/nData */ - - rc = hctJrnlFind(db, &pJrnl); - if( rc!=SQLITE_OK ) return rc; - pJrnl->eInWrite = HCT_JOURNAL_INWRITE; - pServer = pJrnl->pServer; - - /* Check that the journal is in follower mode */ - if( pServer->eMode!=SQLITE_HCT_JOURNAL_MODE_FOLLOWER ){ - hctJournalSetDbError(db, SQLITE_ERROR, "database is not in FOLLOWER mode"); - return SQLITE_ERROR; - } - - /* Check that there is no transaction open on the connection */ - if( rc==SQLITE_OK && sqlite3_get_autocommit(db)==0 ){ - hctJournalSetDbError(db, SQLITE_ERROR, "open transaction on database"); - return SQLITE_ERROR; - } - - /* Open a concurrent transaction on the db handle. Then ensure that the - ** snapshot on the main database has also been opened. */ - rc = sqlite3_exec(db, "BEGIN CONCURRENT", 0, 0, 0); - if( rc==SQLITE_OK ){ - int dummy = 0; - rc = sqlite3BtreeBeginTrans(pBt, 1, &dummy); - } - - /* Check that the snapshot that was just opened has a schema new enough - ** for this transaction to be applied. */ - if( rc==SQLITE_OK ){ - iSnapshotId = sqlite3HctBtreeSnapshotId(pBt); - if( iSchemaCid>iSnapshotId ){ - rc = SQLITE_BUSY; - zErr = sqlite3_mprintf( - "change may not be applied yet (requires newer schema)" - ); - }else if( (iSnapshotId+HCT_MAX_LEADING_WRITE)aDb[0].pBt, iRoot)==0 ){ - iLastCid = hctJournalFindLastWrite(&rc, pJrnl, iRoot, rdr.iRowid); - } - if( iLastCid>iSnapshotId && iLastCidaDb[0].pBt, iRoot)==0 ){ - u64 iLastCid = 0; - iLastCid = hctJournalFindLastWrite(&rc, pJrnl, iRoot, rdr.iRowid); - if( iLastCid>iSnapshotId && iLastCidpDb, &pJrnl->iWriteTid); - sqlite3HctDbJrnlWriteCid(pJrnl->pDb, iCid); - pJrnl->iWriteCid = iCid; - } - - /* Write the sqlite_hct_journal record directly into the HctTree - ** structure. We don't write via the SQL interface here, because - ** writing to the db once sqlite3HctDbStartWrite() has been called - ** causes assert() failures. And we don't write directly to the db - ** either, because the write needs to be rolled back if there is - ** a conflict. */ - if( rc==SQLITE_OK ){ - u8 *pRec = 0; - int nRec = 0; - - /* TODO: "validcid" value */ - pRec = hctJrnlComposeRecord(iCid, zSchema, - pData, nData, iSchemaCid, pJrnl->iWriteTid, iValidCid, &nRec - ); - if( pRec==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - HctTreeCsr *pCsr = 0; - u64 root = hctFindRootByName(db->aDb[0].pSchema, "sqlite_hct_journal"); - - rc = sqlite3HctTreeCsrOpen(pJrnl->pTree, root, &pCsr); - if( rc==SQLITE_OK ){ - rc = sqlite3HctTreeInsert(pCsr, 0, iCid, nRec, pRec, 0); - sqlite3HctTreeCsrClose(pCsr); - } - } - sqlite3_free(pRec); - - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); - } - if( rc==SQLITE_OK ){ - i64 iVal = iValidCid ? iValidCid : iCid; - i64 *pPtr = (i64*)&pServer->aCommit[iCid % pServer->nCommit]; - - /* If this transaction updated the schema, update the Server.iSchemaCid - ** field as well. This field is not used in FOLLOWER mode, but may be - ** if this process switches to LEADER later on. */ - if( zSchema[0] ){ - HctAtomicStore(&pServer->iSchemaCid, iCid); - } - - assert( iVal>=iCid ); - while( 1 ){ - i64 iExist = *pPtr; - if( iExist>=iVal ) break; - if( HctCASBool(pPtr, iExist, iVal) ) break; - } - assert( *pPtr>=iVal ); - - if( HctAtomicLoad(&pServer->iSnapshot)==0 ){ - (void)HctCASBool(&pServer->iSnapshot, (u64)0, (u64)iCid); - } - } - } - - if( rc!=SQLITE_OK ){ - sqlite3_exec(db, "ROLLBACK", 0, 0, 0); - if( zErr ){ - hctJournalSetDbError(db, rc, "%s", zErr); - sqlite3_free(zErr); - }else{ - hctJournalSetDbError(db, rc, 0); - } - } - pJrnl->eInWrite = HCT_JOURNAL_NONE; - sqlite3HctDbJrnlWriteCid(pJrnl->pDb, 0); - return rc; -} - -static int hctBufferAppendIf(HctBuffer *pBuf, const char *zSep){ - int rc = SQLITE_OK; - if( pBuf->nBuf>0 ){ - rc = hctBufferAppend(pBuf, "%s", zSep); - } - return rc; -} - -static void hctJournalEntryFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ - sqlite3 *db = sqlite3_context_db_handle(pCtx); - const u8 *aEntry = 0; - int nEntry = 0; - int ii = 0; - HctBuffer buf; - const char *zTab = "!"; - const char *zSep = " "; - - assert( nArg==1 ); - memset(&buf, 0, sizeof(buf)); - - nEntry = sqlite3_value_bytes(apArg[0]); - aEntry = (const u8*)sqlite3_value_blob(apArg[0]); - - while( ii */ - -/* - * If compiled on a machine that doesn't have a 32-bit integer, - * you just set "uint32" to the appropriate datatype for an - * unsigned 32-bit integer. For example: - * - * cc -Duint32='unsigned long' md5.c - * - */ -#ifndef uint32 -# define uint32 unsigned int -#endif - -struct MD5Context { - int isInit; - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; -typedef struct MD5Context MD5Context; - -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse (unsigned char *buf, unsigned longs){ - uint32 t; - do { - t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(uint32 *)buf = t; - buf += 4; - } while (--longs); -} -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(uint32 buf[4], const uint32 in[16]){ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -static void MD5Init(MD5Context *ctx){ - ctx->isInit = 1; - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static -void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - if( len ) memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -static void MD5Final(unsigned char digest[16], MD5Context *ctx){ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - memcpy(ctx->in + 14*4, ctx->bits, 8); - - MD5Transform(ctx->buf, (uint32 *)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - memcpy(digest, ctx->buf, 16); -} - -/*************************************************************************/ -/*************************************************************************/ -/*************************************************************************/ - - -/* -** Both arguments are assumed to point to SQLITE_HCT_JOURNAL_HASHSIZE -** byte buffers. This function updates the hash stored in buffer pHash -** based on the contents of buffer pData. -*/ -SQLITE_API void sqlite3_hct_journal_hash(void *pHash, const void *pData){ - MD5Context ctx; - MD5Init(&ctx); - MD5Update(&ctx, pHash, SQLITE_HCT_JOURNAL_HASHSIZE); - MD5Update(&ctx, pData, SQLITE_HCT_JOURNAL_HASHSIZE); - MD5Final(pHash, &ctx); -} - -static void md5U64(MD5Context *pCtx, sqlite3_uint64 iVal){ - u8 aVal[8]; - aVal[0] = (iVal >> 56) & 0xFF; - aVal[1] = (iVal >> 48) & 0xFF; - aVal[2] = (iVal >> 40) & 0xFF; - aVal[3] = (iVal >> 32) & 0xFF; - aVal[4] = (iVal >> 24) & 0xFF; - aVal[5] = (iVal >> 16) & 0xFF; - aVal[6] = (iVal >> 8) & 0xFF; - aVal[7] = (iVal >> 0) & 0xFF; - MD5Update(pCtx, aVal, sizeof(aVal)); -} - -/* -** It is assumed that buffer pHash points to a buffer -** SQLITE_HCT_JOURNAL_HASHSIZE bytes in size. This function populates this -** buffer with a hash based on the remaining arguments. -*/ -SQLITE_API void sqlite3_hct_journal_hashentry( - void *pHash, /* OUT: Hash of other arguments */ - sqlite3_int64 iCid, - const char *zSchema, - const void *pData, int nData, - sqlite3_int64 iSchemaCid -){ - MD5Context ctx; - MD5Init(&ctx); - - md5U64(&ctx, (sqlite3_uint64)iCid); - MD5Update(&ctx, (const u8*)zSchema, sqlite3Strlen30(zSchema)); - MD5Update(&ctx, pData, nData); - md5U64(&ctx, (sqlite3_uint64)iSchemaCid); - - MD5Final(pHash, &ctx); -} - - -/************** End of hct_journalhash.c *************************************/ /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } -#endif /* SQLITE_AMALGAMATION */ /************************** End of sqlite3.c ******************************/ diff --git a/libstuff/sqlite3.h b/libstuff/sqlite3.h index 12fe5fda2..263e6356b 100644 --- a/libstuff/sqlite3.h +++ b/libstuff/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.48.0" -#define SQLITE_VERSION_NUMBER 3048000 -#define SQLITE_SOURCE_ID "2024-11-15 19:25:39 ed829bf2b069a48c644ae5706399dad7486e5abb87dc1225764038ac258ea4dc" +#define SQLITE_VERSION "3.47.0" +#define SQLITE_VERSION_NUMBER 3047000 +#define SQLITE_SOURCE_ID "2024-11-13 14:42:32 35aa893d4537d0b3605084a1f2f5529794e82af59b8893053815d3fcb4719a27" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -652,13 +652,6 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. -** -** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read -** from the database file in amounts that are not a multiple of the -** page size and that do not begin at a page boundary. Without this -** property, SQLite is careful to only do full-page reads and write -** on aligned pages, with the one exception that it will do a sub-page -** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -675,7 +668,6 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 -#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -822,7 +814,6 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] -**
  • [SQLITE_IOCAP_SUBPAGE_READ] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1100,11 +1091,6 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** -**
  • [[SQLITE_FCNTL_NULL_IO]] -** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor -** or file handle for the [sqlite3_file] object such that it will no longer -** read or write to the database file. -** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1258,7 +1244,6 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 -#define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2637,14 +2622,10 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE, +** and that if the number of rows modified by the most recent INSERT, UPDATE ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. -** For the purposes of this interface, a CREATE TABLE AS SELECT statement -** does not count as an INSERT, UPDATE or DELETE statement and hence the rows -** added to the new table by the CREATE TABLE AS SELECT statement are not -** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -4241,17 +4222,13 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the -** first zero terminator. ^If nByte is positive, then it is the maximum -** number of bytes read from zSql. When nByte is positive, zSql is read -** up to the first zero terminator or until the nByte bytes have been read, -** whichever comes first. ^If nByte is zero, then no prepared +** first zero terminator. ^If nByte is positive, then it is the +** number of bytes read from zSql. ^If nByte is zero, then no prepared ** statement is generated. ** If the caller knows that the supplied string is nul-terminated, then ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. -** Note that nByte measure the length of the input in bytes, not -** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5622,7 +5599,7 @@ SQLITE_API int sqlite3_create_window_function( ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). -** All SQL functions that invoke [sqlite3_value_subtype()] should have this +** SQL functions that invokes [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. @@ -8387,9 +8364,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ -#define SQLITE_TESTCTRL_HCT_MTCOMMIT 35 -#define SQLITE_TESTCTRL_LAST 35 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_USELONGDOUBLE 34 +#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -9364,16 +9340,6 @@ typedef struct sqlite3_backup sqlite3_backup; ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. -** -** Alternatives To Using The Backup API -** -** Other techniques for safely creating a consistent backup of an SQLite -** database include: -** -**
      -**
    • The [VACUUM INTO] command. -**
    • The [sqlite3_rsync] utility program. -**
    */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ @@ -10573,14 +10539,6 @@ typedef struct sqlite3_snapshot { ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** -** If a read-transaction is opened by this function, then it is guaranteed -** that the returned snapshot object may not be invalidated by a database -** writer or checkpointer until after the read-transaction is closed. This -** is not guaranteed if a read-transaction is already open when this -** function is called. In that case, any subsequent write or checkpoint -** operation on the database may invalidate the returned snapshot handle, -** even while the read-transaction remains open. -** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined @@ -11003,9 +10961,6 @@ SQLITE_API int sqlite3_commit_status( # undef double #endif -SQLITE_API void sqlite3_hct_cas_failure(int nCASFailCnt, int nCASFailReset); -SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); - #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 @@ -11020,7 +10975,7 @@ SQLITE_API void sqlite3_hct_proc_failure(int nProcFailCnt); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ +#endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ /* @@ -13399,6 +13354,7 @@ struct Fts5ExtensionApi { ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting +** ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** @@ -13742,4 +13698,3 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ -#endif /* SQLITE3_H */ diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index d30542694..86424dfb5 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -17,7 +17,7 @@ PortMap BedrockTester::ports; mutex BedrockTester::_testersMutex; set BedrockTester::_testers; -const bool BedrockTester::ENABLE_HCTREE{true}; +const bool BedrockTester::ENABLE_HCTREE{false}; string BedrockTester::getTempFileName(string prefix) { string templateStr = "/tmp/" + prefix + "bedrocktest_XXXXXX.db"; From 7d1ee380b77dc89500e429889d11210652ffcf32 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Wed, 20 Nov 2024 14:43:09 -0800 Subject: [PATCH 11/11] Remove unused header --- libstuff/SSignal.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libstuff/SSignal.cpp b/libstuff/SSignal.cpp index 158536d7d..6b8ac7f2f 100644 --- a/libstuff/SSignal.cpp +++ b/libstuff/SSignal.cpp @@ -9,7 +9,6 @@ #include #include -#include thread_local function SSignalHandlerDieFunc; void SSetSignalHandlerDieFunc(function&& func) { SSignalHandlerDieFunc = move(func);