diff --git a/BUILD.gn b/BUILD.gn index 3b03c3791046de8e2318c198c969cf877be217e9..c34bc83769f24835b6d115ae202ed44ccb2d35e3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -112,6 +112,7 @@ ohos_shared_library("sqlite") { "SQLITE_DIRECT_OVERFLOW_READ", "SQLITE_HAS_CODEC", "SQLITE_EXPORT_SYMBOLS", + "SQLITE_API=SQLITE_EXPORT", "SQLITE_SHARED_BLOCK_OPTIMIZATION", "SQLITE_CODEC_ATTACH_CHANGED", "SQLITE_ENABLE_DROPTABLE_CALLBACK", @@ -158,10 +159,7 @@ ohos_shared_library("sqlite") { ohos_executable("sqlite3") { include_dirs = [ "$sqlite_patched_dir/include" ] - sources = [ - "$sqlite_patched_dir/src/shell.c", - "$sqlite_patched_dir/src/sqlite3.c", - ] + sources = ["$sqlite_patched_dir/src/shell.c"] defines = [ "NDEBUG=1", @@ -192,10 +190,20 @@ ohos_executable("sqlite3") { cflags = [ "-Wno-error=implicit-function-declaration", + "-Wno-macro-redefined", "-Wno-implicit-fallthrough", ] - deps = [ "//third_party/sqlite/patch:apply_patch" ] + deps = [ + ":sqlite", + "//third_party/sqlite/patch:apply_patch", + ] + + public_configs = [ ":sqlite_config" ] + external_deps = [ "c_utils:utils" ] + configs = [ ":sqlite3_private_config" ] + part_name = "sqlite" + subsystem_name = "thirdparty" } if (is_mingw || is_mac) { diff --git a/README.OpenSource b/README.OpenSource index 51af6ce96e67289891fd9f2554e9d322daa58b95..d1cd45244a8c4fe5b0ea9b90be9bd6656a017d22 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,9 +3,9 @@ "Name": "SQLite", "License": "Public Domain", "License File": "LICENSE", - "Version Number": "3.46.1", + "Version Number": "3.40.1", "Owner": "wangbingquan@huawei.com", - "Upstream URL": "https://sqlite.ac.cn/2024/sqlite-amalgamation-3460100.zip", + "Upstream URL": "https://www.sqlite.org/2022/sqlite-amalgamation-3400100.zip", "Description": "SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine." } ] diff --git a/bundle.json b/bundle.json index cc2fc2757e405992d5bf437d8d9b836ffe9d3f86..9d0f67e493a6d17e0924d29318387d0e09cd2806 100644 --- a/bundle.json +++ b/bundle.json @@ -1,7 +1,7 @@ { "name": "@ohos/sqlite", "description": "SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.", - "version": "3.46.1", + "version": "3.40.1", "homePage": "https://www.sqlite.org/", "license": "Public Domain", "publishAs": "code-segment", @@ -31,6 +31,7 @@ "build": { "sub_component": [ "//third_party/sqlite:sqlite", + "//third_party/sqlite:sqlite3", "//third_party/sqlite:sqliteicu" ], "inner_kits": [ @@ -46,6 +47,9 @@ }, { "name": "//third_party/sqlite:sqliteicu" + }, + { + "name": "//third_party/sqlite:sqlite3" } ], "test": [] diff --git a/include/sqlite3.h b/include/sqlite3.h index 3b1a37a5f9f9dd316545f5714549933f223b70b8..4e24bca219f7617799c1b4e974c45b7da8facce7 100644 --- a/include/sqlite3.h +++ b/include/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.46.1" -#define SQLITE_VERSION_NUMBER 3046001 -#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33" +#define SQLITE_VERSION "3.40.1" +#define SQLITE_VERSION_NUMBER 3040001 +#define SQLITE_SOURCE_ID "2022-12-28 14:03:47 df5c253c0b3dd24916e4ec7cf77d3db5294cc9fd45ae7b9c5e82ad8197f38a24" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -420,8 +420,6 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
-** The SQLITE_DIRECTONLY flag is recommended for any -** [application-defined SQL function] -** that has side-effects or that could potentially leak sensitive information. -** This will prevent attacks in which an application is tricked -** into using a database file that has had its schema surreptitiously -** modified to invoke the application-defined function in ways that are -** harmful. -**
-** Some people say it is good practice to set SQLITE_DIRECTONLY on all -** [application-defined SQL functions], regardless of whether or not they -** are security sensitive, as doing so prevents those functions from being used -** inside of the database schema, and thus ensures that the database -** can be inspected and modified using generic tools (such as the [CLI]) -** that do not have access to the application-defined functions. +** The SQLITE_DIRECTONLY flags is a security feature which is recommended +** for all [application-defined SQL functions], and especially for functions +** that have side-effects or that could potentially leak sensitive +** information. **
Otherwise, "BINARY" is returned. ** */ -SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Determine if a virtual table query is DISTINCT @@ -10004,45 +9721,24 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means ** that the query planner does not need the rows returned in any particular -** order, as long as rows with the same values in all columns identified -** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows -** contain the same values for all columns identified by "colUsed", all but -** one such row may optionally be omitted from the result.)^ -** The virtual table is not required to omit rows that are duplicates -** over the "colUsed" columns, but if the virtual table can do that without -** too much extra effort, it could potentially help the query to run faster. +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is always ok for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. ** This mode is used for a DISTINCT query. **
-** ^(If the sqlite3_vtab_distinct() interface returns 3, that means the -** virtual table must return rows in the order defined by "aOrderBy" as -** if the sqlite3_vtab_distinct() interface had returned 0. However if -** two or more rows in the result have the same values for all columns -** identified by "colUsed", then all but one such row may optionally be -** omitted.)^ Like when the return value is 2, the virtual table -** is not required to omit rows that are duplicates over the "colUsed" -** columns, but if the virtual table can do that without -** too much extra effort, it could potentially help the query to run faster. -** This mode is used for queries +** ^(If the sqlite3_vtab_distinct() interface returns 3, that means +** that the query planner needs only distinct rows but it does need the +** rows to be sorted.)^ ^The virtual table implementation is free to omit +** rows that are identical in all aOrderBy columns, if it wants to, but +** it is not required to omit any rows. This mode is used for queries ** that have both DISTINCT and ORDER BY clauses. ** ** -**
The following table summarizes the conditions under which the -** virtual table is allowed to set the "orderByConsumed" flag based on -** the value returned by sqlite3_vtab_distinct(). This table is a -** restatement of the previous four paragraphs: -** -**
sqlite3_vtab_distinct() return value -** | Rows are returned in aOrderBy order -** | Rows with the same value in all aOrderBy columns are adjacent -** | Duplicates over all colUsed columns may be omitted -** |
0 | yes | yes | no -** |
1 | no | yes | no -** |
2 | no | yes | yes -** |
3 | yes | yes | yes -** |
** for(rc=sqlite3_vtab_in_first(pList, &pVal); -** rc==SQLITE_OK && pVal; +** rc==SQLITE_OK && pVal ** rc=sqlite3_vtab_in_next(pList, &pVal) ** ){ ** // do something with pVal @@ -10259,10 +9956,6 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** -** Not all values are available for all query elements. When a value is -** not available, the output variable is set to -1 if the value is numeric, -** or to NULL if it is a string (SQLITE_SCANSTAT_NAME). -** **** [[SQLITE_SCANSTAT_NLOOP]]
*/ #define SQLITE_SCANSTAT_NLOOP 0 @@ -10316,14 +9997,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** #define SQLITE_SCANSTAT_NAME 3 #define SQLITE_SCANSTAT_EXPLAIN 4 #define SQLITE_SCANSTAT_SELECTID 5 -#define SQLITE_SCANSTAT_PARENTID 6 -#define SQLITE_SCANSTAT_NCYCLE 7 /* ** CAPI3REF: Prepared Statement Scan Status ** METHOD: sqlite3_stmt ** -** These interfaces return information about the predicted and measured +** This interface returns information about the predicted and measured ** performance for pStmt. Advanced applications can use this ** interface to compare the predicted and the measured performance and ** issue warnings and/or rerun [ANALYZE] if discrepancies are found. @@ -10334,25 +10013,19 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** ** The "iScanStatusOp" parameter determines which status information to return. ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior -** of this interface is undefined. ^The requested measurement is written into -** a variable pointed to by the "pOut" parameter. -** -** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX -** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If -** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements -** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of -** the EXPLAIN QUERY PLAN output) are available. Invoking API -** sqlite3_stmt_scanstatus() is equivalent to calling -** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter. -** -** Parameter "idx" identifies the specific query element to retrieve statistics -** for. Query elements are numbered starting from zero. A value of -1 may be -** to query for statistics regarding the entire query. ^If idx is out of range -** - less than -1 or greater than or equal to the total number of query -** elements used to implement the statement - a non-zero value is returned and -** the variable that pOut points to is unchanged. +** of this interface is undefined. +** ^The requested measurement is written into a variable pointed to by +** the "pOut" parameter. +** Parameter "idx" identifies the specific loop to retrieve statistics for. +** Loops are numbered starting from zero. ^If idx is out of range - less than +** zero or greater than or equal to the total number of loops used to implement +** the statement - a non-zero value is returned and the variable that pOut +** points to is unchanged. +** +** ^Statistics might not be available for all loops in all statements. ^In cases +** where there exist loops with no available statistics, this function behaves +** as if the loop did not exist - it returns non-zero and leave the variable +** that pOut points to unchanged. ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ @@ -10362,19 +10035,6 @@ SQLITE_API int sqlite3_stmt_scanstatus( int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ ); -SQLITE_API int sqlite3_stmt_scanstatus_v2( - sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ - int idx, /* Index of loop to report on */ - int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ - int flags, /* Mask of flags defined below */ - void *pOut /* Result written here */ -); - -/* -** CAPI3REF: Prepared Statement Scan Status -** KEYWORDS: {scan status flags} -*/ -#define SQLITE_SCANSTAT_COMPLEX 0x0001 /* ** CAPI3REF: Zero Scan-Status Counters @@ -10465,10 +10125,6 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** -** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from -** the previous call on the same [database connection] D, or NULL for -** the first call on D. -** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines @@ -10508,7 +10164,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** When the [sqlite3_blob_write()] API is used to update a blob column, ** the pre-update hook is invoked with SQLITE_DELETE. This is because the ** in this case the new values are not available. In this case, when a -** callback made with op==SQLITE_DELETE is actually a write using the +** callback made with op==SQLITE_DELETE is actuall a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the ** pre-update hook is being invoked for some other reason, including a @@ -10769,13 +10425,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** -** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set, -** the returned buffer content will remain accessible and unchanged -** until either the next write operation on the connection or when -** the connection is closed, and applications must not modify the -** buffer. If the bit had been clear, the returned buffer will not -** be accessed by SQLite after the call. -** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. @@ -10824,9 +10473,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** -** Applications must not modify the buffer P or invalidate it before -** the database connection D is closed. -** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. @@ -10835,13 +10481,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** -** The deserialized database should not be in [WAL mode]. If the database -** is in WAL mode, then any attempt to use the database file will result -** in an [SQLITE_CANTOPEN] error. The application can set the -** [file format version numbers] (bytes 18 and 19) of the input database P -** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the -** database file into rollback mode and work around this limitation. -** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. @@ -10891,19 +10530,6 @@ SQLITE_API int sqlite3_deserialize( # undef double #endif -#if defined(__wasi__) -# undef SQLITE_WASI -# define SQLITE_WASI 1 -# undef SQLITE_OMIT_WAL -# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */ -# ifndef SQLITE_OMIT_LOAD_EXTENSION -# define SQLITE_OMIT_LOAD_EXTENSION -# endif -# ifndef SQLITE_THREADSAFE -# define SQLITE_THREADSAFE 0 -# endif -#endif - #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif @@ -11110,20 +10736,16 @@ SQLITE_API int sqlite3session_create( SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* -** CAPI3REF: Configure a Session Object +** CAPIREF: Conigure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been -** created. At present the only valid values for the second parameter are -** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID]. +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. ** -*/ -SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); - -/* -** CAPI3REF: Options for sqlite3session_object_config +** Arguments for sqlite3session_object_config() ** -** The following values may passed as the the 2nd parameter to +** The following values may passed as the the 4th parameter to ** sqlite3session_object_config(). ** **- SQLITE_SCANSTAT_NLOOP
**- ^The [sqlite3_int64] variable pointed to by the V parameter will be @@ -10290,24 +9983,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** -** [[SQLITE_SCANSTAT_SELECTID]]
- SQLITE_SCANSTAT_SELECTID
+** [[SQLITE_SCANSTAT_SELECTID]]- SQLITE_SCANSTAT_SELECT
**- ^The "int" variable pointed to by the V parameter will be set to the -** id for the X-th query plan element. The id value is unique within the -** statement. The select-id is the same value as is output in the first -** column of an [EXPLAIN QUERY PLAN] query. -** -** [[SQLITE_SCANSTAT_PARENTID]]
- SQLITE_SCANSTAT_PARENTID
-**- The "int" variable pointed to by the V parameter will be set to the -** the id of the parent of the current query element, if applicable, or -** to zero if the query element has no parent. This is the same value as -** returned in the second column of an [EXPLAIN QUERY PLAN] query. -** -** [[SQLITE_SCANSTAT_NCYCLE]]
- SQLITE_SCANSTAT_NCYCLE
-**- The sqlite3_int64 output value is set to the number of cycles, -** according to the processor time-stamp counter, that elapsed while the -** query element was being processed. This value is not available for -** all query elements - if it is unavailable the output variable is -** set to -1. +** "select-id" for the X-th loop. The select-id identifies which query or +** subquery the loop is part of. The main query has a select-id of zero. +** The select-id is the same value as is output in the first column +** of an [EXPLAIN QUERY PLAN] query. **
SQLITE_SESSION_OBJCONFIG_SIZE @@ -11139,21 +10761,12 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. -** -** SQLITE_SESSION_OBJCONFIG_ROWID -** This option is used to set, clear or query the flag that enables -** collection of data for tables with no explicit PRIMARY KEY. -** -** Normally, tables with no explicit PRIMARY KEY are simply ignored -** by the sessions module. However, if this flag is set, it behaves -** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted -** as their leftmost columns. -** -** It is an error (SQLITE_MISUSE) to attempt to modify this setting after -** the first table has been attached to the session object. */ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 -#define SQLITE_SESSION_OBJCONFIG_ROWID 2 +SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object @@ -11914,18 +11527,6 @@ SQLITE_API int sqlite3changeset_concat( ); -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -11972,38 +11573,6 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); -/* -** CAPI3REF: Add a Schema to a Changegroup -** METHOD: sqlite3_changegroup_schema -** -** This method may be used to optionally enforce the rule that the changesets -** added to the changegroup handle must match the schema of database zDb -** ("main", "temp", or the name of an attached database). If -** sqlite3changegroup_add() is called to add a changeset that is not compatible -** with the configured schema, SQLITE_SCHEMA is returned and the changegroup -** object is left in an undefined state. -** -** A changeset schema is considered compatible with the database schema in -** the same way as for sqlite3changeset_apply(). Specifically, for each -** table in the changeset, there exists a database table with: -** -** -**
-** -** The output of the changegroup object always has the same schema as the -** database nominated using this function. In cases where changesets passed -** to sqlite3changegroup_add() have fewer columns than the corresponding table -** in the database schema, these are filled in using the default column -** values from the database schema. This makes it possible to combined -** changesets that have different numbers of columns for a single table -** within a changegroup, provided that they are otherwise compatible. -*/ -SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); - /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup @@ -12072,45 +11641,16 @@ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const c ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the -** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup -** object has been configured with a database schema using the -** sqlite3changegroup_schema() API, then it is possible to combine changesets -** with different numbers of columns for a single table, provided that -** they are otherwise compatible. -** -** If the input changeset appears to be corrupt and the corruption is -** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition -** occurs during processing, this function returns SQLITE_NOMEM. +** case, this function fails with SQLITE_SCHEMA. If the input changeset +** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is +** returned. Or, if an out-of-memory condition occurs during processing, this +** function returns SQLITE_NOMEM. In all cases, if an error occurs the state +** of the final contents of the changegroup is undefined. ** -** In all cases, if an error occurs the state of the final contents of the -** changegroup is undefined. If no error occurs, SQLITE_OK is returned. +** If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); -/* -** CAPI3REF: Add A Single Change To A Changegroup -** METHOD: sqlite3_changegroup -** -** This function adds the single change currently indicated by the iterator -** passed as the second argument to the changegroup object. The rules for -** adding the change are just as described for [sqlite3changegroup_add()]. -** -** If the change is successfully added to the changegroup, SQLITE_OK is -** returned. Otherwise, an SQLite error code is returned. -** -** The iterator must point to a valid entry when this function is called. -** If it does not, SQLITE_ERROR is returned and no change is added to the -** changegroup. Additionally, the iterator must not have been opened with -** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also -** returned. -*/ -SQLITE_API int sqlite3changegroup_add_change( - sqlite3_changegroup*, - sqlite3_changeset_iter* -); - - - /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup @@ -12359,30 +11899,9 @@ SQLITE_API int sqlite3changeset_apply_v2( ** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. -** -**- The name identified by the changeset, and -**
- at least as many columns as recorded in the changeset, and -**
- the primary key columns in the same position as recorded in -** the changeset. -**
SQLITE_CHANGESETAPPLY_IGNORENOOP -** Do not invoke the conflict handler callback for any changes that -** would not actually modify the database even if they were applied. -** Specifically, this means that the conflict handler is not invoked -** for: -** -**
-** -**- a delete change if the row being deleted cannot be found, -**
- an update change if the modified fields are already set to -** their new values in the conflicting row, or -**
- an insert change if all fields of the conflicting row match -** the row being inserted. -**
SQLITE_CHANGESETAPPLY_FKNOACTION -** If this flag it set, then all foreign key constraints in the target -** database behave as if they were declared with "ON UPDATE NO ACTION ON -** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL -** or SET DEFAULT. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 -#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 -#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -12915,8 +12434,8 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken @@ -12948,11 +12467,8 @@ struct Fts5PhraseIter { ** created with the "columnsize=0" option. ** ** xColumnText: -** 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 text of column iCol of -** the current document. If successful, (*pz) is set to point to a buffer +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values @@ -12962,10 +12478,8 @@ struct Fts5PhraseIter { ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** If parameter iCol is less than zero, or greater than or equal to the -** number of phrases in the current query, as returned by xPhraseCount, -** 0 is returned. Otherwise, this function returns the number of tokens in -** phrase iPhrase of the query. Phrases are numbered starting from zero. +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within @@ -12981,13 +12495,12 @@ struct Fts5PhraseIter { ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value -** output by xInstCount(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -13013,10 +12526,6 @@ struct Fts5PhraseIter { ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** -** If parameter iPhrase is less than zero, or greater than or equal to -** the number of phrases in the query, as returned by xPhraseCount(), -** this function returns SQLITE_RANGE. -** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. @@ -13131,39 +12640,6 @@ struct Fts5PhraseIter { ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. -** -** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase iPhrase of the current -** query. Before returning, output parameter *ppToken is set to point -** to a buffer containing the requested token, and *pnToken to the -** size of this buffer in bytes. -** -** If iPhrase or iToken are less than zero, or if iPhrase is greater than -** or equal to the number of phrases in the query as reported by -** xPhraseCount(), or if iToken is equal to or greater than the number of -** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken - are both zeroed. -** -** The output text is not a copy of the query text that specified the -** token. It is the output of the tokenizer module. For tokendata=1 -** tables, this includes any embedded 0x00 and trailing data. -** -** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase hit iIdx within the -** current row. If iIdx is less than zero or greater than or equal to the -** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, -** output variable (*ppToken) is set to point to a buffer containing the -** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. -** -** The output text is not a copy of the document text that was tokenized. -** It is the output of the tokenizer module. For tokendata=1 tables, this -** includes any embedded 0x00 and trailing data. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. */ struct Fts5ExtensionApi { int iVersion; /* Currently always set to 3 */ @@ -13201,13 +12677,6 @@ struct Fts5ExtensionApi { int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); - - /* Below this point are iVersion>=3 only */ - int (*xQueryToken)(Fts5Context*, - int iPhrase, int iToken, - const char **ppToken, int *pnToken - ); - int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); }; /* @@ -13402,8 +12871,8 @@ struct Fts5ExtensionApi { ** as separate queries of the FTS index are required for each synonym. ** ** When using methods (2) or (3), it is important that the tokenizer only -** provide synonyms when tokenizing document text (method (3)) or query -** text (method (2)), not both. Doing so will not cause any errors, but is +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; @@ -13451,7 +12920,7 @@ struct fts5_api { int (*xCreateTokenizer)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_tokenizer *pTokenizer, void (*xDestroy)(void*) ); @@ -13460,7 +12929,7 @@ struct fts5_api { int (*xFindTokenizer)( fts5_api *pApi, const char *zName, - void **ppUserData, + void **ppContext, fts5_tokenizer *pTokenizer ); @@ -13468,7 +12937,7 @@ struct fts5_api { int (*xCreateFunction)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_extension_function xFunction, void (*xDestroy)(void*) ); diff --git a/include/sqlite3ext.h b/include/sqlite3ext.h index 437cd3ebab7d3ca3f696b0fb9629abdecd42ed94..03b6f35f107476e1672c5b329afa899b5aba51a8 100644 --- a/include/sqlite3ext.h +++ b/include/sqlite3ext.h @@ -359,15 +359,10 @@ struct sqlite3_api_routines { const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); - /* Version 3.41.0 and later */ - int (*is_interrupted)(sqlite3*); - /* Version 3.43.0 and later */ - int (*stmt_explain)(sqlite3_stmt*,int); - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK /* handle after drop table done */ int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); +#endif }; /* @@ -395,7 +390,7 @@ typedef int (*sqlite3_loadext_entry)( #ifdef SQLITE3_EXPORT_SYMBOLS extern const sqlite3_api_routines *sqlite3_export_symbols; #define sqlite3_api sqlite3_export_symbols -#endif /* SQLITE3_EXPORT_SYMBOLS */ +#endif #define sqlite3_aggregate_context sqlite3_api->aggregate_context #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_aggregate_count sqlite3_api->aggregate_count @@ -698,16 +693,11 @@ extern const sqlite3_api_routines *sqlite3_export_symbols; #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding -/* Version 3.41.0 and later */ -#define sqlite3_is_interrupted sqlite3_api->is_interrupted -/* Version 3.43.0 and later */ -#define sqlite3_stmt_explain sqlite3_api->stmt_explain -/* Version 3.44.0 and later */ -#define sqlite3_get_clientdata sqlite3_api->get_clientdata -#define sqlite3_set_clientdata sqlite3_api->set_clientdata +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK /* handle after drop table done */ #define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle -#endif /* !defined(SQLITE_CORE) && (!defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE3_EXPORT_SYMBOLS)) */ +#endif +#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable diff --git a/include/sqlite3icu.h b/include/sqlite3icu.h index be58299e46c98cd6ddee5cce82d0966b05ce5304..8c680bc7cab8a2aa730a4bdfa8d0f10954c392e6 100644 --- a/include/sqlite3icu.h +++ b/include/sqlite3icu.h @@ -1,50 +1,50 @@ -/* -** 2001-09-15 -** -** 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. -** -************************************************************************* -*/ -#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) -/************** Include sqliteicu.h in the middle of main.c ******************/ -/************** Begin file sqliteicu.h ***************************************/ -/* -** 2008 May 26` -** -** 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 is used by programs that want to link against the -** ICU extension. All it does is declare the sqlite3IcuInit() interface. -*/ -#include "sqlite3sym.h" -#include "sqlite3tokenizer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SQLITE_API int sqlite3IcuInit(sqlite3 *db); - -/************** End of sqliteicu.h *******************************************/ -/************** Continuing where we left off in main.c ***********************/ -#endif - -#ifdef SQLITE_ENABLE_ICU -SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#endif - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif \ No newline at end of file +/* +** 2001-09-15 +** +** 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. +** +************************************************************************* +*/ +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) +/************** Include sqliteicu.h in the middle of main.c ******************/ +/************** Begin file sqliteicu.h ***************************************/ +/* +** 2008 May 26` +** +** 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 is used by programs that want to link against the +** ICU extension. All it does is declare the sqlite3IcuInit() interface. +*/ +#include "sqlite3sym.h" +#include "sqlite3tokenizer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SQLITE_API int sqlite3IcuInit(sqlite3 *db); + +/************** End of sqliteicu.h *******************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif + +#ifdef SQLITE_ENABLE_ICU +SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#endif + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif \ No newline at end of file diff --git a/include/sqlite3tokenizer.h b/include/sqlite3tokenizer.h index a7f10ca49c6ee3a56cbab174c655a1800dbf68da..b1a1f097e5f4a98011323ad4afa18214f12b9f42 100644 --- a/include/sqlite3tokenizer.h +++ b/include/sqlite3tokenizer.h @@ -1,145 +1,145 @@ -/* -** 2001-09-15 -** -** 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. -** -************************************************************************* -*/ -/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. -** If tokenizers are to be allowed to call sqlite3_*() functions, then -** we will need a way to register the API consistently. -*/ -/* #include "sqlite3.h" */ - -/* -** Structures used by the tokenizer interface. When a new tokenizer -** implementation is registered, the caller provides a pointer to -** an sqlite3_tokenizer_module containing pointers to the callback -** functions that make up an implementation. -** -** When an fts3 table is created, it passes any arguments passed to -** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the -** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer -** implementation. The xCreate() function in turn returns an -** sqlite3_tokenizer structure representing the specific tokenizer to -** be used for the fts3 table (customized by the tokenizer clause arguments). -** -** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() -** method is called. It returns an sqlite3_tokenizer_cursor object -** that may be used to tokenize a specific input buffer based on -** the tokenization rules supplied by a specific sqlite3_tokenizer -** object. -*/ -typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; -typedef struct sqlite3_tokenizer sqlite3_tokenizer; -typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; - -struct sqlite3_tokenizer_module { - - /* - ** Structure version. Should always be set to 0 or 1. - */ - int iVersion; - - /* - ** Create a new tokenizer. The values in the argv[] array are the - ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL - ** TABLE statement that created the fts3 table. For example, if - ** the following SQL is executed: - ** - ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) - ** - ** then argc is set to 2, and the argv[] array contains pointers - ** to the strings "arg1" and "arg2". - ** - ** This method should return either SQLITE_OK (0), or an SQLite error - ** code. If SQLITE_OK is returned, then *ppTokenizer should be set - ** to point at the newly created tokenizer structure. The generic - ** sqlite3_tokenizer.pModule variable should not be initialized by - ** this callback. The caller will do so. - */ - int (*xCreate)( - int argc, /* Size of argv array */ - const char *const*argv, /* Tokenizer argument strings */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ - ); - - /* - ** Destroy an existing tokenizer. The fts3 module calls this method - ** exactly once for each successful call to xCreate(). - */ - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Create a tokenizer cursor to tokenize an input buffer. The caller - ** is responsible for ensuring that the input buffer remains valid - ** until the cursor is closed (using the xClose() method). - */ - int (*xOpen)( - sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ - const char *pInput, int nBytes, /* Input buffer */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ - ); - - /* - ** Destroy an existing tokenizer cursor. The fts3 module calls this - ** method exactly once for each successful call to xOpen(). - */ - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - - /* - ** Retrieve the next token from the tokenizer cursor pCursor. This - ** method should either return SQLITE_OK and set the values of the - ** "OUT" variables identified below, or SQLITE_DONE to indicate that - ** the end of the buffer has been reached, or an SQLite error code. - ** - ** *ppToken should be set to point at a buffer containing the - ** normalized version of the token (i.e. after any case-folding and/or - ** stemming has been performed). *pnBytes should be set to the length - ** of this buffer in bytes. The input text that generated the token is - ** identified by the byte offsets returned in *piStartOffset and - ** *piEndOffset. *piStartOffset should be set to the index of the first - ** byte of the token in the input buffer. *piEndOffset should be set - ** to the index of the first byte just past the end of the token in - ** the input buffer. - ** - ** The buffer *ppToken is set to point at is managed by the tokenizer - ** implementation. It is only required to be valid until the next call - ** to xNext() or xClose(). - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xNext)( - sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ - const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ - int *piStartOffset, /* OUT: Byte offset of token in input buffer */ - int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ - int *piPosition /* OUT: Number of tokens returned before this one */ - ); - - /*********************************************************************** - ** Methods below this point are only available if iVersion>=1. - */ - - /* - ** Configure the language id of a tokenizer cursor. - */ - int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); -}; - -struct sqlite3_tokenizer { - const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; - -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; \ No newline at end of file +/* +** 2001-09-15 +** +** 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. +** +************************************************************************* +*/ +/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. +** If tokenizers are to be allowed to call sqlite3_*() functions, then +** we will need a way to register the API consistently. +*/ +/* #include "sqlite3.h" */ + +/* +** Structures used by the tokenizer interface. When a new tokenizer +** implementation is registered, the caller provides a pointer to +** an sqlite3_tokenizer_module containing pointers to the callback +** functions that make up an implementation. +** +** When an fts3 table is created, it passes any arguments passed to +** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the +** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer +** implementation. The xCreate() function in turn returns an +** sqlite3_tokenizer structure representing the specific tokenizer to +** be used for the fts3 table (customized by the tokenizer clause arguments). +** +** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() +** method is called. It returns an sqlite3_tokenizer_cursor object +** that may be used to tokenize a specific input buffer based on +** the tokenization rules supplied by a specific sqlite3_tokenizer +** object. +*/ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; \ No newline at end of file diff --git a/patch/0001-BaselineWithHistoryOH.patch b/patch/0001-BaselineWithHistoryOH.patch index ef9b8cf801f2719c6123e55d26aa1b25d3ca74c9..af43fdf5e5ff2d285a9b0af819378282a77ac717 100644 --- a/patch/0001-BaselineWithHistoryOH.patch +++ b/patch/0001-BaselineWithHistoryOH.patch @@ -1,30 +1,28 @@ -From f2e21aa63fb875f21e963ba046850e8f9dd4a86d Mon Sep 17 00:00:00 2001 -From: linzhuobin1 -Date: Mon, 24 Feb 2025 18:36:42 +0800 -Subject: [PATCH] IssueNo:#IBNXAW Description:Sqlite baseline update to 3.46.1 - with patch-1-1 Sig: SIG_DataManagement Feature or Bugfix:Feature Binary - Source:No/Yes TDD:Pass/Fail/NA XTS:Pass/Fail/NA Pretest:Pass/Fail/NA +From 04d6f09752f3c7ac5111c3274dbb031fd2530fb5 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Fri, 11 Apr 2025 17:36:47 +0800 +Subject: [PATCH 1/7] BaselineWithHistoryOH -Signed-off-by: linzhuobin1 + Signed-off-by: ryne3366 --- - src/sqlite3.c | 2841 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 2824 insertions(+), 17 deletions(-) + src/sqlite3.c | 2863 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 2823 insertions(+), 40 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index 946815f..d2bfc23 100644 +index 3469f92..a935685 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -881,6 +881,7 @@ SQLITE_API int sqlite3_exec( +@@ -870,6 +870,7 @@ SQLITE_API int sqlite3_exec( + #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) - #define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) +#define SQLITE_WARNING_DUMP (SQLITE_WARNING | (2<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ -@@ -2845,6 +2846,11 @@ struct sqlite3_mem_methods { - #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ - #define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +@@ -2832,6 +2833,11 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + */ + SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION +#define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 @@ -32,9 +30,9 @@ index 946815f..d2bfc23 100644 +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + /* - ** CAPI3REF: Enable Or Disable Extended Result Codes + ** CAPI3REF: Set the Last Insert Rowid value. ** METHOD: sqlite3 -@@ -5316,6 +5322,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); +@@ -5174,6 +5180,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); */ SQLITE_API int sqlite3_step(sqlite3_stmt*); @@ -45,7 +43,7 @@ index 946815f..d2bfc23 100644 /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt -@@ -6716,6 +6726,44 @@ SQLITE_API int sqlite3_collation_needed16( +@@ -6439,6 +6449,44 @@ SQLITE_API int sqlite3_collation_needed16( void(*)(void*,sqlite3*,int eTextRep,const void*) ); @@ -90,7 +88,7 @@ index 946815f..d2bfc23 100644 #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless -@@ -10162,6 +10210,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); +@@ -9872,6 +9920,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); @@ -118,16 +116,21 @@ index 946815f..d2bfc23 100644 /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** -@@ -10221,7 +10290,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); - ** Otherwise, "BINARY" is returned. - ** - */ --SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); -+SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +@@ -14914,13 +14983,6 @@ typedef int VList; + # define SQLITE_MAX_PATHLEN FILENAME_MAX + #endif +-/* Maximum number of symlinks that will be resolved while trying to +-** expand a filename in xFullPathname() in the VFS. +-*/ +-#ifndef SQLITE_MAX_SYMLINK +-# define SQLITE_MAX_SYMLINK 200 +-#endif +- /* - ** CAPI3REF: Determine if a virtual table query is DISTINCT -@@ -15896,6 +15965,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); + ** The default size of a disk sector + */ +@@ -15234,6 +15296,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); @@ -137,7 +140,7 @@ index 946815f..d2bfc23 100644 SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); -@@ -15992,6 +16064,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); +@@ -15330,6 +15395,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); @@ -148,7 +151,7 @@ index 946815f..d2bfc23 100644 /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); -@@ -17632,6 +17708,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); +@@ -16933,6 +17002,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); */ #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) @@ -170,7 +173,7 @@ index 946815f..d2bfc23 100644 /* ** Each database connection is an instance of the following structure. */ -@@ -17776,6 +17867,15 @@ struct sqlite3 { +@@ -17076,6 +17160,15 @@ struct sqlite3 { #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif @@ -186,22 +189,23 @@ index 946815f..d2bfc23 100644 }; /* -@@ -20889,7 +20989,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); +@@ -20046,7 +20139,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); -+#ifndef SQLITE_HAS_CODEC - #define sqlite3CodecQueryParameters(A,B,C) 0 +-#define sqlite3CodecQueryParameters(A,B,C) 0 ++#ifdef SQLITE_HAS_CODEC ++SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); +#else -+SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); -+#endif /* !SQLITE_HAS_CODEC */ ++# define sqlite3CodecQueryParameters(A,B,C) 0 ++#endif /* SQLITE_HAS_CODEC */ +#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) +SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p); +#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE -@@ -21873,6 +21980,10 @@ SQLITE_API extern int sqlite3_open_file_count; +@@ -21098,6 +21198,10 @@ SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) #endif /* defined(SQLITE_TEST) */ @@ -212,7 +216,7 @@ index 946815f..d2bfc23 100644 #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ -@@ -22258,6 +22369,9 @@ static const char * const sqlite3azCompileOpt[] = { +@@ -21480,6 +21584,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif @@ -222,7 +226,7 @@ index 946815f..d2bfc23 100644 #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif -@@ -22266,6 +22380,9 @@ static const char * const sqlite3azCompileOpt[] = { +@@ -21488,6 +21595,9 @@ static const char * const sqlite3azCompileOpt[] = { "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif @@ -232,7 +236,7 @@ index 946815f..d2bfc23 100644 #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif -@@ -22841,9 +22958,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { +@@ -22057,9 +22167,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. @@ -242,15 +246,15 @@ index 946815f..d2bfc23 100644 */ #ifndef SQLITE_USE_URI -# define SQLITE_USE_URI 0 -+#ifndef SQLITE_HAS_CODEC -+#define SQLITE_USE_URI 0 -+#else -+#define SQLITE_USE_URI 1 -+#endif /* !SQLITE_HAS_CODEC */ ++# ifdef SQLITE_HAS_CODEC ++# define SQLITE_USE_URI 1 ++# else ++# define SQLITE_USE_URI 0 ++# endif /* SQLITE_HAS_CODEC */ #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the -@@ -23615,6 +23739,13 @@ struct Vdbe { +@@ -22797,6 +22914,13 @@ struct Vdbe { int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif @@ -264,19 +268,19 @@ index 946815f..d2bfc23 100644 }; /* -@@ -32452,7 +32583,11 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ +@@ -31163,7 +31287,11 @@ 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 */ +#ifndef LOG_DUMP char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ +#else -+char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ ++ char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ +#endif /* !LOG_DUMP */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); -@@ -36425,7 +36560,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ +@@ -34841,7 +34969,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ return (u8)(h & 0xf); } @@ -285,7 +289,7 @@ index 946815f..d2bfc23 100644 /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the -@@ -36446,7 +36581,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ +@@ -34862,7 +34990,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ } return zBlob; } @@ -294,7 +298,7 @@ index 946815f..d2bfc23 100644 /* ** Log an error that is an API call on a connection pointer that should -@@ -38754,6 +38889,29 @@ static pid_t randomnessPid = 0; +@@ -37023,6 +37151,29 @@ static pid_t randomnessPid = 0; #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #endif /* __linux__ */ @@ -324,7 +328,7 @@ index 946815f..d2bfc23 100644 /* ** Different Unix systems declare open() in different ways. Same use -@@ -38764,7 +38922,29 @@ static pid_t randomnessPid = 0; +@@ -37033,7 +37184,29 @@ static pid_t randomnessPid = 0; ** which always has the same well-defined interface. */ static int posixOpen(const char *zFile, int flags, int mode){ @@ -355,7 +359,7 @@ index 946815f..d2bfc23 100644 } /* Forward reference */ -@@ -38785,7 +38965,7 @@ static struct unix_syscall { +@@ -37054,7 +37227,7 @@ static struct unix_syscall { { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) @@ -364,7 +368,7 @@ index 946815f..d2bfc23 100644 #define osClose ((int(*)(int))aSyscall[1].pCurrent) { "access", (sqlite3_syscall_ptr)access, 0 }, -@@ -39789,6 +39969,9 @@ static int findInodeInfo( +@@ -38048,6 +38221,9 @@ static int findInodeInfo( #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif @@ -374,7 +378,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR; } -@@ -39807,11 +39990,17 @@ static int findInodeInfo( +@@ -38066,11 +38242,17 @@ static int findInodeInfo( do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ storeLastErrno(pFile, errno); @@ -392,7 +396,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR; } } -@@ -40973,6 +41162,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { +@@ -39232,6 +39414,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ @@ -402,7 +406,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_UNLOCK; }else{ pFile->eFileLock = NO_LOCK; -@@ -41785,8 +41977,14 @@ static int unixRead( +@@ -40059,8 +40244,14 @@ static int unixRead( #ifdef EDEVERR case EDEVERR: #endif @@ -417,7 +421,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ -@@ -41928,9 +42126,19 @@ static int unixWrite( +@@ -40202,9 +40393,19 @@ static int unixWrite( if( amt>wrote ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ @@ -437,7 +441,7 @@ index 946815f..d2bfc23 100644 return SQLITE_FULL; } } -@@ -42284,7 +42492,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ +@@ -40558,7 +40759,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); @@ -453,7 +457,7 @@ index 946815f..d2bfc23 100644 #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely -@@ -42303,7 +42518,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ +@@ -40577,7 +40785,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ for(/*no-op*/; iWrite
=nSize ) iWrite = nSize - 1; nWrite = seekAndWrite(pFile, iWrite, "", 1); @@ -469,7 +473,7 @@ index 946815f..d2bfc23 100644 } #endif } -@@ -42358,14 +42580,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ +@@ -40632,14 +40847,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); @@ -499,7 +503,7 @@ index 946815f..d2bfc23 100644 return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ -@@ -43378,9 +43615,19 @@ static int unixShmLock( +@@ -41585,9 +41815,19 @@ static int unixShmLock( int *aLock; p = pDbFd->pShm; @@ -521,7 +525,7 @@ index 946815f..d2bfc23 100644 aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); -@@ -44827,6 +45074,9 @@ static int unixOpen( +@@ -42959,6 +43199,9 @@ static int unixOpen( if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); robust_close(p, fd, __LINE__); @@ -531,21 +535,11 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { -@@ -44967,6 +45217,8 @@ static int unixAccess( +@@ -43099,6 +43342,184 @@ static int unixAccess( return SQLITE_OK; } -+#ifndef HARMONY_OS -+ - /* - ** A pathname under construction - */ -@@ -45097,6 +45349,187 @@ static int unixFullPathname( - return SQLITE_OK; - } - -+#else -+ ++#ifdef HARMONY_OS +/* +** If the last component of the pathname in z[0]..z[j-1] is something +** other than ".." then back it out and return true. If the last @@ -722,13 +716,28 @@ index 946815f..d2bfc23 100644 + return rc; +#endif /* HAVE_READLINK && HAVE_LSTAT */ +} -+ -+#endif /* !HARMONY_OS */ -+ ++#else + /* + ** A pathname under construction + */ +@@ -43156,7 +43577,7 @@ static void appendOnePathElement( + }else if( S_ISLNK(buf.st_mode) ){ + ssize_t got; + char zLnk[SQLITE_MAX_PATHLEN+2]; +- if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ ++ if( pPath->nSymlink++ > SQLITE_MAX_SYMLINKS ){ + pPath->rc = SQLITE_CANTOPEN_BKPT; + return; + } +@@ -43230,6 +43651,7 @@ static int unixFullPathname( + if( path.nSymlink ) return SQLITE_OK_SYMLINK; + return SQLITE_OK; + } ++#endif + #ifndef SQLITE_OMIT_LOAD_EXTENSION /* - ** Interfaces for opening a shared library, finding entry points -@@ -45507,6 +45940,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ +@@ -43636,6 +44058,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", lPath, errno, osGetpid(0))); @@ -738,7 +747,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); -@@ -45625,6 +46061,9 @@ static int proxyCreateUnixFile( +@@ -43754,6 +44179,9 @@ static int proxyCreateUnixFile( case EACCES: return SQLITE_PERM; case EIO: @@ -748,7 +757,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; -@@ -45793,6 +46232,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ +@@ -43922,6 +44350,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ struct stat buf; if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); @@ -758,7 +767,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_LOCK; } -@@ -45813,6 +46255,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ +@@ -43942,6 +44373,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ storeLastErrno(pFile, errno); @@ -768,7 +777,7 @@ index 946815f..d2bfc23 100644 return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ -@@ -45887,6 +46332,9 @@ static int proxyTakeConch(unixFile *pFile){ +@@ -44016,6 +44450,9 @@ static int proxyTakeConch(unixFile *pFile){ if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ storeLastErrno(pFile, conchFile->lastErrno); @@ -778,7 +787,21 @@ index 946815f..d2bfc23 100644 rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || -@@ -57514,6 +57962,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ +@@ -51878,13 +52315,6 @@ end_deserialize: + return rc; + } + +-/* +-** Return true if the VFS is the memvfs. +-*/ +-SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){ +- return pVfs==&memdb_vfs; +-} +- + /* + ** This routine is called when the extension is loaded. + ** Register the new VFS. +@@ -55601,6 +56031,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) @@ -799,7 +822,7 @@ index 946815f..d2bfc23 100644 /* ** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. -@@ -57802,6 +58264,12 @@ struct Pager { +@@ -55889,6 +56333,12 @@ struct Pager { #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ @@ -812,7 +835,7 @@ index 946815f..d2bfc23 100644 char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL -@@ -57923,6 +58391,9 @@ static const unsigned char aJournalMagic[] = { +@@ -56010,6 +56460,9 @@ static const unsigned char aJournalMagic[] = { SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; @@ -822,7 +845,7 @@ index 946815f..d2bfc23 100644 #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; -@@ -58155,7 +58626,11 @@ static void setGetterMethod(Pager *pPager){ +@@ -56243,7 +56696,11 @@ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 @@ -835,7 +858,7 @@ index 946815f..d2bfc23 100644 pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ -@@ -59347,6 +59822,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ +@@ -57394,6 +57851,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ return cksum; } @@ -868,7 +891,7 @@ index 946815f..d2bfc23 100644 /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. -@@ -59398,6 +59899,11 @@ static int pager_playback_one_page( +@@ -57445,6 +57928,11 @@ static int pager_playback_one_page( char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ @@ -880,7 +903,7 @@ index 946815f..d2bfc23 100644 assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ -@@ -59527,12 +60033,26 @@ static int pager_playback_one_page( +@@ -57574,12 +58062,26 @@ static int pager_playback_one_page( ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ @@ -907,7 +930,7 @@ index 946815f..d2bfc23 100644 sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); } }else if( !isMainJrnl && pPg==0 ){ -@@ -59583,6 +60103,10 @@ static int pager_playback_one_page( +@@ -57630,6 +58132,10 @@ static int pager_playback_one_page( if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } @@ -918,7 +941,7 @@ index 946815f..d2bfc23 100644 sqlite3PcacheRelease(pPg); } return rc; -@@ -60161,6 +60685,8 @@ static int readDbPage(PgHdr *pPg){ +@@ -58206,6 +58712,8 @@ static int readDbPage(PgHdr *pPg){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } @@ -927,7 +950,7 @@ index 946815f..d2bfc23 100644 PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); -@@ -61306,6 +61832,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ +@@ -59353,6 +59861,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); @@ -938,7 +961,7 @@ index 946815f..d2bfc23 100644 assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); -@@ -61556,7 +62086,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ +@@ -59603,7 +60115,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); @@ -947,7 +970,7 @@ index 946815f..d2bfc23 100644 /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); -@@ -61645,6 +62175,11 @@ static int subjournalPage(PgHdr *pPg){ +@@ -59692,6 +60204,11 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; @@ -959,7 +982,7 @@ index 946815f..d2bfc23 100644 pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); -@@ -62737,6 +63272,9 @@ static int getPageMMap( +@@ -60795,6 +61312,9 @@ static int getPageMMap( ); assert( USEFETCH(pPager) ); @@ -969,7 +992,7 @@ index 946815f..d2bfc23 100644 /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" -@@ -63081,7 +63619,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ +@@ -61125,7 +61645,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); @@ -978,7 +1001,7 @@ index 946815f..d2bfc23 100644 cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the -@@ -63446,7 +63984,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ +@@ -61490,7 +62010,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); @@ -987,7 +1010,7 @@ index 946815f..d2bfc23 100644 if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; -@@ -64209,6 +64747,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ +@@ -62242,6 +62762,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } @@ -1036,7 +1059,7 @@ index 946815f..d2bfc23 100644 #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. -@@ -67063,6 +67643,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ +@@ -64937,6 +65499,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ assert( pInfo->aReadMark[0]==0 ); } @@ -1048,7 +1071,7 @@ index 946815f..d2bfc23 100644 /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. -@@ -67203,6 +67788,10 @@ static int walCheckpoint( +@@ -65077,6 +65644,10 @@ static int walCheckpoint( if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); @@ -1059,7 +1082,7 @@ index 946815f..d2bfc23 100644 rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } -@@ -68833,7 +69422,18 @@ static int walWriteOneFrame( +@@ -66471,7 +67042,18 @@ static int walWriteOneFrame( int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ @@ -1078,7 +1101,7 @@ index 946815f..d2bfc23 100644 walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; -@@ -69018,7 +69618,11 @@ static int walFrames( +@@ -66654,7 +67236,11 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( pWal->iReCksum==0 || iWrite iReCksum ){ pWal->iReCksum = iWrite; } @@ -1090,7 +1113,7 @@ index 946815f..d2bfc23 100644 rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; -@@ -69129,6 +69733,10 @@ static int walFrames( +@@ -66765,6 +67351,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( return rc; } @@ -1099,9 +1122,9 @@ index 946815f..d2bfc23 100644 +#endif /* LOG_DUMP */ + /* - ** Write a set of frames to the log. The caller must hold the write-lock - ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). -@@ -69282,6 +69890,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + ** This routine is called to implement sqlite3_wal_checkpoint() and + ** related interfaces. +@@ -66888,6 +67478,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } @@ -1114,7 +1137,7 @@ index 946815f..d2bfc23 100644 WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; -@@ -70666,6 +71280,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ +@@ -68264,6 +68860,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ } #endif @@ -1147,35 +1170,21 @@ index 946815f..d2bfc23 100644 /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. -@@ -72591,6 +73231,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->intKeyLeaf = 0; - pPage->xCellSize = cellSizePtrIdxLeaf; - pPage->xParseCell = btreeParseCellPtrIndex; +@@ -70094,6 +70716,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ + pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtr; + pPage->xParseCell = btreeParseCellPtrIndex; +#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_CORRUPT, -+ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " -+ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", -+ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, -+ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); ++ sqlite3_log(SQLITE_CORRUPT, ++ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " ++ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", ++ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, ++ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); +#endif /* LOG_DUMP */ - return SQLITE_CORRUPT_PAGE(pPage); - } - }else{ -@@ -72615,6 +73262,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->intKeyLeaf = 0; - pPage->xCellSize = cellSizePtr; - pPage->xParseCell = btreeParseCellPtrIndex; -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_CORRUPT, -+ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " -+ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", -+ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, -+ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); -+#endif /* LOG_DUMP */ - return SQLITE_CORRUPT_PAGE(pPage); - } + return SQLITE_CORRUPT_PAGE(pPage); } -@@ -82246,6 +82900,13 @@ static int backupOnePage( + pPage->max1bytePayload = pBt->max1bytePayload; +@@ -79481,6 +80110,13 @@ static int backupOnePage( int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; @@ -1189,9 +1198,9 @@ index 946815f..d2bfc23 100644 int rc = SQLITE_OK; i64 iOff; -@@ -82256,6 +82917,26 @@ static int backupOnePage( - assert( zSrcData ); - assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 ); +@@ -79497,6 +80133,26 @@ static int backupOnePage( + rc = SQLITE_READONLY; + } +#ifdef SQLITE_HAS_CODEC + /* Backup is not possible if the page size of the destination is changing @@ -1216,7 +1225,7 @@ index 946815f..d2bfc23 100644 /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. -@@ -82754,6 +83435,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ +@@ -79992,6 +80648,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ b.pDest = pTo; b.iNext = 1; @@ -1227,7 +1236,7 @@ index 946815f..d2bfc23 100644 /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes -@@ -91264,6 +91949,15 @@ end_of_step: +@@ -88114,6 +88774,15 @@ end_of_step: return (rc&db->errMask); } @@ -1243,7 +1252,7 @@ index 946815f..d2bfc23 100644 /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, -@@ -91283,6 +91977,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ +@@ -88133,6 +88802,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; @@ -1257,7 +1266,7 @@ index 946815f..d2bfc23 100644 rc = sqlite3Reprepare(v); if( rc!=SQLITE_OK ){ /* This case occurs after failing to recompile an sql statement. -@@ -91304,6 +92005,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ +@@ -88154,6 +88830,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } break; } @@ -1273,7 +1282,7 @@ index 946815f..d2bfc23 100644 sqlite3_reset(pStmt); if( savedPc>=0 ){ /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and -@@ -91314,6 +92024,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ +@@ -88164,6 +88849,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } assert( v->expired==0 ); } @@ -1294,7 +1303,15 @@ index 946815f..d2bfc23 100644 sqlite3_mutex_leave(db->mutex); return rc; } -@@ -93761,6 +94485,61 @@ static int checkSavepointCount(sqlite3 *db){ +@@ -90192,7 +90891,6 @@ static u16 numericType(Mem *pMem){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); + return computeNumericType(pMem); +- return 0; + } + + #ifdef SQLITE_DEBUG +@@ -90351,6 +91049,61 @@ static int checkSavepointCount(sqlite3 *db){ } #endif @@ -1356,7 +1373,7 @@ index 946815f..d2bfc23 100644 /* ** Return the register of pOp->p2 after first preparing it to be ** overwritten with an integer value. -@@ -94361,6 +95140,12 @@ case OP_Halt: { +@@ -90852,6 +91605,12 @@ case OP_Halt: { VdbeFrame *pFrame; int pcx; @@ -1369,7 +1386,7 @@ index 946815f..d2bfc23 100644 #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif -@@ -94806,6 +95591,43 @@ case OP_ResultRow: { +@@ -91295,6 +92054,43 @@ case OP_ResultRow: { assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); @@ -1411,9 +1428,9 @@ index 946815f..d2bfc23 100644 +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + p->cacheCtr = (p->cacheCtr + 2)|1; - p->pResultRow = &aMem[pOp->p1]; + p->pResultSet = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG -@@ -95612,6 +96434,17 @@ case OP_Compare: { +@@ -92091,6 +92887,17 @@ case OP_Compare: { ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ @@ -1429,9 +1446,9 @@ index 946815f..d2bfc23 100644 + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); - assert( iCompareIsInit ); if( iCompare<0 ){ -@@ -100719,6 +101552,20 @@ case OP_IfNotZero: { /* jump, in1 */ + VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; +@@ -97106,6 +97913,20 @@ case OP_IfNotZero: { /* jump, in1 */ ** and jump to P2 if the new value is exactly zero. */ case OP_DecrJumpZero: { /* jump, in1 */ @@ -1452,7 +1469,7 @@ index 946815f..d2bfc23 100644 pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; -@@ -120686,6 +121533,40 @@ static void attachFunc( +@@ -116053,6 +116874,40 @@ static void attachFunc( if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } @@ -1493,7 +1510,7 @@ index 946815f..d2bfc23 100644 sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. -@@ -122260,8 +123141,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char +@@ -117624,8 +118479,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); @@ -1518,7 +1535,7 @@ index 946815f..d2bfc23 100644 } /* -@@ -130873,10 +131770,16 @@ static void groupConcatValue(sqlite3_context *context){ +@@ -125898,10 +126769,16 @@ static void groupConcatValue(sqlite3_context *context){ */ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ int rc = sqlite3_overload_function(db, "MATCH", 2); @@ -1535,10 +1552,10 @@ index 946815f..d2bfc23 100644 } /* -@@ -136799,6 +137702,10 @@ struct sqlite3_api_routines { - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); +@@ -131535,6 +132412,10 @@ struct sqlite3_api_routines { + const char *(*db_name)(sqlite3*,int); + /* Version 3.40.0 and later */ + int (*value_encoding)(sqlite3_value*); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + /* handle after drop table done */ + int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); @@ -1546,10 +1563,10 @@ index 946815f..d2bfc23 100644 }; /* -@@ -137132,6 +138039,10 @@ typedef int (*sqlite3_loadext_entry)( - /* Version 3.44.0 and later */ - #define sqlite3_get_clientdata sqlite3_api->get_clientdata - #define sqlite3_set_clientdata sqlite3_api->set_clientdata +@@ -131861,6 +132742,10 @@ typedef int (*sqlite3_loadext_entry)( + #define sqlite3_db_name sqlite3_api->db_name + /* Version 3.40.0 and later */ + #define sqlite3_value_encoding sqlite3_api->value_encoding +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK +/* handle after drop table done */ +#define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle @@ -1557,7 +1574,7 @@ index 946815f..d2bfc23 100644 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) -@@ -137155,7 +138066,7 @@ typedef int (*sqlite3_loadext_entry)( +@@ -131884,7 +132769,7 @@ typedef int (*sqlite3_loadext_entry)( /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ @@ -1566,7 +1583,7 @@ index 946815f..d2bfc23 100644 /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer -@@ -137169,7 +138080,9 @@ typedef int (*sqlite3_loadext_entry)( +@@ -131898,7 +132783,9 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 #endif @@ -1576,7 +1593,7 @@ index 946815f..d2bfc23 100644 #ifdef SQLITE_OMIT_AUTHORIZATION # define sqlite3_set_authorizer 0 #endif -@@ -137250,6 +138163,7 @@ typedef int (*sqlite3_loadext_entry)( +@@ -131979,6 +132866,7 @@ typedef int (*sqlite3_loadext_entry)( #if defined(SQLITE_OMIT_TRACE) # define sqlite3_trace_v2 0 #endif @@ -1584,7 +1601,7 @@ index 946815f..d2bfc23 100644 /* ** The following structure contains pointers to all SQLite API routines. -@@ -137266,6 +138180,7 @@ typedef int (*sqlite3_loadext_entry)( +@@ -131995,6 +132883,7 @@ typedef int (*sqlite3_loadext_entry)( ** also check to make sure that the pointer to the function is ** not NULL before calling it. */ @@ -1592,7 +1609,7 @@ index 946815f..d2bfc23 100644 static const sqlite3_api_routines sqlite3Apis = { sqlite3_aggregate_context, #ifndef SQLITE_OMIT_DEPRECATED -@@ -137535,7 +138450,11 @@ static const sqlite3_api_routines sqlite3Apis = { +@@ -132264,7 +133153,11 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_bind_blob64, sqlite3_bind_text64, sqlite3_cancel_auto_extension, @@ -1604,21 +1621,19 @@ index 946815f..d2bfc23 100644 sqlite3_malloc64, sqlite3_msize, sqlite3_realloc64, -@@ -137653,7 +138572,12 @@ static const sqlite3_api_routines sqlite3Apis = { - sqlite3_stmt_explain, - /* Version 3.44.0 and later */ - sqlite3_get_clientdata, -- sqlite3_set_clientdata -+ sqlite3_set_clientdata, +@@ -132375,7 +133268,10 @@ static const sqlite3_api_routines sqlite3Apis = { + #endif + sqlite3_db_name, + /* Version 3.40.0 and later */ +- sqlite3_value_encoding ++ sqlite3_value_encoding, +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + sqlite3_set_droptable_handle -+#else -+ 0 +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ }; /* True if x is the directory separator character -@@ -137664,6 +138588,9 @@ static const sqlite3_api_routines sqlite3Apis = { +@@ -132386,6 +133282,9 @@ static const sqlite3_api_routines sqlite3Apis = { # define DirSep(X) ((X)=='/') #endif @@ -1628,7 +1643,7 @@ index 946815f..d2bfc23 100644 /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a -@@ -138143,6 +139070,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ +@@ -132846,6 +133745,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_WAL_CHECKPOINT 43 #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 @@ -1638,7 +1653,7 @@ index 946815f..d2bfc23 100644 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ -@@ -138433,6 +139363,18 @@ static const PragmaName aPragmaName[] = { +@@ -133136,6 +134038,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, @@ -1657,7 +1672,7 @@ index 946815f..d2bfc23 100644 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", -@@ -138485,6 +139427,13 @@ static const PragmaName aPragmaName[] = { +@@ -133188,6 +134102,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -1671,7 +1686,7 @@ index 946815f..d2bfc23 100644 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, -@@ -138592,6 +139541,15 @@ static const PragmaName aPragmaName[] = { +@@ -133295,6 +134216,15 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, @@ -1687,7 +1702,7 @@ index 946815f..d2bfc23 100644 {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, -@@ -138680,6 +139638,18 @@ static const PragmaName aPragmaName[] = { +@@ -133383,6 +134313,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, @@ -1706,7 +1721,7 @@ index 946815f..d2bfc23 100644 #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, -@@ -139149,6 +140119,10 @@ SQLITE_PRIVATE void sqlite3Pragma( +@@ -133824,6 +134766,10 @@ SQLITE_PRIVATE void sqlite3Pragma( Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ @@ -1717,7 +1732,7 @@ index 946815f..d2bfc23 100644 if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; -@@ -139218,6 +140192,13 @@ SQLITE_PRIVATE void sqlite3Pragma( +@@ -133893,6 +134839,13 @@ SQLITE_PRIVATE void sqlite3Pragma( goto pragma_out; } @@ -1731,7 +1746,7 @@ index 946815f..d2bfc23 100644 /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ -@@ -141459,6 +142440,48 @@ SQLITE_PRIVATE void sqlite3Pragma( +@@ -135935,6 +136888,48 @@ SQLITE_PRIVATE void sqlite3Pragma( } #endif @@ -1780,7 +1795,7 @@ index 946815f..d2bfc23 100644 #if defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ -@@ -144023,9 +145046,25 @@ static void selectInnerLoop( +@@ -138460,9 +139455,25 @@ static void selectInnerLoop( assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; @@ -1806,7 +1821,7 @@ index 946815f..d2bfc23 100644 } /* Pull the requested columns. -@@ -144154,6 +145193,16 @@ static void selectInnerLoop( +@@ -138591,6 +139602,16 @@ static void selectInnerLoop( fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); @@ -1823,7 +1838,7 @@ index 946815f..d2bfc23 100644 } } -@@ -144623,11 +145672,23 @@ static void generateSortTail( +@@ -139037,11 +140058,23 @@ static void generateSortTail( addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); assert( p->iLimit==0 && p->iOffset==0 ); @@ -1847,7 +1862,7 @@ index 946815f..d2bfc23 100644 iSortTab = iTab; bSeq = 1; if( p->iOffset>0 ){ -@@ -155217,6 +156278,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( +@@ -148844,6 +149877,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( } nRes = sqlite3BtreeGetRequestedReserve(pMain); @@ -1865,7 +1880,7 @@ index 946815f..d2bfc23 100644 sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); -@@ -180744,6 +181816,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ +@@ -173422,6 +174466,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } @@ -1895,7 +1910,7 @@ index 946815f..d2bfc23 100644 default: { static const struct { int op; /* The opcode */ -@@ -182998,7 +184093,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){ +@@ -175642,7 +176709,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){ return 0; } @@ -1938,7 +1953,7 @@ index 946815f..d2bfc23 100644 /* ** This routine does the work of opening a database on behalf of -@@ -183346,6 +184475,12 @@ opendb_out: +@@ -175987,6 +177088,12 @@ opendb_out: }else if( rc!=SQLITE_OK ){ db->eOpenState = SQLITE_STATE_SICK; } @@ -1951,7 +1966,7 @@ index 946815f..d2bfc23 100644 *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ -@@ -183354,6 +184489,14 @@ opendb_out: +@@ -175995,6 +177102,14 @@ opendb_out: sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); } #endif @@ -1966,7 +1981,34 @@ index 946815f..d2bfc23 100644 sqlite3_free_filename(zOpen); return rc; } -@@ -257677,3 +258820,1667 @@ SQLITE_API int sqlite3_stmt_init( +@@ -217581,15 +218696,19 @@ static int sessionReadRecord( + } + } + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ +- sqlite3_int64 v = sessionGetI64(aVal); +- if( eType==SQLITE_INTEGER ){ +- sqlite3VdbeMemSetInt64(apOut[i], v); ++ if( (pIn->nData-pIn->iNext)<8 ){ ++ rc = SQLITE_CORRUPT_BKPT; + }else{ +- double d; +- memcpy(&d, &v, 8); +- sqlite3VdbeMemSetDouble(apOut[i], d); ++ sqlite3_int64 v = sessionGetI64(aVal); ++ if( eType==SQLITE_INTEGER ){ ++ sqlite3VdbeMemSetInt64(apOut[i], v); ++ }else{ ++ double d; ++ memcpy(&d, &v, 8); ++ sqlite3VdbeMemSetDouble(apOut[i], d); ++ } ++ pIn->iNext += 8; + } +- pIn->iNext += 8; + } + } + } +@@ -243614,3 +244733,1667 @@ SQLITE_API int sqlite3_stmt_init( /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ @@ -3635,5 +3677,5 @@ index 946815f..d2bfc23 100644 +/************** End hw export the symbols *****************************************/ +#endif /* SQLITE_EXPORT_SYMBOLS */ -- -2.46.0.windows.1 +2.47.0.windows.2 diff --git a/patch/0002-busy-debug.patch b/patch/0002-busy-debug.patch index 8fd1663b6f94bd2be7bbfc7d8d603408ed5da7eb..a4366e89a7c31444641128b3276f3107fecf1226 100644 --- a/patch/0002-busy-debug.patch +++ b/patch/0002-busy-debug.patch @@ -1,18 +1,18 @@ -From 4a29b0e98e03fea216795394ac340104e2e1bbfa Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Tue, 25 Feb 2025 11:25:32 +0800 -Subject: [PATCH] suport busy debug +From 7e94a0e2ef2ba3eed067ece5f0df3cd0ac5b693e Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Fri, 11 Apr 2025 19:47:08 +0800 +Subject: [PATCH 2/7] busy debug -Signed-off-by: ryne3366 + Signed-off-by: ryne3366 --- - src/sqlite3.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 355 insertions(+), 13 deletions(-) + src/sqlite3.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 366 insertions(+), 11 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index d2bfc23..1ec1ae9 100644 +index a935685..237d37e 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -38490,6 +38490,45 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ +@@ -36790,6 +36790,45 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ #endif /************** End of os_kv.c ***********************************************/ @@ -58,7 +58,7 @@ index d2bfc23..1ec1ae9 100644 /************** Begin file os_unix.c *****************************************/ /* ** 2004 May 22 -@@ -40313,6 +40352,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38564,6 +38603,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( pFile->eFileLock>=eFileLock ){ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, azFileLock(eFileLock))); @@ -66,7 +66,7 @@ index d2bfc23..1ec1ae9 100644 return SQLITE_OK; } -@@ -40337,6 +40377,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38588,6 +38628,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; @@ -74,7 +74,7 @@ index d2bfc23..1ec1ae9 100644 goto end_lock; } -@@ -40352,6 +40393,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38603,6 +38644,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; @@ -82,15 +82,12 @@ index d2bfc23..1ec1ae9 100644 goto end_lock; } -@@ -40373,6 +40415,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38624,11 +38666,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } + MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); goto end_lock; - }else if( eFileLock==EXCLUSIVE_LOCK ){ - pFile->eFileLock = PENDING_LOCK; -@@ -40380,7 +40423,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ } } @@ -98,7 +95,7 @@ index d2bfc23..1ec1ae9 100644 /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ -@@ -40396,7 +40438,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38644,7 +38686,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); } @@ -107,7 +104,7 @@ index d2bfc23..1ec1ae9 100644 /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; -@@ -40421,6 +40463,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38669,6 +38711,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; @@ -115,7 +112,7 @@ index d2bfc23..1ec1ae9 100644 }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file -@@ -40445,6 +40488,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ +@@ -38693,6 +38736,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ storeLastErrno(pFile, tErrno); } } @@ -123,7 +120,7 @@ index d2bfc23..1ec1ae9 100644 } -@@ -40638,7 +40682,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ +@@ -38890,7 +38934,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pFile->eFileLock = NO_LOCK; } } @@ -131,24 +128,24 @@ index d2bfc23..1ec1ae9 100644 /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. -@@ -42948,6 +42991,7 @@ struct unixShmNode { - sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK]; - #endif +@@ -41187,6 +41230,7 @@ struct unixShmNode { + int nRef; /* Number of unixShm objects pointing to this */ + unixShm *pFirst; /* All unixShm objects pointing to this */ int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ + int aLockTid[SQLITE_SHM_NLOCK]; #ifdef SQLITE_DEBUG - u8 nextShmId; /* Next available unixShm.id value */ - #endif -@@ -43214,6 +43258,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ - #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - pDbFd->iBusyTimeout = iSaveTimeout; - #endif + u8 exclMask; /* Mask of exclusive locks held */ + u8 sharedMask; /* Mask of shared locks held */ +@@ -41429,6 +41473,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); + MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS); + MARK_LAST_BUSY_LINE(rc); /* The first connection to attach must truncate the -shm file. We ** truncate to 3 bytes (an arbitrary small number, less than the ** -shm header size) rather than 0 as a system debugging aid, to -@@ -43225,11 +43271,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ +@@ -41440,11 +41486,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ } }else if( lock.l_type==F_WRLCK ){ rc = SQLITE_BUSY; @@ -164,78 +161,70 @@ index d2bfc23..1ec1ae9 100644 } return rc; } -@@ -43629,7 +43679,7 @@ static int unixShmLock( +@@ -41829,7 +41879,8 @@ static int unixShmLock( return SQLITE_IOERR_SHMLOCK; } aLock = pShmNode->aLock; - + int *aLockTid = pShmNode->aLockTid; ++ u8 useProcessLock = LOCK_BY_THREAD; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); -@@ -43679,6 +43729,7 @@ static int unixShmLock( - assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK) - || 0==(p->exclMask & mask) - ); -+ u8 useProcessLock = LOCK_BY_THREAD; - if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) - || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) - || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) -@@ -43734,7 +43785,7 @@ static int unixShmLock( - p->sharedMask &= ~mask; - } - } -- -+ MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); - if( bUnlock ){ - rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); - if( rc==SQLITE_OK ){ -@@ -43742,6 +43793,8 @@ static int unixShmLock( - p->sharedMask &= ~mask; - p->exclMask &= ~mask; - } -+ useProcessLock = LOCK_BY_PROCESS; -+ TryClearTid(aLockTid, ofst, n); - } - }else if( flags & SQLITE_SHM_SHARED ){ - /* Case (b) - a shared lock. */ -@@ -43751,12 +43804,14 @@ static int unixShmLock( - rc = SQLITE_BUSY; - }else if( aLock[ofst]==0 ){ - rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); -+ useProcessLock = LOCK_BY_PROCESS; - } -- -+ MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock); - /* Get the local shared locks */ +@@ -41884,15 +41935,17 @@ static int unixShmLock( if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - aLock[ofst]++; -+ TryRecordTid(aLockTid, ofst, n); - } - }else{ - /* Case (c) - an exclusive lock. */ -@@ -43774,7 +43829,7 @@ static int unixShmLock( - break; - } + memset(&aLock[ofst], 0, sizeof(int)*n); } ++ useProcessLock = LOCK_BY_PROCESS; + }else if( ALWAYS(p->sharedMask & (1< 1 ); + aLock[ofst]--; + } - ++ MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; ++ TryClearTid(aLockTid, ofst, n); + } + } + }else if( flags & SQLITE_SHM_SHARED ){ +@@ -41903,12 +41956,14 @@ static int unixShmLock( + rc = SQLITE_BUSY; + }else if( aLock[ofst]==0 ){ + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); + useProcessLock = LOCK_BY_PROCESS; - /* Get the exclusive locks at the system level. Then if successful - ** also update the in-memory values. */ - if( rc==SQLITE_OK ){ -@@ -43784,8 +43839,10 @@ static int unixShmLock( - for(ii=ofst; ii sharedMask |= mask; + aLock[ofst]++; ++ TryRecordTid(aLockTid, ofst, n); + } + } + }else{ +@@ -41927,14 +41982,17 @@ static int unixShmLock( + ** also update the in-memory values. */ + if( rc==SQLITE_OK ){ + rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); ++ useProcessLock = LOCK_BY_PROCESS; + if( rc==SQLITE_OK ){ + assert( (p->sharedMask & mask)==0 ); + p->exclMask |= mask; + for(ii=ofst; ii pShmMutex); +@@ -59933,6 +59991,7 @@ static int syncJournal(Pager *pPager, int newHdr){ assert( !pagerUseWal(pPager) ); rc = sqlite3PagerExclusiveLock(pPager); @@ -243,7 +232,7 @@ index d2bfc23..1ec1ae9 100644 if( rc!=SQLITE_OK ) return rc; if( !pPager->noSync ){ -@@ -62796,6 +62854,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ +@@ -60840,6 +60899,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } @@ -251,7 +240,7 @@ index d2bfc23..1ec1ae9 100644 sqlite3EndBenignMalloc(); }else{ /* The journal file exists and no other connection has a reserved -@@ -62885,6 +62944,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ +@@ -60929,6 +60989,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_wait_on_lock(pPager, SHARED_LOCK); @@ -259,7 +248,7 @@ index d2bfc23..1ec1ae9 100644 if( rc!=SQLITE_OK ){ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); goto failed; -@@ -62921,6 +62981,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ +@@ -60965,6 +61026,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** downgraded to SHARED_LOCK before this function returns. */ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); @@ -267,7 +256,7 @@ index d2bfc23..1ec1ae9 100644 if( rc!=SQLITE_OK ){ goto failed; } -@@ -63553,6 +63614,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory +@@ -61579,6 +61641,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); @@ -275,7 +264,7 @@ index d2bfc23..1ec1ae9 100644 if( rc!=SQLITE_OK ){ return rc; } -@@ -63565,6 +63627,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory +@@ -61591,6 +61654,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** holds the write-lock. If possible, the upper layer will call it. */ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); @@ -283,7 +272,7 @@ index d2bfc23..1ec1ae9 100644 }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The -@@ -63572,8 +63635,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory +@@ -61598,8 +61662,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); @@ -294,7 +283,7 @@ index d2bfc23..1ec1ae9 100644 } } -@@ -65085,6 +65150,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ +@@ -63100,6 +63166,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); @@ -302,7 +291,7 @@ index d2bfc23..1ec1ae9 100644 } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); -@@ -65251,6 +65317,7 @@ static int pagerOpenWal(Pager *pPager){ +@@ -63264,6 +63331,7 @@ static int pagerOpenWal(Pager *pPager){ */ if( pPager->exclusiveMode ){ rc = pagerExclusiveLock(pPager); @@ -310,7 +299,7 @@ index d2bfc23..1ec1ae9 100644 } /* Open the connection to the log file. If this operation fails, -@@ -65334,6 +65401,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ +@@ -63347,6 +63415,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ if( !pPager->pWal ){ int logexists = 0; rc = pagerLockDb(pPager, SHARED_LOCK); @@ -318,7 +307,7 @@ index d2bfc23..1ec1ae9 100644 if( rc==SQLITE_OK ){ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists -@@ -65349,6 +65417,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ +@@ -63362,6 +63431,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); @@ -326,7 +315,7 @@ index d2bfc23..1ec1ae9 100644 if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); -@@ -66883,6 +66952,7 @@ static int walIndexRecover(Wal *pWal){ +@@ -64736,6 +64806,7 @@ static int walIndexRecover(Wal *pWal){ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ @@ -334,25 +323,27 @@ index d2bfc23..1ec1ae9 100644 return rc; } -@@ -67720,6 +67790,7 @@ static int walCheckpoint( +@@ -65576,6 +65647,7 @@ static int walCheckpoint( if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); - AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT; -@@ -67814,6 +67885,8 @@ static int walCheckpoint( + AtomicStore(pInfo->aReadMark+i, iMark); +@@ -65670,8 +65742,9 @@ static int walCheckpoint( /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + } else { + MARK_LAST_BUSY_LINE(rc); } - +- if( rc==SQLITE_BUSY ){ -@@ -67833,11 +67906,13 @@ static int walCheckpoint( - SEH_INJECT_FAULT; + /* Reset the return code so as not to report a checkpoint failure + ** just because there are active readers. */ +@@ -65688,11 +65761,13 @@ static int walCheckpoint( + assert( pWal->writeLock ); if( pInfo->nBackfill hdr.mxFrame ){ rc = SQLITE_BUSY; + MARK_LAST_BUSY_LINE(rc); @@ -365,26 +356,24 @@ index d2bfc23..1ec1ae9 100644 if( rc==SQLITE_OK ){ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as -@@ -68025,8 +68100,9 @@ SQLITE_PRIVATE int sqlite3WalClose( +@@ -65790,6 +65865,8 @@ SQLITE_PRIVATE int sqlite3WalClose( walLimitSize(pWal, 0); } } + } else { + MARK_LAST_BUSY_LINE(rc); } -- + walIndexClose(pWal, isDelete); - sqlite3OsClose(pWal->pWalFd); - if( isDelete ){ -@@ -68179,6 +68255,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ +@@ -65944,6 +66021,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } + MARK_LAST_BUSY_LINE(rc); }else{ int bWriteLock = pWal->writeLock; - if( bWriteLock -@@ -68202,6 +68279,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ + if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ +@@ -65964,6 +66042,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } @@ -392,7 +381,7 @@ index d2bfc23..1ec1ae9 100644 } } -@@ -68221,6 +68299,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ +@@ -65983,6 +66062,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** writer truncated the WAL out from under it. If that happens, it ** indicates that a writer has fixed the SHM file for us, so retry */ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; @@ -400,25 +389,25 @@ index d2bfc23..1ec1ae9 100644 } pWal->exclusiveMode = WAL_NORMAL_MODE; } -@@ -68483,6 +68562,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ +@@ -66214,6 +66294,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ ** so it takes care to hold an exclusive lock on the corresponding ** WAL_READ_LOCK() while changing values. */ +static void DumpLocksByWal(Wal *pWal); - static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ + static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ -@@ -68525,6 +68605,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +@@ -66251,6 +66332,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ return SQLITE_PROTOCOL; } - if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; +#if SQLITE_OS_UNIX + if( cnt>=15 ) DumpLocksByWal(pWal); +#endif /* SQLITE_OS_UNIX */ - #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor - ** to block for locks for approximately nDelay us. This affects three -@@ -68576,11 +68659,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ + sqlite3OsSleep(pWal->pVfs, nDelay); + } + +@@ -66277,11 +66361,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** must be zeroed before the requested page is returned. */ rc = WAL_RETRY; @@ -433,7 +422,7 @@ index d2bfc23..1ec1ae9 100644 } } if( rc!=SQLITE_OK ){ -@@ -68604,6 +68690,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +@@ -66304,6 +66391,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** and can be safely ignored. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); @@ -441,7 +430,7 @@ index d2bfc23..1ec1ae9 100644 walShmBarrier(pWal); if( rc==SQLITE_OK ){ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ -@@ -68621,6 +68708,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +@@ -66321,6 +66409,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** it finished. Leaving a corrupt image in the database file. */ walUnlockShared(pWal, WAL_READ_LOCK(0)); @@ -449,7 +438,7 @@ index d2bfc23..1ec1ae9 100644 return WAL_RETRY; } pWal->readLock = 0; -@@ -68665,6 +68753,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +@@ -66365,6 +66454,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ }else if( rc!=SQLITE_BUSY ){ return rc; } @@ -457,15 +446,15 @@ index d2bfc23..1ec1ae9 100644 } } if( mxI==0 ){ -@@ -68684,6 +68773,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - assert( rc!=SQLITE_BUSY_TIMEOUT ); - #endif - assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); +@@ -66374,6 +66464,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + + rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); + if( rc ){ + MARK_LAST_BUSY_LINE(rc); - return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; + return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the -@@ -68726,6 +68816,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +@@ -66416,6 +66507,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); @@ -473,16 +462,23 @@ index d2bfc23..1ec1ae9 100644 return WAL_RETRY; }else{ assert( mxReadMark<=pWal->hdr.mxFrame ); -@@ -68863,7 +68954,7 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ +@@ -66542,6 +66634,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ (void)walEnableBlocking(pWal); rc = walLockShared(pWal, WAL_CKPT_LOCK); walDisableBlocking(pWal); -- + MARK_LAST_BUSY_LINE(rc); + if( rc!=SQLITE_OK ){ return rc; - } -@@ -69810,6 +69901,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( +@@ -67365,6 +67458,7 @@ static sqlite3_int64 g_lastCkptTime = 0; + ** If parameter xBusy is not NULL, it is a pointer to a busy-handler + ** callback. In this case this function runs a blocking checkpoint. + */ ++static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); + SQLITE_PRIVATE int sqlite3WalCheckpoint( + Wal *pWal, /* Wal connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ +@@ -67406,6 +67500,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( ** it will not be invoked in this case. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); @@ -490,7 +486,7 @@ index d2bfc23..1ec1ae9 100644 testcase( rc==SQLITE_BUSY ); testcase( rc!=SQLITE_OK && xBusy2!=0 ); if( rc==SQLITE_OK ){ -@@ -69826,6 +69918,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( +@@ -67422,6 +67517,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); @@ -498,7 +494,20 @@ index d2bfc23..1ec1ae9 100644 if( rc==SQLITE_OK ){ pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ -@@ -73685,6 +73778,7 @@ static void pageReinit(DbPage *pData){ +@@ -67449,7 +67545,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ ++ sqlite3_int64 startTime; ++ sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); + rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); ++ if (rc == SQLITE_OK){ ++ walLogCheckpointInfo(pWal, db, startTime); ++ } + } + + /* If no error occurred, set the output variables. */ +@@ -71166,6 +71267,7 @@ static void pageReinit(DbPage *pData){ } } @@ -506,7 +515,7 @@ index d2bfc23..1ec1ae9 100644 /* ** Invoke the busy handler for a btree. */ -@@ -73692,7 +73786,13 @@ static int btreeInvokeBusyHandler(void *pArg){ +@@ -71173,7 +71275,13 @@ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); @@ -521,7 +530,7 @@ index d2bfc23..1ec1ae9 100644 } /* -@@ -74123,7 +74223,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ +@@ -71601,7 +71709,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ } } #endif @@ -530,7 +539,7 @@ index d2bfc23..1ec1ae9 100644 /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. -@@ -74788,7 +74888,7 @@ static SQLITE_NOINLINE int btreeBeginTrans( +@@ -72261,7 +72369,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers sqlite3BtreeEnter(p); btreeIntegrity(p); @@ -539,7 +548,7 @@ index d2bfc23..1ec1ae9 100644 /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. -@@ -82419,8 +82519,10 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * +@@ -79629,8 +79737,10 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * if( p ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); @@ -550,7 +559,7 @@ index d2bfc23..1ec1ae9 100644 }else{ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); } -@@ -88466,6 +88568,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ +@@ -85479,6 +85589,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ nTrans++; } rc = sqlite3PagerExclusiveLock(pPager); @@ -558,13 +567,13 @@ index d2bfc23..1ec1ae9 100644 sqlite3BtreeLeave(pBt); } } -@@ -260441,9 +260544,248 @@ export_finish: +@@ -246354,9 +246465,253 @@ export_finish: return; } /************** End file hw_codec.c *****************************************/ -#endif /* SQLITE_HAS_CODEC */ +#endif - ++ +#if SQLITE_OS_UNIX +#include +#include @@ -646,16 +655,6 @@ index d2bfc23..1ec1ae9 100644 + } +} + -+static inline const char *TrxLockName(int eLock) -+{ -+ return eLock == NO_LOCK ? "NO_LOCK" : -+ eLock == RESERVED_LOCK ? "RESERVED" : -+ eLock == EXCLUSIVE_LOCK ? "EXCLUSIVE" : -+ eLock == SHARED_LOCK ? "SHARED" : -+ eLock == PENDING_LOCK ? "PENDING": -+ eLock == UNKNOWN_LOCK ? "UNKNOWN" : "UNKNOWN_LOCK"; -+} -+ +static inline const char *IdxToLockName(u32 idx) +{ + const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", @@ -672,7 +671,7 @@ index d2bfc23..1ec1ae9 100644 + for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { + if (lockStatus[i] != NO_LOCK) { + tmp[0] = '\0'; -+ sqlite3_snprintf(availLen, tmp, "<%s, %s>", IdxToLockName((u32)i), TrxLockName(lockStatus[i])); ++ sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); + int len = strlen(tmp); + tmp += len; + availLen -= len; @@ -703,7 +702,7 @@ index d2bfc23..1ec1ae9 100644 + } + return 0; +} -+ + +static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) +{ + unixInodeInfo *inode = file->pInode; @@ -711,8 +710,8 @@ index d2bfc23..1ec1ae9 100644 + sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); + return; + } -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%s, dbRef:%d, lockCnt:%d, curLock:%s, processLock:%d", -+ TrxLockName(file->eFileLock), inode->nRef, inode->nLock, TrxLockName(inode->eFileLock), inode->bProcessLock); ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", ++ file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); + const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; + char *tmp = dumpBuf; + int availLen = dumpBufLen - 1; @@ -729,13 +728,16 @@ index d2bfc23..1ec1ae9 100644 + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf); + } +} -+ + +static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) +{ -+ if (!walEnabled || file->pShm == NULL || file->pShm->pShmNode == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled!"); ++ if (file->pShm == NULL || file->pShm->pShmNode == NULL) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); + return; + } ++ if (!walEnabled) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); ++ } + unixShmNode *pShmNode = file->pShm->pShmNode; + char *tmp = dumpBuf; + int availLen = dumpBufLen - 1; @@ -803,11 +805,23 @@ index d2bfc23..1ec1ae9 100644 +#endif /* #ifndef SQLITE_OMIT_WAL */ +} +#endif /* SQLITE_OS_UNIX */ - ++ ++#ifndef SQLITE_OMIT_WAL ++static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { ++ sqlite3_int64 endTime; ++ sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); ++ sqlite3_int64 timeUse = endTime - startTime; ++ /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ ++ if (timeUse > 1500 || pWal->hdr.mxFrame > 12800) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal ckpt use time: %lld(ms), wal frame: %u", ++ timeUse, pWal->hdr.mxFrame); ++ } ++} ++#endif +// hw export the symbols #ifdef SQLITE_EXPORT_SYMBOLS /************** Begin hw export the symbols *****************************************/ #if defined(__GNUC__) -- -2.34.1 +2.47.0.windows.2 diff --git a/patch/0003-suport-meta-recovery.patch b/patch/0003-support-meta-recovery.patch similarity index 92% rename from patch/0003-suport-meta-recovery.patch rename to patch/0003-support-meta-recovery.patch index bbb574d81e466055c0c7467f36ffc62e59dd8b97..099b8658fb1bc04b0282716af2c7a3c0be1b79b7 100644 --- a/patch/0003-suport-meta-recovery.patch +++ b/patch/0003-support-meta-recovery.patch @@ -1,18 +1,18 @@ -From d35904a31c2fe03afdccba31b75a34deb3bbcdbb Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Tue, 25 Feb 2025 11:28:45 +0800 -Subject: [PATCH] support meta recovery +From 647f4ee711da7b5d98514eb3543cc543f303c423 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 09:26:04 +0800 +Subject: [PATCH 3/7] support meta recovery Signed-off-by: ryne3366 --- - src/sqlite3.c | 1151 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 1140 insertions(+), 11 deletions(-) + src/sqlite3.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 1136 insertions(+), 12 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index 1ec1ae9..17d0d25 100644 +index 237d37e..ddfc377 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -788,6 +788,7 @@ SQLITE_API int sqlite3_exec( +@@ -779,6 +779,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ @@ -20,7 +20,7 @@ index 1ec1ae9..17d0d25 100644 /* end-of-error-codes */ /* -@@ -15626,7 +15627,6 @@ typedef int VList; +@@ -14964,7 +14965,6 @@ typedef int VList; # define SQLITE_OS_UNIX 0 #endif @@ -28,15 +28,7 @@ index 1ec1ae9..17d0d25 100644 #endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ -@@ -45066,6 +45066,7 @@ static int unixOpen( - flags |= SQLITE_OPEN_READONLY; - openFlags |= O_RDONLY; - isReadonly = 1; -+ sqlite3_log(SQLITE_WARNING, "Try open file readonly"); - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; -@@ -58068,6 +58069,26 @@ struct PagerSavepoint { +@@ -56138,6 +56138,26 @@ struct PagerSavepoint { #endif }; @@ -63,7 +55,7 @@ index 1ec1ae9..17d0d25 100644 /* ** Bits of the Pager.doNotSpill flag. See further description below. */ -@@ -58333,6 +58354,13 @@ struct Pager { +@@ -56403,6 +56423,13 @@ struct Pager { Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif @@ -77,7 +69,7 @@ index 1ec1ae9..17d0d25 100644 }; /* -@@ -58691,7 +58719,11 @@ static void setGetterMethod(Pager *pPager){ +@@ -56762,7 +56789,11 @@ static void setGetterMethod(Pager *pPager){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ @@ -89,7 +81,7 @@ index 1ec1ae9..17d0d25 100644 } } -@@ -59765,7 +59797,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ +@@ -57813,7 +57844,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ } sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); } @@ -105,7 +97,7 @@ index 1ec1ae9..17d0d25 100644 if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE -@@ -61860,6 +61899,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ +@@ -59890,6 +59928,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } @@ -115,7 +107,7 @@ index 1ec1ae9..17d0d25 100644 #endif pager_reset(pPager); if( MEMDB ){ -@@ -62699,7 +62741,11 @@ act_like_temp_file: +@@ -60736,7 +60777,11 @@ act_like_temp_file: rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); } @@ -128,7 +120,7 @@ index 1ec1ae9..17d0d25 100644 /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ -@@ -63123,7 +63169,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ +@@ -61168,7 +61213,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } @@ -136,7 +128,7 @@ index 1ec1ae9..17d0d25 100644 failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); -@@ -64416,7 +64461,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ +@@ -62436,7 +62480,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ pPager->eState = PAGER_READER; return SQLITE_OK; } @@ -144,7 +136,7 @@ index 1ec1ae9..17d0d25 100644 PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); -@@ -70676,6 +70720,10 @@ struct BtShared { +@@ -68267,6 +68310,10 @@ struct BtShared { #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ int nPreformatSize; /* Size of last cell written by TransferRow() */ @@ -155,7 +147,7 @@ index 1ec1ae9..17d0d25 100644 }; /* -@@ -74077,8 +74125,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( +@@ -71563,8 +71610,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( } } #endif @@ -165,7 +157,7 @@ index 1ec1ae9..17d0d25 100644 btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ -@@ -75048,7 +75096,12 @@ trans_begun: +@@ -72529,7 +72576,12 @@ trans_begun: rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); } } @@ -179,7 +171,7 @@ index 1ec1ae9..17d0d25 100644 btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; -@@ -75437,6 +75490,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ +@@ -72896,6 +72948,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); @@ -189,7 +181,7 @@ index 1ec1ae9..17d0d25 100644 } }else{ rc = SQLITE_DONE; -@@ -75521,6 +75577,9 @@ static int autoVacuumCommit(Btree *p){ +@@ -72980,6 +73035,9 @@ static int autoVacuumCommit(Btree *p){ put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; @@ -199,7 +191,7 @@ index 1ec1ae9..17d0d25 100644 } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); -@@ -75577,6 +75636,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ +@@ -73036,6 +73094,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } @@ -209,7 +201,7 @@ index 1ec1ae9..17d0d25 100644 #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); sqlite3BtreeLeave(p); -@@ -81669,6 +81731,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ +@@ -78937,6 +78998,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ assert( iMeta==0 || iMeta==1 ); pBt->incrVacuum = (u8)iMeta; } @@ -221,41 +213,37 @@ index 1ec1ae9..17d0d25 100644 #endif } sqlite3BtreeLeave(p); -@@ -82082,7 +82149,6 @@ static int checkTreePage( - if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM; +@@ -79307,7 +79373,6 @@ static int checkTreePage( + "unable to get the page. error code=%d", rc); goto end_of_check; } - /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ savedIsInit = pPage->isInit; -@@ -83293,6 +83359,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ +@@ -80514,6 +80579,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ } } } -+ #ifdef SQLITE_META_DWR -+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ (void)MetaDwrUpdateMetaPages(p->pDest); -+ } -+ #endif ++ if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); } -@@ -83323,6 +83395,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ - } - }else{ +@@ -80546,7 +80612,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ sqlite3PagerTruncateImage(pDestPager, nDestTruncate); -+ #ifdef SQLITE_META_DWR -+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ (void)MetaDwrUpdateMetaPages(p->pDest); -+ } -+ #endif rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } - -@@ -140300,8 +140378,14 @@ SQLITE_PRIVATE void sqlite3Pragma( +- ++ #ifdef SQLITE_META_DWR ++ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { ++ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; ++ (void)MetaDwrUpdateMetaPages(p->pDest); ++ } ++ #endif + /* Finish committing the transaction to the destination database. */ + if( SQLITE_OK==rc + && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) +@@ -134955,8 +135026,14 @@ SQLITE_PRIVATE void sqlite3Pragma( /* sqlite3CodecPragma executes internal */ goto pragma_out; } @@ -272,7 +260,7 @@ index 1ec1ae9..17d0d25 100644 /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ -@@ -155771,7 +155855,6 @@ static void updateVirtualTable( +@@ -149391,7 +149468,6 @@ static void updateVirtualTable( } } @@ -280,7 +268,7 @@ index 1ec1ae9..17d0d25 100644 if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ if( pSrc->nSrc==1 ){ -@@ -182655,6 +182738,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ +@@ -175302,6 +175378,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ zErr = "no more rows available"; break; } @@ -291,7 +279,7 @@ index 1ec1ae9..17d0d25 100644 default: { rc &= 0xff; if( ALWAYS(rc>=0) && rc nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; + assert(nOvfl > 0 || + (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); -+ while (nOvfl--) { ++ while (nOvfl > 0) { ++ nOvfl--; + Pgno iNext = 0; + MemPage *pOvfl = 0; + if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { -+ return SQLITE_CORRUPT_BKPT; ++ sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", ++ pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); ++ return SQLITE_MISUSE; + } + rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); + if (rc) @@ -484,7 +475,7 @@ index 1ec1ae9..17d0d25 100644 + if (pgno > btreePagecount(pBt)) { + return SQLITE_OK; + } -+ rc = getAndInitPage(pBt, pgno, &pPage, 0); ++ rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); + if (rc) { + return rc; + } @@ -502,7 +493,7 @@ index 1ec1ae9..17d0d25 100644 + } + } + pPage->xParseCell(pPage, pCell, &info); -+ if (info.nLocal != info.nPayload) { ++ if (info.nLocal < info.nPayload) { + rc = ScanOverflowPages(pPage, pCell, &info, fn, args); + if (rc) { + goto SCAN_PAGE_OUT; @@ -827,6 +818,7 @@ index 1ec1ae9..17d0d25 100644 + return rc; + } + } ++ hdr->pageCnt = metaPages->pageCnt; + MetaDwrUpdateHeaderDbInfo(pBt->pBt); + return rc; +} @@ -1125,20 +1117,18 @@ index 1ec1ae9..17d0d25 100644 +static int MetaDwrCheckMeta(Btree *pBt) { + int nErr = 0; + Pgno aRoot[2] = {0, 1}; // quick check and only check root btree -+ sqlite3_value aMem[2] = {0}; -+ char *errStr = NULL; -+ int rc = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], &aMem[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, -+ &nErr, &errStr); ++ char *errStr = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, ++ &nErr); + if (nErr == 0) { + assert(errStr == 0); + return SQLITE_OK; + } -+ if (rc != SQLITE_OK) { -+ sqlite3_free(errStr); -+ return rc; ++ if (errStr == 0) { ++ sqlite3_log(SQLITE_NOMEM, "Meta integrity check no mem"); ++ return SQLITE_NOMEM; + } -+ sqlite3_log(SQLITE_WARNING_DUMP, "Integrity check %s", errStr); -+ sqlite3_free(errStr); ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); ++ sqlite3DbFree(pBt->db, errStr); + return SQLITE_CORRUPT; +} + @@ -1342,5 +1332,5 @@ index 1ec1ae9..17d0d25 100644 #include #include -- -2.34.1 +2.47.0.windows.2 diff --git a/patch/0004-Enable-and-optimize-ICU.patch b/patch/0004-Enable-and-optimize-ICU.patch index 41747c37e8cf41dcba2293411185bdbd87f80d5e..5f7fcc22ca7d9bd68f85abd9c32d88fcbe10a4d1 100644 --- a/patch/0004-Enable-and-optimize-ICU.patch +++ b/patch/0004-Enable-and-optimize-ICU.patch @@ -1,28 +1,29 @@ -From 5526b966d88575fd479dfe69af0c70c4ac43de14 Mon Sep 17 00:00:00 2001 -From: MartinChoo <214582617@qq.com> -Date: Tue, 25 Feb 2025 17:02:54 +0800 -Subject: [PATCH] Enable and optimize ICU +From 289181f378cd66cd3fcb963912eca7a984d68db4 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:09:45 +0800 +Subject: [PATCH 4/7] Enable and optimize ICU -Signed-off-by: MartinChoo <214582617@qq.com> +Signed-off-by: ryne3366 --- - src/sqlite3.c | 1065 ++++------------------------------------------ - src/sqlite3icu.c | 925 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 1009 insertions(+), 981 deletions(-) + src/sqlite3.c | 1033 ++++------------------------------------------ + src/sqlite3icu.c | 892 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 976 insertions(+), 949 deletions(-) create mode 100644 src/sqlite3icu.c diff --git a/src/sqlite3.c b/src/sqlite3.c -index 17d0d25..f348f3c 100644 +index ddfc377..a25d540 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -2506,6 +2506,7 @@ struct sqlite3_mem_methods { +@@ -2459,7 +2459,7 @@ struct sqlite3_mem_methods { + #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ - #define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ +- +#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ - /* ** CAPI3REF: Database Connection Configuration Options -@@ -3283,6 +3284,17 @@ SQLITE_API int sqlite3_get_table( + ** +@@ -3193,6 +3193,17 @@ SQLITE_API int sqlite3_get_table( ); SQLITE_API void sqlite3_free_table(char **result); @@ -40,7 +41,7 @@ index 17d0d25..f348f3c 100644 /* ** CAPI3REF: Formatted String Printing Functions ** -@@ -181005,6 +181017,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); +@@ -173713,6 +173724,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); /************** End of rtree.h ***********************************************/ /************** Continuing where we left off in main.c ***********************/ #endif @@ -48,7 +49,7 @@ index 17d0d25..f348f3c 100644 #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) /************** Include sqliteicu.h in the middle of main.c ******************/ /************** Begin file sqliteicu.h ***************************************/ -@@ -181029,13 +181042,54 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); +@@ -173737,13 +173749,54 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); extern "C" { #endif /* __cplusplus */ @@ -104,7 +105,7 @@ index 17d0d25..f348f3c 100644 /************** Continuing where we left off in main.c ***********************/ #endif -@@ -181075,7 +181129,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { +@@ -173793,7 +173846,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { sqlite3Fts5Init, #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) @@ -113,7 +114,7 @@ index 17d0d25..f348f3c 100644 #endif #ifdef SQLITE_ENABLE_RTREE sqlite3RtreeInit, -@@ -181467,6 +181521,19 @@ SQLITE_API int sqlite3_shutdown(void){ +@@ -174150,12 +174203,24 @@ SQLITE_API int sqlite3_shutdown(void){ SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; @@ -131,17 +132,15 @@ index 17d0d25..f348f3c 100644 + } +#endif /* SQLITE_ENABLE_ICU */ - /* sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while - ** the SQLite library is in use. Except, a few selected opcodes -@@ -181484,7 +181551,6 @@ SQLITE_API int sqlite3_config(int op, ...){ - testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ ); - } + /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while + ** the SQLite library is in use. */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; - va_start(ap, op); switch( op ){ /* Mutex configuration options are only available in a threadsafe -@@ -184609,6 +184675,12 @@ static int openDatabase( +@@ -177223,6 +177288,12 @@ static int openDatabase( sqlite3RegisterPerConnectionBuiltinFunctions(db); rc = sqlite3_errcode(db); @@ -154,7 +153,7 @@ index 17d0d25..f348f3c 100644 /* Load compiled-in extensions */ for(i=0; rc==SQLITE_OK && i hash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU @@ -304,7 +303,7 @@ index 17d0d25..f348f3c 100644 #endif ){ rc = SQLITE_NOMEM; -@@ -217955,862 +217923,6 @@ SQLITE_API int sqlite3_rtree_init( +@@ -207668,829 +207635,6 @@ SQLITE_API int sqlite3_rtree_init( #endif /************** End of rtree.c ***********************************************/ @@ -782,7 +781,7 @@ index 17d0d25..f348f3c 100644 - UCollator *pUCollator; /* ICU library collation object */ - int rc; /* Return code from sqlite3_create_collation_x() */ - -- assert(nArg==2 || nArg==3); +- assert(nArg==2); - (void)nArg; /* Unused parameter */ - zLocale = (const char *)sqlite3_value_text(apArg[0]); - zName = (const char *)sqlite3_value_text(apArg[1]); @@ -797,39 +796,7 @@ index 17d0d25..f348f3c 100644 - return; - } - assert(p); -- if(nArg==3){ -- const char *zOption = (const char*)sqlite3_value_text(apArg[2]); -- static const struct { -- const char *zName; -- UColAttributeValue val; -- } aStrength[] = { -- { "PRIMARY", UCOL_PRIMARY }, -- { "SECONDARY", UCOL_SECONDARY }, -- { "TERTIARY", UCOL_TERTIARY }, -- { "DEFAULT", UCOL_DEFAULT_STRENGTH }, -- { "QUARTERNARY", UCOL_QUATERNARY }, -- { "IDENTICAL", UCOL_IDENTICAL }, -- }; -- unsigned int i; -- for(i=0; i =sizeof(aStrength)/sizeof(aStrength[0]) ){ -- sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); -- sqlite3_str_appendf(pStr, -- "unknown collation strength \"%s\" - should be one of:", -- zOption); -- for(i=0; i =sizeof(aStrength)/sizeof(aStrength[0]) ){ -+ sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); -+ sqlite3_str_appendf(pStr, -+ "unknown collation strength \"%s\" - should be one of:", -+ zOption); -+ for(i=0; i -Date: Tue, 25 Feb 2025 22:16:42 +0800 -Subject: [PATCH] Report corruption when runtime detected +From 75beaaa7d0cc8a392bc1ca2d164f2227c0c5b7f8 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:53:34 +0800 +Subject: [PATCH 5/7] Report corruption when runtime detected -Signed-off-by: MartinChoo <214582617@qq.com> +Signed-off-by: ryne3366 --- - src/sqlite3.c | 717 ++++++++++++++++++++++++++++++++++++++++++-------- - 1 file changed, 605 insertions(+), 112 deletions(-) + src/sqlite3.c | 649 +++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 563 insertions(+), 86 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index f348f3c..0666938 100644 +index a25d540..aa629b5 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -2474,6 +2474,21 @@ struct sqlite3_mem_methods { - ** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and - ** recommended case) then the integer is always filled with zero, regardless - ** if its initial value. -+** -+** [[SQLITE_CONFIG_CORRUPTION]] SQLITE_CONFIG_CORRUPTION -+**The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite -+** global [ corruption error]. -+** (^The SQLITE_CONFIG_CORRUPTION option takes two arguments: a pointer to a -+** function with a call signature of void(*)(void*,const void*), -+** and a pointer to void. ^If the function pointer is not NULL, it is -+** invoked to process each data corruption event. ^If the -+** function pointer is NULL, no=op will do when corruption detect. -+** ^The void pointer that is the second argument to SQLITE_CONFIG_CORRUPTION is -+** passed through as the first parameter to the application-defined corruption -+** function whenever that function is invoked. ^The second parameter to -+** the corruption function is a corruption message after formatting via [sqlite3_snprintf()]. -+** In a multi-threaded application, the application-defined corruption -+** function must be threadsafe. - ** - */ - #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ -@@ -2506,7 +2521,8 @@ struct sqlite3_mem_methods { +@@ -2459,6 +2459,7 @@ struct sqlite3_mem_methods { + #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ - #define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ --#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ -+#define SQLITE_CONFIG_CORRUPTION 31 /* xCorruption */ -+#define SQLITE_CONFIG_ENABLE_ICU 32 /* boolean */ - ++#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ + #define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options -@@ -20360,6 +20376,8 @@ struct Sqlite3Config { +@@ -19554,6 +19555,8 @@ struct Sqlite3Config { int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ @@ -53,7 +29,7 @@ index f348f3c..0666938 100644 /* vvvv--- must be last ---vvv */ #ifdef SQLITE_DEBUG sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ -@@ -20627,6 +20645,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis +@@ -19805,6 +19808,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis } \ } @@ -111,7 +87,7 @@ index f348f3c..0666938 100644 /* ** The SQLITE_*_BKPT macros are substitutes for the error codes with ** the same name but without the _BKPT suffix. These macros invoke -@@ -20635,10 +20704,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis +@@ -19813,10 +19867,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis ** to set a debugger breakpoint. */ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); @@ -125,7 +101,7 @@ index f348f3c..0666938 100644 #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG -@@ -20650,12 +20720,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); +@@ -19828,12 +19883,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif @@ -142,16 +118,16 @@ index f348f3c..0666938 100644 /* ** FTS3 and FTS4 both require virtual table support -@@ -23111,6 +23182,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { +@@ -22312,6 +22368,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ + 0, /* xCorruption */ + 0, /* pCorruptionArg */ #ifdef SQLITE_DEBUG - {0,0,0,0,0,0}, /* aTune */ + {0,0,0,0,0,0} /* aTune */ #endif -@@ -60758,7 +60831,7 @@ static int readDbPage(PgHdr *pPg){ +@@ -58784,7 +58842,7 @@ static int readDbPage(PgHdr *pPg){ assert( isOpen(pPager->fd) ); if( pagerUseWal(pPager) ){ @@ -160,7 +136,7 @@ index f348f3c..0666938 100644 if( rc ) return rc; } if( iFrame ){ -@@ -63281,7 +63354,12 @@ static int getPageNormal( +@@ -61324,7 +61382,12 @@ static int getPageNormal( assert( assert_pager_state(pPager) ); assert( pPager->hasHeldSharedLock==1 ); @@ -174,7 +150,7 @@ index f348f3c..0666938 100644 pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); if( pBase==0 ){ pPg = 0; -@@ -63313,7 +63391,11 @@ static int getPageNormal( +@@ -61356,7 +61419,11 @@ static int getPageNormal( ** (2) Never try to fetch the locking page */ if( pgno==PAGER_SJ_PGNO(pPager) ){ @@ -187,7 +163,7 @@ index f348f3c..0666938 100644 goto pager_acquire_err; } -@@ -63399,7 +63481,10 @@ static int getPageMMap( +@@ -61438,7 +61505,10 @@ static int getPageMMap( ** test in the previous statement, and avoid testing pgno==0 in the ** common case where pgno is large. */ if( pgno<=1 && pgno==0 ){ @@ -199,7 +175,7 @@ index f348f3c..0666938 100644 } assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); -@@ -65010,7 +65095,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i +@@ -63024,7 +63094,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i if( pPgOld ){ if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); @@ -212,7 +188,7 @@ index f348f3c..0666938 100644 } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ -@@ -66940,7 +67029,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ +@@ -64792,7 +64866,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ @@ -227,7 +203,7 @@ index f348f3c..0666938 100644 } sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); -@@ -67889,7 +67984,13 @@ static int walCheckpoint( +@@ -65745,7 +65825,13 @@ static int walCheckpoint( ** database plus the amount of data in the wal file, plus the ** maximum size of the pending-byte page (65536 bytes), then ** must be corruption somewhere. */ @@ -242,10 +218,10 @@ index f348f3c..0666938 100644 }else{ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); } -@@ -69201,7 +69302,11 @@ static int walFindFrame( +@@ -66856,7 +66942,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( + iRead = iFrame; } if( (nCollide--)==0 ){ - *piRead = 0; - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); @@ -255,21 +231,21 @@ index f348f3c..0666938 100644 } iKey = walNextHash(iKey); } -@@ -70005,7 +70110,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - /* Copy data from the log to the database file. */ - if( rc==SQLITE_OK ){ - if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", -+ walPagesize(pWal),nBuf,pWal->hdr.mxFrame); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, -+ -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - }else{ - rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); - } -@@ -71469,7 +71579,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ +@@ -67597,7 +67687,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + if( rc==SQLITE_OK ){ + + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", ++ walPagesize(pWal),nBuf,pWal->hdr.mxFrame); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + }else{ + sqlite3_int64 startTime; + sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); +@@ -69055,7 +69150,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ ** with the page number and filename associated with the (MemPage*). */ #ifdef SQLITE_DEBUG @@ -277,8 +253,8 @@ index f348f3c..0666938 100644 +int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ char *zMsg; sqlite3BeginBenignMalloc(); - zMsg = sqlite3_mprintf("database corruption page %u of %s", -@@ -71480,11 +71590,11 @@ int corruptPageError(int lineno, MemPage *p){ + zMsg = sqlite3_mprintf("database corruption page %d of %s", +@@ -69066,11 +69161,11 @@ int corruptPageError(int lineno, MemPage *p){ sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } sqlite3_free(zMsg); @@ -292,8 +268,8 @@ index f348f3c..0666938 100644 +# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) #endif - /* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled -@@ -72210,7 +72320,12 @@ static int btreeMoveto( + #ifndef SQLITE_OMIT_SHARED_CACHE +@@ -69748,7 +69843,12 @@ static int btreeMoveto( if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ @@ -307,7 +283,7 @@ index f348f3c..0666938 100644 }else{ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } -@@ -72407,7 +72522,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ +@@ -69928,7 +70028,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); @@ -316,7 +292,7 @@ index f348f3c..0666938 100644 *pRC = SQLITE_CORRUPT_BKPT; return; } -@@ -72421,12 +72536,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ +@@ -69942,12 +70042,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ /* The first byte of the extra data is the MemPage.isInit byte. ** If that byte is set, it means this page is also being used ** as a btree page. */ @@ -343,7 +319,7 @@ index f348f3c..0666938 100644 goto ptrmap_exit; } assert( offset <= (int)pBt->usableSize-5 ); -@@ -72471,7 +72598,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ +@@ -69992,7 +70104,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ sqlite3PagerUnref(pDbPage); @@ -357,7 +333,7 @@ index f348f3c..0666938 100644 } assert( offset <= (int)pBt->usableSize-5 ); assert( pEType!=0 ); -@@ -72479,7 +72611,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ +@@ -70000,7 +70117,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); @@ -374,9 +350,9 @@ index f348f3c..0666938 100644 return SQLITE_OK; } -@@ -72919,7 +73059,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ +@@ -70392,7 +70517,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ Pgno ovfl; - if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ + if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); - *pRC = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; @@ -390,7 +366,7 @@ index f348f3c..0666938 100644 return; } ovfl = get4byte(&pCell[info.nSize-4]); -@@ -72977,10 +73124,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ +@@ -70450,10 +70582,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); @@ -422,7 +398,7 @@ index f348f3c..0666938 100644 if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; -@@ -72988,16 +73154,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ +@@ -70461,16 +70612,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( top>=iFree ){ @@ -478,10 +454,10 @@ index f348f3c..0666938 100644 } cbrk = top+sz; -@@ -73030,13 +73231,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ +@@ -70503,13 +70689,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** if PRAGMA cell_size_check=ON. */ - if( pc>iCellLast ){ + if( pciCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block @@ -492,7 +468,7 @@ index f348f3c..0666938 100644 + cellOffset + i*2, 2, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } - assert( pc>=0 && pc<=iCellLast ); + assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrk usableSize ){ @@ -505,7 +481,7 @@ index f348f3c..0666938 100644 } assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); -@@ -73050,7 +73262,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ +@@ -70523,7 +70720,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ defragment_out: assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ @@ -520,7 +496,7 @@ index f348f3c..0666938 100644 } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); -@@ -73075,7 +73293,7 @@ defragment_out: +@@ -70548,7 +70751,7 @@ defragment_out: ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ @@ -529,7 +505,7 @@ index f348f3c..0666938 100644 const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ -@@ -73107,7 +73325,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ +@@ -70580,7 +70783,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ return &aData[pc]; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ @@ -546,7 +522,7 @@ index f348f3c..0666938 100644 return 0; }else{ /* The slot remains on the free-list. Reduce its size to account -@@ -73122,14 +73348,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ +@@ -70595,14 +70806,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ if( pc<=iAddr ){ if( pc ){ /* The next slot in the chain comes before the current slot */ @@ -574,7 +550,7 @@ index f348f3c..0666938 100644 } return 0; } -@@ -73177,10 +73414,16 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ +@@ -70651,7 +70873,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ @@ -587,13 +563,9 @@ index f348f3c..0666938 100644 + CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } - }else if( top>(int)pPage->pBt->usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); } - /* If there is enough space between gap and top for one more cell pointer, -@@ -73197,7 +73440,11 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ +@@ -70669,7 +70897,11 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); if( g2<=gap ){ @@ -606,7 +578,7 @@ index f348f3c..0666938 100644 }else{ return SQLITE_OK; } -@@ -73276,12 +73523,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ +@@ -70748,12 +70980,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ while( (iFreeBlk = get2byte(&data[iPtr])) iPtr || iFreeBlk==0 || CORRUPT_DB ); -@@ -73293,10 +73551,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ +@@ -70765,10 +71008,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; @@ -659,7 +631,7 @@ index f348f3c..0666938 100644 } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); -@@ -73309,13 +73581,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ +@@ -70781,13 +71038,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ @@ -689,7 +661,7 @@ index f348f3c..0666938 100644 data[hdr+7] -= nFrag; } pTmp = &data[hdr+5]; -@@ -73329,8 +73615,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ +@@ -70796,8 +71067,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ @@ -713,26 +685,11 @@ index f348f3c..0666938 100644 put2byte(&data[hdr+1], iFreeBlk); put2byte(&data[hdr+5], iEnd); }else{ -@@ -73391,7 +73690,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, - pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); - #endif /* LOG_DUMP */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - }else{ - pPage->childPtrSize = 4; -@@ -73422,7 +73727,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, - pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); +@@ -70882,7 +71166,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ + pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, + pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); #endif /* LOG_DUMP */ -- return SQLITE_CORRUPT_PAGE(pPage); +- return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); @@ -740,10 +697,10 @@ index f348f3c..0666938 100644 + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); - } } + pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; -@@ -73473,12 +73784,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ +@@ -70933,12 +71223,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will ** always be at least one cell before the first freeblock. */ @@ -766,7 +723,7 @@ index f348f3c..0666938 100644 } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); -@@ -73488,11 +73807,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ +@@ -70948,11 +71246,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } if( next>0 ){ /* Freeblock not in ascending order */ @@ -788,7 +745,7 @@ index f348f3c..0666938 100644 } } -@@ -73504,7 +73831,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ +@@ -70964,7 +71270,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ ** area, according to the page header, lies within the page. */ if( nFree>usableSize || nFree nFree = (u16)(nFree - iCellFirst); return SQLITE_OK; -@@ -73535,12 +73868,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ +@@ -70995,12 +71307,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pc iCellLast ){ @@ -826,7 +783,7 @@ index f348f3c..0666938 100644 } } return SQLITE_OK; -@@ -73572,7 +73913,7 @@ static int btreeInitPage(MemPage *pPage){ +@@ -71032,7 +71352,7 @@ static int btreeInitPage(MemPage *pPage){ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating ** the b-tree page type. */ if( decodeFlags(pPage, data[0]) ){ @@ -835,7 +792,7 @@ index f348f3c..0666938 100644 } assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); -@@ -73586,7 +73927,12 @@ static int btreeInitPage(MemPage *pPage){ +@@ -71046,7 +71366,12 @@ static int btreeInitPage(MemPage *pPage){ pPage->nCell = get2byte(&data[3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ @@ -849,20 +806,34 @@ index f348f3c..0666938 100644 } testcase( pPage->nCell==MX_CELL(pBt) ); /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only -@@ -73729,7 +74075,11 @@ static int getAndInitPage( +@@ -71201,7 +71526,11 @@ static int getAndInitPage( + assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ - *ppPage = 0; -- return SQLITE_CORRUPT_BKPT; +- rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); ++ rc = SQLITE_CORRUPT_REPORT(&context); + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); - if( rc ){ -@@ -75199,7 +75549,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ +@@ -71222,7 +71551,12 @@ static int getAndInitPage( + /* If obtaining a child page for a cursor, we must verify that the page is + ** compatible with the root page. */ + if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ +- rc = SQLITE_CORRUPT_PGNO(pgno); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "check btree page, nCell:%u, intKey:%u, cursor->curIntKey:%u", ++ (*ppPage)->nCell, (*ppPage)->intKey, pCur->curIntKey); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + goto getAndInitPage_error2; + } + return SQLITE_OK; +@@ -72656,7 +72990,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ @@ -876,7 +847,7 @@ index f348f3c..0666938 100644 } put4byte(pPage->aData, iTo); }else{ -@@ -75218,7 +75573,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ +@@ -72675,7 +73014,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ @@ -891,7 +862,7 @@ index f348f3c..0666938 100644 } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); -@@ -75227,7 +75588,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ +@@ -72684,7 +73029,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ } }else{ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){ @@ -906,7 +877,7 @@ index f348f3c..0666938 100644 } if( get4byte(pCell)==iFrom ){ put4byte(pCell, iTo); -@@ -75239,7 +75606,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ +@@ -72696,7 +73047,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ @@ -919,7 +890,7 @@ index f348f3c..0666938 100644 } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } -@@ -75372,7 +75743,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ +@@ -72829,7 +73184,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ return rc; } if( eType==PTRMAP_ROOTPAGE ){ @@ -932,7 +903,7 @@ index f348f3c..0666938 100644 } if( eType==PTRMAP_FREEPAGE ){ -@@ -76448,7 +76823,12 @@ static int accessPayload( +@@ -73907,7 +74266,12 @@ static int accessPayload( assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); if( pCur->ix>=pPage->nCell ){ @@ -946,7 +917,7 @@ index f348f3c..0666938 100644 } assert( cursorHoldsMutex(pCur) ); -@@ -76463,7 +76843,12 @@ static int accessPayload( +@@ -73922,7 +74286,12 @@ static int accessPayload( ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ @@ -960,7 +931,7 @@ index f348f3c..0666938 100644 } /* Check if data must be read/written to/from the btree page itself. */ -@@ -76534,7 +76919,16 @@ static int accessPayload( +@@ -73984,7 +74353,16 @@ static int accessPayload( assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ @@ -978,7 +949,7 @@ index f348f3c..0666938 100644 assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); -@@ -76618,7 +77012,11 @@ static int accessPayload( +@@ -74069,7 +74447,11 @@ static int accessPayload( if( rc==SQLITE_OK && amt>0 ){ /* Overflow chain ends prematurely */ @@ -991,16 +962,7 @@ index f348f3c..0666938 100644 } return rc; } -@@ -76770,7 +77168,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ - && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) - ){ - releasePage(pCur->pPage); -- rc = SQLITE_CORRUPT_PGNO(newPgno); -+ rc = SQLITE_CORRUPT_PGNO(newPgno, NULL); - } - if( rc ){ - pCur->pPage = pCur->apPage[--pCur->iPage]; -@@ -76905,7 +77303,12 @@ static int moveToRoot(BtCursor *pCur){ +@@ -74345,7 +74727,12 @@ static int moveToRoot(BtCursor *pCur){ ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ @@ -1014,7 +976,7 @@ index f348f3c..0666938 100644 } skip_init: -@@ -77166,7 +77569,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( +@@ -74599,7 +74986,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ){ @@ -1027,7 +989,7 @@ index f348f3c..0666938 100644 } } } -@@ -77449,7 +77856,12 @@ bypass_moveto_root: +@@ -74882,7 +75273,12 @@ bypass_moveto_root: testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ @@ -1041,16 +1003,7 @@ index f348f3c..0666938 100644 goto moveto_index_finish; } pCellKey = sqlite3Malloc( nCell+nOverrun ); -@@ -77523,7 +77935,7 @@ bypass_moveto_root: - && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) - ){ - releasePage(pCur->pPage); -- rc = SQLITE_CORRUPT_PGNO(chldPg); -+ rc = SQLITE_CORRUPT_PGNO(chldPg, NULL); - } - if( rc ){ - pCur->pPage = pCur->apPage[--pCur->iPage]; -@@ -77807,7 +78219,13 @@ static int allocateBtreePage( +@@ -75210,7 +75606,13 @@ static int allocateBtreePage( n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ @@ -1065,7 +1018,7 @@ index f348f3c..0666938 100644 } if( n>0 ){ /* There are pages on the freelist. Reuse one of those pages. */ -@@ -77863,7 +78281,12 @@ static int allocateBtreePage( +@@ -75266,7 +75668,12 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ @@ -1079,8 +1032,8 @@ index f348f3c..0666938 100644 }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } -@@ -77892,7 +78315,14 @@ static int allocateBtreePage( - TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); +@@ -75295,7 +75702,14 @@ static int allocateBtreePage( + TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ - rc = SQLITE_CORRUPT_PGNO(iTrunk); @@ -1095,7 +1048,7 @@ index f348f3c..0666938 100644 goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList -@@ -77926,7 +78356,14 @@ static int allocateBtreePage( +@@ -75329,7 +75743,14 @@ static int allocateBtreePage( MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ @@ -1111,7 +1064,7 @@ index f348f3c..0666938 100644 goto end_allocate_page; } testcase( iNewTrunk==mxPage ); -@@ -77991,7 +78428,14 @@ static int allocateBtreePage( +@@ -75394,7 +75815,14 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage || iPage<2 ){ @@ -1127,7 +1080,7 @@ index f348f3c..0666938 100644 goto end_allocate_page; } testcase( iPage==mxPage ); -@@ -78176,7 +78620,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ +@@ -75579,7 +76007,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ @@ -1143,7 +1096,7 @@ index f348f3c..0666938 100644 goto freepage_out; } if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ -@@ -78265,7 +78716,12 @@ static SQLITE_NOINLINE int clearCellOverflow( +@@ -75668,7 +76103,12 @@ static SQLITE_NOINLINE int clearCellOverflow( testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ @@ -1157,7 +1110,7 @@ index f348f3c..0666938 100644 } ovflPgno = get4byte(pCell + pInfo->nSize - 4); pBt = pPage->pBt; -@@ -78282,7 +78738,14 @@ static SQLITE_NOINLINE int clearCellOverflow( +@@ -75685,7 +76125,14 @@ static SQLITE_NOINLINE int clearCellOverflow( /* 0 is not a legal page number and page 1 cannot be an ** overflow page. Therefore if ovflPgno<2 or past the end of the ** file the database must be corrupt. */ @@ -1173,7 +1126,7 @@ index f348f3c..0666938 100644 } if( nOvfl ){ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); -@@ -78558,7 +79021,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ +@@ -75958,7 +76405,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ @@ -1187,56 +1140,11 @@ index f348f3c..0666938 100644 return; } rc = freeSpace(pPage, pc, sz); -@@ -79700,7 +80168,7 @@ static int balance_nonroot( - ** table-interior, index-leaf, or index-interior). - */ - if( pOld->aData[0]!=apOld[0]->aData[0] ){ -- rc = SQLITE_CORRUPT_PAGE(pOld); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pOld); - goto balance_cleanup; - } - -@@ -79724,7 +80192,7 @@ static int balance_nonroot( - memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); - if( pOld->nOverflow>0 ){ - if( NEVER(limit aiOvfl[0]) ){ -- rc = SQLITE_CORRUPT_PAGE(pOld); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pOld); - goto balance_cleanup; - } - limit = pOld->aiOvfl[0]; -@@ -80367,7 +80835,7 @@ static int anotherValidCursor(BtCursor *pCur){ - && pOther->eState==CURSOR_VALID - && pOther->pPage==pCur->pPage - ){ -- return SQLITE_CORRUPT_PAGE(pCur->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pCur->pPage); - } - } - return SQLITE_OK; -@@ -80427,7 +80895,7 @@ static int balance(BtCursor *pCur){ - /* The page being written is not a root page, and there is currently - ** more than one reference to it. This only happens if the page is one - ** of its own ancestor pages. Corruption. */ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - MemPage * const pParent = pCur->apPage[iPage-1]; - int const iIdx = pCur->aiIdx[iPage-1]; -@@ -80591,7 +81059,7 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( - rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); - if( rc ) return rc; - if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - if( iOffset+ovflPageSize<(u32)nTotal ){ - ovflPgno = get4byte(pPage->aData); -@@ -80619,7 +81087,14 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ +@@ -77868,7 +78320,14 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd || pCur->info.pPayload < pPage->aData + pPage->cellOffset ){ -- return SQLITE_CORRUPT_PAGE(pPage); +- return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "cell payload cursor point to(%d), size:%u overlaps with non-cell content area:[%u, %d]", @@ -1244,149 +1152,11 @@ index f348f3c..0666938 100644 + (int)(pPage->aDataEnd - pPage->aData)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( pCur->info.nLocal==nTotal ){ - /* The entire cell is local */ -@@ -80700,7 +81175,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - ** Which can only happen if the SQLITE_NoSchemaError flag was set when - ** the schema was loaded. This cannot be asserted though, as a user might - ** set the flag, load the schema, and then unset the flag. */ -- return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot, NULL); - } - } - -@@ -80823,7 +81298,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - if( pPage->nFree<0 ){ - if( NEVER(pCur->eState>CURSOR_INVALID) ){ - /* ^^^^^--- due to the moveToRoot() call above */ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - rc = btreeComputeFreeSpace(pPage); - } -@@ -80865,7 +81340,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - CellInfo info; - assert( idx>=0 ); - if( idx>=pPage->nCell ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - rc = sqlite3PagerWrite(pPage->pDbPage); - if( rc ){ -@@ -80892,10 +81367,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ - assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ - if( oldCell < pPage->aData+pPage->hdrOffset+10 ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - if( oldCell+szNew > pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - memcpy(oldCell, newCell, szNew); - return SQLITE_OK; -@@ -80997,7 +81472,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 - nIn = pSrc->info.nLocal; - aIn = pSrc->info.pPayload; - if( aIn+nIn>pSrc->pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pSrc->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pSrc->pPage); - } - nRem = pSrc->info.nPayload; - if( nIn==nRem && nIn pPage->maxLocal ){ -@@ -81022,7 +81497,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 - - if( nRem>nIn ){ - if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pSrc->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pSrc->pPage); - } - ovflIn = get4byte(&pSrc->info.pPayload[nIn]); - } -@@ -81118,7 +81593,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ - assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); - if( rc || pCur->eState!=CURSOR_VALID ) return rc; - }else{ -- return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot, NULL); - } - } - assert( pCur->eState==CURSOR_VALID ); -@@ -81127,14 +81602,14 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ - iCellIdx = pCur->ix; - pPage = pCur->pPage; - if( pPage->nCell<=iCellIdx ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - pCell = findCell(pPage, iCellIdx); - if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - if( pCell<&pPage->aCellIdx[pPage->nCell] ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - - /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must -@@ -81225,7 +81700,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ - n = pCur->pPage->pgno; - } - pCell = findCell(pLeaf, pLeaf->nCell-1); -- if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf); -+ if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(NULL, pLeaf); - nCell = pLeaf->xCellSize(pLeaf, pCell); - assert( MX_CELL_SIZE(pBt) >= nCell ); - pTmp = pBt->pTmpSpace; -@@ -81341,7 +81816,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ - */ - sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); - if( pgnoRoot>btreePagecount(pBt) ){ -- return SQLITE_CORRUPT_PGNO(pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pgnoRoot, NULL); - } - pgnoRoot++; - -@@ -81389,7 +81864,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ - } - rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); - if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ -- rc = SQLITE_CORRUPT_PGNO(pgnoRoot); -+ rc = SQLITE_CORRUPT_PGNO(pgnoRoot, NULL); - } - if( rc!=SQLITE_OK ){ - releasePage(pRoot); -@@ -81479,14 +81954,14 @@ static int clearDatabasePage( - - assert( sqlite3_mutex_held(pBt->mutex) ); - if( pgno>btreePagecount(pBt) ){ -- return SQLITE_CORRUPT_PGNO(pgno); -+ return SQLITE_CORRUPT_PGNO(pgno, NULL); - } - rc = getAndInitPage(pBt, pgno, &pPage, 0); - if( rc ) return rc; - if( (pBt->openFlags & BTREE_SINGLE)==0 - && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) - ){ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - goto cleardatabasepage_out; - } - hdr = pPage->hdrOffset; -@@ -81590,7 +82065,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ - assert( p->inTrans==TRANS_WRITE ); - assert( iTable>=2 ); - if( iTable>btreePagecount(pBt) ){ -- return SQLITE_CORRUPT_PGNO(iTable); -+ return SQLITE_CORRUPT_PGNO(iTable, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); } - - rc = sqlite3BtreeClearTable(p, iTable, 0); -@@ -85920,7 +86395,7 @@ static int growOpArray(Vdbe *v, int nOp){ + /* Overwrite the local portion first */ + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, +@@ -83064,7 +83523,7 @@ static int growOpArray(Vdbe *v, int nOp){ ** ** Other useful labels for breakpoints include: ** test_trace_breakpoint(pc,pOp) @@ -1395,7 +1165,7 @@ index f348f3c..0666938 100644 ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ -@@ -94157,7 +94632,7 @@ SQLITE_API int sqlite3_found_count = 0; +@@ -90722,7 +91181,7 @@ SQLITE_API int sqlite3_found_count = 0; ** ** Other useful labels for breakpoints include: ** test_addop_breakpoint(pc,pOp) @@ -1404,10 +1174,10 @@ index f348f3c..0666938 100644 ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ -@@ -181855,6 +182330,12 @@ SQLITE_API int sqlite3_config(int op, ...){ - #endif +@@ -174509,6 +174968,12 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } + #endif /* SQLITE_OMIT_DESERIALIZE */ + case SQLITE_CONFIG_CORRUPTION: { + typedef void(*CORRUPTION_FUNC_t)(void*, const void*); + sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); @@ -1417,7 +1187,7 @@ index f348f3c..0666938 100644 default: { rc = SQLITE_ERROR; -@@ -185037,9 +185518,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ +@@ -177587,9 +178052,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ zType, lineno, 20+sqlite3_sourceid()); return iErr; } diff --git a/patch/0006-Add-extention-cksumvfs-and-check-page.patch b/patch/0006-add-extention-cksumvfs-and-check-page.patch similarity index 98% rename from patch/0006-Add-extention-cksumvfs-and-check-page.patch rename to patch/0006-add-extention-cksumvfs-and-check-page.patch index c8d12eeb31d9c2ac2b17ca8accf06bf8ed14759e..b22b8cf5049f160faf156ff0b3de9965c672bb54 100644 --- a/patch/0006-Add-extention-cksumvfs-and-check-page.patch +++ b/patch/0006-add-extention-cksumvfs-and-check-page.patch @@ -1,8 +1,9 @@ -From 506b1d3f9ea38fd7abc841ebc41649723247c1ee Mon Sep 17 00:00:00 2001 -From: MartinChoo <214582617@qq.com> -Date: Wed, 26 Feb 2025 10:16:41 +0800 -Subject: [PATCH] Add extention:cksumvfs and check page +From 4c555db067d3fb7aa245c3c0597151e863b94d69 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:59:29 +0800 +Subject: [PATCH 6/7] add extention:cksumvfs and check page +Signed-off-by: ryne3366 --- ext/misc/cksumvfs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++ src/sqlite3.c | 99 ++++- @@ -932,10 +933,10 @@ index 0000000..6f4c55c +EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; +#endif diff --git a/src/sqlite3.c b/src/sqlite3.c -index 0666938..7e9dcbf 100644 +index aa629b5..1063591 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -58992,17 +58992,70 @@ static int jrnlBufferSize(Pager *pPager){ +@@ -57046,17 +57046,70 @@ static int jrnlBufferSize(Pager *pPager){ ** and debugging only. */ #ifdef SQLITE_CHECK_PAGES @@ -1011,7 +1012,7 @@ index 0666938..7e9dcbf 100644 static u32 pager_pagehash(PgHdr *pPage){ return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData); } -@@ -59018,8 +59071,15 @@ static void pager_set_pagehash(PgHdr *pPage){ +@@ -57072,8 +57125,15 @@ static void pager_set_pagehash(PgHdr *pPage){ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; @@ -1023,13 +1024,13 @@ index 0666938..7e9dcbf 100644 + if( pPg->flags&PGHDR_DIRTY ) { + return; + } -+ if( pPg->pageHash!=pager_pagehash(pPg) ){ ++ if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ + sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); + } } #else -@@ -185754,12 +185814,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo +@@ -178288,12 +178348,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ @@ -1046,8 +1047,8 @@ index 0666938..7e9dcbf 100644 }else if( op==SQLITE_FCNTL_RESET_CACHE ){ sqlite3BtreeClearCache(pBtree); rc = SQLITE_OK; -@@ -261521,6 +261585,27 @@ static void DumpLocksByPager(Pager *pPager) - +@@ -247458,6 +247522,27 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime + #endif // hw export the symbols #ifdef SQLITE_EXPORT_SYMBOLS +#ifndef SQLITE_CKSUMVFS_STATIC diff --git a/patch/0007-BugFix-CurrVersion.patch b/patch/0007-BugFix-CurrVersion.patch index 36d5eac8bfb289677e2bf1055a315f764e5c1464..5f2e5a8633e594768b953d1265feeb77e655b7f8 100644 --- a/patch/0007-BugFix-CurrVersion.patch +++ b/patch/0007-BugFix-CurrVersion.patch @@ -1,101 +1,70 @@ -From 4cb905b575c2103caada8386cb5fe35562059d4a Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Mon, 24 Mar 2025 20:30:45 +0800 -Subject: [PATCH] check permission for meta file +From 3d81c93e1b8859c245a499ce3834929da3671053 Mon Sep 17 00:00:00 2001 +From: wuyichen <664334617@qq.com> +Date: Sat, 19 Apr 2025 10:48:21 +0800 +Subject: [PATCH] Min check page size set to 4K +Signed-off-by: ryne3366 --- - src/sqlite3.c | 120 ++++++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 96 insertions(+), 24 deletions(-) + src/sqlite3.c | 60 +++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index 7e9dcbf..d350cfc 100644 +index 1063591..e7e3557 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c -@@ -45151,7 +45151,7 @@ static int unixOpen( +@@ -43267,6 +43267,9 @@ static int unixOpen( flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; -- sqlite3_log(SQLITE_WARNING, "Try open file readonly"); ++#ifdef LOG_DUMP + sqlite3_log(SQLITE_WARNING, "Try open file readonly sysno %d", errno); - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; -@@ -70082,6 +70082,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( - ** If parameter xBusy is not NULL, it is a pointer to a busy-handler - ** callback. In this case this function runs a blocking checkpoint. - */ -+static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); - SQLITE_PRIVATE int sqlite3WalCheckpoint( - Wal *pWal, /* Wal connection */ - sqlite3 *db, /* Check this handle's interrupt flag */ -@@ -70177,7 +70178,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); - }else{ -- rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); -+ sqlite3_int64 startTime; -+ sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); -+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); -+ if (rc == SQLITE_OK){ -+ walLogCheckpointInfo(pWal, db, startTime); -+ } ++#endif + fd = robust_open(zName, openFlags, openMode); } - - /* If no error occurred, set the output variables. */ -@@ -205751,6 +205757,39 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ - return rc; + } +@@ -57046,6 +57049,9 @@ static int jrnlBufferSize(Pager *pPager){ + ** and debugging only. + */ + #ifdef SQLITE_CHECK_PAGES ++#ifndef SQLITE_MIN_CHECK_PAGE_SIZE ++#define SQLITE_MIN_CHECK_PAGE_SIZE 4096 ++#endif + #if defined (__arm__) || defined (__aarch64__) + #include + u32 deep_fast_hash_arm(void *src, int srcLen){ +@@ -57114,6 +57120,9 @@ static u32 pager_pagehash(PgHdr *pPage){ + return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData); } - -+/* -+** Expression node pExpr is an MSR phrase. This function restarts pExpr -+** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned -+** if successful, or an SQLite error code otherwise. -+*/ -+int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){ -+ int rc = SQLITE_OK; -+ if( pExpr->bEof==0 ){ -+ i64 iDocid = pExpr->iDocid; -+ fts3EvalRestart(pCsr, pExpr, &rc); -+ while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){ -+ fts3EvalNextRow(pCsr, pExpr, &rc); -+ if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB; -+ } -+ } -+ return rc; -+} -+ -+/* -+** If expression pExpr is a phrase expression that uses an MSR query, -+** restart it as a regular, non-incremental query. Return SQLITE_OK -+** if successful, or an SQLite error code otherwise. -+*/ -+static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ -+ TermOffsetCtx *p = (TermOffsetCtx*)ctx; -+ int rc = SQLITE_OK; -+ if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){ -+ rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr); -+ pExpr->pPhrase->bIncr = 0; + static void pager_set_pagehash(PgHdr *pPage){ ++ if( pPage->pPager->pageSize iPrevId; - sCtx.pCsr = pCsr; + pPage->pageHash = pager_pagehash(pPage); + } -+ /* If a query restart will be required, do it here, rather than later of -+ ** after pointers to poslist buffers that may be invalidated by a restart -+ ** have been saved. */ -+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx); -+ if( rc!=SQLITE_OK ) goto offsets_out; -+ - /* Loop through the table columns, appending offset information to - ** string-buffer res for each column. - */ -@@ -260390,7 +260435,7 @@ static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char * +@@ -57125,10 +57134,7 @@ static void pager_set_pagehash(PgHdr *pPage){ + #define CHECK_PAGE(x) checkPage(x) + static void checkPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; +- if( pPager->eState==PAGER_ERROR ){ +- return; +- } +- if( pPg->flags&PGHDR_DIRTY ) { ++ if( pPager->pageSize eState==PAGER_ERROR || pPg->flags&PGHDR_DIRTY ) { + return; + } + if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ +@@ -59101,6 +59107,9 @@ static int pagerWalFrames( + } + + #ifdef SQLITE_CHECK_PAGES ++ if( pPager->pageSize pPCache); + for(p=pList; p; p=p->pDirty){ + pager_set_pagehash(p); +@@ -246320,7 +246329,7 @@ static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char * sqlite3_mutex_enter(db->mutex); // only support enabled meta double write int rc = MetaDwrOpenAndCheck(pBt); @@ -104,7 +73,7 @@ index 7e9dcbf..d350cfc 100644 parse->nErr++; parse->rc = rc; } -@@ -260842,6 +260887,29 @@ static inline const char *GetMetaFilePath(Pager *pPager) +@@ -246776,6 +246785,29 @@ static inline const char *GetMetaFilePath(Pager *pPager) return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); } @@ -134,7 +103,7 @@ index 7e9dcbf..d350cfc 100644 static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { if (pPager->metaFd || pPager->zFilename == NULL) { return SQLITE_OK; -@@ -260858,15 +260926,10 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { +@@ -246792,15 +246824,10 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { return SQLITE_NOMEM_BKPT; } sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); @@ -151,82 +120,26 @@ index 7e9dcbf..d350cfc 100644 u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); if (openCreate) { flags |= SQLITE_OPEN_CREATE; -@@ -261425,16 +261488,6 @@ static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockT - } - } - --static inline const char *TrxLockName(int eLock) --{ -- return eLock == NO_LOCK ? "NO_LOCK" : -- eLock == RESERVED_LOCK ? "RESERVED" : -- eLock == EXCLUSIVE_LOCK ? "EXCLUSIVE" : -- eLock == SHARED_LOCK ? "SHARED" : -- eLock == PENDING_LOCK ? "PENDING": -- eLock == UNKNOWN_LOCK ? "UNKNOWN" : "UNKNOWN_LOCK"; --} -- - static inline const char *IdxToLockName(u32 idx) - { - const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", -@@ -261451,7 +261504,7 @@ static void DumpHandleLock(char *dumpBuf, int dumpBufLen) - for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { - if (lockStatus[i] != NO_LOCK) { - tmp[0] = '\0'; -- sqlite3_snprintf(availLen, tmp, "<%s, %s>", IdxToLockName((u32)i), TrxLockName(lockStatus[i])); -+ sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); - int len = strlen(tmp); - tmp += len; - availLen -= len; -@@ -261490,8 +261543,8 @@ static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) - sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); - return; - } -- sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%s, dbRef:%d, lockCnt:%d, curLock:%s, processLock:%d", -- TrxLockName(file->eFileLock), inode->nRef, inode->nLock, TrxLockName(inode->eFileLock), inode->bProcessLock); -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", -+ file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); - const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; -@@ -261511,10 +261564,13 @@ static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) - - static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) - { -- if (!walEnabled || file->pShm == NULL || file->pShm->pShmNode == NULL) { -- sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled!"); -+ if (file->pShm == NULL || file->pShm->pShmNode == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); - return; - } -+ if (!walEnabled) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); -+ } - unixShmNode *pShmNode = file->pShm->pShmNode; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; -@@ -261583,6 +261639,22 @@ static void DumpLocksByPager(Pager *pPager) - } - #endif /* SQLITE_OS_UNIX */ - -+static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { -+ sqlite3_int64 endTime; -+ sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); -+ sqlite3_int64 timeUse = endTime - startTime; +@@ -247513,11 +247540,16 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime + sqlite3_int64 endTime; + sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); + sqlite3_int64 timeUse = endTime - startTime; + static sqlite3_int64 lastDumpTime = 0; + static sqlite3_int64 ckptCnt = 0; -+ /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ + /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ +- if (timeUse > 1500 || pWal->hdr.mxFrame > 12800) { +- sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal ckpt use time: %lld(ms), wal frame: %u", +- timeUse, pWal->hdr.mxFrame); + if (timeUse > 1500 || (pWal->hdr.mxFrame > 12800 && (lastDumpTime - endTime) > 2000)) { + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal try ckpt count %d use time: %lld(ms), wal frame: %u", + ckptCnt, timeUse, pWal->hdr.mxFrame); + lastDumpTime = endTime; + ckptCnt = 0; -+ } + } + ckptCnt++; -+} -+ + } + #endif // hw export the symbols - #ifdef SQLITE_EXPORT_SYMBOLS - #ifndef SQLITE_CKSUMVFS_STATIC -- -2.34.1 +2.34.1.windows.1 diff --git a/src/shell.c b/src/shell.c index b08671e14de3682ddfc689af355a00878e4e4110..4a753e4056830b7a7a623bac4dd3842f428bee10 100644 --- a/src/shell.c +++ b/src/shell.c @@ -39,7 +39,7 @@ typedef unsigned short int u16; /* ** Optionally #include a user-defined header, whereby compilation options -** may be set prior to where they take effect, but after platform setup. +** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. Note that this macro has a like effect on sqlite3.c compilation. */ @@ -117,20 +117,23 @@ typedef unsigned short int u16; #include #include #include -#include #include "sqlite3.h" +#include "sqlite3sym.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef unsigned char u8; #if SQLITE_USER_AUTHENTICATION # include "sqlite3userauth.h" #endif + +sqlite3_config(SQLITE_CONFIG_ENABLE_ICU); + #include #include #if !defined(_WIN32) && !defined(WIN32) # include -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) +# if !defined(__RTP__) && !defined(_WRS_KERNEL) # include # endif #endif @@ -185,14 +188,6 @@ typedef unsigned char u8; # define SHELL_USE_LOCAL_GETLINE 1 #endif -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if defined(GCC_VERSION) && GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif #if defined(_WIN32) || defined(WIN32) # if SQLITE_OS_WINRT @@ -219,7 +214,7 @@ typedef unsigned char u8; /* Make sure isatty() has a prototype. */ extern int isatty(int); -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) +# if !defined(__RTP__) && !defined(_WRS_KERNEL) /* popen and pclose are not C89 functions and so are ** sometimes omitted from the header */ extern FILE *popen(const char*,const char*); @@ -246,1942 +241,1185 @@ typedef unsigned char u8; #if SQLITE_OS_WINRT #include #endif -#undef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN #include /* string conversion routines only needed on Win32 */ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); +extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); +extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif -/* Use console I/O package as a direct INCLUDE. */ -#define SQLITE_INTERNAL_LINKAGE static - -#ifdef SQLITE_SHELL_FIDDLE -/* Deselect most features from the console I/O package for Fiddle. */ -# define SQLITE_CIO_NO_REDIRECT -# define SQLITE_CIO_NO_CLASSIFY -# define SQLITE_CIO_NO_TRANSLATE -# define SQLITE_CIO_NO_SETMODE -#endif -/************************* Begin ../ext/consio/console_io.h ******************/ -/* -** 2023 November 1 -** -** 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 exposes various interfaces used for console and other I/O -** by the SQLite project command-line tools. These interfaces are used -** at either source conglomeration time, compilation time, or run time. -** This source provides for either inclusion into conglomerated, -** "single-source" forms or separate compilation then linking. -** -** Platform dependencies are "hidden" here by various stratagems so -** that, provided certain conditions are met, the programs using this -** source or object code compiled from it need no explicit conditional -** compilation in their source for their console and stream I/O. -** -** The symbols and functionality exposed here are not a public API. -** This code may change in tandem with other project code as needed. -** -** When this .h file and its companion .c are directly incorporated into -** a source conglomeration (such as shell.c), the preprocessor symbol -** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O -** translation for Windows is effected for the build. -*/ -#define HAVE_CONSOLE_IO_H 1 -#ifndef SQLITE_INTERNAL_LINKAGE -# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */ -# include +/* On Windows, we normally run with output mode of TEXT so that \n characters +** are automatically translated into \r\n. However, this behavior needs +** to be disabled in some cases (ex: when generating CSV output and when +** rendering quoted strings that contain \n characters). The following +** routines take care of that. +*/ +#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT +static void setBinaryMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_BINARY); +} +static void setTextMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_TEXT); +} #else -# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */ +# define setBinaryMode(X,Y) +# define setTextMode(X,Y) #endif -#ifndef SQLITE3_H -/* # include "sqlite3.h" */ +/* True if the timer is enabled */ +static int enableTimer = 0; + +/* A version of strcmp() that works with NULL values */ +static int cli_strcmp(const char *a, const char *b){ + if( a==0 ) a = ""; + if( b==0 ) b = ""; + return strcmp(a,b); +} +static int cli_strncmp(const char *a, const char *b, size_t n){ + if( a==0 ) a = ""; + if( b==0 ) b = ""; + return strncmp(a,b,n); +} + +/* Return the current wall-clock time */ +static sqlite3_int64 timeOfDay(void){ + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs==0 ) return 0; /* Never actually happens */ + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; +} + +#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) +#include +#include + +/* VxWorks does not support getrusage() as far as we can determine */ +#if defined(_WRS_KERNEL) || defined(__RTP__) +struct rusage { + struct timeval ru_utime; /* user CPU time used */ + struct timeval ru_stime; /* system CPU time used */ +}; +#define getrusage(A,B) memset(B,0,sizeof(*B)) #endif -#ifndef SQLITE_CIO_NO_CLASSIFY +/* Saved resource information for the beginning of an operation */ +static struct rusage sBegin; /* CPU time at start */ +static sqlite3_int64 iBegin; /* Wall-clock time at start */ + +/* +** Begin timing an operation +*/ +static void beginTimer(void){ + if( enableTimer ){ + getrusage(RUSAGE_SELF, &sBegin); + iBegin = timeOfDay(); + } +} -/* Define enum for use with following function. */ -typedef enum StreamsAreConsole { - SAC_NoConsole = 0, - SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4, - SAC_AnyConsole = 0x7 -} StreamsAreConsole; +/* Return the difference of two time_structs in seconds */ +static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ + return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + + (double)(pEnd->tv_sec - pStart->tv_sec); +} /* -** Classify the three standard I/O streams according to whether -** they are connected to a console attached to the process. -** -** Returns the bit-wise OR of SAC_{In,Out,Err}Console values, -** or SAC_NoConsole if none of the streams reaches a console. -** -** This function should be called before any I/O is done with -** the given streams. As a side-effect, the given inputs are -** recorded so that later I/O operations on them may be done -** differently than the C library FILE* I/O would be done, -** iff the stream is used for the I/O functions that follow, -** and to support the ones that use an implicit stream. -** -** On some platforms, stream or console mode alteration (aka -** "Setup") may be made which is undone by consoleRestore(). +** Print the timing results. */ -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ); -/* A usual call for convenience: */ -#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr) +static void endTimer(void){ + if( enableTimer ){ + sqlite3_int64 iEnd = timeOfDay(); + struct rusage sEnd; + getrusage(RUSAGE_SELF, &sEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (iEnd - iBegin)*0.001, + timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); + } +} + +#define BEGIN_TIMER beginTimer() +#define END_TIMER endTimer() +#define HAS_TIMER 1 + +#elif (defined(_WIN32) || defined(WIN32)) + +/* Saved resource information for the beginning of an operation */ +static HANDLE hProcess; +static FILETIME ftKernelBegin; +static FILETIME ftUserBegin; +static sqlite3_int64 ftWallBegin; +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, + LPFILETIME, LPFILETIME); +static GETPROCTIMES getProcessTimesAddr = NULL; /* -** After an initial call to consoleClassifySetup(...), renew -** the same setup it effected. (A call not after is an error.) -** This will restore state altered by consoleRestore(); -** -** Applications which run an inferior (child) process which -** inherits the same I/O streams may call this function after -** such a process exits to guard against console mode changes. +** Check to see if we have timer support. Return 1 if necessary +** support found (or found previously). */ -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void); +static int hasTimer(void){ + if( getProcessTimesAddr ){ + return 1; + } else { +#if !SQLITE_OS_WINRT + /* GetProcessTimes() isn't supported in WIN95 and some other Windows + ** versions. See if the version we are running on has it, and if it + ** does, save off a pointer to it and the current process handle. + */ + hProcess = GetCurrentProcess(); + if( hProcess ){ + HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); + if( NULL != hinstLib ){ + getProcessTimesAddr = + (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + if( NULL != getProcessTimesAddr ){ + return 1; + } + FreeLibrary(hinstLib); + } + } +#endif + } + return 0; +} /* -** Undo any side-effects left by consoleClassifySetup(...). -** -** This should be called after consoleClassifySetup() and -** before the process terminates normally. It is suitable -** for use with the atexit() C library procedure. After -** this call, no console I/O should be done until one of -** console{Classify or Renew}Setup(...) is called again. -** -** Applications which run an inferior (child) process that -** inherits the same I/O streams might call this procedure -** before so that said process will have a console setup -** however users have configured it or come to expect. +** Begin timing an operation */ -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ); +static void beginTimer(void){ + if( enableTimer && getProcessTimesAddr ){ + FILETIME ftCreation, ftExit; + getProcessTimesAddr(hProcess,&ftCreation,&ftExit, + &ftKernelBegin,&ftUserBegin); + ftWallBegin = timeOfDay(); + } +} -#else /* defined(SQLITE_CIO_NO_CLASSIFY) */ -# define consoleClassifySetup(i,o,e) -# define consoleRenewSetup() -# define consoleRestore() -#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */ +/* Return the difference of two FILETIME structs in seconds */ +static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ + sqlite_int64 i64Start = *((sqlite_int64 *) pStart); + sqlite_int64 i64End = *((sqlite_int64 *) pEnd); + return (double) ((i64End - i64Start) / 10000000.0); +} -#ifndef SQLITE_CIO_NO_REDIRECT /* -** Set stream to be used for the functions below which write -** to "the designated X stream", where X is Output or Error. -** Returns the previous value. -** -** Alternatively, pass the special value, invalidFileStream, -** to get the designated stream value without setting it. -** -** Before the designated streams are set, they default to -** those passed to consoleClassifySetup(...), and before -** that is called they default to stdout and stderr. -** -** It is error to close a stream so designated, then, without -** designating another, use the corresponding {o,e}Emit(...). +** Print the timing results. */ -SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream; -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf); -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf); -# endif +static void endTimer(void){ + if( enableTimer && getProcessTimesAddr){ + FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; + sqlite3_int64 ftWallEnd = timeOfDay(); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (ftWallEnd - ftWallBegin)*0.001, + timeDiff(&ftUserBegin, &ftUserEnd), + timeDiff(&ftKernelBegin, &ftKernelEnd)); + } +} + +#define BEGIN_TIMER beginTimer() +#define END_TIMER endTimer() +#define HAS_TIMER hasTimer() + #else -# define setOutputStream(pf) -# define setErrorStream(pf) -#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */ +#define BEGIN_TIMER +#define END_TIMER +#define HAS_TIMER 0 +#endif -#ifndef SQLITE_CIO_NO_TRANSLATE /* -** Emit output like fprintf(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write formatted output -** to the provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). +** Used to prevent warnings about unused parameters */ -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...); +#define UNUSED_PARAMETER(x) (void)(x) /* -** Emit output like fputs(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write given text to the -** provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). +** Number of elements in an array */ -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO); -/* Like fPutsUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z); -/* Like fPutsUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z); +#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) /* -** Emit output like fPutsUtf8(), except that the length of the -** accepted char or character sequence is limited by nAccept. -** -** Returns the number of accepted char values. +** If the following flag is set, then command execution stops +** at an error if we are not interactive. */ -#ifdef CONSIO_SPUTB -SQLITE_INTERNAL_LINKAGE int -fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated output. */ -#endif -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated error. */ -#ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept); -#endif +static int bail_on_error = 0; /* -** Collect input like fgets(...) with special provisions for input -** from the console on platforms that require same. Defers to the -** C library fgets() when input is not from the console. Newline -** translation may be done as set by set{Binary,Text}Mode(). As a -** convenience, pfIn==NULL is treated as stdin. +** Threat stdin as an interactive input if the following variable +** is true. Otherwise, assume stdin is connected to a file or pipe. */ -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn); -/* Like fGetsUtf8 except stream is always the designated input. */ -/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */ - -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ +static int stdin_is_interactive = 1; -#ifndef SQLITE_CIO_NO_SETMODE /* -** Set given stream for binary mode, where newline translation is -** not done, or for text mode where, for some platforms, newlines -** are translated to the platform's conventional char sequence. -** If bFlush true, flush the stream. -** -** An additional side-effect is that if the stream is one passed -** to consoleClassifySetup() as an output, it is flushed first. -** -** Note that binary/text mode has no effect on console I/O -** translation. On all platforms, newline to the console starts -** a new line and CR,LF chars from the console become a newline. +** On Windows systems we have to know if standard output is a console +** in order to translate UTF-8 into MBCS. The following variable is +** true if translation is required. */ -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush); -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush); -#endif - -#ifdef SQLITE_CIO_PROMPTED_IN -typedef struct Prompts { - int numPrompts; - const char **azPrompts; -} Prompts; +static int stdout_is_console = 1; /* -** Macros for use of a line editor. -** -** The following macros define operations involving use of a -** line-editing library or simple console interaction. -** A "T" argument is a text (char *) buffer or filename. -** A "N" argument is an integer. -** -** SHELL_ADD_HISTORY(T) // Record text as line(s) of history. -** SHELL_READ_HISTORY(T) // Read history from file named by T. -** SHELL_WRITE_HISTORY(T) // Write history to file named by T. -** SHELL_STIFLE_HISTORY(N) // Limit history to N entries. -** -** A console program which does interactive console input is -** expected to call: -** SHELL_READ_HISTORY(T) before collecting such input; -** SHELL_ADD_HISTORY(T) as record-worthy input is taken; -** SHELL_STIFLE_HISTORY(N) after console input ceases; then -** SHELL_WRITE_HISTORY(T) before the program exits. +** The following is the open SQLite database. We make a pointer +** to this database a static variable so that it can be accessed +** by the SIGINT handler to interrupt database processing. */ +static sqlite3 *globalDb = 0; /* -** Retrieve a single line of input text from an input stream. -** -** If pfIn is the input stream passed to consoleClassifySetup(), -** and azPrompt is not NULL, then a prompt is issued before the -** line is collected, as selected by the isContinuation flag. -** Array azPrompt[{0,1}] holds the {main,continuation} prompt. -** -** If zBufPrior is not NULL then it is a buffer from a prior -** call to this routine that can be reused, or will be freed. -** -** The result is stored in space obtained from malloc() and -** must either be freed by the caller or else passed back to -** this function as zBufPrior for reuse. -** -** This function may call upon services of a line-editing -** library to interactively collect line edited input. +** True if an interrupt (Control-C) has been received. */ -SQLITE_INTERNAL_LINKAGE char * -shellGetLine(FILE *pfIn, char *zBufPrior, int nLen, - short isContinuation, Prompts azPrompt); -#endif /* defined(SQLITE_CIO_PROMPTED_IN) */ +static volatile int seenInterrupt = 0; + /* -** TBD: Define an interface for application(s) to generate -** completion candidates for use by the line-editor. -** -** This may be premature; the CLI is the only application -** that does this. Yet, getting line-editing melded into -** console I/O is desirable because a line-editing library -** may have to establish console operating mode, possibly -** in a way that interferes with the above functionality. +** This is the name of our program. It is set in main(), used +** in a number of other places, mostly for error messages. */ +static char *Argv0; -#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1< =0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm); - -#endif - -/************************* End ../ext/consio/console_io.h ********************/ -/************************* Begin ../ext/consio/console_io.c ******************/ /* -** 2023 November 4 -** -** 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 implements various interfaces used for console and stream I/O -** by the SQLite project command-line tools, as explained in console_io.h . -** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there. +** Prompt strings. Initialized in main. Settable with +** .prompt main continue */ +static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ +static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ -#ifndef SQLITE_CDECL -# define SQLITE_CDECL -#endif - -#ifndef SHELL_NO_SYSINC -# include -# include -# include -# include -# include -/* # include "sqlite3.h" */ -#endif -#ifndef HAVE_CONSOLE_IO_H -# include "console_io.h" -#endif -#if defined(_MSC_VER) -# pragma warning(disable : 4204) +/* +** Render output like fprintf(). Except, if the output is going to the +** console and if this is running on a Windows machine, translate the +** output from UTF-8 into MBCS. +*/ +#if defined(_WIN32) || defined(WIN32) +void utf8_printf(FILE *out, const char *zFormat, ...){ + va_list ap; + va_start(ap, zFormat); + if( stdout_is_console && (out==stdout || out==stderr) ){ + char *z1 = sqlite3_vmprintf(zFormat, ap); + char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); + sqlite3_free(z1); + fputs(z2, out); + sqlite3_free(z2); + }else{ + vfprintf(out, zFormat, ap); + } + va_end(ap); +} +#elif !defined(utf8_printf) +# define utf8_printf fprintf #endif -#ifndef SQLITE_CIO_NO_TRANSLATE -# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT -# ifndef SHELL_NO_SYSINC -# include -# include -# undef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# include -# endif -# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */ -# else -# ifndef SHELL_NO_SYSINC -# include -# endif -# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */ -# endif -#else -# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */ +/* +** Render output like fprintf(). This should not be used on anything that +** includes string formatting (e.g. "%s"). +*/ +#if !defined(raw_printf) +# define raw_printf fprintf #endif -#if CIO_WIN_WC_XLATE -static HANDLE handleOfFile(FILE *pf){ - int fileDesc = _fileno(pf); - union { intptr_t osfh; HANDLE fh; } fid = { - (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE - }; - return fid.fh; +/* Indicate out-of-memory and exit. */ +static void shell_out_of_memory(void){ + raw_printf(stderr,"Error: out of memory\n"); + exit(1); } -#endif -#ifndef SQLITE_CIO_NO_TRANSLATE -typedef struct PerStreamTags { -# if CIO_WIN_WC_XLATE - HANDLE hx; - DWORD consMode; - char acIncomplete[4]; -# else - short reachesConsole; -# endif - FILE *pf; -} PerStreamTags; +/* Check a pointer to see if it is NULL. If it is NULL, exit with an +** out-of-memory error. +*/ +static void shell_check_oom(void *p){ + if( p==0 ) shell_out_of_memory(); +} -/* Define NULL-like value for things which can validly be 0. */ -# define SHELL_INVALID_FILE_PTR ((FILE *)~0) -# if CIO_WIN_WC_XLATE -# define SHELL_INVALID_CONS_MODE 0xFFFF0000 -# endif - -# if CIO_WIN_WC_XLATE -# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \ - {0,0,0,0}, SHELL_INVALID_FILE_PTR } -# else -# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR } -# endif - -/* Quickly say whether a known output is going to the console. */ -# if CIO_WIN_WC_XLATE -static short pstReachesConsole(PerStreamTags *ppst){ - return (ppst->hx != INVALID_HANDLE_VALUE); -} -# else -# define pstReachesConsole(ppst) 0 -# endif - -# if CIO_WIN_WC_XLATE -static void restoreConsoleArb(PerStreamTags *ppst){ - if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode); -} -# else -# define restoreConsoleArb(ppst) -# endif +/* +** Write I/O traces to the following stream. +*/ +#ifdef SQLITE_ENABLE_IOTRACE +static FILE *iotrace = 0; +#endif -/* Say whether FILE* appears to be a console, collect associated info. */ -static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){ -# if CIO_WIN_WC_XLATE - short rv = 0; - DWORD dwCM = SHELL_INVALID_CONS_MODE; - HANDLE fh = handleOfFile(pf); - ppst->pf = pf; - if( INVALID_HANDLE_VALUE != fh ){ - rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM)); - } - ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE; - ppst->consMode = dwCM; - return rv; -# else - ppst->pf = pf; - ppst->reachesConsole = ( (short)isatty(fileno(pf)) ); - return ppst->reachesConsole; -# endif +/* +** This routine works like printf in that its first argument is a +** format string and subsequent arguments are values to be substituted +** in place of % fields. The result of formatting this string +** is written to iotrace. +*/ +#ifdef SQLITE_ENABLE_IOTRACE +static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ + va_list ap; + char *z; + if( iotrace==0 ) return; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + utf8_printf(iotrace, "%s", z); + sqlite3_free(z); } +#endif -# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4) -# endif - -# if CIO_WIN_WC_XLATE -/* Define console modes for use with the Windows Console API. */ -# define SHELL_CONI_MODE \ - (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \ - | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT) -# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \ - | ENABLE_VIRTUAL_TERMINAL_PROCESSING) -# endif - -typedef struct ConsoleInfo { - PerStreamTags pstSetup[3]; - PerStreamTags pstDesignated[3]; - StreamsAreConsole sacSetup; -} ConsoleInfo; - -static short isValidStreamInfo(PerStreamTags *ppst){ - return (ppst->pf != SHELL_INVALID_FILE_PTR); +/* +** Output string zUtf to stream pOut as w characters. If w is negative, +** then right-justify the text. W is the width in UTF-8 characters, not +** in bytes. This is different from the %*.*s specification in printf +** since with %*.*s the width is measured in bytes, not characters. +*/ +static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ + int i; + int n; + int aw = w<0 ? -w : w; + if( zUtf==0 ) zUtf = ""; + for(i=n=0; zUtf[i]; i++){ + if( (zUtf[i]&0xc0)!=0x80 ){ + n++; + if( n==aw ){ + do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); + break; + } + } + } + if( n>=aw ){ + utf8_printf(pOut, "%.*s", i, zUtf); + }else if( w<0 ){ + utf8_printf(pOut, "%*s%s", aw-n, "", zUtf); + }else{ + utf8_printf(pOut, "%s%*s", zUtf, aw-n, ""); + } } -static ConsoleInfo consoleInfo = { - { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - SAC_NoConsole /* sacSetup */ -}; - -SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0; -# if CIO_WIN_WC_XLATE -static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){ - if( pstReachesConsole(ppst) ){ - DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE; - SetConsoleMode(ppst->hx, cm); +/* +** Determines if a string is a number of not. +*/ +static int isNumber(const char *z, int *realnum){ + if( *z=='-' || *z=='+' ) z++; + if( !IsDigit(*z) ){ + return 0; } -} -# else -# define maybeSetupAsConsole(ppst,odir) -# endif - -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){ -# if CIO_WIN_WC_XLATE - int ix = 0; - while( ix < 6 ){ - PerStreamTags *ppst = (ix<3)? - &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3]; - maybeSetupAsConsole(ppst, (ix % 3)>0); - ++ix; + z++; + if( realnum ) *realnum = 0; + while( IsDigit(*z) ){ z++; } + if( *z=='.' ){ + z++; + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } + if( realnum ) *realnum = 1; } -# endif -} - -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){ - StreamsAreConsole rv = SAC_NoConsole; - FILE* apf[3] = { pfIn, pfOut, pfErr }; - int ix; - for( ix = 2; ix >= 0; --ix ){ - PerStreamTags *ppst = &consoleInfo.pstSetup[ix]; - if( streamOfConsole(apf[ix], ppst) ){ - rv |= (SAC_InConsole< 0 ) fflush(apf[ix]); + if( *z=='e' || *z=='E' ){ + z++; + if( *z=='+' || *z=='-' ) z++; + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } + if( realnum ) *realnum = 1; } - consoleInfo.sacSetup = rv; - consoleRenewSetup(); - return rv; + return *z==0; } -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){ -# if CIO_WIN_WC_XLATE - static ConsoleInfo *pci = &consoleInfo; - if( pci->sacSetup ){ - int ix; - for( ix=0; ix<3; ++ix ){ - if( pci->sacSetup & (SAC_InConsole< pstSetup[ix]; - SetConsoleMode(ppst->hx, ppst->consMode); - } - } - } -# endif +/* +** Compute a string length that is limited to what can be stored in +** lower 30 bits of a 32-bit signed integer. +*/ +static int strlen30(const char *z){ + const char *z2 = z; + while( *z2 ){ z2++; } + return 0x3fffffff & (int)(z2 - z); } -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ -#ifdef SQLITE_CIO_INPUT_REDIR -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** readable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. +/* +** Return the length of a string in characters. Multibyte UTF8 characters +** count as a single character. */ -static PerStreamTags * isKnownReadable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; +static int strlenChar(const char *z){ + int n = 0; + while( *z ){ + if( (0xc0&*(z++))!=0x80 ) n++; + } + return n; } -#endif -#ifndef SQLITE_CIO_NO_TRANSLATE -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** writable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. +/* +** Return open FILE * if zFile exists, can be opened for read +** and is an ordinary file or a character stream source. +** Otherwise return 0. */ -static PerStreamTags * isKnownWritable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2], - &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; -} - -static FILE *designateEmitStream(FILE *pf, unsigned chix){ - FILE *rv = consoleInfo.pstDesignated[chix].pf; - if( pf == invalidFileStream ) return rv; - else{ - /* Setting a possibly new output stream. */ - PerStreamTags *ppst = isKnownWritable(pf); - if( ppst != 0 ){ - PerStreamTags pst = *ppst; - consoleInfo.pstDesignated[chix] = pst; - }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]); +static FILE * openChrSource(const char *zFile){ +#ifdef _WIN32 + struct _stat x = {0}; +# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) + /* On Windows, open first, then check the stream nature. This order + ** is necessary because _stat() and sibs, when checking a named pipe, + ** effectively break the pipe as its supplier sees it. */ + FILE *rv = fopen(zFile, "rb"); + if( rv==0 ) return 0; + if( _fstat(_fileno(rv), &x) != 0 + || !STAT_CHR_SRC(x.st_mode)){ + fclose(rv); + rv = 0; } return rv; +#else + struct stat x = {0}; + int rc = stat(zFile, &x); +# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) + if( rc!=0 ) return 0; + if( STAT_CHR_SRC(x.st_mode) ){ + return fopen(zFile, "rb"); + }else{ + return 0; + } +#endif +#undef STAT_CHR_SRC } -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){ - return designateEmitStream(pf, 1); -} -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){ - return designateEmitStream(pf, 2); -} -# endif -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#ifndef SQLITE_CIO_NO_SETMODE -# if CIO_WIN_WC_XLATE -static void setModeFlushQ(FILE *pf, short bFlush, int mode){ - if( bFlush ) fflush(pf); - _setmode(_fileno(pf), mode); -} -# else -# define setModeFlushQ(f, b, m) if(b) fflush(f) -# endif +/* +** This routine reads a line of text from FILE in, stores +** the text in memory obtained from malloc() and returns a pointer +** to the text. NULL is returned at end of file, or if malloc() +** fails. +** +** If zLine is not NULL then it is a malloced buffer returned from +** a previous call to this routine that may be reused. +*/ +static char *local_getline(char *zLine, FILE *in){ + int nLine = zLine==0 ? 0 : 100; + int n = 0; -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_BINARY); -} -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_TEXT); -} -# undef setModeFlushQ - -#else /* defined(SQLITE_CIO_NO_SETMODE) */ -# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -#endif /* defined(SQLITE_CIO_NO_SETMODE) */ - -#ifndef SQLITE_CIO_NO_TRANSLATE -# if CIO_WIN_WC_XLATE -/* Write buffer cBuf as output to stream known to reach console, -** limited to ncTake char's. Return ncTake on success, else 0. */ -static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){ - int rv = 0; - if( z!=NULL ){ - int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0); - if( nwc > 0 ){ - WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR)); - if( zw!=NULL ){ - nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc); - if( nwc > 0 ){ - /* Translation from UTF-8 to UTF-16, then WCHARs out. */ - if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){ - rv = ncTake; - } - } - sqlite3_free(zw); + while( 1 ){ + if( n+100>nLine ){ + nLine = nLine*2 + 100; + zLine = realloc(zLine, nLine); + shell_check_oom(zLine); + } + if( fgets(&zLine[n], nLine - n, in)==0 ){ + if( n==0 ){ + free(zLine); + return 0; } + zLine[n] = 0; + break; + } + while( zLine[n] ) n++; + if( n>0 && zLine[n-1]=='\n' ){ + n--; + if( n>0 && zLine[n-1]=='\r' ) n--; + zLine[n] = 0; + break; } } - return rv; -} - -/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */ -static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){ - char *z = sqlite3_vmprintf(zFormat, ap); - if( z ){ - int rv = conZstrEmit(ppst, z, (int)strlen(z)); - sqlite3_free(z); - return rv; - }else return 0; -} -# endif /* CIO_WIN_WC_XLATE */ - -# ifdef CONSIO_GET_EMIT_STREAM -static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix, - PerStreamTags *ppst){ - PerStreamTags *rv = isKnownWritable(pf); - short isValid = (rv!=0)? isValidStreamInfo(rv) : 0; - if( rv != 0 && isValid ) return rv; - streamOfConsole(pf, ppst); - return ppst; +#if defined(_WIN32) || defined(WIN32) + /* For interactive input on Windows systems, translate the + ** multi-byte characterset characters into UTF-8. */ + if( stdin_is_interactive && in==stdin ){ + char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); + if( zTrans ){ + i64 nTrans = strlen(zTrans)+1; + if( nTrans>nLine ){ + zLine = realloc(zLine, nTrans); + shell_check_oom(zLine); + } + memcpy(zLine, zTrans, nTrans); + sqlite3_free(zTrans); + } + } +#endif /* defined(_WIN32) || defined(WIN32) */ + return zLine; } -# endif -/* Get stream info, either for designated output or error stream when -** chix equals 1 or 2, or for an arbitrary stream when chix == 0. -** In either case, ppst references a caller-owned PerStreamTags -** struct which may be filled in if none of the known writable -** streams is being held by consoleInfo. The ppf parameter is a -** byref output when chix!=0 and a byref input when chix==0. - */ -static PerStreamTags * -getEmitStreamInfo(unsigned chix, PerStreamTags *ppst, - /* in/out */ FILE **ppf){ - PerStreamTags *ppstTry; - FILE *pfEmit; - if( chix > 0 ){ - ppstTry = &consoleInfo.pstDesignated[chix]; - if( !isValidStreamInfo(ppstTry) ){ - ppstTry = &consoleInfo.pstSetup[chix]; - pfEmit = ppst->pf; - }else pfEmit = ppstTry->pf; - if( !isValidStreamInfo(ppstTry) ){ - pfEmit = (chix > 1)? stderr : stdout; - ppstTry = ppst; - streamOfConsole(pfEmit, ppstTry); - } - *ppf = pfEmit; +/* +** Retrieve a single line of input text. +** +** If in==0 then read from standard input and prompt before each line. +** If isContinuation is true, then a continuation prompt is appropriate. +** If isContinuation is zero, then the main prompt should be used. +** +** If zPrior is not NULL then it is a buffer from a prior call to this +** routine that can be reused. +** +** The result is stored in space obtained from malloc() and must either +** be freed by the caller or else passed back into this routine via the +** zPrior argument for reuse. +*/ +#ifndef SQLITE_SHELL_FIDDLE +static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ + char *zPrompt; + char *zResult; + if( in!=0 ){ + zResult = local_getline(zPrior, in); }else{ - ppstTry = isKnownWritable(*ppf); - if( ppstTry != 0 ) return ppstTry; - streamOfConsole(*ppf, ppst); - return ppst; + zPrompt = isContinuation ? continuePrompt : mainPrompt; +#if SHELL_USE_LOCAL_GETLINE + printf("%s", zPrompt); + fflush(stdout); + zResult = local_getline(zPrior, stdin); +#else + free(zPrior); + zResult = shell_readline(zPrompt); + if( zResult && *zResult ) shell_add_history(zResult); +#endif } - return ppstTry; + return zResult; } +#endif /* !SQLITE_SHELL_FIDDLE */ -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfOut, zFormat, ap); -# if CIO_WIN_WC_XLATE - } -# endif - va_end(ap); - return rv; +/* +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. +*/ +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# else - getEmitStreamInfo(2, &pst, &pfErr); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfErr, zFormat, ap); -# if CIO_WIN_WC_XLATE +/* +** Interpret zArg as an integer value, possibly with suffixes. +*/ +static sqlite3_int64 integerValue(const char *zArg){ + sqlite3_int64 v = 0; + static const struct { char *zSuffix; int iMult; } aMult[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "KB", 1000 }, + { "MB", 1000000 }, + { "GB", 1000000000 }, + { "K", 1000 }, + { "M", 1000000 }, + { "G", 1000000000 }, + }; + int i; + int isNeg = 0; + if( zArg[0]=='-' ){ + isNeg = 1; + zArg++; + }else if( zArg[0]=='+' ){ + zArg++; } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){ - va_list ap; - int rv; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - maybeSetupAsConsole(ppst, 1); - rv = conioVmPrintf(ppst, zFormat, ap); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } }else{ -# endif - rv = vfprintf(pfO, zFormat, ap); -# if CIO_WIN_WC_XLATE + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){ - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(z!=0); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - int rv; - maybeSetupAsConsole(ppst, 1); - rv = conZstrEmit(ppst, z, (int)strlen(z)); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (fputs(z, pfO)<0)? 0 : (int)strlen(z); -# if CIO_WIN_WC_XLATE + for(i=0; i z); + initText(p); } -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ +/* zIn is either a pointer to a NULL-terminated string in memory obtained +** from malloc(), or a NULL pointer. The string pointed to by zAppend is +** added to zIn, and the result returned in memory obtained from malloc(). +** zIn, if it was not NULL, is freed. +** +** If the third argument, quote, is not '\0', then it is used as a +** quote character for zAppend. +*/ +static void appendText(ShellText *p, const char *zAppend, char quote){ + i64 len; + i64 i; + i64 nAppend = strlen30(zAppend); -#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1< =0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm){ - int ng = (nAccept<0)? -nAccept : 0; - const char *pcLimit = (nAccept>=0)? z+nAccept : 0; - assert(z!=0); - while( (pcLimit)? (z = pcLimit ) return z; - else{ - char ct = *zt++; - if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){ - /* Trailing bytes are too few, too many, or invalid. */ - return z; - } - } - } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */ - z = zt; + len = nAppend+p->n+1; + if( quote ){ + len += 2; + for(i=0; i pf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfO); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif - -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept){ - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfOut); -# if CIO_WIN_WC_XLATE - } -# endif -} -# ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept){ - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfErr); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif /* defined(CONSIO_EPUTB) */ - -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){ - if( pfIn==0 ) pfIn = stdin; -# if CIO_WIN_WC_XLATE - if( pfIn == consoleInfo.pstSetup[0].pf - && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){ -# if CIO_WIN_WC_XLATE==1 -# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */ - WCHAR wcBuf[SHELL_GULP+1]; - int lend = 0, noc = 0; - if( ncMax > 0 ) cBuf[0] = 0; - while( noc < ncMax-8-1 && !lend ){ - /* There is room for at least 2 more characters and a 0-terminator. */ - int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4; -# undef SHELL_GULP - DWORD nbr = 0; - BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0); - if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){ - /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */ - DWORD nbrx; - bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0); - if( bRC ) nbr += nbrx; - } - if( !bRC || (noc==0 && nbr==0) ) return 0; - if( nbr > 0 ){ - int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0); - if( nmb != 0 && noc+nmb <= ncMax ){ - int iseg = noc; - nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0); - noc += nmb; - /* Fixup line-ends as coded by Windows for CR (or "Enter".) - ** This is done without regard for any setMode{Text,Binary}() - ** call that might have been done on the interactive input. - */ - if( noc > 0 ){ - if( cBuf[noc-1]=='\n' ){ - lend = 1; - if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n'; - } - } - /* Check for ^Z (anywhere in line) too, to act as EOF. */ - while( iseg < noc ){ - if( cBuf[iseg]=='\x1a' ){ - noc = iseg; /* Chop ^Z and anything following. */ - lend = 1; /* Counts as end of line too. */ - break; - } - ++iseg; - } - }else break; /* Drop apparent garbage in. (Could assert.) */ - }else break; - } - /* If got nothing, (after ^Z chop), must be at end-of-file. */ - if( noc > 0 ){ - cBuf[noc] = 0; - return cBuf; - }else return 0; -# endif - }else{ -# endif - return fgets(cBuf, ncMax, pfIn); -# if CIO_WIN_WC_XLATE + if( p->z==0 || p->n+len>=p->nAlloc ){ + p->nAlloc = p->nAlloc*2 + len + 20; + p->z = realloc(p->z, p->nAlloc); + shell_check_oom(p->z); } -# endif -} -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#if defined(_MSC_VER) -# pragma warning(default : 4204) -#endif - -#undef SHELL_INVALID_FILE_PTR - -/************************* End ../ext/consio/console_io.c ********************/ - -#ifndef SQLITE_SHELL_FIDDLE - -/* From here onward, fgets() is redirected to the console_io library. */ -# define fgets(b,n,f) fGetsUtf8(b,n,f) -/* - * Define macros for emitting output text in various ways: - * sputz(s, z) => emit 0-terminated string z to given stream s - * sputf(s, f, ...) => emit varargs per format f to given stream s - * oputz(z) => emit 0-terminated string z to default stream - * oputf(f, ...) => emit varargs per format f to default stream - * eputz(z) => emit 0-terminated string z to error stream - * eputf(f, ...) => emit varargs per format f to error stream - * oputb(b, n) => emit char buffer b[0..n-1] to default stream - * - * Note that the default stream is whatever has been last set via: - * setOutputStream(FILE *pf) - * This is normally the stream that CLI normal output goes to. - * For the stand-alone CLI, it is stdout with no .output redirect. - * - * The ?putz(z) forms are required for the Fiddle builds for string literal - * output, in aid of enforcing format string to argument correspondence. - */ -# define sputz(s,z) fPutsUtf8(z,s) -# define sputf fPrintfUtf8 -# define oputz(z) oPutsUtf8(z) -# define oputf oPrintfUtf8 -# define eputz(z) ePutsUtf8(z) -# define eputf ePrintfUtf8 -# define oputb(buf,na) oPutbUtf8(buf,na) - -#else -/* For Fiddle, all console handling and emit redirection is omitted. */ -/* These next 3 macros are for emitting formatted output. When complaints - * from the WASM build are issued for non-formatted output, (when a mere - * string literal is to be emitted, the ?putz(z) forms should be used. - * (This permits compile-time checking of format string / argument mismatch.) - */ -# define oputf(fmt, ...) printf(fmt,__VA_ARGS__) -# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__) -# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__) -/* These next 3 macros are for emitting simple string literals. */ -# define oputz(z) fputs(z,stdout) -# define eputz(z) fputs(z,stderr) -# define sputz(fp,z) fputs(z,fp) -# define oputb(buf,na) fwrite(buf,1,na,stdout) -#endif - -/* True if the timer is enabled */ -static int enableTimer = 0; - -/* A version of strcmp() that works with NULL values */ -static int cli_strcmp(const char *a, const char *b){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strcmp(a,b); -} -static int cli_strncmp(const char *a, const char *b, size_t n){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strncmp(a,b,n); -} -/* Return the current wall-clock time */ -static sqlite3_int64 timeOfDay(void){ - static sqlite3_vfs *clockVfs = 0; - sqlite3_int64 t; - if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs==0 ) return 0; /* Never actually happens */ - if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ - clockVfs->xCurrentTimeInt64(clockVfs, &t); + if( quote ){ + char *zCsr = p->z+p->n; + *zCsr++ = quote; + for(i=0; i n = (int)(zCsr - p->z); + *zCsr = '\0'; }else{ - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = (sqlite3_int64)(r*86400000.0); + memcpy(p->z+p->n, zAppend, nAppend); + p->n += nAppend; + p->z[p->n] = '\0'; } - return t; } -#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) -#include -#include - -/* VxWorks does not support getrusage() as far as we can determine */ -#if defined(_WRS_KERNEL) || defined(__RTP__) -struct rusage { - struct timeval ru_utime; /* user CPU time used */ - struct timeval ru_stime; /* system CPU time used */ -}; -#define getrusage(A,B) memset(B,0,sizeof(*B)) -#endif - -/* Saved resource information for the beginning of an operation */ -static struct rusage sBegin; /* CPU time at start */ -static sqlite3_int64 iBegin; /* Wall-clock time at start */ - /* -** Begin timing an operation +** Attempt to determine if identifier zName needs to be quoted, either +** because it contains non-alphanumeric characters, or because it is an +** SQLite keyword. Be conservative in this estimate: When in doubt assume +** that quoting is required. +** +** Return '"' if quoting is required. Return 0 if no quoting is required. */ -static void beginTimer(void){ - if( enableTimer ){ - getrusage(RUSAGE_SELF, &sBegin); - iBegin = timeOfDay(); +static char quoteChar(const char *zName){ + int i; + if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; + for(i=0; zName[i]; i++){ + if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; } -} - -/* Return the difference of two time_structs in seconds */ -static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ - return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + - (double)(pEnd->tv_sec - pStart->tv_sec); + return sqlite3_keyword_check(zName, i) ? '"' : 0; } /* -** Print the timing results. +** Construct a fake object name and column list to describe the structure +** of the view, virtual table, or table valued function zSchema.zName. */ -static void endTimer(void){ - if( enableTimer ){ - sqlite3_int64 iEnd = timeOfDay(); - struct rusage sEnd; - getrusage(RUSAGE_SELF, &sEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (iEnd - iBegin)*0.001, - timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), - timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); - } -} - -#define BEGIN_TIMER beginTimer() -#define END_TIMER endTimer() -#define HAS_TIMER 1 - -#elif (defined(_WIN32) || defined(WIN32)) - -/* Saved resource information for the beginning of an operation */ -static HANDLE hProcess; -static FILETIME ftKernelBegin; -static FILETIME ftUserBegin; -static sqlite3_int64 ftWallBegin; -typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, - LPFILETIME, LPFILETIME); -static GETPROCTIMES getProcessTimesAddr = NULL; +static char *shellFakeSchema( + sqlite3 *db, /* The database connection containing the vtab */ + const char *zSchema, /* Schema of the database holding the vtab */ + const char *zName /* The name of the virtual table */ +){ + sqlite3_stmt *pStmt = 0; + char *zSql; + ShellText s; + char cQuote; + char *zDiv = "("; + int nRow = 0; -/* -** Check to see if we have timer support. Return 1 if necessary -** support found (or found previously). -*/ -static int hasTimer(void){ - if( getProcessTimesAddr ){ - return 1; - } else { -#if !SQLITE_OS_WINRT - /* GetProcessTimes() isn't supported in WIN95 and some other Windows - ** versions. See if the version we are running on has it, and if it - ** does, save off a pointer to it and the current process handle. - */ - hProcess = GetCurrentProcess(); - if( hProcess ){ - HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); - if( NULL != hinstLib ){ - getProcessTimesAddr = - (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); - if( NULL != getProcessTimesAddr ){ - return 1; - } - FreeLibrary(hinstLib); - } - } -#endif + zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", + zSchema ? zSchema : "main", zName); + shell_check_oom(zSql); + sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + initText(&s); + if( zSchema ){ + cQuote = quoteChar(zSchema); + if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; + appendText(&s, zSchema, cQuote); + appendText(&s, ".", 0); } - return 0; + cQuote = quoteChar(zName); + appendText(&s, zName, cQuote); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); + nRow++; + appendText(&s, zDiv, 0); + zDiv = ","; + if( zCol==0 ) zCol = ""; + cQuote = quoteChar(zCol); + appendText(&s, zCol, cQuote); + } + appendText(&s, ")", 0); + sqlite3_finalize(pStmt); + if( nRow==0 ){ + freeText(&s); + s.z = 0; + } + return s.z; } /* -** Begin timing an operation +** SQL function: shell_module_schema(X) +** +** Return a fake schema for the table-valued function or eponymous virtual +** table X. */ -static void beginTimer(void){ - if( enableTimer && getProcessTimesAddr ){ - FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess,&ftCreation,&ftExit, - &ftKernelBegin,&ftUserBegin); - ftWallBegin = timeOfDay(); +static void shellModuleSchema( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + const char *zName; + char *zFake; + UNUSED_PARAMETER(nVal); + zName = (const char*)sqlite3_value_text(apVal[0]); + zFake = zName ? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; + if( zFake ){ + sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), + -1, sqlite3_free); + free(zFake); } } -/* Return the difference of two FILETIME structs in seconds */ -static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ - sqlite_int64 i64Start = *((sqlite_int64 *) pStart); - sqlite_int64 i64End = *((sqlite_int64 *) pEnd); - return (double) ((i64End - i64Start) / 10000000.0); -} - /* -** Print the timing results. +** SQL function: shell_add_schema(S,X) +** +** Add the schema name X to the CREATE statement in S and return the result. +** Examples: +** +** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x); +** +** Also works on +** +** CREATE INDEX +** CREATE UNIQUE INDEX +** CREATE VIEW +** CREATE TRIGGER +** CREATE VIRTUAL TABLE +** +** This UDF is used by the .schema command to insert the schema name of +** attached databases into the middle of the sqlite_schema.sql field. */ -static void endTimer(void){ - if( enableTimer && getProcessTimesAddr){ - FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; - sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (ftWallEnd - ftWallBegin)*0.001, - timeDiff(&ftUserBegin, &ftUserEnd), - timeDiff(&ftKernelBegin, &ftKernelEnd)); +static void shellAddSchemaName( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + static const char *aPrefix[] = { + "TABLE", + "INDEX", + "UNIQUE INDEX", + "VIEW", + "TRIGGER", + "VIRTUAL TABLE" + }; + int i = 0; + const char *zIn = (const char*)sqlite3_value_text(apVal[0]); + const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); + const char *zName = (const char*)sqlite3_value_text(apVal[2]); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + UNUSED_PARAMETER(nVal); + if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){ + for(i=0; i +#include +#include +#include +#include +#include +#include /* -** This is the name of our program. It is set in main(), used -** in a number of other places, mostly for error messages. +** We may need several defines that should have been in "sys/stat.h". */ -static char *Argv0; -/* -** Prompt strings. Initialized in main. Settable with -** .prompt main continue -*/ -#define PROMPT_LEN_MAX 20 -/* First line prompt. default: "sqlite> " */ -static char mainPrompt[PROMPT_LEN_MAX]; -/* Continuation prompt. default: " ...> " */ -static char continuePrompt[PROMPT_LEN_MAX]; - -/* This is variant of the standard-library strncpy() routine with the -** one change that the destination string is always zero-terminated, even -** if there is no zero-terminator in the first n-1 characters of the source -** string. -*/ -static char *shell_strncpy(char *dest, const char *src, size_t n){ - size_t i; - for(i=0; i inParenLevel += ni; - if( ni==0 ) p->inParenLevel = 0; - p->zScannerAwaits = 0; -} - -/* Record that a lexeme is opened, or closed with args==0. */ -static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){ - if( s!=0 || c==0 ){ - p->zScannerAwaits = s; - p->acAwait[0] = 0; - }else{ - p->acAwait[0] = c; - p->zScannerAwaits = p->acAwait; - } -} - -/* Upon demand, derive the continuation prompt to display. */ -static char *dynamicContinuePrompt(void){ - if( continuePrompt[0]==0 - || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ - return continuePrompt; - }else{ - if( dynPrompt.zScannerAwaits ){ - size_t ncp = strlen(continuePrompt); - size_t ndp = strlen(dynPrompt.zScannerAwaits); - if( ndp > ncp-3 ) return continuePrompt; - strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits); - while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' '; - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - }else{ - if( dynPrompt.inParenLevel>9 ){ - shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4); - }else if( dynPrompt.inParenLevel<0 ){ - shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4); - }else{ - shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4); - dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); - } - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - } - } - return dynPrompt.dynamicPrompt; -} -#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif -/* Indicate out-of-memory and exit. */ -static void shell_out_of_memory(void){ - eputz("Error: out of memory\n"); - exit(1); -} +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif -/* Check a pointer to see if it is NULL. If it is NULL, exit with an -** out-of-memory error. -*/ -static void shell_check_oom(const void *p){ - if( p==0 ) shell_out_of_memory(); -} +#ifndef S_ISLNK +#define S_ISLNK(mode) (0) +#endif /* -** Write I/O traces to the following stream. +** We may need to provide the "mode_t" type. */ -#ifdef SQLITE_ENABLE_IOTRACE -static FILE *iotrace = 0; + +#ifndef MODE_T_DEFINED + #define MODE_T_DEFINED + typedef unsigned short mode_t; #endif /* -** This routine works like printf in that its first argument is a -** format string and subsequent arguments are values to be substituted -** in place of % fields. The result of formatting this string -** is written to iotrace. +** We may need to provide the "ino_t" type. */ -#ifdef SQLITE_ENABLE_IOTRACE -static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ - va_list ap; - char *z; - if( iotrace==0 ) return; - va_start(ap, zFormat); - z = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - sputf(iotrace, "%s", z); - sqlite3_free(z); -} + +#ifndef INO_T_DEFINED + #define INO_T_DEFINED + typedef unsigned short ino_t; #endif /* -** Output string zUtf to Out stream as w characters. If w is negative, -** then right-justify the text. W is the width in UTF-8 characters, not -** in bytes. This is different from the %*.*s specification in printf -** since with %*.*s the width is measured in bytes, not characters. +** We need to define "NAME_MAX" if it was not present in "limits.h". */ -static void utf8_width_print(int w, const char *zUtf){ - int i; - int n; - int aw = w<0 ? -w : w; - if( zUtf==0 ) zUtf = ""; - for(i=n=0; zUtf[i]; i++){ - if( (zUtf[i]&0xc0)!=0x80 ){ - n++; - if( n==aw ){ - do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); - break; - } - } - } - if( n>=aw ){ - oputf("%.*s", i, zUtf); - }else if( w<0 ){ - oputf("%*s%s", aw-n, "", zUtf); - }else{ - oputf("%s%*s", zUtf, aw-n, ""); - } -} +#ifndef NAME_MAX +# ifdef FILENAME_MAX +# define NAME_MAX (FILENAME_MAX) +# else +# define NAME_MAX (260) +# endif +#endif /* -** Determines if a string is a number of not. +** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". */ -static int isNumber(const char *z, int *realnum){ - if( *z=='-' || *z=='+' ) z++; - if( !IsDigit(*z) ){ - return 0; - } - z++; - if( realnum ) *realnum = 0; - while( IsDigit(*z) ){ z++; } - if( *z=='.' ){ - z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - if( *z=='e' || *z=='E' ){ - z++; - if( *z=='+' || *z=='-' ) z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - return *z==0; -} + +#ifndef NULL_INTPTR_T +# define NULL_INTPTR_T ((intptr_t)(0)) +#endif + +#ifndef BAD_INTPTR_T +# define BAD_INTPTR_T ((intptr_t)(-1)) +#endif /* -** Compute a string length that is limited to what can be stored in -** lower 30 bits of a 32-bit signed integer. +** We need to provide the necessary structures and related types. */ -static int strlen30(const char *z){ - const char *z2 = z; - while( *z2 ){ z2++; } - return 0x3fffffff & (int)(z2 - z); -} + +#ifndef DIRENT_DEFINED +#define DIRENT_DEFINED +typedef struct DIRENT DIRENT; +typedef DIRENT *LPDIRENT; +struct DIRENT { + ino_t d_ino; /* Sequence number, do not use. */ + unsigned d_attributes; /* Win32 file attributes. */ + char d_name[NAME_MAX + 1]; /* Name within the directory. */ +}; +#endif + +#ifndef DIR_DEFINED +#define DIR_DEFINED +typedef struct DIR DIR; +typedef DIR *LPDIR; +struct DIR { + intptr_t d_handle; /* Value returned by "_findfirst". */ + DIRENT d_first; /* DIRENT constructed based on "_findfirst". */ + DIRENT d_next; /* DIRENT constructed based on "_findnext". */ +}; +#endif /* -** Return the length of a string in characters. Multibyte UTF8 characters -** count as a single character. +** Provide a macro, for use by the implementation, to determine if a +** particular directory entry should be skipped over when searching for +** the next directory entry that should be returned by the readdir() or +** readdir_r() functions. */ -static int strlenChar(const char *z){ - int n = 0; - while( *z ){ - if( (0xc0&*(z++))!=0x80 ) n++; - } - return n; -} + +#ifndef is_filtered +# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) +#endif /* -** Return open FILE * if zFile exists, can be opened for read -** and is an ordinary file or a character stream source. -** Otherwise return 0. +** Provide the function prototype for the POSIX compatiable getenv() +** function. This function is not thread-safe. */ -static FILE * openChrSource(const char *zFile){ -#if defined(_WIN32) || defined(WIN32) - struct __stat64 x = {0}; -# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) - /* On Windows, open first, then check the stream nature. This order - ** is necessary because _stat() and sibs, when checking a named pipe, - ** effectively break the pipe as its supplier sees it. */ - FILE *rv = fopen(zFile, "rb"); - if( rv==0 ) return 0; - if( _fstat64(_fileno(rv), &x) != 0 - || !STAT_CHR_SRC(x.st_mode)){ - fclose(rv); - rv = 0; - } - return rv; -#else - struct stat x = {0}; - int rc = stat(zFile, &x); -# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) - if( rc!=0 ) return 0; - if( STAT_CHR_SRC(x.st_mode) ){ - return fopen(zFile, "rb"); - }else{ - return 0; - } -#endif -#undef STAT_CHR_SRC -} + +extern const char *windirent_getenv(const char *name); /* -** This routine reads a line of text from FILE in, stores -** the text in memory obtained from malloc() and returns a pointer -** to the text. NULL is returned at end of file, or if malloc() -** fails. -** -** If zLine is not NULL then it is a malloced buffer returned from -** a previous call to this routine that may be reused. +** Finally, we can provide the function prototypes for the opendir(), +** readdir(), readdir_r(), and closedir() POSIX functions. */ -static char *local_getline(char *zLine, FILE *in){ - int nLine = zLine==0 ? 0 : 100; - int n = 0; - while( 1 ){ - if( n+100>nLine ){ - nLine = nLine*2 + 100; - zLine = realloc(zLine, nLine); - shell_check_oom(zLine); - } - if( fgets(&zLine[n], nLine - n, in)==0 ){ - if( n==0 ){ - free(zLine); - return 0; - } - zLine[n] = 0; - break; - } - while( zLine[n] ) n++; - if( n>0 && zLine[n-1]=='\n' ){ - n--; - if( n>0 && zLine[n-1]=='\r' ) n--; - zLine[n] = 0; - break; - } - } - return zLine; -} +extern LPDIR opendir(const char *dirname); +extern LPDIRENT readdir(LPDIR dirp); +extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); +extern INT closedir(LPDIR dirp); +#endif /* defined(WIN32) && defined(_MSC_VER) */ + +/************************* End test_windirent.h ********************/ +/************************* Begin test_windirent.c ******************/ /* -** Retrieve a single line of input text. +** 2015 November 30 ** -** If in==0 then read from standard input and prompt before each line. -** If isContinuation is true, then a continuation prompt is appropriate. -** If isContinuation is zero, then the main prompt should be used. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** If zPrior is not NULL then it is a buffer from a prior call to this -** routine that can be reused. +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** The result is stored in space obtained from malloc() and must either -** be freed by the caller or else passed back into this routine via the -** zPrior argument for reuse. +************************************************************************* +** This file contains code to implement most of the opendir() family of +** POSIX functions on Win32 using the MSVCRT. */ -#ifndef SQLITE_SHELL_FIDDLE -static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ - char *zPrompt; - char *zResult; - if( in!=0 ){ - zResult = local_getline(zPrior, in); - }else{ - zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt; -#if SHELL_USE_LOCAL_GETLINE - sputz(stdout, zPrompt); - fflush(stdout); - do{ - zResult = local_getline(zPrior, stdin); - zPrior = 0; - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - if( zResult==0 ) sqlite3_sleep(50); - }while( zResult==0 && seenInterrupt>0 ); -#else - free(zPrior); - zResult = shell_readline(zPrompt); - while( zResult==0 ){ - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - sqlite3_sleep(50); - if( seenInterrupt==0 ) break; - zResult = shell_readline(""); - } - if( zResult && *zResult ) shell_add_history(zResult); -#endif - } - return zResult; -} -#endif /* !SQLITE_SHELL_FIDDLE */ -/* -** Return the value of a hexadecimal digit. Return -1 if the input -** is not a hex digit. -*/ -static int hexDigitValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; -} +#if defined(_WIN32) && defined(_MSC_VER) +/* #include "test_windirent.h" */ /* -** Interpret zArg as an integer value, possibly with suffixes. +** Implementation of the POSIX getenv() function using the Win32 API. +** This function is not thread-safe. */ -static sqlite3_int64 integerValue(const char *zArg){ - sqlite3_int64 v = 0; - static const struct { char *zSuffix; int iMult; } aMult[] = { - { "KiB", 1024 }, - { "MiB", 1024*1024 }, - { "GiB", 1024*1024*1024 }, - { "KB", 1000 }, - { "MB", 1000000 }, - { "GB", 1000000000 }, - { "K", 1000 }, - { "M", 1000000 }, - { "G", 1000000000 }, - }; - int i; - int isNeg = 0; - if( zArg[0]=='-' ){ - isNeg = 1; - zArg++; - }else if( zArg[0]=='+' ){ - zArg++; - } - if( zArg[0]=='0' && zArg[1]=='x' ){ - int x; - zArg += 2; - while( (x = hexDigitValue(zArg[0]))>=0 ){ - v = (v<<4) + x; - zArg++; - } +const char *windirent_getenv( + const char *name +){ + static char value[32768]; /* Maximum length, per MSDN */ + DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */ + DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */ + + memset(value, 0, sizeof(value)); + dwRet = GetEnvironmentVariableA(name, value, dwSize); + if( dwRet==0 || dwRet>dwSize ){ + /* + ** The function call to GetEnvironmentVariableA() failed -OR- + ** the buffer is not large enough. Either way, return NULL. + */ + return 0; }else{ - while( IsDigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; - } - } - for(i=0; i z); - initText(p); -} +LPDIR opendir( + const char *dirname +){ + struct _finddata_t data; + LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); + SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); -/* zIn is either a pointer to a NULL-terminated string in memory obtained -** from malloc(), or a NULL pointer. The string pointed to by zAppend is -** added to zIn, and the result returned in memory obtained from malloc(). -** zIn, if it was not NULL, is freed. -** -** If the third argument, quote, is not '\0', then it is used as a -** quote character for zAppend. -*/ -static void appendText(ShellText *p, const char *zAppend, char quote){ - i64 len; - i64 i; - i64 nAppend = strlen30(zAppend); + if( dirp==NULL ) return NULL; + memset(dirp, 0, sizeof(DIR)); - len = nAppend+p->n+1; - if( quote ){ - len += 2; - for(i=0; i z==0 || p->n+len>=p->nAlloc ){ - p->nAlloc = p->nAlloc*2 + len + 20; - p->z = realloc(p->z, p->nAlloc); - shell_check_oom(p->z); + memset(&data, 0, sizeof(struct _finddata_t)); + _snprintf(data.name, namesize, "%s\\*", dirname); + dirp->d_handle = _findfirst(data.name, &data); + + if( dirp->d_handle==BAD_INTPTR_T ){ + closedir(dirp); + return NULL; } - if( quote ){ - char *zCsr = p->z+p->n; - *zCsr++ = quote; - for(i=0; i d_handle, &data)==-1 ){ + closedir(dirp); + return NULL; } - *zCsr++ = quote; - p->n = (int)(zCsr - p->z); - *zCsr = '\0'; - }else{ - memcpy(p->z+p->n, zAppend, nAppend); - p->n += nAppend; - p->z[p->n] = '\0'; + + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; } + + dirp->d_first.d_attributes = data.attrib; + strncpy(dirp->d_first.d_name, data.name, NAME_MAX); + dirp->d_first.d_name[NAME_MAX] = '\0'; + + return dirp; } /* -** Attempt to determine if identifier zName needs to be quoted, either -** because it contains non-alphanumeric characters, or because it is an -** SQLite keyword. Be conservative in this estimate: When in doubt assume -** that quoting is required. -** -** Return '"' if quoting is required. Return 0 if no quoting is required. +** Implementation of the POSIX readdir() function using the MSVCRT. */ -static char quoteChar(const char *zName){ - int i; - if( zName==0 ) return '"'; - if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; - for(i=0; zName[i]; i++){ - if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; +LPDIRENT readdir( + LPDIR dirp +){ + struct _finddata_t data; + + if( dirp==NULL ) return NULL; + + if( dirp->d_first.d_ino==0 ){ + dirp->d_first.d_ino++; + dirp->d_next.d_ino++; + + return &dirp->d_first; } - return sqlite3_keyword_check(zName, i) ? '"' : 0; + +next: + + memset(&data, 0, sizeof(struct _finddata_t)); + if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; + + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; + + dirp->d_next.d_ino++; + dirp->d_next.d_attributes = data.attrib; + strncpy(dirp->d_next.d_name, data.name, NAME_MAX); + dirp->d_next.d_name[NAME_MAX] = '\0'; + + return &dirp->d_next; } /* -** Construct a fake object name and column list to describe the structure -** of the view, virtual table, or table valued function zSchema.zName. +** Implementation of the POSIX readdir_r() function using the MSVCRT. */ -static char *shellFakeSchema( - sqlite3 *db, /* The database connection containing the vtab */ - const char *zSchema, /* Schema of the database holding the vtab */ - const char *zName /* The name of the virtual table */ +INT readdir_r( + LPDIR dirp, + LPDIRENT entry, + LPDIRENT *result ){ - sqlite3_stmt *pStmt = 0; - char *zSql; - ShellText s; - char cQuote; - char *zDiv = "("; - int nRow = 0; + struct _finddata_t data; - zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", - zSchema ? zSchema : "main", zName); - shell_check_oom(zSql); - sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - initText(&s); - if( zSchema ){ - cQuote = quoteChar(zSchema); - if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; - appendText(&s, zSchema, cQuote); - appendText(&s, ".", 0); - } - cQuote = quoteChar(zName); - appendText(&s, zName, cQuote); - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); - nRow++; - appendText(&s, zDiv, 0); - zDiv = ","; - if( zCol==0 ) zCol = ""; - cQuote = quoteChar(zCol); - appendText(&s, zCol, cQuote); + if( dirp==NULL ) return EBADF; + + if( dirp->d_first.d_ino==0 ){ + dirp->d_first.d_ino++; + dirp->d_next.d_ino++; + + entry->d_ino = dirp->d_first.d_ino; + entry->d_attributes = dirp->d_first.d_attributes; + strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); + entry->d_name[NAME_MAX] = '\0'; + + *result = entry; + return 0; } - appendText(&s, ")", 0); - sqlite3_finalize(pStmt); - if( nRow==0 ){ - freeText(&s); - s.z = 0; + +next: + + memset(&data, 0, sizeof(struct _finddata_t)); + if( _findnext(dirp->d_handle, &data)==-1 ){ + *result = NULL; + return ENOENT; } - return s.z; -} -/* -** SQL function: strtod(X) -** -** Use the C-library strtod() function to convert string X into a double. -** Used for comparing the accuracy of SQLite's internal text-to-float conversion -** routines against the C-library. -*/ -static void shellStrtod( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal -){ - char *z = (char*)sqlite3_value_text(apVal[0]); - UNUSED_PARAMETER(nVal); - if( z==0 ) return; - sqlite3_result_double(pCtx, strtod(z,0)); + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; + + entry->d_ino = (ino_t)-1; /* not available */ + entry->d_attributes = data.attrib; + strncpy(entry->d_name, data.name, NAME_MAX); + entry->d_name[NAME_MAX] = '\0'; + + *result = entry; + return 0; } /* -** SQL function: dtostr(X) -** -** Use the C-library printf() function to convert real value X into a string. -** Used for comparing the accuracy of SQLite's internal float-to-text conversion -** routines against the C-library. +** Implementation of the POSIX closedir() function using the MSVCRT. */ -static void shellDtostr( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal +INT closedir( + LPDIR dirp ){ - double r = sqlite3_value_double(apVal[0]); - int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; - char z[400]; - if( n<1 ) n = 1; - if( n>350 ) n = 350; - sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); - sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); -} + INT result = 0; + if( dirp==NULL ) return EINVAL; -/* -** SQL function: shell_module_schema(X) -** -** Return a fake schema for the table-valued function or eponymous virtual -** table X. -*/ -static void shellModuleSchema( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal -){ - const char *zName; - char *zFake; - UNUSED_PARAMETER(nVal); - zName = (const char*)sqlite3_value_text(apVal[0]); - zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; - if( zFake ){ - sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), - -1, sqlite3_free); - free(zFake); + if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ + result = _findclose(dirp->d_handle); } -} -/* -** SQL function: shell_add_schema(S,X) -** -** Add the schema name X to the CREATE statement in S and return the result. -** Examples: -** -** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x); -** -** Also works on -** -** CREATE INDEX -** CREATE UNIQUE INDEX -** CREATE VIEW -** CREATE TRIGGER -** CREATE VIRTUAL TABLE -** -** This UDF is used by the .schema command to insert the schema name of -** attached databases into the middle of the sqlite_schema.sql field. -*/ -static void shellAddSchemaName( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal -){ - static const char *aPrefix[] = { - "TABLE", - "INDEX", - "UNIQUE INDEX", - "VIEW", - "TRIGGER", - "VIRTUAL TABLE" - }; - int i = 0; - const char *zIn = (const char*)sqlite3_value_text(apVal[0]); - const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); - const char *zName = (const char*)sqlite3_value_text(apVal[2]); - sqlite3 *db = sqlite3_context_db_handle(pCtx); - UNUSED_PARAMETER(nVal); - if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){ - for(i=0; i +#include #include -#include -#include -#include -#include -#include -#include - -/* -** We may need several defines that should have been in "sys/stat.h". -*/ - -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISLNK -#define S_ISLNK(mode) (0) -#endif - -/* -** We may need to provide the "mode_t" type. -*/ -#ifndef MODE_T_DEFINED - #define MODE_T_DEFINED - typedef unsigned short mode_t; -#endif +/* The original memory allocation routines */ +static sqlite3_mem_methods memtraceBase; +static FILE *memtraceOut; -/* -** We may need to provide the "ino_t" type. -*/ - -#ifndef INO_T_DEFINED - #define INO_T_DEFINED - typedef unsigned short ino_t; -#endif - -/* -** We need to define "NAME_MAX" if it was not present in "limits.h". -*/ - -#ifndef NAME_MAX -# ifdef FILENAME_MAX -# define NAME_MAX (FILENAME_MAX) -# else -# define NAME_MAX (260) -# endif -#endif - -/* -** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". -*/ - -#ifndef NULL_INTPTR_T -# define NULL_INTPTR_T ((intptr_t)(0)) -#endif - -#ifndef BAD_INTPTR_T -# define BAD_INTPTR_T ((intptr_t)(-1)) -#endif - -/* -** We need to provide the necessary structures and related types. -*/ - -#ifndef DIRENT_DEFINED -#define DIRENT_DEFINED -typedef struct DIRENT DIRENT; -typedef DIRENT *LPDIRENT; -struct DIRENT { - ino_t d_ino; /* Sequence number, do not use. */ - unsigned d_attributes; /* Win32 file attributes. */ - char d_name[NAME_MAX + 1]; /* Name within the directory. */ -}; -#endif +/* Methods that trace memory allocations */ +static void *memtraceMalloc(int n){ + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", + memtraceBase.xRoundup(n)); + } + return memtraceBase.xMalloc(n); +} +static void memtraceFree(void *p){ + if( p==0 ) return; + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); + } + memtraceBase.xFree(p); +} +static void *memtraceRealloc(void *p, int n){ + if( p==0 ) return memtraceMalloc(n); + if( n==0 ){ + memtraceFree(p); + return 0; + } + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", + memtraceBase.xSize(p), memtraceBase.xRoundup(n)); + } + return memtraceBase.xRealloc(p, n); +} +static int memtraceSize(void *p){ + return memtraceBase.xSize(p); +} +static int memtraceRoundup(int n){ + return memtraceBase.xRoundup(n); +} +static int memtraceInit(void *p){ + return memtraceBase.xInit(p); +} +static void memtraceShutdown(void *p){ + memtraceBase.xShutdown(p); +} -#ifndef DIR_DEFINED -#define DIR_DEFINED -typedef struct DIR DIR; -typedef DIR *LPDIR; -struct DIR { - intptr_t d_handle; /* Value returned by "_findfirst". */ - DIRENT d_first; /* DIRENT constructed based on "_findfirst". */ - DIRENT d_next; /* DIRENT constructed based on "_findnext". */ +/* The substitute memory allocator */ +static sqlite3_mem_methods ersaztMethods = { + memtraceMalloc, + memtraceFree, + memtraceRealloc, + memtraceSize, + memtraceRoundup, + memtraceInit, + memtraceShutdown, + 0 }; -#endif - -/* -** Provide a macro, for use by the implementation, to determine if a -** particular directory entry should be skipped over when searching for -** the next directory entry that should be returned by the readdir() or -** readdir_r() functions. -*/ - -#ifndef is_filtered -# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) -#endif - -/* -** Provide the function prototype for the POSIX compatible getenv() -** function. This function is not thread-safe. -*/ - -extern const char *windirent_getenv(const char *name); - -/* -** Finally, we can provide the function prototypes for the opendir(), -** readdir(), readdir_r(), and closedir() POSIX functions. -*/ -extern LPDIR opendir(const char *dirname); -extern LPDIRENT readdir(LPDIR dirp); -extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); -extern INT closedir(LPDIR dirp); +/* Begin tracing memory allocations to out. */ +int sqlite3MemTraceActivate(FILE *out){ + int rc = SQLITE_OK; + if( memtraceBase.xMalloc==0 ){ + rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); + if( rc==SQLITE_OK ){ + rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); + } + } + memtraceOut = out; + return rc; +} -#endif /* defined(WIN32) && defined(_MSC_VER) */ +/* Deactivate memory tracing */ +int sqlite3MemTraceDeactivate(void){ + int rc = SQLITE_OK; + if( memtraceBase.xMalloc!=0 ){ + rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); + if( rc==SQLITE_OK ){ + memset(&memtraceBase, 0, sizeof(memtraceBase)); + } + } + memtraceOut = 0; + return rc; +} -/************************* End test_windirent.h ********************/ -/************************* Begin test_windirent.c ******************/ +/************************* End ../ext/misc/memtrace.c ********************/ +/************************* Begin ../ext/misc/shathree.c ******************/ /* -** 2015 November 30 +** 2017-03-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -2352,1310 +1539,1458 @@ extern INT closedir(LPDIR dirp); ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** -************************************************************************* -** This file contains code to implement most of the opendir() family of -** POSIX functions on Win32 using the MSVCRT. +****************************************************************************** +** +** This SQLite extension implements functions that compute SHA3 hashes. +** Two SQL functions are implemented: +** +** sha3(X,SIZE) +** sha3_query(Y,SIZE) +** +** The sha3(X) function computes the SHA3 hash of the input X, or NULL if +** X is NULL. +** +** The sha3_query(Y) function evaluates all queries in the SQL statements of Y +** and returns a hash of their results. +** +** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm +** is used. If SIZE is included it must be one of the integers 224, 256, +** 384, or 512, to determine SHA3 hash variant that is computed. */ +/* #include "sqlite3ext.h" */ +SQLITE_EXTENSION_INIT1 +#include +#include +#include -#if defined(_WIN32) && defined(_MSC_VER) -/* #include "test_windirent.h" */ +#ifndef SQLITE_AMALGAMATION +/* typedef sqlite3_uint64 u64; */ +#endif /* SQLITE_AMALGAMATION */ +/****************************************************************************** +** The Hash Engine +*/ /* -** Implementation of the POSIX getenv() function using the Win32 API. -** This function is not thread-safe. +** Macros to determine whether the machine is big or little endian, +** and whether or not that determination is run-time or compile-time. +** +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSHA3_BYTEORDER=0 is set, then byte-order is determined +** at run-time. */ -const char *windirent_getenv( - const char *name -){ - static char value[32768]; /* Maximum length, per MSDN */ - DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */ - DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */ +#ifndef SHA3_BYTEORDER +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SHA3_BYTEORDER 1234 +# elif defined(sparc) || defined(__ppc__) +# define SHA3_BYTEORDER 4321 +# else +# define SHA3_BYTEORDER 0 +# endif +#endif - memset(value, 0, sizeof(value)); - dwRet = GetEnvironmentVariableA(name, value, dwSize); - if( dwRet==0 || dwRet>dwSize ){ - /* - ** The function call to GetEnvironmentVariableA() failed -OR- - ** the buffer is not large enough. Either way, return NULL. - */ - return 0; - }else{ - /* - ** The function call to GetEnvironmentVariableA() succeeded - ** -AND- the buffer contains the entire value. - */ - return value; - } -} /* -** Implementation of the POSIX opendir() function using the MSVCRT. +** State structure for a SHA3 hash in progress */ -LPDIR opendir( - const char *dirname -){ - struct _finddata_t data; - LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); - SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); - - if( dirp==NULL ) return NULL; - memset(dirp, 0, sizeof(DIR)); - - /* TODO: Remove this if Unix-style root paths are not used. */ - if( sqlite3_stricmp(dirname, "/")==0 ){ - dirname = windirent_getenv("SystemDrive"); - } - - memset(&data, 0, sizeof(struct _finddata_t)); - _snprintf(data.name, namesize, "%s\\*", dirname); - dirp->d_handle = _findfirst(data.name, &data); - - if( dirp->d_handle==BAD_INTPTR_T ){ - closedir(dirp); - return NULL; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ){ -next: - - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - closedir(dirp); - return NULL; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; - } - - dirp->d_first.d_attributes = data.attrib; - strncpy(dirp->d_first.d_name, data.name, NAME_MAX); - dirp->d_first.d_name[NAME_MAX] = '\0'; - - return dirp; -} +typedef struct SHA3Context SHA3Context; +struct SHA3Context { + union { + u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ + unsigned char x[1600]; /* ... or 1600 bytes */ + } u; + unsigned nRate; /* Bytes of input accepted per Keccak iteration */ + unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ + unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ +}; /* -** Implementation of the POSIX readdir() function using the MSVCRT. +** A single step of the Keccak mixing function for a 1600-bit state */ -LPDIRENT readdir( - LPDIR dirp -){ - struct _finddata_t data; +static void KeccakF1600Step(SHA3Context *p){ + int i; + u64 b0, b1, b2, b3, b4; + u64 c0, c1, c2, c3, c4; + u64 d0, d1, d2, d3, d4; + static const u64 RC[] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, + 0x800000000000808aULL, 0x8000000080008000ULL, + 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, + 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, + 0x0000000080000001ULL, 0x8000000080008008ULL + }; +# define a00 (p->u.s[0]) +# define a01 (p->u.s[1]) +# define a02 (p->u.s[2]) +# define a03 (p->u.s[3]) +# define a04 (p->u.s[4]) +# define a10 (p->u.s[5]) +# define a11 (p->u.s[6]) +# define a12 (p->u.s[7]) +# define a13 (p->u.s[8]) +# define a14 (p->u.s[9]) +# define a20 (p->u.s[10]) +# define a21 (p->u.s[11]) +# define a22 (p->u.s[12]) +# define a23 (p->u.s[13]) +# define a24 (p->u.s[14]) +# define a30 (p->u.s[15]) +# define a31 (p->u.s[16]) +# define a32 (p->u.s[17]) +# define a33 (p->u.s[18]) +# define a34 (p->u.s[19]) +# define a40 (p->u.s[20]) +# define a41 (p->u.s[21]) +# define a42 (p->u.s[22]) +# define a43 (p->u.s[23]) +# define a44 (p->u.s[24]) +# define ROL64(a,x) ((a< >(64-x))) - if( dirp==NULL ) return NULL; + for(i=0; i<24; i+=4){ + c0 = a00^a10^a20^a30^a40; + c1 = a01^a11^a21^a31^a41; + c2 = a02^a12^a22^a32^a42; + c3 = a03^a13^a23^a33^a43; + c4 = a04^a14^a24^a34^a44; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; + b0 = (a00^d0); + b1 = ROL64((a11^d1), 44); + b2 = ROL64((a22^d2), 43); + b3 = ROL64((a33^d3), 21); + b4 = ROL64((a44^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i]; + a11 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); - return &dirp->d_first; - } + b2 = ROL64((a20^d0), 3); + b3 = ROL64((a31^d1), 45); + b4 = ROL64((a42^d2), 61); + b0 = ROL64((a03^d3), 28); + b1 = ROL64((a14^d4), 20); + a20 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); -next: + b4 = ROL64((a40^d0), 18); + b0 = ROL64((a01^d1), 1); + b1 = ROL64((a12^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a34^d4), 8); + a40 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; + b1 = ROL64((a10^d0), 36); + b2 = ROL64((a21^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a43^d3), 56); + b0 = ROL64((a04^d4), 27); + a10 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; + b3 = ROL64((a30^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a02^d2), 62); + b1 = ROL64((a13^d3), 55); + b2 = ROL64((a24^d4), 39); + a30 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); - dirp->d_next.d_ino++; - dirp->d_next.d_attributes = data.attrib; - strncpy(dirp->d_next.d_name, data.name, NAME_MAX); - dirp->d_next.d_name[NAME_MAX] = '\0'; + c0 = a00^a20^a40^a10^a30; + c1 = a11^a31^a01^a21^a41; + c2 = a22^a42^a12^a32^a02; + c3 = a33^a03^a23^a43^a13; + c4 = a44^a14^a34^a04^a24; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); - return &dirp->d_next; -} + b0 = (a00^d0); + b1 = ROL64((a31^d1), 44); + b2 = ROL64((a12^d2), 43); + b3 = ROL64((a43^d3), 21); + b4 = ROL64((a24^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+1]; + a31 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); -/* -** Implementation of the POSIX readdir_r() function using the MSVCRT. -*/ -INT readdir_r( - LPDIR dirp, - LPDIRENT entry, - LPDIRENT *result -){ - struct _finddata_t data; + b2 = ROL64((a40^d0), 3); + b3 = ROL64((a21^d1), 45); + b4 = ROL64((a02^d2), 61); + b0 = ROL64((a33^d3), 28); + b1 = ROL64((a14^d4), 20); + a40 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); - if( dirp==NULL ) return EBADF; + b4 = ROL64((a30^d0), 18); + b0 = ROL64((a11^d1), 1); + b1 = ROL64((a42^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a04^d4), 8); + a30 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; + b1 = ROL64((a20^d0), 36); + b2 = ROL64((a01^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a13^d3), 56); + b0 = ROL64((a44^d4), 27); + a20 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); - entry->d_ino = dirp->d_first.d_ino; - entry->d_attributes = dirp->d_first.d_attributes; - strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; + b3 = ROL64((a10^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a22^d2), 62); + b1 = ROL64((a03^d3), 55); + b2 = ROL64((a34^d4), 39); + a10 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); - *result = entry; - return 0; - } + c0 = a00^a40^a30^a20^a10; + c1 = a31^a21^a11^a01^a41; + c2 = a12^a02^a42^a32^a22; + c3 = a43^a33^a23^a13^a03; + c4 = a24^a14^a04^a44^a34; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); -next: - - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - *result = NULL; - return ENOENT; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; + b0 = (a00^d0); + b1 = ROL64((a21^d1), 44); + b2 = ROL64((a42^d2), 43); + b3 = ROL64((a13^d3), 21); + b4 = ROL64((a34^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+2]; + a21 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); - entry->d_ino = (ino_t)-1; /* not available */ - entry->d_attributes = data.attrib; - strncpy(entry->d_name, data.name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; + b2 = ROL64((a30^d0), 3); + b3 = ROL64((a01^d1), 45); + b4 = ROL64((a22^d2), 61); + b0 = ROL64((a43^d3), 28); + b1 = ROL64((a14^d4), 20); + a30 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); - *result = entry; - return 0; -} + b4 = ROL64((a10^d0), 18); + b0 = ROL64((a31^d1), 1); + b1 = ROL64((a02^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a44^d4), 8); + a10 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); -/* -** Implementation of the POSIX closedir() function using the MSVCRT. -*/ -INT closedir( - LPDIR dirp -){ - INT result = 0; + b1 = ROL64((a40^d0), 36); + b2 = ROL64((a11^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a03^d3), 56); + b0 = ROL64((a24^d4), 27); + a40 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); - if( dirp==NULL ) return EINVAL; + b3 = ROL64((a20^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a12^d2), 62); + b1 = ROL64((a33^d3), 55); + b2 = ROL64((a04^d4), 39); + a20 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); - if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ - result = _findclose(dirp->d_handle); - } + c0 = a00^a30^a10^a40^a20; + c1 = a21^a01^a31^a11^a41; + c2 = a42^a22^a02^a32^a12; + c3 = a13^a43^a23^a03^a33; + c4 = a34^a14^a44^a24^a04; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); - sqlite3_free(dirp); - return result; -} + b0 = (a00^d0); + b1 = ROL64((a01^d1), 44); + b2 = ROL64((a02^d2), 43); + b3 = ROL64((a03^d3), 21); + b4 = ROL64((a04^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+3]; + a01 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); -#endif /* defined(WIN32) && defined(_MSC_VER) */ + b2 = ROL64((a10^d0), 3); + b3 = ROL64((a11^d1), 45); + b4 = ROL64((a12^d2), 61); + b0 = ROL64((a13^d3), 28); + b1 = ROL64((a14^d4), 20); + a10 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); -/************************* End test_windirent.c ********************/ -#define dirent DIRENT -#endif -/************************* Begin ../ext/misc/memtrace.c ******************/ -/* -** 2019-01-21 -** -** 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 implements an extension that uses the SQLITE_CONFIG_MALLOC -** mechanism to add a tracing layer on top of SQLite. If this extension -** is registered prior to sqlite3_initialize(), it will cause all memory -** allocation activities to be logged on standard output, or to some other -** FILE specified by the initializer. -** -** This file needs to be compiled into the application that uses it. -** -** This extension is used to implement the --memtrace option of the -** command-line shell. -*/ -#include -#include -#include + b4 = ROL64((a20^d0), 18); + b0 = ROL64((a21^d1), 1); + b1 = ROL64((a22^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a24^d4), 8); + a20 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); -/* The original memory allocation routines */ -static sqlite3_mem_methods memtraceBase; -static FILE *memtraceOut; + b1 = ROL64((a30^d0), 36); + b2 = ROL64((a31^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a33^d3), 56); + b0 = ROL64((a34^d4), 27); + a30 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); -/* Methods that trace memory allocations */ -static void *memtraceMalloc(int n){ - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", - memtraceBase.xRoundup(n)); - } - return memtraceBase.xMalloc(n); -} -static void memtraceFree(void *p){ - if( p==0 ) return; - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); + b3 = ROL64((a40^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a42^d2), 62); + b1 = ROL64((a43^d3), 55); + b2 = ROL64((a44^d4), 39); + a40 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); } - memtraceBase.xFree(p); } -static void *memtraceRealloc(void *p, int n){ - if( p==0 ) return memtraceMalloc(n); - if( n==0 ){ - memtraceFree(p); - return 0; + +/* +** Initialize a new hash. iSize determines the size of the hash +** in bits and should be one of 224, 256, 384, or 512. Or iSize +** can be zero to use the default hash size of 256 bits. +*/ +static void SHA3Init(SHA3Context *p, int iSize){ + memset(p, 0, sizeof(*p)); + if( iSize>=128 && iSize<=512 ){ + p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; + }else{ + p->nRate = (1600 - 2*256)/8; } - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", - memtraceBase.xSize(p), memtraceBase.xRoundup(n)); +#if SHA3_BYTEORDER==1234 + /* Known to be little-endian at compile-time. No-op */ +#elif SHA3_BYTEORDER==4321 + p->ixMask = 7; /* Big-endian */ +#else + { + static unsigned int one = 1; + if( 1==*(unsigned char*)&one ){ + /* Little endian. No byte swapping. */ + p->ixMask = 0; + }else{ + /* Big endian. Byte swap. */ + p->ixMask = 7; + } } - return memtraceBase.xRealloc(p, n); -} -static int memtraceSize(void *p){ - return memtraceBase.xSize(p); -} -static int memtraceRoundup(int n){ - return memtraceBase.xRoundup(n); -} -static int memtraceInit(void *p){ - return memtraceBase.xInit(p); -} -static void memtraceShutdown(void *p){ - memtraceBase.xShutdown(p); +#endif } -/* The substitute memory allocator */ -static sqlite3_mem_methods ersaztMethods = { - memtraceMalloc, - memtraceFree, - memtraceRealloc, - memtraceSize, - memtraceRoundup, - memtraceInit, - memtraceShutdown, - 0 -}; - -/* Begin tracing memory allocations to out. */ -int sqlite3MemTraceActivate(FILE *out){ - int rc = SQLITE_OK; - if( memtraceBase.xMalloc==0 ){ - rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); - if( rc==SQLITE_OK ){ - rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); +/* +** Make consecutive calls to the SHA3Update function to add new content +** to the hash +*/ +static void SHA3Update( + SHA3Context *p, + const unsigned char *aData, + unsigned int nData +){ + unsigned int i = 0; + if( aData==0 ) return; +#if SHA3_BYTEORDER==1234 + if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ + for(; i+7 u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; + p->nLoaded += 8; + if( p->nLoaded>=p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; + } } } - memtraceOut = out; - return rc; -} - -/* Deactivate memory tracing */ -int sqlite3MemTraceDeactivate(void){ - int rc = SQLITE_OK; - if( memtraceBase.xMalloc!=0 ){ - rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); - if( rc==SQLITE_OK ){ - memset(&memtraceBase, 0, sizeof(memtraceBase)); +#endif + for(; i u.x[p->nLoaded] ^= aData[i]; +#elif SHA3_BYTEORDER==4321 + p->u.x[p->nLoaded^0x07] ^= aData[i]; +#else + p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; +#endif + p->nLoaded++; + if( p->nLoaded==p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; } } - memtraceOut = 0; - return rc; } -/************************* End ../ext/misc/memtrace.c ********************/ -/************************* Begin ../ext/misc/pcachetrace.c ******************/ /* -** 2023-06-21 -** -** 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 implements an extension that uses the SQLITE_CONFIG_PCACHE2 -** mechanism to add a tracing layer on top of pluggable page cache of -** SQLite. If this extension is registered prior to sqlite3_initialize(), -** it will cause all page cache activities to be logged on standard output, -** or to some other FILE specified by the initializer. -** -** This file needs to be compiled into the application that uses it. -** -** This extension is used to implement the --pcachetrace option of the -** command-line shell. +** After all content has been added, invoke SHA3Final() to compute +** the final hash. The function returns a pointer to the binary +** hash value. */ -#include -#include -#include - -/* The original page cache routines */ -static sqlite3_pcache_methods2 pcacheBase; -static FILE *pcachetraceOut; - -/* Methods that trace pcache activity */ -static int pcachetraceInit(void *pArg){ - int nRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p)\n", pArg); - } - nRes = pcacheBase.xInit(pArg); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xInit(%p) -> %d\n", pArg, nRes); - } - return nRes; -} -static void pcachetraceShutdown(void *pArg){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xShutdown(%p)\n", pArg); - } - pcacheBase.xShutdown(pArg); -} -static sqlite3_pcache *pcachetraceCreate(int szPage, int szExtra, int bPurge){ - sqlite3_pcache *pRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d)\n", - szPage, szExtra, bPurge); - } - pRes = pcacheBase.xCreate(szPage, szExtra, bPurge); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCreate(%d,%d,%d) -> %p\n", - szPage, szExtra, bPurge, pRes); - } - return pRes; -} -static void pcachetraceCachesize(sqlite3_pcache *p, int nCachesize){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xCachesize(%p, %d)\n", p, nCachesize); - } - pcacheBase.xCachesize(p, nCachesize); -} -static int pcachetracePagecount(sqlite3_pcache *p){ - int nRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p)\n", p); - } - nRes = pcacheBase.xPagecount(p); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xPagecount(%p) -> %d\n", p, nRes); - } - return nRes; -} -static sqlite3_pcache_page *pcachetraceFetch( - sqlite3_pcache *p, - unsigned key, - int crFg -){ - sqlite3_pcache_page *pRes; - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d)\n", p, key, crFg); - } - pRes = pcacheBase.xFetch(p, key, crFg); - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xFetch(%p,%u,%d) -> %p\n", - p, key, crFg, pRes); +static unsigned char *SHA3Final(SHA3Context *p){ + unsigned int i; + if( p->nLoaded==p->nRate-1 ){ + const unsigned char c1 = 0x86; + SHA3Update(p, &c1, 1); + }else{ + const unsigned char c2 = 0x06; + const unsigned char c3 = 0x80; + SHA3Update(p, &c2, 1); + p->nLoaded = p->nRate - 1; + SHA3Update(p, &c3, 1); } - return pRes; -} -static void pcachetraceUnpin( - sqlite3_pcache *p, - sqlite3_pcache_page *pPg, - int bDiscard -){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xUnpin(%p, %p, %d)\n", - p, pPg, bDiscard); + for(i=0; i nRate; i++){ + p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; } - pcacheBase.xUnpin(p, pPg, bDiscard); + return &p->u.x[p->nRate]; } -static void pcachetraceRekey( - sqlite3_pcache *p, - sqlite3_pcache_page *pPg, - unsigned oldKey, - unsigned newKey -){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xRekey(%p, %p, %u, %u)\n", - p, pPg, oldKey, newKey); - } - pcacheBase.xRekey(p, pPg, oldKey, newKey); -} -static void pcachetraceTruncate(sqlite3_pcache *p, unsigned n){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xTruncate(%p, %u)\n", p, n); - } - pcacheBase.xTruncate(p, n); -} -static void pcachetraceDestroy(sqlite3_pcache *p){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xDestroy(%p)\n", p); - } - pcacheBase.xDestroy(p); -} -static void pcachetraceShrink(sqlite3_pcache *p){ - if( pcachetraceOut ){ - fprintf(pcachetraceOut, "PCACHETRACE: xShrink(%p)\n", p); - } - pcacheBase.xShrink(p); -} - -/* The substitute pcache methods */ -static sqlite3_pcache_methods2 ersaztPcacheMethods = { - 0, - 0, - pcachetraceInit, - pcachetraceShutdown, - pcachetraceCreate, - pcachetraceCachesize, - pcachetracePagecount, - pcachetraceFetch, - pcachetraceUnpin, - pcachetraceRekey, - pcachetraceTruncate, - pcachetraceDestroy, - pcachetraceShrink -}; +/* End of the hashing logic +*****************************************************************************/ -/* Begin tracing memory allocations to out. */ -int sqlite3PcacheTraceActivate(FILE *out){ - int rc = SQLITE_OK; - if( pcacheBase.xFetch==0 ){ - rc = sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &pcacheBase); - if( rc==SQLITE_OK ){ - rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &ersaztPcacheMethods); +/* +** Implementation of the sha3(X,SIZE) function. +** +** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default +** size is 256. If X is a BLOB, it is hashed as is. +** For all other non-NULL types of input, X is converted into a UTF-8 string +** and the string is hashed without the trailing 0x00 terminator. The hash +** of a NULL value is NULL. +*/ +static void sha3Func( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + SHA3Context cx; + int eType = sqlite3_value_type(argv[0]); + int nByte = sqlite3_value_bytes(argv[0]); + int iSize; + if( argc==1 ){ + iSize = 256; + }else{ + iSize = sqlite3_value_int(argv[1]); + if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ + sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " + "384 512", -1); + return; } } - pcachetraceOut = out; - return rc; + if( eType==SQLITE_NULL ) return; + SHA3Init(&cx, iSize); + if( eType==SQLITE_BLOB ){ + SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte); + }else{ + SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte); + } + sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } -/* Deactivate memory tracing */ -int sqlite3PcacheTraceDeactivate(void){ - int rc = SQLITE_OK; - if( pcacheBase.xFetch!=0 ){ - rc = sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcacheBase); - if( rc==SQLITE_OK ){ - memset(&pcacheBase, 0, sizeof(pcacheBase)); - } - } - pcachetraceOut = 0; - return rc; +/* Compute a string using sqlite3_vsnprintf() with a maximum length +** of 50 bytes and add it to the hash. +*/ +static void hash_step_vformat( + SHA3Context *p, /* Add content to this context */ + const char *zFormat, + ... +){ + va_list ap; + int n; + char zBuf[50]; + va_start(ap, zFormat); + sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); + va_end(ap); + n = (int)strlen(zBuf); + SHA3Update(p, (unsigned char*)zBuf, n); } -/************************* End ../ext/misc/pcachetrace.c ********************/ -/************************* Begin ../ext/misc/shathree.c ******************/ /* -** 2017-03-08 -** -** 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. -** -****************************************************************************** +** Implementation of the sha3_query(SQL,SIZE) function. ** -** This SQLite extension implements functions that compute SHA3 hashes -** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard. -** Two SQL functions are implemented: +** This function compiles and runs the SQL statement(s) given in the +** argument. The results are hashed using a SIZE-bit SHA3. The default +** size is 256. ** -** sha3(X,SIZE) -** sha3_query(Y,SIZE) +** The format of the byte stream that is hashed is summarized as follows: ** -** The sha3(X) function computes the SHA3 hash of the input X, or NULL if -** X is NULL. +** S : +** R +** N +** I +** F +** B : +** T : ** -** The sha3_query(Y) function evaluates all queries in the SQL statements of Y -** and returns a hash of their results. +** is the original SQL text for each statement run and is +** the size of that text. The SQL text is UTF-8. A single R character +** occurs before the start of each row. N means a NULL value. +** I mean an 8-byte little-endian integer . F is a floating point +** number with an 8-byte little-endian IEEE floating point value . +** B means blobs of bytes. T means text rendered as +** bytes of UTF-8. The and values are expressed as an ASCII +** text integers. ** -** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm -** is used. If SIZE is included it must be one of the integers 224, 256, -** 384, or 512, to determine SHA3 hash variant that is computed. +** For each SQL statement in the X input, there is one S segment. Each +** S segment is followed by zero or more R segments, one for each row in the +** result set. After each R, there are one or more N, I, F, B, or T segments, +** one for each column in the result set. Segments are concatentated directly +** with no delimiters of any kind. */ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -#ifndef SQLITE_AMALGAMATION -/* typedef sqlite3_uint64 u64; */ -#endif /* SQLITE_AMALGAMATION */ +static void sha3QueryFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zSql = (const char*)sqlite3_value_text(argv[0]); + sqlite3_stmt *pStmt = 0; + int nCol; /* Number of columns in the result set */ + int i; /* Loop counter */ + int rc; + int n; + const char *z; + SHA3Context cx; + int iSize; + + if( argc==1 ){ + iSize = 256; + }else{ + iSize = sqlite3_value_int(argv[1]); + if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ + sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " + "384 512", -1); + return; + } + } + if( zSql==0 ) return; + SHA3Init(&cx, iSize); + while( zSql[0] ){ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); + if( rc ){ + char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", + zSql, sqlite3_errmsg(db)); + sqlite3_finalize(pStmt); + sqlite3_result_error(context, zMsg, -1); + sqlite3_free(zMsg); + return; + } + if( !sqlite3_stmt_readonly(pStmt) ){ + char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); + sqlite3_finalize(pStmt); + sqlite3_result_error(context, zMsg, -1); + sqlite3_free(zMsg); + return; + } + nCol = sqlite3_column_count(pStmt); + z = sqlite3_sql(pStmt); + if( z ){ + n = (int)strlen(z); + hash_step_vformat(&cx,"S%d:",n); + SHA3Update(&cx,(unsigned char*)z,n); + } + + /* Compute a hash over the result of the query */ + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + SHA3Update(&cx,(const unsigned char*)"R",1); + for(i=0; i =1; j--){ + x[j] = u & 0xff; + u >>= 8; + } + x[0] = 'I'; + SHA3Update(&cx, x, 9); + break; + } + case SQLITE_FLOAT: { + sqlite3_uint64 u; + int j; + unsigned char x[9]; + double r = sqlite3_column_double(pStmt,i); + memcpy(&u, &r, 8); + for(j=8; j>=1; j--){ + x[j] = u & 0xff; + u >>= 8; + } + x[0] = 'F'; + SHA3Update(&cx,x,9); + break; + } + case SQLITE_TEXT: { + int n2 = sqlite3_column_bytes(pStmt, i); + const unsigned char *z2 = sqlite3_column_text(pStmt, i); + hash_step_vformat(&cx,"T%d:",n2); + SHA3Update(&cx, z2, n2); + break; + } + case SQLITE_BLOB: { + int n2 = sqlite3_column_bytes(pStmt, i); + const unsigned char *z2 = sqlite3_column_blob(pStmt, i); + hash_step_vformat(&cx,"B%d:",n2); + SHA3Update(&cx, z2, n2); + break; + } + } + } + } + sqlite3_finalize(pStmt); + } + sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); +} + + +#ifdef _WIN32 -/****************************************************************************** -** The Hash Engine -*/ -/* -** Macros to determine whether the machine is big or little endian, -** and whether or not that determination is run-time or compile-time. -** -** For best performance, an attempt is made to guess at the byte-order -** using C-preprocessor macros. If that is unsuccessful, or if -** -DSHA3_BYTEORDER=0 is set, then byte-order is determined -** at run-time. -*/ -#ifndef SHA3_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) -# define SHA3_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) -# define SHA3_BYTEORDER 4321 -# else -# define SHA3_BYTEORDER 0 -# endif #endif +int sqlite3_shathree_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "sha3", 1, + SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, + 0, sha3Func, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3", 2, + SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, + 0, sha3Func, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3_query", 1, + SQLITE_UTF8 | SQLITE_DIRECTONLY, + 0, sha3QueryFunc, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3_query", 2, + SQLITE_UTF8 | SQLITE_DIRECTONLY, + 0, sha3QueryFunc, 0, 0); + } + return rc; +} +/************************* End ../ext/misc/shathree.c ********************/ +/************************* Begin ../ext/misc/uint.c ******************/ +/* +** 2020-04-14 +** +** 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 SQLite extension implements the UINT collating sequence. +** +** UINT works like BINARY for text, except that embedded strings +** of digits compare in numeric order. +** +** * Leading zeros are handled properly, in the sense that +** they do not mess of the maginitude comparison of embedded +** strings of digits. "x00123y" is equal to "x123y". +** +** * Only unsigned integers are recognized. Plus and minus +** signs are ignored. Decimal points and exponential notation +** are ignored. +** +** * Embedded integers can be of arbitrary length. Comparison +** is *not* limited integers that can be expressed as a +** 64-bit machine integer. +*/ +/* #include "sqlite3ext.h" */ +SQLITE_EXTENSION_INIT1 +#include +#include +#include /* -** State structure for a SHA3 hash in progress +** Compare text in lexicographic order, except strings of digits +** compare in numeric order. */ -typedef struct SHA3Context SHA3Context; -struct SHA3Context { - union { - u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ - unsigned char x[1600]; /* ... or 1600 bytes */ - } u; - unsigned nRate; /* Bytes of input accepted per Keccak iteration */ - unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ - unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ -}; +static int uintCollFunc( + void *notUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + const unsigned char *zA = (const unsigned char*)pKey1; + const unsigned char *zB = (const unsigned char*)pKey2; + int i=0, j=0, x; + (void)notUsed; + while( i u.s[0]) -# define a01 (p->u.s[1]) -# define a02 (p->u.s[2]) -# define a03 (p->u.s[3]) -# define a04 (p->u.s[4]) -# define a10 (p->u.s[5]) -# define a11 (p->u.s[6]) -# define a12 (p->u.s[7]) -# define a13 (p->u.s[8]) -# define a14 (p->u.s[9]) -# define a20 (p->u.s[10]) -# define a21 (p->u.s[11]) -# define a22 (p->u.s[12]) -# define a23 (p->u.s[13]) -# define a24 (p->u.s[14]) -# define a30 (p->u.s[15]) -# define a31 (p->u.s[16]) -# define a32 (p->u.s[17]) -# define a33 (p->u.s[18]) -# define a34 (p->u.s[19]) -# define a40 (p->u.s[20]) -# define a41 (p->u.s[21]) -# define a42 (p->u.s[22]) -# define a43 (p->u.s[23]) -# define a44 (p->u.s[24]) -# define ROL64(a,x) ((a< >(64-x))) - - for(i=0; i<24; i+=4){ - c0 = a00^a10^a20^a30^a40; - c1 = a01^a11^a21^a31^a41; - c2 = a02^a12^a22^a32^a42; - c3 = a03^a13^a23^a33^a43; - c4 = a04^a14^a24^a34^a44; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); +/* #include "sqlite3ext.h" */ +SQLITE_EXTENSION_INIT1 +#include +#include +#include +#include - b0 = (a00^d0); - b1 = ROL64((a11^d1), 44); - b2 = ROL64((a22^d2), 43); - b3 = ROL64((a33^d3), 21); - b4 = ROL64((a44^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i]; - a11 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAMETER +# define UNUSED_PARAMETER(X) (void)(X) +#endif - b2 = ROL64((a20^d0), 3); - b3 = ROL64((a31^d1), 45); - b4 = ROL64((a42^d2), 61); - b0 = ROL64((a03^d3), 28); - b1 = ROL64((a14^d4), 20); - a20 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - b4 = ROL64((a40^d0), 18); - b0 = ROL64((a01^d1), 1); - b1 = ROL64((a12^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a34^d4), 8); - a40 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); +/* A decimal object */ +typedef struct Decimal Decimal; +struct Decimal { + char sign; /* 0 for positive, 1 for negative */ + char oom; /* True if an OOM is encountered */ + char isNull; /* True if holds a NULL rather than a number */ + char isInit; /* True upon initialization */ + int nDigit; /* Total number of digits */ + int nFrac; /* Number of digits to the right of the decimal point */ + signed char *a; /* Array of digits. Most significant first. */ +}; - b1 = ROL64((a10^d0), 36); - b2 = ROL64((a21^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a43^d3), 56); - b0 = ROL64((a04^d4), 27); - a10 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); +/* +** Release memory held by a Decimal, but do not free the object itself. +*/ +static void decimal_clear(Decimal *p){ + sqlite3_free(p->a); +} - b3 = ROL64((a30^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a02^d2), 62); - b1 = ROL64((a13^d3), 55); - b2 = ROL64((a24^d4), 39); - a30 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); +/* +** Destroy a Decimal object +*/ +static void decimal_free(Decimal *p){ + if( p ){ + decimal_clear(p); + sqlite3_free(p); + } +} - c0 = a00^a20^a40^a10^a30; - c1 = a11^a31^a01^a21^a41; - c2 = a22^a42^a12^a32^a02; - c3 = a33^a03^a23^a43^a13; - c4 = a44^a14^a34^a04^a24; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); +/* +** Allocate a new Decimal object. Initialize it to the number given +** by the input string. +*/ +static Decimal *decimal_new( + sqlite3_context *pCtx, + sqlite3_value *pIn, + int nAlt, + const unsigned char *zAlt +){ + Decimal *p; + int n, i; + const unsigned char *zIn; + int iExp = 0; + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) goto new_no_mem; + p->sign = 0; + p->oom = 0; + p->isInit = 1; + p->isNull = 0; + p->nDigit = 0; + p->nFrac = 0; + if( zAlt ){ + n = nAlt, + zIn = zAlt; + }else{ + if( sqlite3_value_type(pIn)==SQLITE_NULL ){ + p->a = 0; + p->isNull = 1; + return p; + } + n = sqlite3_value_bytes(pIn); + zIn = sqlite3_value_text(pIn); + } + p->a = sqlite3_malloc64( n+1 ); + if( p->a==0 ) goto new_no_mem; + for(i=0; isspace(zIn[i]); i++){} + if( zIn[i]=='-' ){ + p->sign = 1; + i++; + }else if( zIn[i]=='+' ){ + i++; + } + while( i ='0' && c<='9' ){ + p->a[p->nDigit++] = c - '0'; + }else if( c=='.' ){ + p->nFrac = p->nDigit + 1; + }else if( c=='e' || c=='E' ){ + int j = i+1; + int neg = 0; + if( j>=n ) break; + if( zIn[j]=='-' ){ + neg = 1; + j++; + }else if( zIn[j]=='+' ){ + j++; + } + while( j ='0' && zIn[j]<='9' ){ + iExp = iExp*10 + zIn[j] - '0'; + } + j++; + } + if( neg ) iExp = -iExp; + break; + } + i++; + } + if( p->nFrac ){ + p->nFrac = p->nDigit - (p->nFrac - 1); + } + if( iExp>0 ){ + if( p->nFrac>0 ){ + if( iExp<=p->nFrac ){ + p->nFrac -= iExp; + iExp = 0; + }else{ + iExp -= p->nFrac; + p->nFrac = 0; + } + } + if( iExp>0 ){ + p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); + if( p->a==0 ) goto new_no_mem; + memset(p->a+p->nDigit, 0, iExp); + p->nDigit += iExp; + } + }else if( iExp<0 ){ + int nExtra; + iExp = -iExp; + nExtra = p->nDigit - p->nFrac - 1; + if( nExtra ){ + if( nExtra>=iExp ){ + p->nFrac += iExp; + iExp = 0; + }else{ + iExp -= nExtra; + p->nFrac = p->nDigit - 1; + } + } + if( iExp>0 ){ + p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); + if( p->a==0 ) goto new_no_mem; + memmove(p->a+iExp, p->a, p->nDigit); + memset(p->a, 0, iExp); + p->nDigit += iExp; + p->nFrac += iExp; + } + } + return p; - b0 = (a00^d0); - b1 = ROL64((a31^d1), 44); - b2 = ROL64((a12^d2), 43); - b3 = ROL64((a43^d3), 21); - b4 = ROL64((a24^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+1]; - a31 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a40^d0), 3); - b3 = ROL64((a21^d1), 45); - b4 = ROL64((a02^d2), 61); - b0 = ROL64((a33^d3), 28); - b1 = ROL64((a14^d4), 20); - a40 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a30^d0), 18); - b0 = ROL64((a11^d1), 1); - b1 = ROL64((a42^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a04^d4), 8); - a30 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a20^d0), 36); - b2 = ROL64((a01^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a13^d3), 56); - b0 = ROL64((a44^d4), 27); - a20 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a10^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a22^d2), 62); - b1 = ROL64((a03^d3), 55); - b2 = ROL64((a34^d4), 39); - a10 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - c0 = a00^a40^a30^a20^a10; - c1 = a31^a21^a11^a01^a41; - c2 = a12^a02^a42^a32^a22; - c3 = a43^a33^a23^a13^a03; - c4 = a24^a14^a04^a44^a34; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a21^d1), 44); - b2 = ROL64((a42^d2), 43); - b3 = ROL64((a13^d3), 21); - b4 = ROL64((a34^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+2]; - a21 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a30^d0), 3); - b3 = ROL64((a01^d1), 45); - b4 = ROL64((a22^d2), 61); - b0 = ROL64((a43^d3), 28); - b1 = ROL64((a14^d4), 20); - a30 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a10^d0), 18); - b0 = ROL64((a31^d1), 1); - b1 = ROL64((a02^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a44^d4), 8); - a10 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a40^d0), 36); - b2 = ROL64((a11^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a03^d3), 56); - b0 = ROL64((a24^d4), 27); - a40 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a20^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a12^d2), 62); - b1 = ROL64((a33^d3), 55); - b2 = ROL64((a04^d4), 39); - a20 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - c0 = a00^a30^a10^a40^a20; - c1 = a21^a01^a31^a11^a41; - c2 = a42^a22^a02^a32^a12; - c3 = a13^a43^a23^a03^a33; - c4 = a34^a14^a44^a24^a04; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a01^d1), 44); - b2 = ROL64((a02^d2), 43); - b3 = ROL64((a03^d3), 21); - b4 = ROL64((a04^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+3]; - a01 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a10^d0), 3); - b3 = ROL64((a11^d1), 45); - b4 = ROL64((a12^d2), 61); - b0 = ROL64((a13^d3), 28); - b1 = ROL64((a14^d4), 20); - a10 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a20^d0), 18); - b0 = ROL64((a21^d1), 1); - b1 = ROL64((a22^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a24^d4), 8); - a20 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a30^d0), 36); - b2 = ROL64((a31^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a33^d3), 56); - b0 = ROL64((a34^d4), 27); - a30 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a40^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a42^d2), 62); - b1 = ROL64((a43^d3), 55); - b2 = ROL64((a44^d4), 39); - a40 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - } -} +new_no_mem: + if( pCtx ) sqlite3_result_error_nomem(pCtx); + sqlite3_free(p); + return 0; +} /* -** Initialize a new hash. iSize determines the size of the hash -** in bits and should be one of 224, 256, 384, or 512. Or iSize -** can be zero to use the default hash size of 256 bits. +** Make the given Decimal the result. */ -static void SHA3Init(SHA3Context *p, int iSize){ - memset(p, 0, sizeof(*p)); - if( iSize>=128 && iSize<=512 ){ - p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; - }else{ - p->nRate = (1600 - 2*256)/8; +static void decimal_result(sqlite3_context *pCtx, Decimal *p){ + char *z; + int i, j; + int n; + if( p==0 || p->oom ){ + sqlite3_result_error_nomem(pCtx); + return; } -#if SHA3_BYTEORDER==1234 - /* Known to be little-endian at compile-time. No-op */ -#elif SHA3_BYTEORDER==4321 - p->ixMask = 7; /* Big-endian */ -#else - { - static unsigned int one = 1; - if( 1==*(unsigned char*)&one ){ - /* Little endian. No byte swapping. */ - p->ixMask = 0; - }else{ - /* Big endian. Byte swap. */ - p->ixMask = 7; - } + if( p->isNull ){ + sqlite3_result_null(pCtx); + return; } -#endif + z = sqlite3_malloc( p->nDigit+4 ); + if( z==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + i = 0; + if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ + p->sign = 0; + } + if( p->sign ){ + z[0] = '-'; + i = 1; + } + n = p->nDigit - p->nFrac; + if( n<=0 ){ + z[i++] = '0'; + } + j = 0; + while( n>1 && p->a[j]==0 ){ + j++; + n--; + } + while( n>0 ){ + z[i++] = p->a[j] + '0'; + j++; + n--; + } + if( p->nFrac ){ + z[i++] = '.'; + do{ + z[i++] = p->a[j] + '0'; + j++; + }while( j nDigit ); + } + z[i] = 0; + sqlite3_result_text(pCtx, z, i, sqlite3_free); } /* -** Make consecutive calls to the SHA3Update function to add new content -** to the hash +** SQL Function: decimal(X) +** +** Convert input X into decimal and then back into text */ -static void SHA3Update( - SHA3Context *p, - const unsigned char *aData, - unsigned int nData -){ - unsigned int i = 0; - if( aData==0 ) return; -#if SHA3_BYTEORDER==1234 - if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ - for(; i+7 u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; - p->nLoaded += 8; - if( p->nLoaded>=p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } - } - } -#endif - for(; i u.x[p->nLoaded] ^= aData[i]; -#elif SHA3_BYTEORDER==4321 - p->u.x[p->nLoaded^0x07] ^= aData[i]; -#else - p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; -#endif - p->nLoaded++; - if( p->nLoaded==p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } - } +static void decimalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Decimal *p = decimal_new(context, argv[0], 0, 0); + UNUSED_PARAMETER(argc); + decimal_result(context, p); + decimal_free(p); } /* -** After all content has been added, invoke SHA3Final() to compute -** the final hash. The function returns a pointer to the binary -** hash value. +** Compare to Decimal objects. Return negative, 0, or positive if the +** first object is less than, equal to, or greater than the second. +** +** Preconditions for this routine: +** +** pA!=0 +** pA->isNull==0 +** pB!=0 +** pB->isNull==0 */ -static unsigned char *SHA3Final(SHA3Context *p){ - unsigned int i; - if( p->nLoaded==p->nRate-1 ){ - const unsigned char c1 = 0x86; - SHA3Update(p, &c1, 1); - }else{ - const unsigned char c2 = 0x06; - const unsigned char c3 = 0x80; - SHA3Update(p, &c2, 1); - p->nLoaded = p->nRate - 1; - SHA3Update(p, &c3, 1); +static int decimal_cmp(const Decimal *pA, const Decimal *pB){ + int nASig, nBSig, rc, n; + if( pA->sign!=pB->sign ){ + return pA->sign ? -1 : +1; } - for(i=0; i nRate; i++){ - p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; + if( pA->sign ){ + const Decimal *pTemp = pA; + pA = pB; + pB = pTemp; } - return &p->u.x[p->nRate]; + nASig = pA->nDigit - pA->nFrac; + nBSig = pB->nDigit - pB->nFrac; + if( nASig!=nBSig ){ + return nASig - nBSig; + } + n = pA->nDigit; + if( n>pB->nDigit ) n = pB->nDigit; + rc = memcmp(pA->a, pB->a, n); + if( rc==0 ){ + rc = pA->nDigit - pB->nDigit; + } + return rc; } -/* End of the hashing logic -*****************************************************************************/ /* -** Implementation of the sha3(X,SIZE) function. +** SQL Function: decimal_cmp(X, Y) ** -** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default -** size is 256. If X is a BLOB, it is hashed as is. -** For all other non-NULL types of input, X is converted into a UTF-8 string -** and the string is hashed without the trailing 0x00 terminator. The hash -** of a NULL value is NULL. +** Return negative, zero, or positive if X is less then, equal to, or +** greater than Y. */ -static void sha3Func( +static void decimalCmpFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - SHA3Context cx; - int eType = sqlite3_value_type(argv[0]); - int nByte = sqlite3_value_bytes(argv[0]); - int iSize; - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } + Decimal *pA = 0, *pB = 0; + int rc; + + UNUSED_PARAMETER(argc); + pA = decimal_new(context, argv[0], 0, 0); + if( pA==0 || pA->isNull ) goto cmp_done; + pB = decimal_new(context, argv[1], 0, 0); + if( pB==0 || pB->isNull ) goto cmp_done; + rc = decimal_cmp(pA, pB); + if( rc<0 ) rc = -1; + else if( rc>0 ) rc = +1; + sqlite3_result_int(context, rc); +cmp_done: + decimal_free(pA); + decimal_free(pB); +} + +/* +** Expand the Decimal so that it has a least nDigit digits and nFrac +** digits to the right of the decimal point. +*/ +static void decimal_expand(Decimal *p, int nDigit, int nFrac){ + int nAddSig; + int nAddFrac; + if( p==0 ) return; + nAddFrac = nFrac - p->nFrac; + nAddSig = (nDigit - p->nDigit) - nAddFrac; + if( nAddFrac==0 && nAddSig==0 ) return; + p->a = sqlite3_realloc64(p->a, nDigit+1); + if( p->a==0 ){ + p->oom = 1; + return; } - if( eType==SQLITE_NULL ) return; - SHA3Init(&cx, iSize); - if( eType==SQLITE_BLOB ){ - SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte); + if( nAddSig ){ + memmove(p->a+nAddSig, p->a, p->nDigit); + memset(p->a, 0, nAddSig); + p->nDigit += nAddSig; + } + if( nAddFrac ){ + memset(p->a+p->nDigit, 0, nAddFrac); + p->nDigit += nAddFrac; + p->nFrac += nAddFrac; + } +} + +/* +** Add the value pB into pA. +** +** Both pA and pB might become denormalized by this routine. +*/ +static void decimal_add(Decimal *pA, Decimal *pB){ + int nSig, nFrac, nDigit; + int i, rc; + if( pA==0 ){ + return; + } + if( pA->oom || pB==0 || pB->oom ){ + pA->oom = 1; + return; + } + if( pA->isNull || pB->isNull ){ + pA->isNull = 1; + return; + } + nSig = pA->nDigit - pA->nFrac; + if( nSig && pA->a[0]==0 ) nSig--; + if( nSig nDigit-pB->nFrac ){ + nSig = pB->nDigit - pB->nFrac; + } + nFrac = pA->nFrac; + if( nFrac nFrac ) nFrac = pB->nFrac; + nDigit = nSig + nFrac + 1; + decimal_expand(pA, nDigit, nFrac); + decimal_expand(pB, nDigit, nFrac); + if( pA->oom || pB->oom ){ + pA->oom = 1; }else{ - SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte); + if( pA->sign==pB->sign ){ + int carry = 0; + for(i=nDigit-1; i>=0; i--){ + int x = pA->a[i] + pB->a[i] + carry; + if( x>=10 ){ + carry = 1; + pA->a[i] = x - 10; + }else{ + carry = 0; + pA->a[i] = x; + } + } + }else{ + signed char *aA, *aB; + int borrow = 0; + rc = memcmp(pA->a, pB->a, nDigit); + if( rc<0 ){ + aA = pB->a; + aB = pA->a; + pA->sign = !pA->sign; + }else{ + aA = pA->a; + aB = pB->a; + } + for(i=nDigit-1; i>=0; i--){ + int x = aA[i] - aB[i] - borrow; + if( x<0 ){ + pA->a[i] = x+10; + borrow = 1; + }else{ + pA->a[i] = x; + borrow = 0; + } + } + } } - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } -/* Compute a string using sqlite3_vsnprintf() with a maximum length -** of 50 bytes and add it to the hash. +/* +** Compare text in decimal order. */ -static void sha3_step_vformat( - SHA3Context *p, /* Add content to this context */ - const char *zFormat, - ... +static int decimalCollFunc( + void *notUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 ){ - va_list ap; - int n; - char zBuf[50]; - va_start(ap, zFormat); - sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); - va_end(ap); - n = (int)strlen(zBuf); - SHA3Update(p, (unsigned char*)zBuf, n); + const unsigned char *zA = (const unsigned char*)pKey1; + const unsigned char *zB = (const unsigned char*)pKey2; + Decimal *pA = decimal_new(0, 0, nKey1, zA); + Decimal *pB = decimal_new(0, 0, nKey2, zB); + int rc; + UNUSED_PARAMETER(notUsed); + if( pA==0 || pB==0 ){ + rc = 0; + }else{ + rc = decimal_cmp(pA, pB); + } + decimal_free(pA); + decimal_free(pB); + return rc; } + /* -** Implementation of the sha3_query(SQL,SIZE) function. +** SQL Function: decimal_add(X, Y) +** decimal_sub(X, Y) ** -** This function compiles and runs the SQL statement(s) given in the -** argument. The results are hashed using a SIZE-bit SHA3. The default -** size is 256. -** -** The format of the byte stream that is hashed is summarized as follows: -** -** S : -** R -** N -** I -** F -** B : -** T : -** -** is the original SQL text for each statement run and is -** the size of that text. The SQL text is UTF-8. A single R character -** occurs before the start of each row. N means a NULL value. -** I mean an 8-byte little-endian integer . F is a floating point -** number with an 8-byte little-endian IEEE floating point value . -** B means blobs of bytes. T means text rendered as -** bytes of UTF-8. The and values are expressed as an ASCII -** text integers. -** -** For each SQL statement in the X input, there is one S segment. Each -** S segment is followed by zero or more R segments, one for each row in the -** result set. After each R, there are one or more N, I, F, B, or T segments, -** one for each column in the result set. Segments are concatentated directly -** with no delimiters of any kind. +** Return the sum or difference of X and Y. */ -static void sha3QueryFunc( +static void decimalAddFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - sqlite3 *db = sqlite3_context_db_handle(context); - const char *zSql = (const char*)sqlite3_value_text(argv[0]); - sqlite3_stmt *pStmt = 0; - int nCol; /* Number of columns in the result set */ - int i; /* Loop counter */ - int rc; - int n; - const char *z; - SHA3Context cx; - int iSize; - - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + UNUSED_PARAMETER(argc); + decimal_add(pA, pB); + decimal_result(context, pA); + decimal_free(pA); + decimal_free(pB); +} +static void decimalSubFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + UNUSED_PARAMETER(argc); + if( pB ){ + pB->sign = !pB->sign; + decimal_add(pA, pB); + decimal_result(context, pA); } - if( zSql==0 ) return; - SHA3Init(&cx, iSize); - while( zSql[0] ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); - if( rc ){ - char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", - zSql, sqlite3_errmsg(db)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - if( !sqlite3_stmt_readonly(pStmt) ){ - char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - nCol = sqlite3_column_count(pStmt); - z = sqlite3_sql(pStmt); - if( z ){ - n = (int)strlen(z); - sha3_step_vformat(&cx,"S%d:",n); - SHA3Update(&cx,(unsigned char*)z,n); - } + decimal_free(pA); + decimal_free(pB); +} - /* Compute a hash over the result of the query */ - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - SHA3Update(&cx,(const unsigned char*)"R",1); - for(i=0; i =1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'I'; - SHA3Update(&cx, x, 9); - break; - } - case SQLITE_FLOAT: { - sqlite3_uint64 u; - int j; - unsigned char x[9]; - double r = sqlite3_column_double(pStmt,i); - memcpy(&u, &r, 8); - for(j=8; j>=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'F'; - SHA3Update(&cx,x,9); - break; - } - case SQLITE_TEXT: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_text(pStmt, i); - sha3_step_vformat(&cx,"T%d:",n2); - SHA3Update(&cx, z2, n2); - break; - } - case SQLITE_BLOB: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_blob(pStmt, i); - sha3_step_vformat(&cx,"B%d:",n2); - SHA3Update(&cx, z2, n2); - break; - } - } - } +/* Aggregate funcion: decimal_sum(X) +** +** Works like sum() except that it uses decimal arithmetic for unlimited +** precision. +*/ +static void decimalSumStep( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Decimal *p; + Decimal *pArg; + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( p==0 ) return; + if( !p->isInit ){ + p->isInit = 1; + p->a = sqlite3_malloc(2); + if( p->a==0 ){ + p->oom = 1; + }else{ + p->a[0] = 0; } - sqlite3_finalize(pStmt); + p->nDigit = 1; + p->nFrac = 0; } - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pArg = decimal_new(context, argv[0], 0, 0); + decimal_add(p, pArg); + decimal_free(pArg); } - - -#ifdef _WIN32 - -#endif -int sqlite3_shathree_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi +static void decimalSumInverse( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "sha3", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3", 2, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 1, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 2, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - return rc; + Decimal *p; + Decimal *pArg; + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( p==0 ) return; + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pArg = decimal_new(context, argv[0], 0, 0); + if( pArg ) pArg->sign = !pArg->sign; + decimal_add(p, pArg); + decimal_free(pArg); +} +static void decimalSumValue(sqlite3_context *context){ + Decimal *p = sqlite3_aggregate_context(context, 0); + if( p==0 ) return; + decimal_result(context, p); +} +static void decimalSumFinalize(sqlite3_context *context){ + Decimal *p = sqlite3_aggregate_context(context, 0); + if( p==0 ) return; + decimal_result(context, p); + decimal_clear(p); } -/************************* End ../ext/misc/shathree.c ********************/ -/************************* Begin ../ext/misc/uint.c ******************/ /* -** 2020-04-14 -** -** 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 SQLite extension implements the UINT collating sequence. -** -** UINT works like BINARY for text, except that embedded strings -** of digits compare in numeric order. -** -** * Leading zeros are handled properly, in the sense that -** they do not mess of the maginitude comparison of embedded -** strings of digits. "x00123y" is equal to "x123y". +** SQL Function: decimal_mul(X, Y) ** -** * Only unsigned integers are recognized. Plus and minus -** signs are ignored. Decimal points and exponential notation -** are ignored. +** Return the product of X and Y. ** -** * Embedded integers can be of arbitrary length. Comparison -** is *not* limited integers that can be expressed as a -** 64-bit machine integer. -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -/* -** Compare text in lexicographic order, except strings of digits -** compare in numeric order. +** All significant digits after the decimal point are retained. +** Trailing zeros after the decimal point are omitted as long as +** the number of digits after the decimal point is no less than +** either the number of digits in either input. */ -static int uintCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 +static void decimalMulFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - int i=0, j=0, x; - (void)notUsed; - while( i oom || pA->isNull + || pB==0 || pB->oom || pB->isNull + ){ + goto mul_end; + } + acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); + if( acc==0 ){ + sqlite3_result_error_nomem(context); + goto mul_end; + } + memset(acc, 0, pA->nDigit + pB->nDigit + 2); + minFrac = pA->nFrac; + if( pB->nFrac nFrac; + for(i=pA->nDigit-1; i>=0; i--){ + signed char f = pA->a[i]; + int carry = 0, x; + for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ + x = acc[k] + f*pB->a[j] + carry; + acc[k] = x%10; + carry = x/10; } + x = acc[k] + carry; + acc[k] = x%10; + acc[k-1] += x/10; } - return (nKey1 - i) - (nKey2 - j); + sqlite3_free(pA->a); + pA->a = acc; + acc = 0; + pA->nDigit += pB->nDigit + 2; + pA->nFrac += pB->nFrac; + pA->sign ^= pB->sign; + while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ + pA->nFrac--; + pA->nDigit--; + } + decimal_result(context, pA); + +mul_end: + sqlite3_free(acc); + decimal_free(pA); + decimal_free(pB); } #ifdef _WIN32 #endif -int sqlite3_uint_init( +int sqlite3_decimal_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ - SQLITE_EXTENSION_INIT2(pApi); + int rc = SQLITE_OK; + static const struct { + const char *zFuncName; + int nArg; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "decimal", 1, decimalFunc }, + { "decimal_cmp", 2, decimalCmpFunc }, + { "decimal_add", 2, decimalAddFunc }, + { "decimal_sub", 2, decimalSubFunc }, + { "decimal_mul", 2, decimalMulFunc }, + }; + unsigned int i; (void)pzErrMsg; /* Unused parameter */ - return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc); + + SQLITE_EXTENSION_INIT2(pApi); + + for(i=0; i 'ieee754(2,0)' +** ieee754(45.25) -> 'ieee754(181,-2)' +** ieee754(2, 0) -> 2.0 +** ieee754(181, -2) -> 45.25 +** +** Two additional functions break apart the one-argument ieee754() +** result into separate integer values: +** +** ieee754_mantissa(45.25) -> 181 +** ieee754_exponent(45.25) -> -2 +** +** These functions convert binary64 numbers into blobs and back again. +** +** ieee754_from_blob(x'3ff0000000000000') -> 1.0 +** ieee754_to_blob(1.0) -> x'3ff0000000000000' +** +** In all single-argument functions, if the argument is an 8-byte blob +** then that blob is interpreted as a big-endian binary64 value. +** +** +** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES +** ----------------------------------------------- +** +** This extension in combination with the separate 'decimal' extension +** can be used to compute the exact decimal representation of binary64 +** values. To begin, first compute a table of exponent values: +** +** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); +** WITH RECURSIVE c(x,v) AS ( +** VALUES(0,'1') +** UNION ALL +** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 +** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; +** WITH RECURSIVE c(x,v) AS ( +** VALUES(-1,'0.5') +** UNION ALL +** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 +** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; +** +** Then, to compute the exact decimal representation of a floating +** point value (the value 47.49 is used in the example) do: +** +** WITH c(n) AS (VALUES(47.49)) +** ---------------^^^^^---- Replace with whatever you want +** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) +** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); +** +** Here is a query to show various boundry values for the binary64 +** number format: +** +** WITH c(name,bin) AS (VALUES +** ('minimum positive value', x'0000000000000001'), +** ('maximum subnormal value', x'000fffffffffffff'), +** ('mininum positive nornal value', x'0010000000000000'), +** ('maximum value', x'7fefffffffffffff')) +** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v) +** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin); ** -** The focus here is on simplicity and correctness, not performance. */ /* #include "sqlite3ext.h" */ SQLITE_EXTENSION_INIT1 #include #include -#include -#include /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ @@ -3683,4517 +3087,1552 @@ SQLITE_EXTENSION_INIT1 # define UNUSED_PARAMETER(X) (void)(X) #endif - -/* A decimal object */ -typedef struct Decimal Decimal; -struct Decimal { - char sign; /* 0 for positive, 1 for negative */ - char oom; /* True if an OOM is encountered */ - char isNull; /* True if holds a NULL rather than a number */ - char isInit; /* True upon initialization */ - int nDigit; /* Total number of digits */ - int nFrac; /* Number of digits to the right of the decimal point */ - signed char *a; /* Array of digits. Most significant first. */ -}; - -/* -** Release memory held by a Decimal, but do not free the object itself. -*/ -static void decimal_clear(Decimal *p){ - sqlite3_free(p->a); -} - -/* -** Destroy a Decimal object -*/ -static void decimal_free(Decimal *p){ - if( p ){ - decimal_clear(p); - sqlite3_free(p); - } -} - /* -** Allocate a new Decimal object initialized to the text in zIn[]. -** Return NULL if any kind of error occurs. +** Implementation of the ieee754() function */ -static Decimal *decimalNewFromText(const char *zIn, int n){ - Decimal *p = 0; - int i; - int iExp = 0; - - p = sqlite3_malloc( sizeof(*p) ); - if( p==0 ) goto new_from_text_failed; - p->sign = 0; - p->oom = 0; - p->isInit = 1; - p->isNull = 0; - p->nDigit = 0; - p->nFrac = 0; - p->a = sqlite3_malloc64( n+1 ); - if( p->a==0 ) goto new_from_text_failed; - for(i=0; isspace(zIn[i]); i++){} - if( zIn[i]=='-' ){ - p->sign = 1; - i++; - }else if( zIn[i]=='+' ){ - i++; - } - while( i ='0' && c<='9' ){ - p->a[p->nDigit++] = c - '0'; - }else if( c=='.' ){ - p->nFrac = p->nDigit + 1; - }else if( c=='e' || c=='E' ){ - int j = i+1; - int neg = 0; - if( j>=n ) break; - if( zIn[j]=='-' ){ - neg = 1; - j++; - }else if( zIn[j]=='+' ){ - j++; - } - while( j ='0' && zIn[j]<='9' ){ - iExp = iExp*10 + zIn[j] - '0'; - } - j++; - } - if( neg ) iExp = -iExp; - break; - } - i++; - } - if( p->nFrac ){ - p->nFrac = p->nDigit - (p->nFrac - 1); - } - if( iExp>0 ){ - if( p->nFrac>0 ){ - if( iExp<=p->nFrac ){ - p->nFrac -= iExp; - iExp = 0; - }else{ - iExp -= p->nFrac; - p->nFrac = 0; - } - } - if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); - if( p->a==0 ) goto new_from_text_failed; - memset(p->a+p->nDigit, 0, iExp); - p->nDigit += iExp; - } - }else if( iExp<0 ){ - int nExtra; - iExp = -iExp; - nExtra = p->nDigit - p->nFrac - 1; - if( nExtra ){ - if( nExtra>=iExp ){ - p->nFrac += iExp; - iExp = 0; - }else{ - iExp -= nExtra; - p->nFrac = p->nDigit - 1; - } - } - if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); - if( p->a==0 ) goto new_from_text_failed; - memmove(p->a+iExp, p->a, p->nDigit); - memset(p->a, 0, iExp); - p->nDigit += iExp; - p->nFrac += iExp; - } - } - return p; - -new_from_text_failed: - if( p ){ - if( p->a ) sqlite3_free(p->a); - sqlite3_free(p); - } - return 0; -} - -/* Forward reference */ -static Decimal *decimalFromDouble(double); - -/* -** Allocate a new Decimal object from an sqlite3_value. Return a pointer -** to the new object, or NULL if there is an error. If the pCtx argument -** is not NULL, then errors are reported on it as well. -** -** If the pIn argument is SQLITE_TEXT or SQLITE_INTEGER, it is converted -** directly into a Decimal. For SQLITE_FLOAT or for SQLITE_BLOB of length -** 8 bytes, the resulting double value is expanded into its decimal equivalent. -** If pIn is NULL or if it is a BLOB that is not exactly 8 bytes in length, -** then NULL is returned. -*/ -static Decimal *decimal_new( - sqlite3_context *pCtx, /* Report error here, if not null */ - sqlite3_value *pIn, /* Construct the decimal object from this */ - int bTextOnly /* Always interpret pIn as text if true */ +static void ieee754func( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *p = 0; - int eType = sqlite3_value_type(pIn); - if( bTextOnly && (eType==SQLITE_FLOAT || eType==SQLITE_BLOB) ){ - eType = SQLITE_TEXT; - } - switch( eType ){ - case SQLITE_TEXT: - case SQLITE_INTEGER: { - const char *zIn = (const char*)sqlite3_value_text(pIn); - int n = sqlite3_value_bytes(pIn); - p = decimalNewFromText(zIn, n); - if( p==0 ) goto new_failed; - break; - } - - case SQLITE_FLOAT: { - p = decimalFromDouble(sqlite3_value_double(pIn)); - break; - } - - case SQLITE_BLOB: { - const unsigned char *x; + if( argc==1 ){ + sqlite3_int64 m, a; + double r; + int e; + int isNeg; + char zResult[100]; + assert( sizeof(m)==sizeof(r) ); + if( sqlite3_value_type(argv[0])==SQLITE_BLOB + && sqlite3_value_bytes(argv[0])==sizeof(r) + ){ + const unsigned char *x = sqlite3_value_blob(argv[0]); unsigned int i; sqlite3_uint64 v = 0; - double r; - - if( sqlite3_value_bytes(pIn)!=sizeof(r) ) break; - x = sqlite3_value_blob(pIn); for(i=0; i oom ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( p->isNull ){ - sqlite3_result_null(pCtx); - return; - } - z = sqlite3_malloc( p->nDigit+4 ); - if( z==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - i = 0; - if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ - p->sign = 0; - } - if( p->sign ){ - z[0] = '-'; - i = 1; - } - n = p->nDigit - p->nFrac; - if( n<=0 ){ - z[i++] = '0'; - } - j = 0; - while( n>1 && p->a[j]==0 ){ - j++; - n--; - } - while( n>0 ){ - z[i++] = p->a[j] + '0'; - j++; - n--; - } - if( p->nFrac ){ - z[i++] = '.'; - do{ - z[i++] = p->a[j] + '0'; - j++; - }while( j nDigit ); - } - z[i] = 0; - sqlite3_result_text(pCtx, z, i, sqlite3_free); -} - -/* -** Make the given Decimal the result in an format similar to '%+#e'. -** In other words, show exponential notation with leading and trailing -** zeros omitted. -*/ -static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){ - char *z; /* The output buffer */ - int i; /* Loop counter */ - int nZero; /* Number of leading zeros */ - int nDigit; /* Number of digits not counting trailing zeros */ - int nFrac; /* Digits to the right of the decimal point */ - int exp; /* Exponent value */ - signed char zero; /* Zero value */ - signed char *a; /* Array of digits */ - - if( p==0 || p->oom ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( p->isNull ){ - sqlite3_result_null(pCtx); - return; - } - for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){} - for(nZero=0; nZero a[nZero]==0; nZero++){} - nFrac = p->nFrac + (nDigit - p->nDigit); - nDigit -= nZero; - z = sqlite3_malloc( nDigit+20 ); - if( z==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( nDigit==0 ){ - zero = 0; - a = &zero; - nDigit = 1; - nFrac = 0; - }else{ - a = &p->a[nZero]; - } - if( p->sign && nDigit>0 ){ - z[0] = '-'; - }else{ - z[0] = '+'; - } - z[1] = a[0]+'0'; - z[2] = '.'; - if( nDigit==1 ){ - z[3] = '0'; - i = 4; - }else{ - for(i=1; i isNull==0 -** pB!=0 -** pB->isNull==0 -*/ -static int decimal_cmp(const Decimal *pA, const Decimal *pB){ - int nASig, nBSig, rc, n; - if( pA->sign!=pB->sign ){ - return pA->sign ? -1 : +1; - } - if( pA->sign ){ - const Decimal *pTemp = pA; - pA = pB; - pB = pTemp; - } - nASig = pA->nDigit - pA->nFrac; - nBSig = pB->nDigit - pB->nFrac; - if( nASig!=nBSig ){ - return nASig - nBSig; - } - n = pA->nDigit; - if( n>pB->nDigit ) n = pB->nDigit; - rc = memcmp(pA->a, pB->a, n); - if( rc==0 ){ - rc = pA->nDigit - pB->nDigit; - } - return rc; -} - -/* -** SQL Function: decimal_cmp(X, Y) -** -** Return negative, zero, or positive if X is less then, equal to, or -** greater than Y. -*/ -static void decimalCmpFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = 0, *pB = 0; - int rc; - - UNUSED_PARAMETER(argc); - pA = decimal_new(context, argv[0], 1); - if( pA==0 || pA->isNull ) goto cmp_done; - pB = decimal_new(context, argv[1], 1); - if( pB==0 || pB->isNull ) goto cmp_done; - rc = decimal_cmp(pA, pB); - if( rc<0 ) rc = -1; - else if( rc>0 ) rc = +1; - sqlite3_result_int(context, rc); -cmp_done: - decimal_free(pA); - decimal_free(pB); -} - -/* -** Expand the Decimal so that it has a least nDigit digits and nFrac -** digits to the right of the decimal point. -*/ -static void decimal_expand(Decimal *p, int nDigit, int nFrac){ - int nAddSig; - int nAddFrac; - if( p==0 ) return; - nAddFrac = nFrac - p->nFrac; - nAddSig = (nDigit - p->nDigit) - nAddFrac; - if( nAddFrac==0 && nAddSig==0 ) return; - p->a = sqlite3_realloc64(p->a, nDigit+1); - if( p->a==0 ){ - p->oom = 1; - return; - } - if( nAddSig ){ - memmove(p->a+nAddSig, p->a, p->nDigit); - memset(p->a, 0, nAddSig); - p->nDigit += nAddSig; - } - if( nAddFrac ){ - memset(p->a+p->nDigit, 0, nAddFrac); - p->nDigit += nAddFrac; - p->nFrac += nAddFrac; - } -} - -/* -** Add the value pB into pA. A := A + B. -** -** Both pA and pB might become denormalized by this routine. -*/ -static void decimal_add(Decimal *pA, Decimal *pB){ - int nSig, nFrac, nDigit; - int i, rc; - if( pA==0 ){ - return; - } - if( pA->oom || pB==0 || pB->oom ){ - pA->oom = 1; - return; - } - if( pA->isNull || pB->isNull ){ - pA->isNull = 1; - return; - } - nSig = pA->nDigit - pA->nFrac; - if( nSig && pA->a[0]==0 ) nSig--; - if( nSig nDigit-pB->nFrac ){ - nSig = pB->nDigit - pB->nFrac; - } - nFrac = pA->nFrac; - if( nFrac nFrac ) nFrac = pB->nFrac; - nDigit = nSig + nFrac + 1; - decimal_expand(pA, nDigit, nFrac); - decimal_expand(pB, nDigit, nFrac); - if( pA->oom || pB->oom ){ - pA->oom = 1; - }else{ - if( pA->sign==pB->sign ){ - int carry = 0; - for(i=nDigit-1; i>=0; i--){ - int x = pA->a[i] + pB->a[i] + carry; - if( x>=10 ){ - carry = 1; - pA->a[i] = x - 10; - }else{ - carry = 0; - pA->a[i] = x; - } - } - }else{ - signed char *aA, *aB; - int borrow = 0; - rc = memcmp(pA->a, pB->a, nDigit); - if( rc<0 ){ - aA = pB->a; - aB = pA->a; - pA->sign = !pA->sign; - }else{ - aA = pA->a; - aB = pB->a; - } - for(i=nDigit-1; i>=0; i--){ - int x = aA[i] - aB[i] - borrow; - if( x<0 ){ - pA->a[i] = x+10; - borrow = 1; - }else{ - pA->a[i] = x; - borrow = 0; - } - } - } - } -} - -/* -** Multiply A by B. A := A * B -** -** All significant digits after the decimal point are retained. -** Trailing zeros after the decimal point are omitted as long as -** the number of digits after the decimal point is no less than -** either the number of digits in either input. -*/ -static void decimalMul(Decimal *pA, Decimal *pB){ - signed char *acc = 0; - int i, j, k; - int minFrac; - - if( pA==0 || pA->oom || pA->isNull - || pB==0 || pB->oom || pB->isNull - ){ - goto mul_end; - } - acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); - if( acc==0 ){ - pA->oom = 1; - goto mul_end; - } - memset(acc, 0, pA->nDigit + pB->nDigit + 2); - minFrac = pA->nFrac; - if( pB->nFrac nFrac; - for(i=pA->nDigit-1; i>=0; i--){ - signed char f = pA->a[i]; - int carry = 0, x; - for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ - x = acc[k] + f*pB->a[j] + carry; - acc[k] = x%10; - carry = x/10; - } - x = acc[k] + carry; - acc[k] = x%10; - acc[k-1] += x/10; - } - sqlite3_free(pA->a); - pA->a = acc; - acc = 0; - pA->nDigit += pB->nDigit + 2; - pA->nFrac += pB->nFrac; - pA->sign ^= pB->sign; - while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ - pA->nFrac--; - pA->nDigit--; - } - -mul_end: - sqlite3_free(acc); -} - -/* -** Create a new Decimal object that contains an integer power of 2. -*/ -static Decimal *decimalPow2(int N){ - Decimal *pA = 0; /* The result to be returned */ - Decimal *pX = 0; /* Multiplier */ - if( N<-20000 || N>20000 ) goto pow2_fault; - pA = decimalNewFromText("1.0", 3); - if( pA==0 || pA->oom ) goto pow2_fault; - if( N==0 ) return pA; - if( N>0 ){ - pX = decimalNewFromText("2.0", 3); - }else{ - N = -N; - pX = decimalNewFromText("0.5", 3); - } - if( pX==0 || pX->oom ) goto pow2_fault; - while( 1 /* Exit by break */ ){ - if( N & 1 ){ - decimalMul(pA, pX); - if( pA->oom ) goto pow2_fault; - } - N >>= 1; - if( N==0 ) break; - decimalMul(pX, pX); - } - decimal_free(pX); - return pA; - -pow2_fault: - decimal_free(pA); - decimal_free(pX); - return 0; -} - -/* -** Use an IEEE754 binary64 ("double") to generate a new Decimal object. -*/ -static Decimal *decimalFromDouble(double r){ - sqlite3_int64 m, a; - int e; - int isNeg; - Decimal *pA; - Decimal *pX; - char zNum[100]; - if( r<0.0 ){ - isNeg = 1; - r = -r; - }else{ - isNeg = 0; - } - memcpy(&a,&r,sizeof(a)); - if( a==0 ){ - e = 0; - m = 0; - }else{ - e = a>>52; - m = a & ((((sqlite3_int64)1)<<52)-1); - if( e==0 ){ - m <<= 1; - }else{ - m |= ((sqlite3_int64)1)<<52; - } - while( e<1075 && m>0 && (m&1)==0 ){ - m >>= 1; - e++; - } - if( isNeg ) m = -m; - e = e - 1075; - if( e>971 ){ - return 0; /* A NaN or an Infinity */ - } - } - - /* At this point m is the integer significand and e is the exponent */ - sqlite3_snprintf(sizeof(zNum), zNum, "%lld", m); - pA = decimalNewFromText(zNum, (int)strlen(zNum)); - pX = decimalPow2(e); - decimalMul(pA, pX); - decimal_free(pX); - return pA; -} - -/* -** SQL Function: decimal(X) -** OR: decimal_exp(X) -** -** Convert input X into decimal and then back into text. -** -** If X is originally a float, then a full decimal expansion of that floating -** point value is done. Or if X is an 8-byte blob, it is interpreted -** as a float and similarly expanded. -** -** The decimal_exp(X) function returns the result in exponential notation. -** decimal(X) returns a complete decimal, without the e+NNN at the end. -*/ -static void decimalFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p = decimal_new(context, argv[0], 0); - UNUSED_PARAMETER(argc); - if( p ){ - if( sqlite3_user_data(context)!=0 ){ - decimal_result_sci(context, p); - }else{ - decimal_result(context, p); - } - decimal_free(p); - } -} - -/* -** Compare text in decimal order. -*/ -static int decimalCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 -){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - Decimal *pA = decimalNewFromText((const char*)zA, nKey1); - Decimal *pB = decimalNewFromText((const char*)zB, nKey2); - int rc; - UNUSED_PARAMETER(notUsed); - if( pA==0 || pB==0 ){ - rc = 0; - }else{ - rc = decimal_cmp(pA, pB); - } - decimal_free(pA); - decimal_free(pB); - return rc; -} - - -/* -** SQL Function: decimal_add(X, Y) -** decimal_sub(X, Y) -** -** Return the sum or difference of X and Y. -*/ -static void decimalAddFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - decimal_add(pA, pB); - decimal_result(context, pA); - decimal_free(pA); - decimal_free(pB); -} -static void decimalSubFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - if( pB ){ - pB->sign = !pB->sign; - decimal_add(pA, pB); - decimal_result(context, pA); - } - decimal_free(pA); - decimal_free(pB); -} - -/* Aggregate funcion: decimal_sum(X) -** -** Works like sum() except that it uses decimal arithmetic for unlimited -** precision. -*/ -static void decimalSumStep( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( !p->isInit ){ - p->isInit = 1; - p->a = sqlite3_malloc(2); - if( p->a==0 ){ - p->oom = 1; - }else{ - p->a[0] = 0; - } - p->nDigit = 1; - p->nFrac = 0; - } - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 1); - decimal_add(p, pArg); - decimal_free(pArg); -} -static void decimalSumInverse( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 1); - if( pArg ) pArg->sign = !pArg->sign; - decimal_add(p, pArg); - decimal_free(pArg); -} -static void decimalSumValue(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); -} -static void decimalSumFinalize(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); - decimal_clear(p); -} - -/* -** SQL Function: decimal_mul(X, Y) -** -** Return the product of X and Y. -*/ -static void decimalMulFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - Decimal *pA = decimal_new(context, argv[0], 1); - Decimal *pB = decimal_new(context, argv[1], 1); - UNUSED_PARAMETER(argc); - if( pA==0 || pA->oom || pA->isNull - || pB==0 || pB->oom || pB->isNull - ){ - goto mul_end; - } - decimalMul(pA, pB); - if( pA->oom ){ - goto mul_end; - } - decimal_result(context, pA); - -mul_end: - decimal_free(pA); - decimal_free(pB); -} - -/* -** SQL Function: decimal_pow2(N) -** -** Return the N-th power of 2. N must be an integer. -*/ -static void decimalPow2Func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ - Decimal *pA = decimalPow2(sqlite3_value_int(argv[0])); - decimal_result_sci(context, pA); - decimal_free(pA); - } -} - -#ifdef _WIN32 - -#endif -int sqlite3_decimal_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - static const struct { - const char *zFuncName; - int nArg; - int iArg; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "decimal", 1, 0, decimalFunc }, - { "decimal_exp", 1, 1, decimalFunc }, - { "decimal_cmp", 2, 0, decimalCmpFunc }, - { "decimal_add", 2, 0, decimalAddFunc }, - { "decimal_sub", 2, 0, decimalSubFunc }, - { "decimal_mul", 2, 0, decimalMulFunc }, - { "decimal_pow2", 1, 0, decimalPow2Func }, - }; - unsigned int i; - (void)pzErrMsg; /* Unused parameter */ - - SQLITE_EXTENSION_INIT2(pApi); - - for(i=0; i<(int)(sizeof(aFunc)/sizeof(aFunc[0])) && rc==SQLITE_OK; i++){ - rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - aFunc[i].iArg ? db : 0, aFunc[i].xFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_window_function(db, "decimal_sum", 1, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, - decimalSumStep, decimalSumFinalize, - decimalSumValue, decimalSumInverse, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8, - 0, decimalCollFunc); - } - return rc; -} - -/************************* End ../ext/misc/decimal.c ********************/ -#undef sqlite3_base_init -#define sqlite3_base_init sqlite3_base64_init -/************************* Begin ../ext/misc/base64.c ******************/ -/* -** 2022-11-18 -** -** 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 is a SQLite extension for converting in either direction -** between a (binary) blob and base64 text. Base64 can transit a -** sane USASCII channel unmolested. It also plays nicely in CSV or -** written as TCL brace-enclosed literals or SQL string literals, -** and can be used unmodified in XML-like documents. -** -** This is an independent implementation of conversions specified in -** RFC 4648, done on the above date by the author (Larry Brasfield) -** who thereby has the right to put this into the public domain. -** -** The conversions meet RFC 4648 requirements, provided that this -** C source specifies that line-feeds are included in the encoded -** data to limit visible line lengths to 72 characters and to -** terminate any encoded blob having non-zero length. -** -** Length limitations are not imposed except that the runtime -** SQLite string or blob length limits are respected. Otherwise, -** any length binary sequence can be represented and recovered. -** Generated base64 sequences, with their line-feeds included, -** can be concatenated; the result converted back to binary will -** be the concatenation of the represented binary sequences. -** -** This SQLite3 extension creates a function, base64(x), which -** either: converts text x containing base64 to a returned blob; -** or converts a blob x to returned text containing base64. An -** error will be thrown for other input argument types. -** -** This code relies on UTF-8 encoding only with respect to the -** meaning of the first 128 (7-bit) codes matching that of USASCII. -** It will fail miserably if somehow made to try to convert EBCDIC. -** Because it is table-driven, it could be enhanced to handle that, -** but the world and SQLite have moved on from that anachronism. -** -** To build the extension: -** Set shell variable SQDIR= -** *Nix: gcc -O2 -shared -I$SQDIR -fPIC -o base64.so base64.c -** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR -o base64.dylib base64.c -** Win32: gcc -O2 -shared -I%SQDIR% -o base64.dll base64.c -** Win32: cl /Os -I%SQDIR% base64.c -link -dll -out:base64.dll -*/ - -#include - -/* #include "sqlite3ext.h" */ - -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif - -SQLITE_EXTENSION_INIT1; - -#define PC 0x80 /* pad character */ -#define WS 0x81 /* whitespace */ -#define ND 0x82 /* Not above or digit-value */ -#define PAD_CHAR '=' - -#ifndef U8_TYPEDEF -/* typedef unsigned char u8; */ -#define U8_TYPEDEF -#endif - -/* Decoding table, ASCII (7-bit) value to base 64 digit value or other */ -static const u8 b64DigitValues[128] = { - /* HT LF VT FF CR */ - ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND, - /* US */ - ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, - /*sp + / */ - WS,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,62, ND,ND,ND,63, - /* 0 1 5 9 = */ - 52,53,54,55, 56,57,58,59, 60,61,ND,ND, ND,PC,ND,ND, - /* A O */ - ND, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - /* P Z */ - 15,16,17,18, 19,20,21,22, 23,24,25,ND, ND,ND,ND,ND, - /* a o */ - ND,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - /* p z */ - 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND -}; - -static const char b64Numerals[64+1] -= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -#define BX_DV_PROTO(c) \ - ((((u8)(c))<0x80)? (u8)(b64DigitValues[(u8)(c)]) : 0x80) -#define IS_BX_DIGIT(bdp) (((u8)(bdp))<0x80) -#define IS_BX_WS(bdp) ((bdp)==WS) -#define IS_BX_PAD(bdp) ((bdp)==PC) -#define BX_NUMERAL(dv) (b64Numerals[(u8)(dv)]) -/* Width of base64 lines. Should be an integer multiple of 4. */ -#define B64_DARK_MAX 72 - -/* Encode a byte buffer into base64 text with linefeeds appended to limit -** encoded group lengths to B64_DARK_MAX or to terminate the last group. -*/ -static char* toBase64( u8 *pIn, int nbIn, char *pOut ){ - int nCol = 0; - while( nbIn >= 3 ){ - /* Do the bit-shuffle, exploiting unsigned input to avoid masking. */ - pOut[0] = BX_NUMERAL(pIn[0]>>2); - pOut[1] = BX_NUMERAL(((pIn[0]<<4)|(pIn[1]>>4))&0x3f); - pOut[2] = BX_NUMERAL(((pIn[1]&0xf)<<2)|(pIn[2]>>6)); - pOut[3] = BX_NUMERAL(pIn[2]&0x3f); - pOut += 4; - nbIn -= 3; - pIn += 3; - if( (nCol += 4)>=B64_DARK_MAX || nbIn<=0 ){ - *pOut++ = '\n'; - nCol = 0; - } - } - if( nbIn > 0 ){ - signed char nco = nbIn+1; - int nbe; - unsigned long qv = *pIn++; - for( nbe=1; nbe<3; ++nbe ){ - qv <<= 8; - if( nbe =0; --nbe ){ - char ce = (nbe >= 6; - pOut[nbe] = ce; - } - pOut += 4; - *pOut++ = '\n'; - } - *pOut = 0; - return pOut; -} - -/* Skip over text which is not base64 numeral(s). */ -static char * skipNonB64( char *s, int nc ){ - char c; - while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; - return s; -} - -/* Decode base64 text into a byte buffer. */ -static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ - if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; - while( ncIn>0 && *pIn!=PAD_CHAR ){ - static signed char nboi[] = { 0, 0, 1, 2, 3 }; - char *pUse = skipNonB64(pIn, ncIn); - unsigned long qv = 0L; - int nti, nbo, nac; - ncIn -= (pUse - pIn); - pIn = pUse; - nti = (ncIn>4)? 4 : ncIn; - ncIn -= nti; - nbo = nboi[nti]; - if( nbo==0 ) break; - for( nac=0; nac<4; ++nac ){ - char c = (nac >8) & 0xff; - case 1: - pOut[0] = (qv>>16) & 0xff; - } - pOut += nbo; - } - return pOut; -} - -/* This function does the work for the SQLite base64(x) UDF. */ -static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ - int nb, nc, nv = sqlite3_value_bytes(av[0]); - int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), - SQLITE_LIMIT_LENGTH, -1); - char *cBuf; - u8 *bBuf; - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_BLOB: - nb = nv; - nc = 4*(nv+2/3); /* quads needed */ - nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */ - if( nvMax < nc ){ - sqlite3_result_error(context, "blob expanded to base64 too big", -1); - return; - } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } - cBuf = sqlite3_malloc(nc); - if( !cBuf ) goto memFail; - nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); - sqlite3_result_text(context, cBuf, nc, sqlite3_free); - break; - case SQLITE_TEXT: - nc = nv; - nb = 3*((nv+3)/4); /* may overestimate due to LF and padding */ - if( nvMax < nb ){ - sqlite3_result_error(context, "blob from base64 may be too big", -1); - return; - }else if( nb<1 ){ - nb = 1; - } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } - bBuf = sqlite3_malloc(nb); - if( !bBuf ) goto memFail; - nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf); - sqlite3_result_blob(context, bBuf, nb, sqlite3_free); - break; - default: - sqlite3_result_error(context, "base64 accepts only blob or text", -1); - return; - } - return; - memFail: - sqlite3_result_error(context, "base64 OOM", -1); -} - -/* -** Establish linkage to running SQLite library. -*/ -#ifndef SQLITE_SHELL_EXTFUNCS -#ifdef _WIN32 - -#endif -int sqlite3_base_init -#else -static int sqlite3_base64_init -#endif -(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErr; - return sqlite3_create_function - (db, "base64", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, - 0, base64, 0, 0); -} - -/* -** Define some macros to allow this extension to be built into the shell -** conveniently, in conjunction with use of SQLITE_SHELL_EXTFUNCS. This -** allows shell.c, as distributed, to have this extension built in. -*/ -#define BASE64_INIT(db) sqlite3_base64_init(db, 0, 0) -#define BASE64_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ - -/************************* End ../ext/misc/base64.c ********************/ -#undef sqlite3_base_init -#define sqlite3_base_init sqlite3_base85_init -#define OMIT_BASE85_CHECKER -/************************* Begin ../ext/misc/base85.c ******************/ -/* -** 2022-11-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. -** -************************************************************************* -** -** This is a utility for converting binary to base85 or vice-versa. -** It can be built as a standalone program or an SQLite3 extension. -** -** Much like base64 representations, base85 can be sent through a -** sane USASCII channel unmolested. It also plays nicely in CSV or -** written as TCL brace-enclosed literals or SQL string literals. -** It is not suited for unmodified use in XML-like documents. -** -** The encoding used resembles Ascii85, but was devised by the author -** (Larry Brasfield) before Mozilla, Adobe, ZMODEM or other Ascii85 -** variant sources existed, in the 1984 timeframe on a VAX mainframe. -** Further, this is an independent implementation of a base85 system. -** Hence, the author has rightfully put this into the public domain. -** -** Base85 numerals are taken from the set of 7-bit USASCII codes, -** excluding control characters and Space ! " ' ( ) { | } ~ Del -** in code order representing digit values 0 to 84 (base 10.) -** -** Groups of 4 bytes, interpreted as big-endian 32-bit values, -** are represented as 5-digit base85 numbers with MS to LS digit -** order. Groups of 1-3 bytes are represented with 2-4 digits, -** still big-endian but 8-24 bit values. (Using big-endian yields -** the simplest transition to byte groups smaller than 4 bytes. -** These byte groups can also be considered base-256 numbers.) -** Groups of 0 bytes are represented with 0 digits and vice-versa. -** No pad characters are used; Encoded base85 numeral sequence -** (aka "group") length maps 1-to-1 to the decoded binary length. -** -** Any character not in the base85 numeral set delimits groups. -** When base85 is streamed or stored in containers of indefinite -** size, newline is used to separate it into sub-sequences of no -** more than 80 digits so that fgets() can be used to read it. -** -** Length limitations are not imposed except that the runtime -** SQLite string or blob length limits are respected. Otherwise, -** any length binary sequence can be represented and recovered. -** Base85 sequences can be concatenated by separating them with -** a non-base85 character; the conversion to binary will then -** be the concatenation of the represented binary sequences. - -** The standalone program either converts base85 on stdin to create -** a binary file or converts a binary file to base85 on stdout. -** Read or make it blurt its help for invocation details. -** -** The SQLite3 extension creates a function, base85(x), which will -** either convert text base85 to a blob or a blob to text base85 -** and return the result (or throw an error for other types.) -** Unless built with OMIT_BASE85_CHECKER defined, it also creates a -** function, is_base85(t), which returns 1 iff the text t contains -** nothing other than base85 numerals and whitespace, or 0 otherwise. -** -** To build the extension: -** Set shell variable SQDIR= -** and variable OPTS to -DOMIT_BASE85_CHECKER if is_base85() unwanted. -** *Nix: gcc -O2 -shared -I$SQDIR $OPTS -fPIC -o base85.so base85.c -** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR $OPTS -o base85.dylib base85.c -** Win32: gcc -O2 -shared -I%SQDIR% %OPTS% -o base85.dll base85.c -** Win32: cl /Os -I%SQDIR% %OPTS% base85.c -link -dll -out:base85.dll -** -** To build the standalone program, define PP symbol BASE85_STANDALONE. Eg. -** *Nix or OSX: gcc -O2 -DBASE85_STANDALONE base85.c -o base85 -** Win32: gcc -O2 -DBASE85_STANDALONE -o base85.exe base85.c -** Win32: cl /Os /MD -DBASE85_STANDALONE base85.c -*/ - -#include -#include -#include -#include -#ifndef OMIT_BASE85_CHECKER -# include -#endif - -#ifndef BASE85_STANDALONE - -/* # include "sqlite3ext.h" */ - -SQLITE_EXTENSION_INIT1; - -#else - -# ifdef _WIN32 -# include -# include -# else -# define setmode(fd,m) -# endif - -static char *zHelp = - "Usage: base85 \n" - " is either -r to read or -w to write ,\n" - " content to be converted to/from base85 on stdout/stdin.\n" - " names a binary file to be rendered or created.\n" - " Or, the name '-' refers to the stdin or stdout stream.\n" - ; - -static void sayHelp(){ - printf("%s", zHelp); -} -#endif - -#ifndef U8_TYPEDEF -/* typedef unsigned char u8; */ -#define U8_TYPEDEF -#endif - -/* Classify c according to interval within USASCII set w.r.t. base85 - * Values of 1 and 3 are base85 numerals. Values of 0, 2, or 4 are not. - */ -#define B85_CLASS( c ) (((c)>='#')+((c)>'&')+((c)>='*')+((c)>'z')) - -/* Provide digitValue to b85Numeral offset as a function of above class. */ -static u8 b85_cOffset[] = { 0, '#', 0, '*'-4, 0 }; -#define B85_DNOS( c ) b85_cOffset[B85_CLASS(c)] - -/* Say whether c is a base85 numeral. */ -#define IS_B85( c ) (B85_CLASS(c) & 1) - -#if 0 /* Not used, */ -static u8 base85DigitValue( char c ){ - u8 dv = (u8)(c - '#'); - if( dv>87 ) return 0xff; - return (dv > 3)? dv-3 : dv; -} -#endif - -/* Width of base64 lines. Should be an integer multiple of 5. */ -#define B85_DARK_MAX 80 - - -static char * skipNonB85( char *s, int nc ){ - char c; - while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s; - return s; -} - -/* Convert small integer, known to be in 0..84 inclusive, to base85 numeral. - * Do not use the macro form with argument expression having a side-effect.*/ -#if 0 -static char base85Numeral( u8 b ){ - return (b < 4)? (char)(b + '#') : (char)(b - 4 + '*'); -} -#else -# define base85Numeral( dn )\ - ((char)(((dn) < 4)? (char)((dn) + '#') : (char)((dn) - 4 + '*'))) -#endif - -static char *putcs(char *pc, char *s){ - char c; - while( (c = *s++)!=0 ) *pc++ = c; - return pc; -} - -/* Encode a byte buffer into base85 text. If pSep!=0, it's a C string -** to be appended to encoded groups to limit their length to B85_DARK_MAX -** or to terminate the last group (to aid concatenation.) -*/ -static char* toBase85( u8 *pIn, int nbIn, char *pOut, char *pSep ){ - int nCol = 0; - while( nbIn >= 4 ){ - int nco = 5; - unsigned long qbv = (((unsigned long)pIn[0])<<24) | - (pIn[1]<<16) | (pIn[2]<<8) | pIn[3]; - while( nco > 0 ){ - unsigned nqv = (unsigned)(qbv/85UL); - unsigned char dv = qbv - 85UL*nqv; - qbv = nqv; - pOut[--nco] = base85Numeral(dv); - } - nbIn -= 4; - pIn += 4; - pOut += 5; - if( pSep && (nCol += 5)>=B85_DARK_MAX ){ - pOut = putcs(pOut, pSep); - nCol = 0; - } - } - if( nbIn > 0 ){ - int nco = nbIn + 1; - unsigned long qv = *pIn++; - int nbe = 1; - while( nbe++ < nbIn ){ - qv = (qv<<8) | *pIn++; - } - nCol += nco; - while( nco > 0 ){ - u8 dv = (u8)(qv % 85); - qv /= 85; - pOut[--nco] = base85Numeral(dv); - } - pOut += (nbIn+1); - } - if( pSep && nCol>0 ) pOut = putcs(pOut, pSep); - *pOut = 0; - return pOut; -} - -/* Decode base85 text into a byte buffer. */ -static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){ - if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; - while( ncIn>0 ){ - static signed char nboi[] = { 0, 0, 1, 2, 3, 4 }; - char *pUse = skipNonB85(pIn, ncIn); - unsigned long qv = 0L; - int nti, nbo; - ncIn -= (pUse - pIn); - pIn = pUse; - nti = (ncIn>5)? 5 : ncIn; - nbo = nboi[nti]; - if( nbo==0 ) break; - while( nti>0 ){ - char c = *pIn++; - u8 cdo = B85_DNOS(c); - --ncIn; - if( cdo==0 ) break; - qv = 85 * qv + (c - cdo); - --nti; - } - nbo -= nti; /* Adjust for early (non-digit) end of group. */ - switch( nbo ){ - case 4: - *pOut++ = (qv >> 24)&0xff; - case 3: - *pOut++ = (qv >> 16)&0xff; - case 2: - *pOut++ = (qv >> 8)&0xff; - case 1: - *pOut++ = qv&0xff; - case 0: - break; - } - } - return pOut; -} - -#ifndef OMIT_BASE85_CHECKER -/* Say whether input char sequence is all (base85 and/or whitespace).*/ -static int allBase85( char *p, int len ){ - char c; - while( len-- > 0 && (c = *p++) != 0 ){ - if( !IS_B85(c) && !isspace(c) ) return 0; - } - return 1; -} -#endif - -#ifndef BASE85_STANDALONE - -# ifndef OMIT_BASE85_CHECKER -/* This function does the work for the SQLite is_base85(t) UDF. */ -static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){ - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_TEXT: - { - int rv = allBase85( (char *)sqlite3_value_text(av[0]), - sqlite3_value_bytes(av[0]) ); - sqlite3_result_int(context, rv); - } - break; - case SQLITE_NULL: - sqlite3_result_null(context); - break; - default: - sqlite3_result_error(context, "is_base85 accepts only text or NULL", -1); - return; - } -} -# endif - -/* This function does the work for the SQLite base85(x) UDF. */ -static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ - int nb, nc, nv = sqlite3_value_bytes(av[0]); - int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), - SQLITE_LIMIT_LENGTH, -1); - char *cBuf; - u8 *bBuf; - assert(na==1); - switch( sqlite3_value_type(av[0]) ){ - case SQLITE_BLOB: - nb = nv; - /* ulongs tail newlines tailenc+nul*/ - nc = 5*(nv/4) + nv%4 + nv/64+1 + 2; - if( nvMax < nc ){ - sqlite3_result_error(context, "blob expanded to base85 too big", -1); - return; - } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } - cBuf = sqlite3_malloc(nc); - if( !cBuf ) goto memFail; - nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf); - sqlite3_result_text(context, cBuf, nc, sqlite3_free); - break; - case SQLITE_TEXT: - nc = nv; - nb = 4*(nv/5) + nv%5; /* may overestimate */ - if( nvMax < nb ){ - sqlite3_result_error(context, "blob from base85 may be too big", -1); - return; - }else if( nb<1 ){ - nb = 1; - } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } - bBuf = sqlite3_malloc(nb); - if( !bBuf ) goto memFail; - nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf); - sqlite3_result_blob(context, bBuf, nb, sqlite3_free); - break; - default: - sqlite3_result_error(context, "base85 accepts only blob or text.", -1); - return; - } - return; - memFail: - sqlite3_result_error(context, "base85 OOM", -1); -} - -/* -** Establish linkage to running SQLite library. -*/ -#ifndef SQLITE_SHELL_EXTFUNCS -#ifdef _WIN32 - -#endif -int sqlite3_base_init -#else -static int sqlite3_base85_init -#endif -(sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErr; -# ifndef OMIT_BASE85_CHECKER - { - int rc = sqlite3_create_function - (db, "is_base85", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_UTF8, - 0, is_base85, 0, 0); - if( rc!=SQLITE_OK ) return rc; - } -# endif - return sqlite3_create_function - (db, "base85", 1, - SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, - 0, base85, 0, 0); -} - -/* -** Define some macros to allow this extension to be built into the shell -** conveniently, in conjunction with use of SQLITE_SHELL_EXTFUNCS. This -** allows shell.c, as distributed, to have this extension built in. -*/ -# define BASE85_INIT(db) sqlite3_base85_init(db, 0, 0) -# define BASE85_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ - -#else /* standalone program */ - -int main(int na, char *av[]){ - int cin; - int rc = 0; - u8 bBuf[4*(B85_DARK_MAX/5)]; - char cBuf[5*(sizeof(bBuf)/4)+2]; - size_t nio; -# ifndef OMIT_BASE85_CHECKER - int b85Clean = 1; -# endif - char rw; - FILE *fb = 0, *foc = 0; - char fmode[3] = "xb"; - if( na < 3 || av[1][0]!='-' || (rw = av[1][1])==0 || (rw!='r' && rw!='w') ){ - sayHelp(); - return 0; - } - fmode[0] = rw; - if( av[2][0]=='-' && av[2][1]==0 ){ - switch( rw ){ - case 'r': - fb = stdin; - setmode(fileno(stdin), O_BINARY); - break; - case 'w': - fb = stdout; - setmode(fileno(stdout), O_BINARY); - break; - } - }else{ - fb = fopen(av[2], fmode); - foc = fb; - } - if( !fb ){ - fprintf(stderr, "Cannot open %s for %c\n", av[2], rw); - rc = 1; - }else{ - switch( rw ){ - case 'r': - while( (nio = fread( bBuf, 1, sizeof(bBuf), fb))>0 ){ - toBase85( bBuf, (int)nio, cBuf, 0 ); - fprintf(stdout, "%s\n", cBuf); - } - break; - case 'w': - while( 0 != fgets(cBuf, sizeof(cBuf), stdin) ){ - int nc = strlen(cBuf); - size_t nbo = fromBase85( cBuf, nc, bBuf ) - bBuf; - if( 1 != fwrite(bBuf, nbo, 1, fb) ) rc = 1; -# ifndef OMIT_BASE85_CHECKER - b85Clean &= allBase85( cBuf, nc ); -# endif - } - break; - default: - sayHelp(); - rc = 1; - } - if( foc ) fclose(foc); - } -# ifndef OMIT_BASE85_CHECKER - if( !b85Clean ){ - fprintf(stderr, "Base85 input had non-base85 dark or control content.\n"); - } -# endif - return rc; -} - -#endif - -/************************* End ../ext/misc/base85.c ********************/ -/************************* Begin ../ext/misc/ieee754.c ******************/ -/* -** 2013-04-17 -** -** 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 SQLite extension implements functions for the exact display -** and input of IEEE754 Binary64 floating-point numbers. -** -** ieee754(X) -** ieee754(Y,Z) -** -** In the first form, the value X should be a floating-point number. -** The function will return a string of the form 'ieee754(Y,Z)' where -** Y and Z are integers such that X==Y*pow(2,Z). -** -** In the second form, Y and Z are integers which are the mantissa and -** base-2 exponent of a new floating point number. The function returns -** a floating-point value equal to Y*pow(2,Z). -** -** Examples: -** -** ieee754(2.0) -> 'ieee754(2,0)' -** ieee754(45.25) -> 'ieee754(181,-2)' -** ieee754(2, 0) -> 2.0 -** ieee754(181, -2) -> 45.25 -** -** Two additional functions break apart the one-argument ieee754() -** result into separate integer values: -** -** ieee754_mantissa(45.25) -> 181 -** ieee754_exponent(45.25) -> -2 -** -** These functions convert binary64 numbers into blobs and back again. -** -** ieee754_from_blob(x'3ff0000000000000') -> 1.0 -** ieee754_to_blob(1.0) -> x'3ff0000000000000' -** -** In all single-argument functions, if the argument is an 8-byte blob -** then that blob is interpreted as a big-endian binary64 value. -** -** -** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES -** ----------------------------------------------- -** -** This extension in combination with the separate 'decimal' extension -** can be used to compute the exact decimal representation of binary64 -** values. To begin, first compute a table of exponent values: -** -** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); -** WITH RECURSIVE c(x,v) AS ( -** VALUES(0,'1') -** UNION ALL -** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 -** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; -** WITH RECURSIVE c(x,v) AS ( -** VALUES(-1,'0.5') -** UNION ALL -** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 -** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; -** -** Then, to compute the exact decimal representation of a floating -** point value (the value 47.49 is used in the example) do: -** -** WITH c(n) AS (VALUES(47.49)) -** ---------------^^^^^---- Replace with whatever you want -** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) -** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); -** -** Here is a query to show various boundry values for the binary64 -** number format: -** -** WITH c(name,bin) AS (VALUES -** ('minimum positive value', x'0000000000000001'), -** ('maximum subnormal value', x'000fffffffffffff'), -** ('mininum positive nornal value', x'0010000000000000'), -** ('maximum value', x'7fefffffffffffff')) -** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v) -** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin); -** -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include - -/* Mark a function parameter as unused, to suppress nuisance compiler -** warnings. */ -#ifndef UNUSED_PARAMETER -# define UNUSED_PARAMETER(X) (void)(X) -#endif - -/* -** Implementation of the ieee754() function -*/ -static void ieee754func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - if( argc==1 ){ - sqlite3_int64 m, a; - double r; - int e; - int isNeg; - char zResult[100]; - assert( sizeof(m)==sizeof(r) ); - if( sqlite3_value_type(argv[0])==SQLITE_BLOB - && sqlite3_value_bytes(argv[0])==sizeof(r) - ){ - const unsigned char *x = sqlite3_value_blob(argv[0]); - unsigned int i; - sqlite3_uint64 v = 0; - for(i=0; i >52; - m = a & ((((sqlite3_int64)1)<<52)-1); - if( e==0 ){ - m <<= 1; - }else{ - m |= ((sqlite3_int64)1)<<52; - } - while( e<1075 && m>0 && (m&1)==0 ){ - m >>= 1; - e++; - } - if( isNeg ) m = -m; - } - switch( *(int*)sqlite3_user_data(context) ){ - case 0: - sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", - m, e-1075); - sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); - break; - case 1: - sqlite3_result_int64(context, m); - break; - case 2: - sqlite3_result_int(context, e-1075); - break; - } - }else{ - sqlite3_int64 m, e, a; - double r; - int isNeg = 0; - m = sqlite3_value_int64(argv[0]); - e = sqlite3_value_int64(argv[1]); - - /* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */ - if( e>10000 ){ - e = 10000; - }else if( e<-10000 ){ - e = -10000; - } - - if( m<0 ){ - isNeg = 1; - m = -m; - if( m<0 ) return; - }else if( m==0 && e>-1000 && e<1000 ){ - sqlite3_result_double(context, 0.0); - return; - } - while( (m>>32)&0xffe00000 ){ - m >>= 1; - e++; - } - while( m!=0 && ((m>>32)&0xfff00000)==0 ){ - m <<= 1; - e--; - } - e += 1075; - if( e<=0 ){ - /* Subnormal */ - if( 1-e >= 64 ){ - m = 0; - }else{ - m >>= 1-e; - } - e = 0; - }else if( e>0x7ff ){ - e = 0x7ff; - } - a = m & ((((sqlite3_int64)1)<<52)-1); - a |= e<<52; - if( isNeg ) a |= ((sqlite3_uint64)1)<<63; - memcpy(&r, &a, sizeof(r)); - sqlite3_result_double(context, r); - } -} - -/* -** Functions to convert between blobs and floats. -*/ -static void ieee754func_from_blob( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_BLOB - && sqlite3_value_bytes(argv[0])==sizeof(double) - ){ - double r; - const unsigned char *x = sqlite3_value_blob(argv[0]); - unsigned int i; - sqlite3_uint64 v = 0; - for(i=0; i >= 8; - } - sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); - } -} - -/* -** SQL Function: ieee754_inc(r,N) -** -** Move the floating point value r by N quantums and return the new -** values. -** -** Behind the scenes: this routine merely casts r into a 64-bit unsigned -** integer, adds N, then casts the value back into float. -** -** Example: To find the smallest positive number: -** -** SELECT ieee754_inc(0.0,+1); -*/ -static void ieee754inc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - double r; - sqlite3_int64 N; - sqlite3_uint64 m1, m2; - double r2; - UNUSED_PARAMETER(argc); - r = sqlite3_value_double(argv[0]); - N = sqlite3_value_int64(argv[1]); - memcpy(&m1, &r, 8); - m2 = m1 + N; - memcpy(&r2, &m2, 8); - sqlite3_result_double(context, r2); -} - - -#ifdef _WIN32 - -#endif -int sqlite3_ieee_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - static const struct { - char *zFName; - int nArg; - int iAux; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "ieee754", 1, 0, ieee754func }, - { "ieee754", 2, 0, ieee754func }, - { "ieee754_mantissa", 1, 1, ieee754func }, - { "ieee754_exponent", 1, 2, ieee754func }, - { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, - { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, - { "ieee754_inc", 2, 0, ieee754inc }, - }; - unsigned int i; - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - for(i=0; i = 0 ) -** for each produced value (independent of production time ordering.) -** -** All parameters must be either integer or convertable to integer. -** The start parameter is required. -** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff) -** The step parameter defaults to 1 and 0 is treated as 1. -** -** Examples: -** -** SELECT * FROM generate_series(0,100,5); -** -** The query above returns integers from 0 through 100 counting by steps -** of 5. -** -** SELECT * FROM generate_series(0,100); -** -** Integers from 0 through 100 with a step size of 1. -** -** SELECT * FROM generate_series(20) LIMIT 10; -** -** Integers 20 through 29. -** -** SELECT * FROM generate_series(0,-100,-5); -** -** Integers 0 -5 -10 ... -100. -** -** SELECT * FROM generate_series(0,-1); -** -** Empty sequence. -** -** HOW IT WORKS -** -** The generate_series "function" is really a virtual table with the -** following schema: -** -** CREATE TABLE generate_series( -** value, -** start HIDDEN, -** stop HIDDEN, -** step HIDDEN -** ); -** -** The virtual table also has a rowid, logically equivalent to n+1 where -** "n" is the ascending integer in the aforesaid production definition. -** -** Function arguments in queries against this virtual table are translated -** into equality constraints against successive hidden columns. In other -** words, the following pairs of queries are equivalent to each other: -** -** SELECT * FROM generate_series(0,100,5); -** SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5; -** -** SELECT * FROM generate_series(0,100); -** SELECT * FROM generate_series WHERE start=0 AND stop=100; -** -** SELECT * FROM generate_series(20) LIMIT 10; -** SELECT * FROM generate_series WHERE start=20 LIMIT 10; -** -** The generate_series virtual table implementation leaves the xCreate method -** set to NULL. This means that it is not possible to do a CREATE VIRTUAL -** TABLE command with "generate_series" as the USING argument. Instead, there -** is a single generate_series virtual table that is always available without -** having to be created first. -** -** The xBestIndex method looks for equality constraints against the hidden -** start, stop, and step columns, and if present, it uses those constraints -** to bound the sequence of generated values. If the equality constraints -** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step. -** xBestIndex returns a small cost when both start and stop are available, -** and a very large cost if either start or stop are unavailable. This -** encourages the query planner to order joins such that the bounds of the -** series are well-defined. -*/ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -#ifndef SQLITE_OMIT_VIRTUALTABLE -/* -** Return that member of a generate_series(...) sequence whose 0-based -** index is ix. The 0th member is given by smBase. The sequence members -** progress per ix increment by smStep. -*/ -static sqlite3_int64 genSeqMember( - sqlite3_int64 smBase, - sqlite3_int64 smStep, - sqlite3_uint64 ix -){ - static const sqlite3_uint64 mxI64 = - ((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff; - if( ix>=mxI64 ){ - /* Get ix into signed i64 range. */ - ix -= mxI64; - /* With 2's complement ALU, this next can be 1 step, but is split into - * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */ - smBase += (mxI64/2) * smStep; - smBase += (mxI64 - mxI64/2) * smStep; - } - /* Under UBSAN (or on 1's complement machines), must do this last term - * in steps to avoid the dreaded (and harmless) signed multiply overlow. */ - if( ix>=2 ){ - sqlite3_int64 ix2 = (sqlite3_int64)ix/2; - smBase += ix2*smStep; - ix -= ix2; - } - return smBase + ((sqlite3_int64)ix)*smStep; -} - -/* typedef unsigned char u8; */ - -typedef struct SequenceSpec { - sqlite3_int64 iBase; /* Starting value ("start") */ - sqlite3_int64 iTerm; /* Given terminal value ("stop") */ - sqlite3_int64 iStep; /* Increment ("step") */ - sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */ - sqlite3_uint64 uSeqIndexNow; /* Current index during generation */ - sqlite3_int64 iValueNow; /* Current value during generation */ - u8 isNotEOF; /* Sequence generation not exhausted */ - u8 isReversing; /* Sequence is being reverse generated */ -} SequenceSpec; - -/* -** Prepare a SequenceSpec for use in generating an integer series -** given initialized iBase, iTerm and iStep values. Sequence is -** initialized per given isReversing. Other members are computed. -*/ -static void setupSequence( SequenceSpec *pss ){ - int bSameSigns; - pss->uSeqIndexMax = 0; - pss->isNotEOF = 0; - bSameSigns = (pss->iBase < 0)==(pss->iTerm < 0); - if( pss->iTerm < pss->iBase ){ - sqlite3_uint64 nuspan = 0; - if( bSameSigns ){ - nuspan = (sqlite3_uint64)(pss->iBase - pss->iTerm); - }else{ - /* Under UBSAN (or on 1's complement machines), must do this in steps. - * In this clause, iBase>=0 and iTerm<0 . */ - nuspan = 1; - nuspan += pss->iBase; - nuspan += -(pss->iTerm+1); - } - if( pss->iStep<0 ){ - pss->isNotEOF = 1; - if( nuspan==ULONG_MAX ){ - pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1; - }else if( pss->iStep>LLONG_MIN ){ - pss->uSeqIndexMax = nuspan/-pss->iStep; - } - } - }else if( pss->iTerm > pss->iBase ){ - sqlite3_uint64 puspan = 0; - if( bSameSigns ){ - puspan = (sqlite3_uint64)(pss->iTerm - pss->iBase); - }else{ - /* Under UBSAN (or on 1's complement machines), must do this in steps. - * In this clause, iTerm>=0 and iBase<0 . */ - puspan = 1; - puspan += pss->iTerm; - puspan += -(pss->iBase+1); - } - if( pss->iStep>0 ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = puspan/pss->iStep; - } - }else if( pss->iTerm == pss->iBase ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = 0; - } - pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0; - pss->iValueNow = (pss->isReversing) - ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax) - : pss->iBase; -} - -/* -** Progress sequence generator to yield next value, if any. -** Leave its state to either yield next value or be at EOF. -** Return whether there is a next value, or 0 at EOF. -*/ -static int progressSequence( SequenceSpec *pss ){ - if( !pss->isNotEOF ) return 0; - if( pss->isReversing ){ - if( pss->uSeqIndexNow > 0 ){ - pss->uSeqIndexNow--; - pss->iValueNow -= pss->iStep; - }else{ - pss->isNotEOF = 0; - } - }else{ - if( pss->uSeqIndexNow < pss->uSeqIndexMax ){ - pss->uSeqIndexNow++; - pss->iValueNow += pss->iStep; - }else{ - pss->isNotEOF = 0; - } - } - return pss->isNotEOF; -} - -/* series_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 series_cursor series_cursor; -struct series_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - SequenceSpec ss; /* (this) Derived class data */ -}; - -/* -** The seriesConnect() method is invoked to create a new -** series_vtab that describes the generate_series virtual table. -** -** Think of this routine as the constructor for series_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the series_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against generate_series will look like. -*/ -static int seriesConnect( - sqlite3 *db, - void *pUnused, - int argcUnused, const char *const*argvUnused, - sqlite3_vtab **ppVtab, - char **pzErrUnused -){ - sqlite3_vtab *pNew; - int rc; - -/* Column numbers */ -#define SERIES_COLUMN_VALUE 0 -#define SERIES_COLUMN_START 1 -#define SERIES_COLUMN_STOP 2 -#define SERIES_COLUMN_STEP 3 - - (void)pUnused; - (void)argcUnused; - (void)argvUnused; - (void)pzErrUnused; - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); - if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - } - return rc; -} - -/* -** This method is the destructor for series_cursor objects. -*/ -static int seriesDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; -} - -/* -** Constructor for a new series_cursor object. -*/ -static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){ - series_cursor *pCur; - (void)pUnused; - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a series_cursor. -*/ -static int seriesClose(sqlite3_vtab_cursor *cur){ - sqlite3_free(cur); - return SQLITE_OK; -} - - -/* -** Advance a series_cursor to its next row of output. -*/ -static int seriesNext(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - progressSequence( & pCur->ss ); - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the series_cursor -** is currently pointing. -*/ -static int seriesColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - series_cursor *pCur = (series_cursor*)cur; - sqlite3_int64 x = 0; - switch( i ){ - case SERIES_COLUMN_START: x = pCur->ss.iBase; break; - case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break; - case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break; - default: x = pCur->ss.iValueNow; break; - } - sqlite3_result_int64(ctx, x); - return SQLITE_OK; -} - -#ifndef LARGEST_UINT64 -#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32)) -#endif - -/* -** Return the rowid for the current row, logically equivalent to n+1 where -** "n" is the ascending integer in the aforesaid production definition. -*/ -static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - series_cursor *pCur = (series_cursor*)cur; - sqlite3_uint64 n = pCur->ss.uSeqIndexNow; - *pRowid = (sqlite3_int64)((n ss.isNotEOF; -} - -/* True to cause run-time checking of the start=, stop=, and/or step= -** parameters. The only reason to do this is for testing the -** constraint checking logic for virtual tables in the SQLite core. -*/ -#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY -# define SQLITE_SERIES_CONSTRAINT_VERIFY 0 -#endif - -/* -** This method is called to "rewind" the series_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to seriesColumn() or seriesRowid() or -** seriesEof(). -** -** The query plan selected by seriesBestIndex is passed in the idxNum -** parameter. (idxStr is not used in this implementation.) idxNum -** is a bitmask showing which constraints are available: -** -** 0x01: start=VALUE -** 0x02: stop=VALUE -** 0x04: step=VALUE -** 0x08: descending order -** 0x10: ascending order -** 0x20: LIMIT VALUE -** 0x40: OFFSET VALUE -** -** This routine should initialize the cursor and position it so that it -** is pointing at the first row, or pointing off the end of the table -** (so that seriesEof() will return true) if the table is empty. -*/ -static int seriesFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStrUnused, - int argc, sqlite3_value **argv -){ - series_cursor *pCur = (series_cursor *)pVtabCursor; - int i = 0; - (void)idxStrUnused; - if( idxNum & 0x01 ){ - pCur->ss.iBase = sqlite3_value_int64(argv[i++]); - }else{ - pCur->ss.iBase = 0; - } - if( idxNum & 0x02 ){ - pCur->ss.iTerm = sqlite3_value_int64(argv[i++]); - }else{ - pCur->ss.iTerm = 0xffffffff; - } - if( idxNum & 0x04 ){ - pCur->ss.iStep = sqlite3_value_int64(argv[i++]); - if( pCur->ss.iStep==0 ){ - pCur->ss.iStep = 1; - }else if( pCur->ss.iStep<0 ){ - if( (idxNum & 0x10)==0 ) idxNum |= 0x08; - } - }else{ - pCur->ss.iStep = 1; - } - if( idxNum & 0x20 ){ - sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]); - sqlite3_int64 iTerm; - if( idxNum & 0x40 ){ - sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]); - if( iOffset>0 ){ - pCur->ss.iBase += pCur->ss.iStep*iOffset; - } - } - if( iLimit>=0 ){ - iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep; - if( pCur->ss.iStep<0 ){ - if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm; - }else{ - if( iTerm ss.iTerm ) pCur->ss.iTerm = iTerm; - } - } - } - for(i=0; i ss.iBase = 1; - pCur->ss.iTerm = 0; - pCur->ss.iStep = 1; - break; - } - } - if( idxNum & 0x08 ){ - pCur->ss.isReversing = pCur->ss.iStep > 0; - }else{ - pCur->ss.isReversing = pCur->ss.iStep < 0; - } - setupSequence( &pCur->ss ); - return SQLITE_OK; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the generate_series virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -** -** In this implementation idxNum is used to represent the -** query plan. idxStr is unused. -** -** The query plan is represented by bits in idxNum: -** -** 0x01 start = $value -- constraint exists -** 0x02 stop = $value -- constraint exists -** 0x04 step = $value -- constraint exists -** 0x08 output is in descending order -** 0x10 output is in ascending order -** 0x20 LIMIT $value -- constraint exists -** 0x40 OFFSET $value -- constraint exists -*/ -static int seriesBestIndex( - sqlite3_vtab *pVTab, - sqlite3_index_info *pIdxInfo -){ - int i, j; /* Loop over constraints */ - int idxNum = 0; /* The query plan bitmask */ -#ifndef ZERO_ARGUMENT_GENERATE_SERIES - int bStartSeen = 0; /* EQ constraint seen on the START column */ -#endif - int unusableMask = 0; /* Mask of unusable constraints */ - int nArg = 0; /* Number of arguments that seriesFilter() expects */ - int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */ - const struct sqlite3_index_constraint *pConstraint; - - /* This implementation assumes that the start, stop, and step columns - ** are the last three columns in the virtual table. */ - assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); - assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); - - aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1; - pConstraint = pIdxInfo->aConstraint; - for(i=0; i nConstraint; i++, pConstraint++){ - int iCol; /* 0 for start, 1 for stop, 2 for step */ - int iMask; /* bitmask for those column */ - int op = pConstraint->op; - if( op>=SQLITE_INDEX_CONSTRAINT_LIMIT - && op<=SQLITE_INDEX_CONSTRAINT_OFFSET - ){ - if( pConstraint->usable==0 ){ - /* do nothing */ - }else if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){ - aIdx[3] = i; - idxNum |= 0x20; - }else{ - assert( op==SQLITE_INDEX_CONSTRAINT_OFFSET ); - aIdx[4] = i; - idxNum |= 0x40; - } - continue; - } - if( pConstraint->iColumn iColumn - SERIES_COLUMN_START; - assert( iCol>=0 && iCol<=2 ); - iMask = 1 << iCol; -#ifndef ZERO_ARGUMENT_GENERATE_SERIES - if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){ - bStartSeen = 1; - } -#endif - if( pConstraint->usable==0 ){ - unusableMask |= iMask; - continue; - }else if( op==SQLITE_INDEX_CONSTRAINT_EQ ){ - idxNum |= iMask; - aIdx[iCol] = i; - } - } - if( aIdx[3]==0 ){ - /* Ignore OFFSET if LIMIT is omitted */ - idxNum &= ~0x60; - aIdx[4] = 0; - } - for(i=0; i<5; i++){ - if( (j = aIdx[i])>=0 ){ - pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[j].omit = - !SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3; - } - } - /* The current generate_column() implementation requires at least one - ** argument (the START value). Legacy versions assumed START=0 if the - ** first argument was omitted. Compile with -DZERO_ARGUMENT_GENERATE_SERIES - ** to obtain the legacy behavior */ -#ifndef ZERO_ARGUMENT_GENERATE_SERIES - if( !bStartSeen ){ - sqlite3_free(pVTab->zErrMsg); - pVTab->zErrMsg = sqlite3_mprintf( - "first argument to \"generate_series()\" missing or unusable"); - return SQLITE_ERROR; - } -#endif - if( (unusableMask & ~idxNum)!=0 ){ - /* The start, stop, and step columns are inputs. Therefore if there - ** are unusable constraints on any of start, stop, or step then - ** this plan is unusable */ - return SQLITE_CONSTRAINT; - } - if( (idxNum & 0x03)==0x03 ){ - /* Both start= and stop= boundaries are available. This is the - ** the preferred case */ - pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); - pIdxInfo->estimatedRows = 1000; - if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn==0 ){ - if( pIdxInfo->aOrderBy[0].desc ){ - idxNum |= 0x08; - }else{ - idxNum |= 0x10; - } - pIdxInfo->orderByConsumed = 1; - } - }else if( (idxNum & 0x21)==0x21 ){ - /* We have start= and LIMIT */ - pIdxInfo->estimatedRows = 2500; - }else{ - /* If either boundary is missing, we have to generate a huge span - ** of numbers. Make this case very expensive so that the query - ** planner will work hard to avoid it. */ - pIdxInfo->estimatedRows = 2147483647; - } - pIdxInfo->idxNum = idxNum; - return SQLITE_OK; -} - -/* -** This following structure defines all the methods for the -** generate_series virtual table. -*/ -static sqlite3_module seriesModule = { - 0, /* iVersion */ - 0, /* xCreate */ - seriesConnect, /* xConnect */ - seriesBestIndex, /* xBestIndex */ - seriesDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - seriesOpen, /* xOpen - open a cursor */ - seriesClose, /* xClose - close a cursor */ - seriesFilter, /* xFilter - configure scan constraints */ - seriesNext, /* xNext - advance a cursor */ - seriesEof, /* xEof - check for end of scan */ - seriesColumn, /* xColumn - read data */ - seriesRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ -}; - -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - -#ifdef _WIN32 - -#endif -int sqlite3_series_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){ - *pzErrMsg = sqlite3_mprintf( - "generate_series() requires SQLite 3.8.12 or later"); - return SQLITE_ERROR; - } - rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0); -#endif - return rc; -} - -/************************* End ../ext/misc/series.c ********************/ -/************************* Begin ../ext/misc/regexp.c ******************/ -/* -** 2012-11-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. -** -****************************************************************************** -** -** The code in this file implements a compact but reasonably -** efficient regular-expression matcher for posix extended regular -** expressions against UTF8 text. -** -** This file is an SQLite extension. It registers a single function -** named "regexp(A,B)" where A is the regular expression and B is the -** string to be matched. By registering this function, SQLite will also -** then implement the "B regexp A" operator. Note that with the function -** the regular expression comes first, but with the operator it comes -** second. -** -** The following regular expression syntax is supported: -** -** X* zero or more occurrences of X -** X+ one or more occurrences of X -** X? zero or one occurrences of X -** X{p,q} between p and q occurrences of X -** (X) match X -** X|Y X or Y -** ^X X occurring at the beginning of the string -** X$ X occurring at the end of the string -** . Match any single character -** \c Character c where c is one of \{}()[]|*+?. -** \c C-language escapes for c in afnrtv. ex: \t or \n -** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX -** \xXX Where XX is exactly 2 hex digits, unicode value XX -** [abc] Any single character from the set abc -** [^abc] Any single character not in the set abc -** [a-z] Any single character in the range a-z -** [^a-z] Any single character not in the range a-z -** \b Word boundary -** \w Word character. [A-Za-z0-9_] -** \W Non-word character -** \d Digit -** \D Non-digit -** \s Whitespace character -** \S Non-whitespace character -** -** A nondeterministic finite automaton (NFA) is used for matching, so the -** performance is bounded by O(N*M) where N is the size of the regular -** expression and M is the size of the input string. The matcher never -** exhibits exponential behavior. Note that the X{p,q} operator expands -** to p copies of X following by q-p copies of X? and that the size of the -** regular expression in the O(N*M) performance bound is computed after -** this expansion. -*/ -#include -#include -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 - -/* -** The following #defines change the names of some functions implemented in -** this file to prevent name collisions with C-library functions of the -** same name. -*/ -#define re_match sqlite3re_match -#define re_compile sqlite3re_compile -#define re_free sqlite3re_free - -/* The end-of-input character */ -#define RE_EOF 0 /* End of input */ -#define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */ - -/* The NFA is implemented as sequence of opcodes taken from the following -** set. Each opcode has a single integer argument. -*/ -#define RE_OP_MATCH 1 /* Match the one character in the argument */ -#define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ -#define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ -#define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */ -#define RE_OP_GOTO 5 /* Jump to opcode at iArg */ -#define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */ -#define RE_OP_CC_INC 7 /* Beginning of a [...] character class */ -#define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */ -#define RE_OP_CC_VALUE 9 /* Single value in a character class */ -#define RE_OP_CC_RANGE 10 /* Range of values in a character class */ -#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ -#define RE_OP_NOTWORD 12 /* Not a perl word character */ -#define RE_OP_DIGIT 13 /* digit: [0-9] */ -#define RE_OP_NOTDIGIT 14 /* Not a digit */ -#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ -#define RE_OP_NOTSPACE 16 /* Not a digit */ -#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ -#define RE_OP_ATSTART 18 /* Currently at the start of the string */ - -#if defined(SQLITE_DEBUG) -/* Opcode names used for symbolic debugging */ -static const char *ReOpName[] = { - "EOF", - "MATCH", - "ANY", - "ANYSTAR", - "FORK", - "GOTO", - "ACCEPT", - "CC_INC", - "CC_EXC", - "CC_VALUE", - "CC_RANGE", - "WORD", - "NOTWORD", - "DIGIT", - "NOTDIGIT", - "SPACE", - "NOTSPACE", - "BOUNDARY", - "ATSTART", -}; -#endif /* SQLITE_DEBUG */ - - -/* Each opcode is a "state" in the NFA */ -typedef unsigned short ReStateNumber; - -/* Because this is an NFA and not a DFA, multiple states can be active at -** once. An instance of the following object records all active states in -** the NFA. The implementation is optimized for the common case where the -** number of actives states is small. -*/ -typedef struct ReStateSet { - unsigned nState; /* Number of current states */ - ReStateNumber *aState; /* Current states */ -} ReStateSet; - -/* An input string read one character at a time. -*/ -typedef struct ReInput ReInput; -struct ReInput { - const unsigned char *z; /* All text */ - int i; /* Next byte to read */ - int mx; /* EOF when i>=mx */ -}; - -/* A compiled NFA (or an NFA that is in the process of being compiled) is -** an instance of the following object. -*/ -typedef struct ReCompiled ReCompiled; -struct ReCompiled { - ReInput sIn; /* Regular expression text */ - const char *zErr; /* Error message to return */ - char *aOp; /* Operators for the virtual machine */ - int *aArg; /* Arguments to each operator */ - unsigned (*xNextChar)(ReInput*); /* Next character function */ - unsigned char zInit[12]; /* Initial text to match */ - int nInit; /* Number of bytes in zInit */ - unsigned nState; /* Number of entries in aOp[] and aArg[] */ - unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ -}; - -/* Add a state to the given state set if it is not already there */ -static void re_add_state(ReStateSet *pSet, int newState){ - unsigned i; - for(i=0; i nState; i++) if( pSet->aState[i]==newState ) return; - pSet->aState[pSet->nState++] = (ReStateNumber)newState; -} - -/* Extract the next unicode character from *pzIn and return it. Advance -** *pzIn to the first byte past the end of the character returned. To -** be clear: this routine converts utf8 to unicode. This routine is -** optimized for the common case where the next character is a single byte. -*/ -static unsigned re_next_char(ReInput *p){ - unsigned c; - if( p->i>=p->mx ) return 0; - c = p->z[p->i++]; - if( c>=0x80 ){ - if( (c&0xe0)==0xc0 && p->i mx && (p->z[p->i]&0xc0)==0x80 ){ - c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); - if( c<0x80 ) c = 0xfffd; - }else if( (c&0xf0)==0xe0 && p->i+1 mx && (p->z[p->i]&0xc0)==0x80 - && (p->z[p->i+1]&0xc0)==0x80 ){ - c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); - p->i += 2; - if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; - }else if( (c&0xf8)==0xf0 && p->i+2 mx && (p->z[p->i]&0xc0)==0x80 - && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ - c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) - | (p->z[p->i+2]&0x3f); - p->i += 3; - if( c<=0xffff || c>0x10ffff ) c = 0xfffd; - }else{ - c = 0xfffd; - } - } - return c; -} -static unsigned re_next_char_nocase(ReInput *p){ - unsigned c = re_next_char(p); - if( c>='A' && c<='Z' ) c += 'a' - 'A'; - return c; -} - -/* Return true if c is a perl "word" character: [A-Za-z0-9_] */ -static int re_word_char(int c){ - return (c>='0' && c<='9') || (c>='a' && c<='z') - || (c>='A' && c<='Z') || c=='_'; -} - -/* Return true if c is a "digit" character: [0-9] */ -static int re_digit_char(int c){ - return (c>='0' && c<='9'); -} - -/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */ -static int re_space_char(int c){ - return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; -} - -/* Run a compiled regular expression on the zero-terminated input -** string zIn[]. Return true on a match and false if there is no match. -*/ -static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ - ReStateSet aStateSet[2], *pThis, *pNext; - ReStateNumber aSpace[100]; - ReStateNumber *pToFree; - unsigned int i = 0; - unsigned int iSwap = 0; - int c = RE_START; - int cPrev = 0; - int rc = 0; - ReInput in; - - in.z = zIn; - in.i = 0; - in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); - - /* Look for the initial prefix match, if there is one. */ - if( pRe->nInit ){ - unsigned char x = pRe->zInit[0]; - while( in.i+pRe->nInit<=in.mx - && (zIn[in.i]!=x || - strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) - ){ - in.i++; - } - if( in.i+pRe->nInit>in.mx ) return 0; - c = RE_START-1; - } - - if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ - pToFree = 0; - aStateSet[0].aState = aSpace; - }else{ - pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState ); - if( pToFree==0 ) return -1; - aStateSet[0].aState = pToFree; - } - aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; - pNext = &aStateSet[1]; - pNext->nState = 0; - re_add_state(pNext, 0); - while( c!=RE_EOF && pNext->nState>0 ){ - cPrev = c; - c = pRe->xNextChar(&in); - pThis = pNext; - pNext = &aStateSet[iSwap]; - iSwap = 1 - iSwap; - pNext->nState = 0; - for(i=0; i nState; i++){ - int x = pThis->aState[i]; - switch( pRe->aOp[x] ){ - case RE_OP_MATCH: { - if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); - break; - } - case RE_OP_ATSTART: { - if( cPrev==RE_START ) re_add_state(pThis, x+1); - break; - } - case RE_OP_ANY: { - if( c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_WORD: { - if( re_word_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTWORD: { - if( !re_word_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_DIGIT: { - if( re_digit_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTDIGIT: { - if( !re_digit_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_SPACE: { - if( re_space_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTSPACE: { - if( !re_space_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_BOUNDARY: { - if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); - break; - } - case RE_OP_ANYSTAR: { - re_add_state(pNext, x); - re_add_state(pThis, x+1); - break; - } - case RE_OP_FORK: { - re_add_state(pThis, x+pRe->aArg[x]); - re_add_state(pThis, x+1); - break; - } - case RE_OP_GOTO: { - re_add_state(pThis, x+pRe->aArg[x]); - break; - } - case RE_OP_ACCEPT: { - rc = 1; - goto re_match_end; - } - case RE_OP_CC_EXC: { - if( c==0 ) break; - /* fall-through */ goto re_op_cc_inc; - } - case RE_OP_CC_INC: re_op_cc_inc: { - int j = 1; - int n = pRe->aArg[x]; - int hit = 0; - for(j=1; j>0 && j aOp[x+j]==RE_OP_CC_VALUE ){ - if( pRe->aArg[x+j]==c ){ - hit = 1; - j = -1; - } - }else{ - if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ - hit = 1; - j = -1; - }else{ - j++; - } - } - } - if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; - if( hit ) re_add_state(pNext, x+n); - break; - } - } - } - } - for(i=0; i nState; i++){ - int x = pNext->aState[i]; - while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x]; - if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; } - } -re_match_end: - sqlite3_free(pToFree); - return rc; -} - -/* Resize the opcode and argument arrays for an RE under construction. -*/ -static int re_resize(ReCompiled *p, int N){ - char *aOp; - int *aArg; - aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0])); - if( aOp==0 ) return 1; - p->aOp = aOp; - aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0])); - if( aArg==0 ) return 1; - p->aArg = aArg; - p->nAlloc = N; - return 0; -} - -/* Insert a new opcode and argument into an RE under construction. The -** insertion point is just prior to existing opcode iBefore. -*/ -static int re_insert(ReCompiled *p, int iBefore, int op, int arg){ - int i; - if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; - for(i=p->nState; i>iBefore; i--){ - p->aOp[i] = p->aOp[i-1]; - p->aArg[i] = p->aArg[i-1]; - } - p->nState++; - p->aOp[iBefore] = (char)op; - p->aArg[iBefore] = arg; - return iBefore; -} - -/* Append a new opcode and argument to the end of the RE under construction. -*/ -static int re_append(ReCompiled *p, int op, int arg){ - return re_insert(p, p->nState, op, arg); -} - -/* Make a copy of N opcodes starting at iStart onto the end of the RE -** under construction. -*/ -static void re_copy(ReCompiled *p, int iStart, int N){ - if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return; - memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); - memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); - p->nState += N; -} - -/* Return true if c is a hexadecimal digit character: [0-9a-fA-F] -** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If -** c is not a hex digit *pV is unchanged. -*/ -static int re_hex(int c, int *pV){ - if( c>='0' && c<='9' ){ - c -= '0'; - }else if( c>='a' && c<='f' ){ - c -= 'a' - 10; - }else if( c>='A' && c<='F' ){ - c -= 'A' - 10; - }else{ - return 0; - } - *pV = (*pV)*16 + (c & 0xff); - return 1; -} - -/* A backslash character has been seen, read the next character and -** return its interpretation. -*/ -static unsigned re_esc_char(ReCompiled *p){ - static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; - static const char zTrans[] = "\a\f\n\r\t\v"; - int i, v = 0; - char c; - if( p->sIn.i>=p->sIn.mx ) return 0; - c = p->sIn.z[p->sIn.i]; - if( c=='u' && p->sIn.i+4 sIn.mx ){ - const unsigned char *zIn = p->sIn.z + p->sIn.i; - if( re_hex(zIn[1],&v) - && re_hex(zIn[2],&v) - && re_hex(zIn[3],&v) - && re_hex(zIn[4],&v) - ){ - p->sIn.i += 5; - return v; - } - } - if( c=='x' && p->sIn.i+2 sIn.mx ){ - const unsigned char *zIn = p->sIn.z + p->sIn.i; - if( re_hex(zIn[1],&v) - && re_hex(zIn[2],&v) - ){ - p->sIn.i += 3; - return v; - } - } - for(i=0; zEsc[i] && zEsc[i]!=c; i++){} - if( zEsc[i] ){ - if( i<6 ) c = zTrans[i]; - p->sIn.i++; - }else{ - p->zErr = "unknown \\ escape"; - } - return c; -} - -/* Forward declaration */ -static const char *re_subcompile_string(ReCompiled*); - -/* Peek at the next byte of input */ -static unsigned char rePeek(ReCompiled *p){ - return p->sIn.i sIn.mx ? p->sIn.z[p->sIn.i] : 0; -} - -/* Compile RE text into a sequence of opcodes. Continue up to the -** first unmatched ")" character, then return. If an error is found, -** return a pointer to the error message string. -*/ -static const char *re_subcompile_re(ReCompiled *p){ - const char *zErr; - int iStart, iEnd, iGoto; - iStart = p->nState; - zErr = re_subcompile_string(p); - if( zErr ) return zErr; - while( rePeek(p)=='|' ){ - iEnd = p->nState; - re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); - iGoto = re_append(p, RE_OP_GOTO, 0); - p->sIn.i++; - zErr = re_subcompile_string(p); - if( zErr ) return zErr; - p->aArg[iGoto] = p->nState - iGoto; - } - return 0; -} - -/* Compile an element of regular expression text (anything that can be -** an operand to the "|" operator). Return NULL on success or a pointer -** to the error message if there is a problem. -*/ -static const char *re_subcompile_string(ReCompiled *p){ - int iPrev = -1; - int iStart; - unsigned c; - const char *zErr; - while( (c = p->xNextChar(&p->sIn))!=0 ){ - iStart = p->nState; - switch( c ){ - case '|': - case ')': { - p->sIn.i--; - return 0; - } - case '(': { - zErr = re_subcompile_re(p); - if( zErr ) return zErr; - if( rePeek(p)!=')' ) return "unmatched '('"; - p->sIn.i++; - break; - } - case '.': { - if( rePeek(p)=='*' ){ - re_append(p, RE_OP_ANYSTAR, 0); - p->sIn.i++; - }else{ - re_append(p, RE_OP_ANY, 0); - } - break; - } - case '*': { - if( iPrev<0 ) return "'*' without operand"; - re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); - re_append(p, RE_OP_FORK, iPrev - p->nState + 1); - break; - } - case '+': { - if( iPrev<0 ) return "'+' without operand"; - re_append(p, RE_OP_FORK, iPrev - p->nState); - break; - } - case '?': { - if( iPrev<0 ) return "'?' without operand"; - re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); - break; - } - case '$': { - re_append(p, RE_OP_MATCH, RE_EOF); - break; - } - case '^': { - re_append(p, RE_OP_ATSTART, 0); - break; - } - case '{': { - int m = 0, n = 0; - int sz, j; - if( iPrev<0 ) return "'{m,n}' without operand"; - while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } - n = m; - if( c==',' ){ - p->sIn.i++; - n = 0; - while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } - } - if( c!='}' ) return "unmatched '{'"; - if( n>0 && n sIn.i++; - sz = p->nState - iPrev; - if( m==0 ){ - if( n==0 ) return "both m and n are zero in '{m,n}'"; - re_insert(p, iPrev, RE_OP_FORK, sz+1); - iPrev++; - n--; - }else{ - for(j=1; j 0 ){ - re_append(p, RE_OP_FORK, -sz); - } - break; + memcpy(&a,&r,sizeof(a)); + if( a==0 ){ + e = 0; + m = 0; + }else{ + e = a>>52; + m = a & ((((sqlite3_int64)1)<<52)-1); + if( e==0 ){ + m <<= 1; + }else{ + m |= ((sqlite3_int64)1)<<52; } - case '[': { - unsigned int iFirst = p->nState; - if( rePeek(p)=='^' ){ - re_append(p, RE_OP_CC_EXC, 0); - p->sIn.i++; - }else{ - re_append(p, RE_OP_CC_INC, 0); - } - while( (c = p->xNextChar(&p->sIn))!=0 ){ - if( c=='[' && rePeek(p)==':' ){ - return "POSIX character classes not supported"; - } - if( c=='\\' ) c = re_esc_char(p); - if( rePeek(p)=='-' ){ - re_append(p, RE_OP_CC_RANGE, c); - p->sIn.i++; - c = p->xNextChar(&p->sIn); - if( c=='\\' ) c = re_esc_char(p); - re_append(p, RE_OP_CC_RANGE, c); - }else{ - re_append(p, RE_OP_CC_VALUE, c); - } - if( rePeek(p)==']' ){ p->sIn.i++; break; } - } - if( c==0 ) return "unclosed '['"; - if( p->nState>iFirst ) p->aArg[iFirst] = p->nState - iFirst; - break; + while( e<1075 && m>0 && (m&1)==0 ){ + m >>= 1; + e++; } - case '\\': { - int specialOp = 0; - switch( rePeek(p) ){ - case 'b': specialOp = RE_OP_BOUNDARY; break; - case 'd': specialOp = RE_OP_DIGIT; break; - case 'D': specialOp = RE_OP_NOTDIGIT; break; - case 's': specialOp = RE_OP_SPACE; break; - case 'S': specialOp = RE_OP_NOTSPACE; break; - case 'w': specialOp = RE_OP_WORD; break; - case 'W': specialOp = RE_OP_NOTWORD; break; - } - if( specialOp ){ - p->sIn.i++; - re_append(p, specialOp, 0); - }else{ - c = re_esc_char(p); - re_append(p, RE_OP_MATCH, c); - } + if( isNeg ) m = -m; + } + switch( *(int*)sqlite3_user_data(context) ){ + case 0: + sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", + m, e-1075); + sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); break; - } - default: { - re_append(p, RE_OP_MATCH, c); + case 1: + sqlite3_result_int64(context, m); + break; + case 2: + sqlite3_result_int(context, e-1075); break; + } + }else{ + sqlite3_int64 m, e, a; + double r; + int isNeg = 0; + m = sqlite3_value_int64(argv[0]); + e = sqlite3_value_int64(argv[1]); + + /* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */ + if( e>10000 ){ + e = 10000; + }else if( e<-10000 ){ + e = -10000; + } + + if( m<0 ){ + isNeg = 1; + m = -m; + if( m<0 ) return; + }else if( m==0 && e>-1000 && e<1000 ){ + sqlite3_result_double(context, 0.0); + return; + } + while( (m>>32)&0xffe00000 ){ + m >>= 1; + e++; + } + while( m!=0 && ((m>>32)&0xfff00000)==0 ){ + m <<= 1; + e--; + } + e += 1075; + if( e<=0 ){ + /* Subnormal */ + if( 1-e >= 64 ){ + m = 0; + }else{ + m >>= 1-e; } + e = 0; + }else if( e>0x7ff ){ + e = 0x7ff; } - iPrev = iStart; + a = m & ((((sqlite3_int64)1)<<52)-1); + a |= e<<52; + if( isNeg ) a |= ((sqlite3_uint64)1)<<63; + memcpy(&r, &a, sizeof(r)); + sqlite3_result_double(context, r); } - return 0; } -/* Free and reclaim all the memory used by a previously compiled -** regular expression. Applications should invoke this routine once -** for every call to re_compile() to avoid memory leaks. +/* +** Functions to convert between blobs and floats. +*/ +static void ieee754func_from_blob( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_BLOB + && sqlite3_value_bytes(argv[0])==sizeof(double) + ){ + double r; + const unsigned char *x = sqlite3_value_blob(argv[0]); + unsigned int i; + sqlite3_uint64 v = 0; + for(i=0; i >= 8; + } + sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); + } +} + + +#ifdef _WIN32 + +#endif +int sqlite3_ieee_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + static const struct { + char *zFName; + int nArg; + int iAux; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "ieee754", 1, 0, ieee754func }, + { "ieee754", 2, 0, ieee754func }, + { "ieee754_mantissa", 1, 1, ieee754func }, + { "ieee754_exponent", 1, 2, ieee754func }, + { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, + { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, + + }; + unsigned int i; + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + for(i=0; i +#include + +#ifndef SQLITE_OMIT_VIRTUALTABLE + + +/* series_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 */ -static void re_free(ReCompiled *pRe){ - if( pRe ){ - sqlite3_free(pRe->aOp); - sqlite3_free(pRe->aArg); - sqlite3_free(pRe); - } -} +typedef struct series_cursor series_cursor; +struct series_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + int isDesc; /* True to count down rather than up */ + sqlite3_int64 iRowid; /* The rowid */ + sqlite3_int64 iValue; /* Current value ("value") */ + sqlite3_int64 mnValue; /* Mimimum value ("start") */ + sqlite3_int64 mxValue; /* Maximum value ("stop") */ + sqlite3_int64 iStep; /* Increment ("step") */ +}; /* -** Compile a textual regular expression in zIn[] into a compiled regular -** expression suitable for us by re_match() and return a pointer to the -** compiled regular expression in *ppRe. Return NULL on success or an -** error message if something goes wrong. +** The seriesConnect() method is invoked to create a new +** series_vtab that describes the generate_series virtual table. +** +** Think of this routine as the constructor for series_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the series_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against generate_series will look like. */ -static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ - ReCompiled *pRe; - const char *zErr; - int i, j; +static int seriesConnect( + sqlite3 *db, + void *pUnused, + int argcUnused, const char *const*argvUnused, + sqlite3_vtab **ppVtab, + char **pzErrUnused +){ + sqlite3_vtab *pNew; + int rc; - *ppRe = 0; - pRe = sqlite3_malloc( sizeof(*pRe) ); - if( pRe==0 ){ - return "out of memory"; - } - memset(pRe, 0, sizeof(*pRe)); - pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char; - if( re_resize(pRe, 30) ){ - re_free(pRe); - return "out of memory"; - } - if( zIn[0]=='^' ){ - zIn++; - }else{ - re_append(pRe, RE_OP_ANYSTAR, 0); - } - pRe->sIn.z = (unsigned char*)zIn; - pRe->sIn.i = 0; - pRe->sIn.mx = (int)strlen(zIn); - zErr = re_subcompile_re(pRe); - if( zErr ){ - re_free(pRe); - return zErr; - } - if( pRe->sIn.i>=pRe->sIn.mx ){ - re_append(pRe, RE_OP_ACCEPT, 0); - *ppRe = pRe; - }else{ - re_free(pRe); - return "unrecognized character"; - } +/* Column numbers */ +#define SERIES_COLUMN_VALUE 0 +#define SERIES_COLUMN_START 1 +#define SERIES_COLUMN_STOP 2 +#define SERIES_COLUMN_STEP 3 - /* The following is a performance optimization. If the regex begins with - ** ".*" (if the input regex lacks an initial "^") and afterwards there are - ** one or more matching characters, enter those matching characters into - ** zInit[]. The re_match() routine can then search ahead in the input - ** string looking for the initial match without having to run the whole - ** regex engine over the string. Do not worry about trying to match - ** unicode characters beyond plane 0 - those are very rare and this is - ** just an optimization. */ - if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ - for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ - unsigned x = pRe->aArg[i]; - if( x<=0x7f ){ - pRe->zInit[j++] = (unsigned char)x; - }else if( x<=0x7ff ){ - pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); - pRe->zInit[j++] = 0x80 | (x&0x3f); - }else if( x<=0xffff ){ - pRe->zInit[j++] = (unsigned char)(0xe0 | (x>>12)); - pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); - pRe->zInit[j++] = 0x80 | (x&0x3f); - }else{ - break; - } - } - if( j>0 && pRe->zInit[j-1]==0 ) j--; - pRe->nInit = j; + (void)pUnused; + (void)argcUnused; + (void)argvUnused; + (void)pzErrUnused; + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } - return pRe->zErr; + return rc; } /* -** Implementation of the regexp() SQL function. This function implements -** the build-in REGEXP operator. The first argument to the function is the -** pattern and the second argument is the string. So, the SQL statements: -** -** A REGEXP B -** -** is implemented as regexp(B,A). +** This method is the destructor for series_cursor objects. */ -static void re_sql_func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - ReCompiled *pRe; /* Compiled regular expression */ - const char *zPattern; /* The regular expression */ - const unsigned char *zStr;/* String being searched */ - const char *zErr; /* Compile error message */ - int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ +static int seriesDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} - (void)argc; /* Unused */ - pRe = sqlite3_get_auxdata(context, 0); - if( pRe==0 ){ - zPattern = (const char*)sqlite3_value_text(argv[0]); - if( zPattern==0 ) return; - zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); - if( zErr ){ - re_free(pRe); - sqlite3_result_error(context, zErr, -1); - return; - } - if( pRe==0 ){ - sqlite3_result_error_nomem(context); - return; - } - setAux = 1; - } - zStr = (const unsigned char*)sqlite3_value_text(argv[1]); - if( zStr!=0 ){ - sqlite3_result_int(context, re_match(pRe, zStr, -1)); - } - if( setAux ){ - sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); - } +/* +** Constructor for a new series_cursor object. +*/ +static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){ + series_cursor *pCur; + (void)pUnused; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; } -#if defined(SQLITE_DEBUG) /* -** This function is used for testing and debugging only. It is only available -** if the SQLITE_DEBUG compile-time option is used. -** -** Compile a regular expression and then convert the compiled expression into -** text and return that text. +** Destructor for a series_cursor. */ -static void re_bytecode_func( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zPattern; - const char *zErr; - ReCompiled *pRe; - sqlite3_str *pStr; - int i; - int n; - char *z; - (void)argc; +static int seriesClose(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur); + return SQLITE_OK; +} - zPattern = (const char*)sqlite3_value_text(argv[0]); - if( zPattern==0 ) return; - zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); - if( zErr ){ - re_free(pRe); - sqlite3_result_error(context, zErr, -1); - return; - } - if( pRe==0 ){ - sqlite3_result_error_nomem(context); - return; - } - pStr = sqlite3_str_new(0); - if( pStr==0 ) goto re_bytecode_func_err; - if( pRe->nInit>0 ){ - sqlite3_str_appendf(pStr, "INIT "); - for(i=0; i nInit; i++){ - sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); - } - sqlite3_str_appendf(pStr, "\n"); - } - for(i=0; (unsigned)i nState; i++){ - sqlite3_str_appendf(pStr, "%-8s %4d\n", - ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); - } - n = sqlite3_str_length(pStr); - z = sqlite3_str_finish(pStr); - if( n==0 ){ - sqlite3_free(z); + +/* +** Advance a series_cursor to its next row of output. +*/ +static int seriesNext(sqlite3_vtab_cursor *cur){ + series_cursor *pCur = (series_cursor*)cur; + if( pCur->isDesc ){ + pCur->iValue -= pCur->iStep; }else{ - sqlite3_result_text(context, z, n-1, sqlite3_free); + pCur->iValue += pCur->iStep; } - -re_bytecode_func_err: - re_free(pRe); + pCur->iRowid++; + return SQLITE_OK; } -#endif /* SQLITE_DEBUG */ - - /* -** Invoke this routine to register the regexp() function with the -** SQLite database connection. +** Return values of columns for the row at which the series_cursor +** is currently pointing. */ -#ifdef _WIN32 - -#endif -int sqlite3_regexp_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi +static int seriesColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused */ - rc = sqlite3_create_function(db, "regexp", 2, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - 0, re_sql_func, 0, 0); - if( rc==SQLITE_OK ){ - /* The regexpi(PATTERN,STRING) function is a case-insensitive version - ** of regexp(PATTERN,STRING). */ - rc = sqlite3_create_function(db, "regexpi", 2, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - (void*)db, re_sql_func, 0, 0); -#if defined(SQLITE_DEBUG) - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "regexp_bytecode", 1, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - 0, re_bytecode_func, 0, 0); - } -#endif /* SQLITE_DEBUG */ + series_cursor *pCur = (series_cursor*)cur; + sqlite3_int64 x = 0; + switch( i ){ + case SERIES_COLUMN_START: x = pCur->mnValue; break; + case SERIES_COLUMN_STOP: x = pCur->mxValue; break; + case SERIES_COLUMN_STEP: x = pCur->iStep; break; + default: x = pCur->iValue; break; } - return rc; + sqlite3_result_int64(ctx, x); + return SQLITE_OK; } -/************************* End ../ext/misc/regexp.c ********************/ -#ifndef SQLITE_SHELL_FIDDLE -/************************* Begin ../ext/misc/fileio.c ******************/ /* -** 2014-06-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. -** -****************************************************************************** -** -** This SQLite extension implements SQL functions readfile() and -** writefile(), and eponymous virtual type "fsdir". -** -** WRITEFILE(FILE, DATA [, MODE [, MTIME]]): -** -** If neither of the optional arguments is present, then this UDF -** function writes blob DATA to file FILE. If successful, the number -** of bytes written is returned. If an error occurs, NULL is returned. -** -** If the first option argument - MODE - is present, then it must -** be passed an integer value that corresponds to a POSIX mode -** value (file type + permissions, as returned in the stat.st_mode -** field by the stat() system call). Three types of files may -** be written/created: -** -** regular files: (mode & 0170000)==0100000 -** symbolic links: (mode & 0170000)==0120000 -** directories: (mode & 0170000)==0040000 -** -** For a directory, the DATA is ignored. For a symbolic link, it is -** interpreted as text and used as the target of the link. For a -** regular file, it is interpreted as a blob and written into the -** named file. Regardless of the type of file, its permissions are -** set to (mode & 0777) before returning. -** -** If the optional MTIME argument is present, then it is interpreted -** as an integer - the number of seconds since the unix epoch. The -** modification-time of the target file is set to this value before -** returning. -** -** If three or more arguments are passed to this function and an -** error is encountered, an exception is raised. -** -** READFILE(FILE): -** -** Read and return the contents of file FILE (type blob) from disk. -** -** FSDIR: -** -** Used as follows: -** -** SELECT * FROM fsdir($path [, $dir]); -** -** Parameter $path is an absolute or relative pathname. If the file that it -** refers to does not exist, it is an error. If the path refers to a regular -** file or symbolic link, it returns a single row. Or, if the path refers -** to a directory, it returns one row for the directory, and one row for each -** file within the hierarchy rooted at $path. -** -** Each row has the following columns: -** -** name: Path to file or directory (text value). -** mode: Value of stat.st_mode for directory entry (an integer). -** mtime: Value of stat.st_mtime for directory entry (an integer). -** data: For a regular file, a blob containing the file data. For a -** symlink, a text value containing the text of the link. For a -** directory, NULL. -** -** If a non-NULL value is specified for the optional $dir parameter and -** $path is a relative path, then $path is interpreted relative to $dir. -** And the paths returned in the "name" column of the table are also -** relative to directory $dir. -** -** Notes on building this extension for Windows: -** Unless linked statically with the SQLite library, a preprocessor -** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone -** DLL form of this extension for WIN32. See its use below for details. +** Return the rowid for the current row. In this implementation, the +** first row returned is assigned rowid value 1, and each subsequent +** row a value 1 more than that of the previous. */ -/* #include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -#include -#include -#include -#if !defined(_WIN32) && !defined(WIN32) -# include -# include -# include -# include -#else -# include "windows.h" -# include -# include -/* # include "test_windirent.h" */ -# define dirent DIRENT -# ifndef chmod -# define chmod _chmod -# endif -# ifndef stat -# define stat _stat -# endif -# define mkdir(path,mode) _mkdir(path) -# define lstat(path,buf) stat(path,buf) -#endif -#include -#include