DELETED .fossil-settings/crnl-glob Index: .fossil-settings/crnl-glob ================================================================== --- .fossil-settings/crnl-glob +++ /dev/null @@ -1,1 +0,0 @@ -* DELETED .fossil-settings/ignore-glob Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ /dev/null @@ -1,7 +0,0 @@ -*.mistachkin.eagle -*.sln -Externals/Eagle/bin/Eagle*.pdb -SQLite.Interop/*.vcxproj -SQLite.Interop/*.vcxproj.filters -System.Data.SQLite/*.csproj -testce/*.csproj Index: Doc/Extra/dbfactorysupport.html ================================================================== --- Doc/Extra/dbfactorysupport.html +++ Doc/Extra/dbfactorysupport.html @@ -83,11 +83,11 @@ <DbProviderFactories> <remove invariant="System.Data.SQLite"/> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, - Version=1.0.86.0, Culture=neutral, + Version=1.0.83.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"/> </DbProviderFactories> </system.data> </configuration> Index: Doc/Extra/environment.html ================================================================== --- Doc/Extra/environment.html +++ Doc/Extra/environment.html @@ -72,43 +72,23 @@ the native library pre-loading will attempt to load the native SQLite library from architecture-specific (e.g. "x86", "amd64", "x64") or platform-specific (e.g. "Win32") directories that reside underneath the application base directory. - - No_SQLiteFunctions - If this environment variable is set [to anything], the initial - search for types in all loaded assemblies that are tagged with the - SQLiteFunction attribute will be skipped. Normally, this search is - conducted only once per application domain by the static constructor - of the SQLiteFunction class; however, these implementation details - are subject to change. - PreLoadSQLite_BaseDirectory If this environment variable is set [to anything], it will be used instead of the application base directory by the native - library pre-loader. This environment variable can be especially - useful in ASP.NET and other hosted environments where direct control - of the location of the managed assemblies is not under the control - of the application. + library pre-loader. PreLoadSQLite_ProcessorArchitecture If this environment variable is set [to anything], it will be used instead of the processor architecture value contained in the PROCESSOR_ARCHITECTURE environment variable to help build the path of the native library to pre-load. - - PreLoadSQLite_UseAssemblyDirectory - If this environment variable is set [to anything], the location - of the currently executing assembly (i.e. the one containing all the - managed components for System.Data.SQLite) will be used as the basis - for locating the the native library to pre-load (i.e. instead of - using the application domain base directory). - PROCESSOR_ARCHITECTURE This environment variable is normally set by the operating system itself and should reflect the native processor architecture of the current process (e.g. a 32-bit x86 application running on a Index: Doc/Extra/version.html ================================================================== --- Doc/Extra/version.html +++ Doc/Extra/version.html @@ -41,57 +41,17 @@

Version History

-

1.0.86.0 - May XX, 2013 (release scheduled)

- -

1.0.85.0 - April 18, 2013

- -

1.0.84.0 - January 9, 2013

- -

1.0.83.0 - December 29, 2012

- */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 @@ -1493,12 +1448,10 @@ #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 -#define SQLITE_FCNTL_TEMPFILENAME 16 -#define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an @@ -2161,13 +2114,11 @@ **
^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^
** ** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
-**
The SQLITE_CONFIG_LOG option is used to configure the SQLite -** global [error log]. -** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a +**
^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is @@ -2194,11 +2145,11 @@ ** database connection is opened. By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined. ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN -**
This option takes a single integer argument which is interpreted as +**
This option taks a single integer argument which is interpreted as ** a boolean in order to enable or disable the use of covering indices for ** full table scans in the query optimizer. The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans @@ -2209,42 +2160,10 @@ ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] **
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE **
These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. -**
-** -** [[SQLITE_CONFIG_SQLLOG]] -**
SQLITE_CONFIG_SQLLOG -**
This option is only available if sqlite is compiled with the -** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should -** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). -** The second should be of type (void*). The callback is invoked by the library -** in three separate circumstances, identified by the value passed as the -** fourth parameter. If the fourth parameter is 0, then the database connection -** passed as the second argument has just been opened. The third argument -** points to a buffer containing the name of the main database file. If the -** fourth parameter is 1, then the SQL statement that the third parameter -** points to has just been executed. Or, if the fourth parameter is 2, then -** the connection being passed as the second parameter is being closed. The -** third parameter is passed NULL In this case. An example of using this -** configuration option can be seen in the "test_sqllog.c" source file in -** the canonical SQLite source tree.
-** -** [[SQLITE_CONFIG_MMAP_SIZE]] -**
SQLITE_CONFIG_MMAP_SIZE -**
SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values -** that are the default mmap size limit (the default setting for -** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. -** The default setting can be overridden by each database connection using -** either the [PRAGMA mmap_size] command, or by using the -** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size -** cannot be changed at run-time. Nor may the maximum allowed mmap size -** exceed the compile-time maximum mmap size set by the -** [SQLITE_MAX_MMAP_SIZE] compile-time option. -** If either argument to this option is negative, then that argument is -** changed to its compile-time default. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -2263,12 +2182,10 @@ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ -#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ -#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that @@ -3098,13 +3015,10 @@ ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** -** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit -** the length of [bound parameter] expansion in the output of sqlite3_trace(). -** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation @@ -3292,11 +3206,11 @@ ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in -** a URI filename, its value overrides any behavior requested by setting +** a URI filename, its value overrides any behaviour requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query @@ -3639,12 +3553,11 @@ ** **
    **
  1. ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL -** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] -** retries will occur before sqlite3_step() gives up and returns an error. +** statement and try to run it again. **
  2. ** **
  3. ** ^When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. ^The legacy behavior was that @@ -3844,13 +3757,10 @@ ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** ** ^The third argument is the value to bind to the parameter. -** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() -** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter -** is ignored and the end result is the same as sqlite3_bind_null(). ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() @@ -4614,12 +4524,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); -SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), - void*,sqlite3_int64); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64); #endif /* ** CAPI3REF: Obtaining SQL Function Parameter Values ** @@ -4695,21 +4604,18 @@ ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** -** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer -** when first called if N is less than or equal to zero or if a memory -** allocate error occurs. +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is +** less than or equal to zero or if a memory allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory -** allocation.)^ Within the xFinal callback, it is customary to set -** N=0 in calls to sqlite3_aggregate_context(C,N) so that no -** pointless memory allocations occur. +** allocation.)^ ** ** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the @@ -4803,11 +4709,11 @@ ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain -** C++ compilers. +** C++ compilers. See ticket #2191. */ typedef void (*sqlite3_destructor_type)(void*); #define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) @@ -5602,24 +5508,15 @@ ** CAPI3REF: Load An Extension ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an -** [SQLite extension] library contained in the file zFile. If -** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. -** So for example, if "samplelib" cannot be loaded, then names like -** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might -** be tried also. +** SQLite extension library contained in the file zFile. ** ** ^The entry point is zProc. -** ^(zProc may be 0, in which case SQLite will try to come up with an -** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** ^zProc may be 0, in which case the name of the entry point +** defaults to "sqlite3_extension_init". ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the ** [sqlite3_load_extension()] interface shall attempt to ** fill *pzErrMsg with error message text stored in memory @@ -5641,15 +5538,15 @@ /* ** CAPI3REF: Enable Or Disable Extension Loading ** ** ^So as not to open security holes in older applications that are -** unprepared to deal with [extension loading], and as a means of disabling -** [extension loading] while evaluating user-entered SQL, the following API +** unprepared to deal with extension loading, and as a means of disabling +** extension loading while evaluating user-entered SQL, the following API ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** -** ^Extension loading is off by default. +** ^Extension loading is off by default. See ticket #1863. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); @@ -5657,11 +5554,11 @@ /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that -** xEntryPoint() is the entry point for a statically linked [SQLite extension] +** xEntryPoint() is the entry point for a statically linked SQLite extension ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects and integer result as if the signature of the @@ -7008,11 +6905,11 @@ ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** ** -**
    createFlag Behavior when page is not already in cache +**
    createFlag Behaviour when page is not already in cache **
    0 Do not allocate a new page. Return NULL. **
    1 Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. **
    2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. @@ -7437,29 +7334,14 @@ ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); -/* -** CAPI3REF: String Globbing -* -** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches -** the glob pattern P, and it returns non-zero if string X does not match -** the glob pattern P. ^The definition of glob pattern matching used in -** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the -** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case -** sensitive. -** -** Note that this routine returns zero on a match and non-zero if the strings -** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. -*/ -SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); - /* ** CAPI3REF: Error Logging Interface ** -** ^The [sqlite3_log()] interface writes a message into the [error log] +** ^The [sqlite3_log()] interface writes a message into the error log ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** ^If logging is enabled, the zFormat string and subsequent arguments are ** used with [sqlite3_snprintf()] to generate the final output string. ** ** The sqlite3_log() interface is intended for use by extensions such as @@ -7828,11 +7710,11 @@ ** 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 the header file for the generic hash-table implementation +** This is the header file for the generic hash-table implemenation ** used in SQLite. */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ @@ -8140,11 +8022,10 @@ ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 -# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. @@ -8288,53 +8169,10 @@ # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif -/* -** Disable MMAP on platforms where it is known to not work -*/ -#if defined(__OpenBSD__) || defined(__QNXNTO__) -# undef SQLITE_MAX_MMAP_SIZE -# define SQLITE_MAX_MMAP_SIZE 0 -#endif - -/* -** Default maximum size of memory used by memory-mapped I/O in the VFS -*/ -#ifdef __APPLE__ -# include -# if TARGET_OS_IPHONE -# undef SQLITE_MAX_MMAP_SIZE -# define SQLITE_MAX_MMAP_SIZE 0 -# endif -#endif -#ifndef SQLITE_MAX_MMAP_SIZE -# if defined(__linux__) \ - || defined(_WIN32) \ - || (defined(__APPLE__) && defined(__MACH__)) \ - || defined(__sun) -# define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */ -# else -# define SQLITE_MAX_MMAP_SIZE 0 -# endif -# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ -#endif - -/* -** The default MMAP_SIZE is zero on all platforms. Or, even if a larger -** default MMAP_SIZE is specified at compile-time, make sure that it does -** not exceed the maximum mmap size. -*/ -#ifndef SQLITE_DEFAULT_MMAP_SIZE -# define SQLITE_DEFAULT_MMAP_SIZE 0 -# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ -#endif -#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE -# undef SQLITE_DEFAULT_MMAP_SIZE -# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE -#endif /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** @@ -8372,15 +8210,10 @@ ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) -/* -** Determine if the argument is a power of two -*/ -#define IsPowerOfTwo(X) (((X)&((X)-1))==0) - /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any @@ -8552,11 +8385,10 @@ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); -SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); @@ -8607,12 +8439,10 @@ SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); -SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); - /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta ** should be one of the following values. The integer values are assigned ** to constants so that the offset of the corresponding field in an ** SQLite database header may be found using the following formula: @@ -8629,11 +8459,10 @@ #define BTREE_DEFAULT_CACHE_SIZE 3 #define BTREE_LARGEST_ROOT_PAGE 4 #define BTREE_TEXT_ENCODING 5 #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 -#define BTREE_APPLICATION_ID 8 /* ** Values that may be OR'd together to form the second argument of an ** sqlite3BtreeCursorHints() call. */ @@ -9124,11 +8953,11 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG @@ -9254,16 +9083,10 @@ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ -/* -** Flags that make up the mask passed to sqlite3PagerAcquire(). -*/ -#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */ -#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */ - /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ @@ -9284,11 +9107,10 @@ /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); -SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); SQLITE_PRIVATE void sqlite3PagerShrink(Pager*); SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); @@ -9431,12 +9253,10 @@ ** writing this page to the database */ #define PGHDR_NEED_READ 0x008 /* Content is unread */ #define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */ #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ -#define PGHDR_MMAP 0x040 /* This is an mmap page object */ - /* Initialize and shutdown the page cache subsystem */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void); SQLITE_PRIVATE void sqlite3PcacheShutdown(void); /* Page cache buffer management: @@ -9644,10 +9464,18 @@ */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif +/* +** When compiled for WinCE or WinRT, there is no concept of the current +** directory. + */ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +# define SQLITE_CURDIR 1 +#endif + /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) @@ -9796,12 +9624,10 @@ SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); -SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); -SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); /* ** Functions for accessing sqlite3_vfs methods */ @@ -10037,15 +9863,14 @@ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ int flags; /* Miscellaneous flags. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ - i64 szMmap; /* Default mmap_size setting */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ - u16 dbOptFlags; /* Flags to enable/disable optimizations */ + u8 dbOptFlags; /* Flags to enable/disable optimizations */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ @@ -10158,11 +9983,11 @@ #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */ -#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */ + /* 0x00000200 Unused */ #define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */ #define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */ @@ -10186,13 +10011,11 @@ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ -#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ -#define SQLITE_Transitive 0x0200 /* Transitive constraints */ -#define SQLITE_AllOpts 0xffff /* All optimizations */ +#define SQLITE_AllOpts 0x00ff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #ifndef SQLITE_OMIT_BUILTIN_TEST @@ -10365,11 +10188,23 @@ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** -** If CollSeq.xCmp is NULL, it means that the +** There may two separate implementations of the collation function, one +** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that +** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine +** native byte order. When a collation sequence is invoked, SQLite selects +** the version that will require the least expensive encoding +** translations, if any. +** +** The CollSeq.pUser member variable is an extra parameter that passed in +** as the first argument to the UTF-8 comparison function, xCmp. +** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function, +** xCmp16. +** +** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the ** collating sequence is undefined. Indices built on an undefined ** collating sequence may not be read or written. */ struct CollSeq { char *zName; /* Name of the collating sequence, UTF-8 encoded */ @@ -10699,24 +10534,24 @@ ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { - char *zName; /* Name of this index */ - int *aiColumn; /* Which columns are used by this index. 1st is 0 */ - tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */ - Table *pTable; /* The SQL table being indexed */ - char *zColAff; /* String defining the affinity of each column */ - Index *pNext; /* The next index associated with the same table */ - Schema *pSchema; /* Schema containing this index */ - u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ - char **azColl; /* Array of collation sequence names for index */ - int tnum; /* DB Page containing root of this index */ - u16 nColumn; /* Number of columns in table used by this index */ - u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ - unsigned bUnordered:1; /* Use this index for == or IN queries only */ + char *zName; /* Name of this index */ + int *aiColumn; /* Which columns are used by this index. 1st is 0 */ + tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ + Table *pTable; /* The SQL table being indexed */ + char *zColAff; /* String defining the affinity of each column */ + Index *pNext; /* The next index associated with the same table */ + Schema *pSchema; /* Schema containing this index */ + u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ + char **azColl; /* Array of collation sequence names for index */ + int nColumn; /* Number of columns in the table used by this index */ + int tnum; /* Page containing root of this index in database file */ + u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ + u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ + u8 bUnordered; /* Use this index for == or IN queries only */ #ifdef SQLITE_ENABLE_STAT3 int nSample; /* Number of elements in aSample[] */ tRowcnt avgEq; /* Average nEq value for key values not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ #endif @@ -10893,10 +10728,11 @@ Expr *pRight; /* Right subnode */ union { ExprList *pList; /* Function arguments or in " IN ( IN ( @@ -76800,12 +75055,11 @@ iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); - assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); - eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; + eType = IN_INDEX_INDEX; sqlite3VdbeJumpHere(v, iAddr); if( prNotFound && !pTab->aCol[iCol].notNull ){ *prNotFound = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); @@ -77987,11 +76241,10 @@ sqlite3VdbeAddOp3(v, OP_And, r3, r4, target); sqlite3ReleaseTempReg(pParse, r3); sqlite3ReleaseTempReg(pParse, r4); break; } - case TK_COLLATE: case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } @@ -78154,12 +76407,11 @@ assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affinity==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); }else{ - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, - pExpr->affinity, pExpr->u.zToken, 0); + sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0); } break; } #endif @@ -78358,16 +76610,10 @@ case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; - case TK_COLLATE: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken); - break; - } - case TK_AGG_FUNCTION: case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){ @@ -78501,16 +76747,10 @@ for(i=0; inExpr; i++){ sqlite3ExplainPrintf(pOut, "item[%d] = ", i); sqlite3ExplainPush(pOut); sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainPop(pOut); - if( pList->a[i].zName ){ - sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); - } - if( pList->a[i].bSpanIsTab ){ - sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); - } if( inExpr-1 ){ sqlite3ExplainNL(pOut); } } sqlite3ExplainPop(pOut); @@ -78588,13 +76828,10 @@ switch( pExpr->op ){ case TK_IN: case TK_REGISTER: { return WRC_Prune; } - case TK_COLLATE: { - return WRC_Continue; - } case TK_FUNCTION: case TK_AGG_FUNCTION: case TK_CONST_FUNC: { /* The arguments to a function have a fixed destination. ** Mark them this way to avoid generated unneeded OP_SCopy @@ -78612,15 +76849,13 @@ break; } } if( isAppropriateForFactoring(pExpr) ){ int r1 = ++pParse->nMem; - int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); - /* If r2!=r1, it means that register r1 is never used. That is harmless - ** but suboptimal, so we want to know about the situation to fix it. - ** Hence the following assert: */ - assert( r2==r1 ); + int r2; + r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); + if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1); pExpr->op2 = pExpr->op; pExpr->op = TK_REGISTER; pExpr->iTable = r2; return WRC_Prune; } @@ -78645,12 +76880,12 @@ */ SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return; - memset(&w, 0, sizeof(w)); w.xExprCallback = evalConstExpr; + w.xSelectCallback = 0; w.pParse = pParse; sqlite3WalkExpr(&w, pExpr); } @@ -78759,11 +76994,11 @@ int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); - if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ + if( NEVER(v==0) ) return; /* Existance of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); @@ -78879,11 +77114,11 @@ int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); - if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ + if( NEVER(v==0) ) return; /* Existance of VDBE checked by caller */ if( pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op @@ -79033,19 +77268,11 @@ assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) ); if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){ return 2; } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; - if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){ - return 1; - } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){ - return 1; - } - return 2; - } + if( pA->op!=pB->op ) return 2; if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2; if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2; if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2; if( ExprHasProperty(pA, EP_IntValue) ){ @@ -79053,13 +77280,15 @@ return 2; } }else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2; if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ - return pA->op==TK_COLLATE ? 1 : 2; + return 2; } } + if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1; + if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2; return 0; } /* ** Compare two ExprList objects. Return 0 if they are identical and @@ -79296,14 +77525,12 @@ */ assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); ExprSetIrreducible(pExpr); pExpr->iAgg = (i16)i; pExpr->pAggInfo = pAggInfo; - return WRC_Prune; - }else{ - return WRC_Continue; } + return WRC_Prune; } } return WRC_Continue; } static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ @@ -79311,14 +77538,13 @@ UNUSED_PARAMETER(pSelect); return WRC_Continue; } /* -** Analyze the pExpr expression looking for aggregate functions and -** for variables that need to be added to AggInfo object that pNC->pAggInfo -** points to. Additional entries are made on the AggInfo object as -** necessary. +** Analyze the given expression looking for aggregate functions and +** for variables that need to be added to the pParse->aAgg[] array. +** Make additional entries to the pParse->aAgg[] array as necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ResolveExprNames(). */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ @@ -80714,11 +78940,11 @@ } if( pTab->tnum==0 ){ /* Do not gather statistics on views or virtual tables */ return; } - if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){ + if( memcmp(pTab->zName, "sqlite_", 7)==0 ){ /* Do not gather statistics on system tables */ return; } assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -81124,11 +79350,11 @@ } if( i==0 ) pTable->nRowEst = v; if( pIndex==0 ) break; pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; - if( strcmp(z, "unordered")==0 ){ + if( memcmp(z, "unordered", 10)==0 ){ pIndex->bUnordered = 1; break; } } return 0; @@ -81476,11 +79702,11 @@ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } - /* Allocate the new entry in the db->aDb[] array and initialize the schema + /* Allocate the new entry in the db->aDb[] array and initialise the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; @@ -81493,11 +79719,11 @@ aNew = &db->aDb[db->nDb]; memset(aNew, 0, sizeof(*aNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may - ** or may not be initialized. + ** or may not be initialised. */ flags = db->openFlags; rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; @@ -81838,11 +80064,11 @@ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return 1; } - sqlite3DbFree(pFix->pParse->db, pItem->zDatabase); + sqlite3_free(pItem->zDatabase); pItem->zDatabase = 0; pItem->pSchema = pFix->pSchema; #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; @@ -82306,11 +80532,10 @@ */ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - assert( pParse->pToplevel==0 ); db = pParse->db; if( db->mallocFailed ) return; if( pParse->nested ) return; if( pParse->nErr ) return; @@ -84279,11 +82504,11 @@ #endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being - ** dropped. Triggers are handled separately because a trigger can be + ** dropped. Triggers are handled seperately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", @@ -84571,10 +82796,13 @@ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ +#ifdef SQLITE_OMIT_MERGE_SORT + int regIdxKey; /* Registers containing the index key */ +#endif int regRecord; /* Register holding assemblied index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION @@ -84598,20 +82826,25 @@ pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); +#ifndef SQLITE_OMIT_MERGE_SORT /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO); +#else + iSorter = iTab; +#endif /* Open the table. Loop through all rows of the table, inserting index ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); +#ifndef SQLITE_OMIT_MERGE_SORT sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); @@ -84618,19 +82851,43 @@ if( pIndex->onError!=OE_None ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord); - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, - OE_Abort, "indexed columns are not unique", P4_STATIC + sqlite3HaltConstraint( + pParse, OE_Abort, "indexed columns are not unique", P4_STATIC ); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); +#else + regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); + addr2 = addr1 + 1; + if( pIndex->onError!=OE_None ){ + const int regRowid = regIdxKey + pIndex->nColumn; + const int j2 = sqlite3VdbeCurrentAddr(v) + 2; + void * const pRegKey = SQLITE_INT_TO_PTR(regIdxKey); + + /* The registers accessed by the OP_IsUnique opcode were allocated + ** using sqlite3GetTempRange() inside of the sqlite3GenerateIndexKey() + ** call above. Just before that function was freed they were released + ** (made available to the compiler for reuse) using + ** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique + ** opcode use the values stored within seems dangerous. However, since + ** we can be sure that no other temp registers have been allocated + ** since sqlite3ReleaseTempRange() was called, it is safe to do so. + */ + sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32); + sqlite3HaltConstraint( + pParse, OE_Abort, "indexed columns are not unique", P4_STATIC); + } + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); +#endif sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); @@ -84741,11 +82998,11 @@ pDb = &db->aDb[iDb]; assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ + && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ @@ -84838,12 +83095,16 @@ ** specified collation sequence names. */ for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; if( pExpr ){ - assert( pExpr->op==TK_COLLATE ); - nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); + CollSeq *pColl = pExpr->pColl; + /* Either pColl!=0 or there was an OOM failure. But if an OOM + ** failure we have quit before reaching this point. */ + if( ALWAYS(pColl) ){ + nExtra += (1 + sqlite3Strlen30(pColl->zName)); + } } } /* ** Allocate the index structure. @@ -84912,23 +83173,29 @@ pTab->zName, zColName); pParse->checkSchema = 1; goto exit_create_index; } pIndex->aiColumn[i] = j; - if( pListItem->pExpr ){ + /* Justification of the ALWAYS(pListItem->pExpr->pColl): Because of + ** the way the "idxlist" non-terminal is constructed by the parser, + ** if pListItem->pExpr is not null then either pListItem->pExpr->pColl + ** must exist or else there must have been an OOM error. But if there + ** was an OOM error, we would never reach this point. */ + if( pListItem->pExpr && ALWAYS(pListItem->pExpr->pColl) ){ int nColl; - assert( pListItem->pExpr->op==TK_COLLATE ); - zColl = pListItem->pExpr->u.zToken; + zColl = pListItem->pExpr->pColl->zName; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); memcpy(zExtra, zColl, nColl); zColl = zExtra; zExtra += nColl; nExtra -= nColl; }else{ zColl = pTab->aCol[j].zColl; - if( !zColl ) zColl = "BINARY"; + if( !zColl ){ + zColl = "BINARY"; + } } if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } pIndex->azColl[i] = zColl; @@ -84980,11 +83247,11 @@ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the - ** explicitly specified behavior for the index. + ** explicitly specified behaviour for the index. */ if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } @@ -85727,19 +83994,10 @@ ** early in the code, before we know if any database tables will be used. */ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); -#ifndef SQLITE_OMIT_TRIGGER - if( pToplevel!=pParse ){ - /* This branch is taken if a trigger is currently being coded. In this - ** case, set cookieGoto to a non-zero value to show that this function - ** has been called. This is used by the sqlite3ExprCodeConstants() - ** function. */ - pParse->cookieGoto = -1; - } -#endif if( pToplevel->cookieGoto==0 ){ Vdbe *v = sqlite3GetVdbe(pToplevel); if( v==0 ) return; /* This only happens if there was a prior error */ pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1; } @@ -85833,23 +84091,16 @@ /* ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT ** error. The onError parameter determines which (if any) of the statement ** and/or current transaction is rolled back. */ -SQLITE_PRIVATE void sqlite3HaltConstraint( - Parse *pParse, /* Parsing context */ - int errCode, /* extended error code */ - int onError, /* Constraint type */ - char *p4, /* Error message */ - int p4type /* P4_STATIC or P4_TRANSIENT */ -){ +SQLITE_PRIVATE void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){ Vdbe *v = sqlite3GetVdbe(pParse); - assert( (errCode&0xff)==SQLITE_CONSTRAINT ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } - sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type); } /* ** Check to see if pIndex uses the collating sequence pColl. Return ** true if it does and false if it does not. @@ -86590,32 +84841,33 @@ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ int iCur /* Cursor number for ephemerial table */ ){ SelectDest dest; - Select *pSel; - SrcList *pFrom; + Select *pDup; sqlite3 *db = pParse->db; - int iDb = sqlite3SchemaToIndex(db, pView->pSchema); - - pWhere = sqlite3ExprDup(db, pWhere, 0); - pFrom = sqlite3SrcListAppend(db, 0, 0, 0); - - if( pFrom ){ - assert( pFrom->nSrc==1 ); - pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); - assert( pFrom->a[0].pOn==0 ); - assert( pFrom->a[0].pUsing==0 ); - } - - pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0); - if( pSel ) pSel->selFlags |= SF_Materialize; - + + pDup = sqlite3SelectDup(db, pView->pSelect, 0); + if( pWhere ){ + SrcList *pFrom; + + pWhere = sqlite3ExprDup(db, pWhere, 0); + pFrom = sqlite3SrcListAppend(db, 0, 0, 0); + if( pFrom ){ + assert( pFrom->nSrc==1 ); + pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName); + pFrom->a[0].pSelect = pDup; + assert( pFrom->a[0].pOn==0 ); + assert( pFrom->a[0].pUsing==0 ); + }else{ + sqlite3SelectDelete(db, pDup); + } + pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0); + } sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); - sqlite3Select(pParse, pSel, &dest); - sqlite3SelectDelete(db, pSel); + sqlite3Select(pParse, pDup, &dest); + sqlite3SelectDelete(db, pDup); } #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* @@ -87318,60 +85570,10 @@ break; } } } -/* -** Implementation of the instr() function. -** -** instr(haystack,needle) finds the first occurrence of needle -** in haystack and returns the number of previous characters plus 1, -** or 0 if needle does not occur within haystack. -** -** If both haystack and needle are BLOBs, then the result is one more than -** the number of bytes in haystack prior to the first occurrence of needle, -** or 0 if needle never occurs in haystack. -*/ -static void instrFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const unsigned char *zHaystack; - const unsigned char *zNeedle; - int nHaystack; - int nNeedle; - int typeHaystack, typeNeedle; - int N = 1; - int isText; - - UNUSED_PARAMETER(argc); - typeHaystack = sqlite3_value_type(argv[0]); - typeNeedle = sqlite3_value_type(argv[1]); - if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; - nHaystack = sqlite3_value_bytes(argv[0]); - nNeedle = sqlite3_value_bytes(argv[1]); - if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ - zHaystack = sqlite3_value_blob(argv[0]); - zNeedle = sqlite3_value_blob(argv[1]); - isText = 0; - }else{ - zHaystack = sqlite3_value_text(argv[0]); - zNeedle = sqlite3_value_text(argv[1]); - isText = 1; - } - while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ - N++; - do{ - nHaystack--; - zHaystack++; - }while( isText && (zHaystack[0]&0xc0)==0x80 ); - } - if( nNeedle>nHaystack ) N = 0; - sqlite3_result_int(context, N); -} - /* ** Implementation of the substr() function. ** ** substr(x,p1,p2) returns p2 characters of x[] beginning with p1. ** p1 is 1-indexed. So substr(x,1,1) returns the first character @@ -87843,17 +86045,10 @@ } } return *zString==0; } -/* -** The sqlite3_strglob() interface. -*/ -SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){ - return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; -} - /* ** Count the number of times that the LIKE operator (or GLOB which is ** just a variation of LIKE) gets called. This is used for testing ** only. */ @@ -88119,66 +86314,10 @@ break; } } } -/* -** The unicode() function. Return the integer unicode code-point value -** for the first character of the input string. -*/ -static void unicodeFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const unsigned char *z = sqlite3_value_text(argv[0]); - (void)argc; - if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z)); -} - -/* -** The char() function takes zero or more arguments, each of which is -** an integer. It constructs a string where each character of the string -** is the unicode character for the corresponding integer argument. -*/ -static void charFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - unsigned char *z, *zOut; - int i; - zOut = z = sqlite3_malloc( argc*4 ); - if( z==0 ){ - sqlite3_result_error_nomem(context); - return; - } - for(i=0; i0x10ffff ) x = 0xfffd; - c = (unsigned)(x & 0x1fffff); - if( c<0x00080 ){ - *zOut++ = (u8)(c&0xFF); - }else if( c<0x00800 ){ - *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); - *zOut++ = 0x80 + (u8)(c & 0x3F); - }else if( c<0x10000 ){ - *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); - *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); - *zOut++ = 0x80 + (u8)(c & 0x3F); - }else{ - *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); - *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); - *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); - *zOut++ = 0x80 + (u8)(c & 0x3F); - } \ - } - sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free); -} - /* ** The hex() function. Interpret the argument as a blob. Return ** a hexadecimal rendering as text. */ static void hexFunc( @@ -88799,15 +86938,12 @@ FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), - FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), - FUNCTION(unicode, 1, 0, 0, unicodeFunc ), - FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif @@ -88895,13 +87031,12 @@ /* ** Deferred and Immediate FKs ** -------------------------- ** ** Foreign keys in SQLite come in two flavours: deferred and immediate. -** If an immediate foreign key constraint is violated, -** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current -** statement transaction rolled back. If a +** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT +** is returned and the current statement transaction rolled back. If a ** deferred foreign key constraint is violated, no action is taken ** immediately. However if the application attempts to commit the ** transaction before fixing the constraint violation, the attempt fails. ** ** Deferred constraints are implemented using a simple counter associated @@ -88961,12 +87096,11 @@ ** row is inserted. ** ** Immediate constraints are usually handled similarly. The only difference ** is that the counter used is stored as part of each individual statement ** object (struct Vdbe). If, after the statement has run, its immediate -** constraint counter is greater than zero, -** it returns SQLITE_CONSTRAINT_FOREIGNKEY +** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT ** and the statement transaction is rolled back. An exception is an INSERT ** statement that inserts a single row only (no triggers). In this case, ** instead of using a counter, an exception is thrown immediately if the ** INSERT violates a foreign key constraint. This is necessary as such ** an INSERT does not open a statement transaction. @@ -89018,11 +87152,11 @@ /* ** A foreign key constraint requires that the key columns in the parent ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. ** Given that pParent is the parent table for foreign key constraint pFKey, -** search the schema for a unique index on the parent key columns. +** search the schema a unique index on the parent key columns. ** ** If successful, zero is returned. If the parent key is an INTEGER PRIMARY ** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx ** is set to point to the unique index. ** @@ -89054,11 +87188,11 @@ ** ** then non-zero is returned, and a "foreign key mismatch" error loaded ** into pParse. If an OOM error occurs, non-zero is returned and the ** pParse->db->mallocFailed flag is set. */ -SQLITE_PRIVATE int sqlite3FkLocateIndex( +static int locateFkeyIndex( Parse *pParse, /* Parse context to store any error in */ Table *pParent, /* Parent table of FK constraint pFKey */ FKey *pFKey, /* Foreign key to find index for */ Index **ppIdx, /* OUT: Unique index on parent table */ int **paiCol /* OUT: Map of index columns in pFKey */ @@ -89151,13 +87285,11 @@ } } if( !pIdx ){ if( !pParse->disableTriggers ){ - sqlite3ErrorMsg(pParse, - "foreign key mismatch - \"%w\" referencing \"%w\"", - pFKey->pFrom->zName, pFKey->zTo); + sqlite3ErrorMsg(pParse, "foreign key mismatch"); } sqlite3DbFree(pParse->db, aiCol); return 1; } @@ -89302,12 +87434,12 @@ /* Special case: If this is an INSERT statement that will insert exactly ** one row into the table, raise a constraint immediately instead of ** incrementing a counter. This is necessary as the VM code is being ** generated for will not open a statement transaction. */ assert( nIncr==1 ); - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, - OE_Abort, "foreign key constraint failed", P4_STATIC + sqlite3HaltConstraint( + pParse, OE_Abort, "foreign key constraint failed", P4_STATIC ); }else{ if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } @@ -89389,19 +87521,16 @@ if( pLeft ){ /* Set the collation sequence and affinity of the LHS of each TK_EQ ** expression to the parent key column defaults. */ if( pIdx ){ Column *pCol; - const char *zColl; iCol = pIdx->aiColumn[i]; pCol = &pTab->aCol[iCol]; if( pTab->iPKey==iCol ) iCol = -1; pLeft->iTable = regData+iCol+1; pLeft->affinity = pCol->affinity; - zColl = pCol->zColl; - if( zColl==0 ) zColl = db->pDfltColl->zName; - pLeft = sqlite3ExprAddCollateString(pParse, pLeft, zColl); + pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl); }else{ pLeft->iTable = regData; pLeft->affinity = SQLITE_AFF_INTEGER; } } @@ -89543,12 +87672,12 @@ /* If the DELETE has generated immediate foreign key constraint ** violations, halt the VDBE and return an error at this point, before ** any modifications to the schema are made. This is because statement ** transactions are not able to rollback schema changes. */ sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, - OE_Abort, "foreign key constraint failed", P4_STATIC + sqlite3HaltConstraint( + pParse, OE_Abort, "foreign key constraint failed", P4_STATIC ); if( iSkip ){ sqlite3VdbeResolveLabel(v, iSkip); } @@ -89614,11 +87743,11 @@ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } - if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ + if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; if( pTo==0 ){ /* If isIgnoreErrors is true, then a table is being dropped. In this ** case SQLite runs a "DELETE FROM xxx" on the table being dropped @@ -89694,11 +87823,11 @@ /* Inserting a single row into a parent table cannot cause an immediate ** foreign key violation. So do nothing in this case. */ continue; } - if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ + if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); @@ -89749,11 +87878,11 @@ for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; - sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); + locateFkeyIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; inColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } @@ -89875,11 +88004,11 @@ ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */ int i; /* Iterator variable */ Expr *pWhen = 0; /* WHEN clause for the trigger */ - if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; + if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; assert( aiCol || pFKey->nCol==1 ); for(i=0; inCol; i++){ Token tOld = { "old", 3 }; /* Literal "old" token */ Token tNew = { "new", 3 }; /* Literal "new" token */ @@ -90128,11 +88257,11 @@ int iDb, /* The database index in sqlite3.aDb[] */ Table *pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ){ Vdbe *v; - assert( !IsVirtual(pTab) ); + if( IsVirtual(pTab) ) return; v = sqlite3GetVdbe(p); assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb); sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32); @@ -91348,11 +89477,11 @@ sqlite3MayAbort(pParse); case OE_Rollback: case OE_Fail: { char *zMsg; sqlite3VdbeAddOp3(v, OP_HaltIfNull, - SQLITE_CONSTRAINT_NOTNULL, onError, regData+i); + SQLITE_CONSTRAINT, onError, regData+i); zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); break; } @@ -91377,25 +89506,29 @@ ExprList *pCheck = pTab->pCheck; pParse->ckBase = regData; onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; inExpr; i++){ int allOk = sqlite3VdbeMakeLabel(v); - sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL); - if( onError==OE_Ignore ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); - }else{ - char *zConsName = pCheck->a[i].zName; - if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ - if( zConsName ){ - zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName); - }else{ - zConsName = 0; - } - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, - onError, zConsName, P4_DYNAMIC); - } - sqlite3VdbeResolveLabel(v, allOk); + Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0); + if( !db->mallocFailed ){ + assert( pDup!=0 ); + sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL); + if( onError==OE_Ignore ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); + }else{ + char *zConsName = pCheck->a[i].zName; + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ + if( zConsName ){ + zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName); + }else{ + zConsName = 0; + } + sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC); + } + sqlite3VdbeResolveLabel(v, allOk); + } + sqlite3ExprDelete(db, pDup); } } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key @@ -91420,12 +89553,12 @@ /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY, - onError, "PRIMARY KEY must be unique", P4_STATIC); + sqlite3HaltConstraint( + pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { /* If there are DELETE triggers on this table and the ** recursive-triggers flag is set, call GenerateRowDelete() to @@ -91548,12 +89681,11 @@ sqlite3StrAccumAppend(&errMsg, zCol, -1); } sqlite3StrAccumAppend(&errMsg, pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); zErr = sqlite3StrAccumFinish(&errMsg); - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, - onError, zErr, 0); + sqlite3HaltConstraint(pParse, onError, zErr, 0); sqlite3DbFree(errMsg.db, zErr); break; } case OE_Ignore: { assert( seenReplace==0 ); @@ -91957,12 +90089,12 @@ regData = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY, - onError, "PRIMARY KEY must be unique", P4_STATIC); + sqlite3HaltConstraint( + pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ @@ -92050,23 +90182,24 @@ ){ int rc = SQLITE_OK; /* Return code */ const char *zLeftover; /* Tail of unprocessed SQL */ sqlite3_stmt *pStmt = 0; /* The current SQL statement */ char **azCols = 0; /* Names of result columns */ + int nRetry = 0; /* Number of retry attempts */ int callbackIsInit; /* True if callback data is initialized */ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK, 0); - while( rc==SQLITE_OK && zSql[0] ){ + while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){ int nCol; char **azVals = 0; pStmt = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); + rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); if( rc!=SQLITE_OK ){ continue; } if( !pStmt ){ @@ -92119,12 +90252,15 @@ } if( rc!=SQLITE_ROW ){ rc = sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; - zSql = zLeftover; - while( sqlite3Isspace(zSql[0]) ) zSql++; + if( rc!=SQLITE_SCHEMA ){ + nRetry = 0; + zSql = zLeftover; + while( sqlite3Isspace(zSql[0]) ) zSql++; + } break; } } sqlite3DbFree(db, azCols); @@ -92411,24 +90547,10 @@ int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); - /* Version 3.7.16 and later */ - int (*close_v2)(sqlite3*); - const char *(*db_filename)(sqlite3*,const char*); - int (*db_readonly)(sqlite3*,const char*); - int (*db_release_memory)(sqlite3*); - const char *(*errstr)(int); - int (*stmt_busy)(sqlite3_stmt*); - int (*stmt_readonly)(sqlite3_stmt*); - int (*stricmp)(const char*,const char*); - int (*uri_boolean)(const char*,const char*,int); - sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); - const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); - int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); }; /* ** The following macros redefine the API routines so that they are ** redirected throught the global sqlite3_api structure. @@ -92628,37 +90750,14 @@ #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict -/* Version 3.7.16 and later */ -#define sqlite3_close_v2 sqlite3_api->close_v2 -#define sqlite3_db_filename sqlite3_api->db_filename -#define sqlite3_db_readonly sqlite3_api->db_readonly -#define sqlite3_db_release_memory sqlite3_api->db_release_memory -#define sqlite3_errstr sqlite3_api->errstr -#define sqlite3_stmt_busy sqlite3_api->stmt_busy -#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly -#define sqlite3_stricmp sqlite3_api->stricmp -#define sqlite3_uri_boolean sqlite3_api->uri_boolean -#define sqlite3_uri_int64 sqlite3_api->uri_int64 -#define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf -#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 #endif /* SQLITE_CORE */ -#ifndef SQLITE_CORE - /* This case when the file really is being compiled as a loadable - ** extension */ -# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; -# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; -#else - /* This case when the file is being statically linked into the - ** application */ -# define SQLITE_EXTENSION_INIT1 /*no-op*/ -# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ -#endif +#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; +#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ @@ -93020,23 +91119,10 @@ 0, #endif sqlite3_blob_reopen, sqlite3_vtab_config, sqlite3_vtab_on_conflict, - sqlite3_close_v2, - sqlite3_db_filename, - sqlite3_db_readonly, - sqlite3_db_release_memory, - sqlite3_errstr, - sqlite3_stmt_busy, - sqlite3_stmt_readonly, - sqlite3_stricmp, - sqlite3_uri_boolean, - sqlite3_uri_int64, - sqlite3_uri_parameter, - sqlite3_vsnprintf, - sqlite3_wal_checkpoint_v2 }; /* ** 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 @@ -93057,27 +91143,12 @@ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; - const char *zEntry; - char *zAltEntry = 0; void **aHandle; int nMsg = 300 + sqlite3Strlen30(zFile); - int ii; - - /* Shared library endings to try if zFile cannot be loaded as written */ - static const char *azEndings[] = { -#if SQLITE_OS_WIN - "dll" -#elif defined(__APPLE__) - "dylib" -#else - "so" -#endif - }; - if( pzErrMsg ) *pzErrMsg = 0; /* Ticket #1863. To avoid a creating security problems for older ** applications that relink against newer versions of SQLite, the @@ -93090,21 +91161,15 @@ *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } - zEntry = zProc ? zProc : "sqlite3_extension_init"; + if( zProc==0 ){ + zProc = "sqlite3_extension_init"; + } handle = sqlite3OsDlOpen(pVfs, zFile); -#if SQLITE_OS_UNIX || SQLITE_OS_WIN - for(ii=0; ii sqlite3_example_init - ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init - */ - if( xInit==0 && zProc==0 ){ - int iFile, iEntry, c; - int ncFile = sqlite3Strlen30(zFile); - zAltEntry = sqlite3_malloc(ncFile+30); - if( zAltEntry==0 ){ - sqlite3OsDlClose(pVfs, handle); - return SQLITE_NOMEM; - } - memcpy(zAltEntry, "sqlite3_", 8); - for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){} - iFile++; - if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; - for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ - if( sqlite3Isalpha(c) ){ - zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; - } - } - memcpy(zAltEntry+iEntry, "_init", 6); - zEntry = zAltEntry; - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - sqlite3OsDlSym(pVfs, handle, zEntry); - } + sqlite3OsDlSym(pVfs, handle, zProc); if( xInit==0 ){ if( pzErrMsg ){ - nMsg += sqlite3Strlen30(zEntry); + nMsg += sqlite3Strlen30(zProc); *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, - "no entry point [%s] in shared library [%s]", zEntry, zFile); + "no entry point [%s] in shared library [%s]", zProc,zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } + sqlite3OsDlClose(pVfs, handle); } - sqlite3OsDlClose(pVfs, handle); - sqlite3_free(zAltEntry); return SQLITE_ERROR; - } - sqlite3_free(zAltEntry); - if( xInit(db, &zErrmsg, &sqlite3Apis) ){ + }else if( xInit(db, &zErrmsg, &sqlite3Apis) ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); @@ -93557,13 +91585,10 @@ #endif #ifdef SQLITE_DEBUG { "sql_trace", SQLITE_SqlTrace }, { "vdbe_listing", SQLITE_VdbeListing }, { "vdbe_trace", SQLITE_VdbeTrace }, - { "vdbe_addoptrace", SQLITE_VdbeAddopTrace}, - { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing - | SQLITE_VdbeTrace }, #endif #ifndef SQLITE_OMIT_CHECK { "ignore_check_constraints", SQLITE_IgnoreChecks }, #endif /* The following is VERY experimental */ @@ -93692,11 +91717,11 @@ int iDb; /* Database index for */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ - Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ + Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */ if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; @@ -93775,16 +91800,15 @@ */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ - { OP_IfPos, 1, 8, 0}, + { OP_IfPos, 1, 7, 0}, { OP_Integer, 0, 2, 0}, { OP_Subtract, 1, 2, 1}, - { OP_IfPos, 1, 8, 0}, + { OP_IfPos, 1, 7, 0}, { OP_Integer, 0, 1, 0}, /* 6 */ - { OP_Noop, 0, 0, 0}, { OP_ResultRow, 1, 1, 0}, }; int addr; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeUsesBtree(v, iDb); @@ -94118,47 +92142,10 @@ pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else - /* - ** PRAGMA [database.]mmap_size(N) - ** - ** Used to set mapping size limit. The mapping size limit is - ** used to limit the aggregate size of all memory mapped regions of the - ** database file. If this parameter is set to zero, then memory mapping - ** is not used at all. If N is negative, then the default memory map - ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set. - ** The parameter N is measured in bytes. - ** - ** This value is advisory. The underlying VFS is free to memory map - ** as little or as much as it wants. Except, if N is set to 0 then the - ** upper layers will never invoke the xFetch interfaces to the VFS. - */ - if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){ - sqlite3_int64 sz; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - if( zRight ){ - int ii; - sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8); - if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; - if( pId2->n==0 ) db->szMmap = sz; - for(ii=db->nDb-1; ii>=0; ii--){ - if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ - sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz); - } - } - } - sz = -1; - if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){ -#if SQLITE_MAX_MMAP_SIZE==0 - sz = 0; -#endif - returnSingleInt(pParse, "mmap_size", sz); - } - }else - /* ** PRAGMA temp_store ** PRAGMA temp_store = "default"|"memory"|"file" ** ** Return or set the local value of the temp_store flag. Changing @@ -94362,18 +92349,15 @@ if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ - int i, k; + int i; int nHidden = 0; Column *pCol; - Index *pPk; - for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){} sqlite3VdbeSetNumCols(v, 6); pParse->nMem = 6; - sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC); sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC); @@ -94392,18 +92376,12 @@ if( pCol->zDflt ){ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, 5); } - if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ - k = 0; - }else if( pPk==0 ){ - k = 1; - }else{ - for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} - } - sqlite3VdbeAddOp2(v, OP_Integer, k, 6); + sqlite3VdbeAddOp2(v, OP_Integer, + (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } }else @@ -94415,11 +92393,10 @@ if( pIdx ){ int i; pTab = pIdx->pTable; sqlite3VdbeSetNumCols(v, 3); pParse->nMem = 3; - sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); for(i=0; inColumn; i++){ int cnum = pIdx->aiColumn[i]; @@ -94442,11 +92419,10 @@ pIdx = pTab->pIndex; if( pIdx ){ int i = 0; sqlite3VdbeSetNumCols(v, 3); pParse->nMem = 3; - sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); while(pIdx){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); @@ -94506,11 +92482,10 @@ pFK = pTab->pFKey; if( pFK ){ int i = 0; sqlite3VdbeSetNumCols(v, 8); pParse->nMem = 8; - sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC); sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC); @@ -94538,126 +92513,10 @@ pFK = pFK->pNextFrom; } } } }else -#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ - -#ifndef SQLITE_OMIT_FOREIGN_KEY -#ifndef SQLITE_OMIT_TRIGGER - if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){ - FKey *pFK; /* A foreign key constraint */ - Table *pTab; /* Child table contain "REFERENCES" keyword */ - Table *pParent; /* Parent table that child points to */ - Index *pIdx; /* Index in the parent table */ - int i; /* Loop counter: Foreign key number for pTab */ - int j; /* Loop counter: Field of the foreign key */ - HashElem *k; /* Loop counter: Next table in schema */ - int x; /* result variable */ - int regResult; /* 3 registers to hold a result row */ - int regKey; /* Register to hold key for checking the FK */ - int regRow; /* Registers to hold a row from pTab */ - int addrTop; /* Top of a loop checking foreign keys */ - int addrOk; /* Jump here if the key is OK */ - int *aiCols; /* child to parent column mapping */ - - if( sqlite3ReadSchema(pParse) ) goto pragma_out; - regResult = pParse->nMem+1; - pParse->nMem += 4; - regKey = ++pParse->nMem; - regRow = ++pParse->nMem; - v = sqlite3GetVdbe(pParse); - sqlite3VdbeSetNumCols(v, 4); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC); - sqlite3CodeVerifySchema(pParse, iDb); - k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); - while( k ){ - if( zRight ){ - pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); - k = 0; - }else{ - pTab = (Table*)sqliteHashData(k); - k = sqliteHashNext(k); - } - if( pTab==0 || pTab->pFKey==0 ) continue; - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; - sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); - sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName, - P4_TRANSIENT); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ - pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); - if( pParent==0 ) break; - pIdx = 0; - sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); - x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); - if( x==0 ){ - if( pIdx==0 ){ - sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); - }else{ - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); - sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); - sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); - } - }else{ - k = 0; - break; - } - } - if( pFK ) break; - if( pParse->nTabnTab = i; - addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ - pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); - assert( pParent!=0 ); - pIdx = 0; - aiCols = 0; - x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); - assert( x==0 ); - addrOk = sqlite3VdbeMakeLabel(v); - if( pIdx==0 ){ - int iKey = pFK->aCol[0].iFrom; - assert( iKey>=0 && iKeynCol ); - if( iKey!=pTab->iPKey ){ - sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); - sqlite3ColumnDefault(v, pTab, iKey, regRow); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); - sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, - sqlite3VdbeCurrentAddr(v)+3); - }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); - } - sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk); - sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); - }else{ - for(j=0; jnCol; j++){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, - aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); - } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey); - sqlite3VdbeChangeP4(v, -1, - sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); - sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); - } - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); - sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, - pFK->zTo, P4_TRANSIENT); - sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3); - sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); - sqlite3VdbeResolveLabel(v, addrOk); - sqlite3DbFree(db, aiCols); - } - sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); - sqlite3VdbeJumpHere(v, addrTop); - } - }else -#endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ if( zRight ){ @@ -94940,15 +92799,10 @@ ** PRAGMA [database.]schema_version = ** ** PRAGMA [database.]user_version ** PRAGMA [database.]user_version = ** - ** PRAGMA [database.]freelist_count = - ** - ** PRAGMA [database.]application_id - ** PRAGMA [database.]application_id = - ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both ** the schema-version and the user-version are 32-bit signed integers ** stored in the database header. ** @@ -94966,18 +92820,14 @@ ** applications for any purpose. */ if( sqlite3StrICmp(zLeft, "schema_version")==0 || sqlite3StrICmp(zLeft, "user_version")==0 || sqlite3StrICmp(zLeft, "freelist_count")==0 - || sqlite3StrICmp(zLeft, "application_id")==0 ){ int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ - case 'a': case 'A': - iCookie = BTREE_APPLICATION_ID; - break; case 'f': case 'F': iCookie = BTREE_FREE_PAGE_COUNT; break; case 's': case 'S': iCookie = BTREE_SCHEMA_VERSION; @@ -95162,11 +93012,11 @@ sqlite3_rekey(db, zKey, i/2); } }else #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){ + if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){ #ifdef SQLITE_HAS_CODEC if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ sqlite3_activate_see(&zRight[4]); } #endif @@ -95379,11 +93229,11 @@ assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being - ** initialized. zMasterName is the name of the master table. + ** initialised. zMasterName is the name of the master table. */ if( !OMIT_TEMPDB && iDb==1 ){ zMasterSchema = temp_master_schema; }else{ zMasterSchema = master_schema; @@ -95459,19 +93309,15 @@ ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ if( iDb==0 ){ -#ifndef SQLITE_OMIT_UTF16 u8 encoding; /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; ENC(db) = encoding; -#else - ENC(db) = SQLITE_UTF8; -#endif }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); @@ -95604,11 +93450,11 @@ if( rc ){ sqlite3ResetOneSchema(db, i); } } - /* Once all the other databases have been initialized, load the schema + /* Once all the other databases have been initialised, load the schema ** for the TEMP database. This is loaded last, as the TEMP database ** schema may contain references to objects in other databases. */ #ifndef SQLITE_OMIT_TEMPDB if( rc==SQLITE_OK && ALWAYS(db->nDb>1) @@ -95627,11 +93473,11 @@ return rc; } /* -** This routine is a no-op if the database schema is already initialized. +** This routine is a no-op if the database schema is already initialised. ** Otherwise, the schema is loaded. An error code is returned. */ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ int rc = SQLITE_OK; sqlite3 *db = pParse->db; @@ -95854,10 +93700,11 @@ azColName[i], SQLITE_STATIC); } } #endif + assert( db->init.busy==0 || saveSqlFlag==0 ); if( db->init.busy==0 ){ Vdbe *pVdbe = pParse->pVdbe; sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag); } if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ @@ -96124,11 +93971,11 @@ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ - u16 selFlags, /* Flag parameters, such as SF_Distinct */ + int isDistinct, /* true if the DISTINCT keyword is present */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ ){ Select *pNew; Select standin; @@ -96148,11 +93995,11 @@ pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; - pNew->selFlags = selFlags; + pNew->selFlags = isDistinct ? SF_Distinct : 0; pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; @@ -97404,11 +95251,13 @@ *paCol = aCol; for(i=0, pCol=aCol; ia[i].pExpr); + p = pEList->a[i].pExpr; + assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue) + || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 ); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS " phrase, use as the name */ zName = sqlite3DbStrDup(db, zName); }else{ Expr *pColExpr = p; /* The expression that is the result column name */ @@ -97442,13 +95291,10 @@ */ nName = sqlite3Strlen30(zName); for(j=cnt=0; j1 && sqlite3Isdigit(zName[k]); k--){} - if( zName[k]==':' ) nName = k; zName[nName] = 0; zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); sqlite3DbFree(db, zName); zName = zNewName; j = -1; @@ -97776,12 +95622,10 @@ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); - pPrior->iLimit = p->iLimit; - pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &dest); p->pLimit = 0; @@ -98405,17 +96249,16 @@ pKeyMerge->nField = (u16)nOrderBy; pKeyMerge->enc = ENC(db); for(i=0; ia[i].pExpr; - if( pTerm->flags & EP_Collate ){ - pColl = sqlite3ExprCollSeq(pParse, pTerm); + if( pTerm->flags & EP_ExpCollate ){ + pColl = pTerm->pColl; }else{ pColl = multiSelectCollSeq(pParse, p, aPermute[i]); - if( pColl==0 ) pColl = db->pDfltColl; - pOrderBy->a[i].pExpr = - sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName); + pTerm->flags |= EP_ExpCollate; + pTerm->pColl = pColl; } pKeyMerge->aColl[i] = pColl; pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder; } } @@ -98435,12 +96278,11 @@ if( op==TK_ALL ){ regPrev = 0; }else{ int nExpr = p->pEList->nExpr; assert( nOrderBy>=nExpr || db->mallocFailed ); - regPrev = pParse->nMem+1; - pParse->nMem += nExpr+1; + regPrev = sqlite3GetTempRange(pParse, nExpr+1); sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); pKeyDup = sqlite3DbMallocZero(db, sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) ); if( pKeyDup ){ pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr]; @@ -98615,12 +96457,17 @@ */ sqlite3VdbeResolveLabel(v, labelCmpr); sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO_HANDOFF); - sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); + + /* Release temporary registers + */ + if( regPrev ){ + sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1); + } /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); @@ -98677,10 +96524,13 @@ }else{ Expr *pNew; assert( pEList!=0 && pExpr->iColumnnExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0); + if( pNew && pExpr->pColl ){ + pNew->pColl = pExpr->pColl; + } sqlite3ExprDelete(db, pExpr); pExpr = pNew; } }else{ pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList); @@ -99029,19 +96879,16 @@ */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; - Expr *pOffset = p->pOffset; Select *pPrior = p->pPrior; p->pOrderBy = 0; p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; - p->pOffset = 0; pNew = sqlite3SelectDup(db, p, 0); - p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; p->pRightmost = 0; @@ -99167,13 +97014,14 @@ ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ pList = pParent->pEList; for(i=0; inExpr; i++){ if( pList->a[i].zName==0 ){ - char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan); - sqlite3Dequote(zName); - pList->a[i].zName = zName; + const char *zSpan = pList->a[i].zSpan; + if( ALWAYS(zSpan) ){ + pList->a[i].zName = sqlite3DbStrDup(db, zSpan); + } } } substExprList(db, pParent->pEList, iParent, pSub->pEList); if( isAgg ){ substExprList(db, pParent->pGroupBy, iParent, pSub->pEList); @@ -99230,47 +97078,38 @@ return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** Based on the contents of the AggInfo structure indicated by the first -** argument, this function checks if the following are true: -** -** * the query contains just a single aggregate function, -** * the aggregate function is either min() or max(), and -** * the argument to the aggregate function is a column value. -** -** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX -** is returned as appropriate. Also, *ppMinMax is set to point to the -** list of arguments passed to the aggregate before returning. -** -** Or, if the conditions above are not met, *ppMinMax is set to 0 and -** WHERE_ORDERBY_NORMAL is returned. -*/ -static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ - int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ - - *ppMinMax = 0; - if( pAggInfo->nFunc==1 ){ - Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */ - ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */ - - assert( pExpr->op==TK_AGG_FUNCTION ); - if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){ - const char *zFunc = pExpr->u.zToken; - if( sqlite3StrICmp(zFunc, "min")==0 ){ - eRet = WHERE_ORDERBY_MIN; - *ppMinMax = pEList; - }else if( sqlite3StrICmp(zFunc, "max")==0 ){ - eRet = WHERE_ORDERBY_MAX; - *ppMinMax = pEList; - } - } - } - - assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 ); - return eRet; +** Analyze the SELECT statement passed as an argument to see if it +** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if +** it is, or 0 otherwise. At present, a query is considered to be +** a min()/max() query if: +** +** 1. There is a single object in the FROM clause. +** +** 2. There is a single expression in the result set, and it is +** either min(x) or max(x), where x is a column reference. +*/ +static u8 minMaxQuery(Select *p){ + Expr *pExpr; + ExprList *pEList = p->pEList; + + if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL; + pExpr = pEList->a[0].pExpr; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; + if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0; + pEList = pExpr->x.pList; + if( pEList==0 || pEList->nExpr!=1 ) return 0; + if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){ + return WHERE_ORDERBY_MIN; + }else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){ + return WHERE_ORDERBY_MAX; + } + return WHERE_ORDERBY_NORMAL; } /* ** The select statement passed as the first argument is an aggregate query. ** The second argment is the associated aggregate-info object. This @@ -99329,73 +97168,10 @@ } pFrom->pIndex = pIdx; } return SQLITE_OK; } -/* -** Detect compound SELECT statements that use an ORDER BY clause with -** an alternative collating sequence. -** -** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ... -** -** These are rewritten as a subquery: -** -** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) -** ORDER BY ... COLLATE ... -** -** This transformation is necessary because the multiSelectOrderBy() routine -** above that generates the code for a compound SELECT with an ORDER BY clause -** uses a merge algorithm that requires the same collating sequence on the -** result columns as on the ORDER BY clause. See ticket -** http://www.sqlite.org/src/info/6709574d2a -** -** This transformation is only needed for EXCEPT, INTERSECT, and UNION. -** The UNION ALL operator works fine with multiSelectOrderBy() even when -** there are COLLATE terms in the ORDER BY. -*/ -static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ - int i; - Select *pNew; - Select *pX; - sqlite3 *db; - struct ExprList_item *a; - SrcList *pNewSrc; - Parse *pParse; - Token dummy; - - if( p->pPrior==0 ) return WRC_Continue; - if( p->pOrderBy==0 ) return WRC_Continue; - for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} - if( pX==0 ) return WRC_Continue; - a = p->pOrderBy->a; - for(i=p->pOrderBy->nExpr-1; i>=0; i--){ - if( a[i].pExpr->flags & EP_Collate ) break; - } - if( i<0 ) return WRC_Continue; - - /* If we reach this point, that means the transformation is required. */ - - pParse = pWalker->pParse; - db = pParse->db; - pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); - if( pNew==0 ) return WRC_Abort; - memset(&dummy, 0, sizeof(dummy)); - pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0); - if( pNewSrc==0 ) return WRC_Abort; - *pNew = *p; - p->pSrc = pNewSrc; - p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0)); - p->op = TK_SELECT; - p->pWhere = 0; - pNew->pGroupBy = 0; - pNew->pHaving = 0; - pNew->pOrderBy = 0; - p->pPrior = 0; - pNew->pLimit = 0; - pNew->pOffset = 0; - return WRC_Continue; -} /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: ** @@ -99424,20 +97200,18 @@ int i, j, k; SrcList *pTabList; ExprList *pEList; struct SrcList_item *pFrom; sqlite3 *db = pParse->db; - Expr *pE, *pRight, *pExpr; - u16 selFlags = p->selFlags; - p->selFlags |= SF_Expanded; if( db->mallocFailed ){ return WRC_Abort; } - if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ + if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } + p->selFlags |= SF_Expanded; pTabList = p->pSrc; pEList = p->pEList; /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. @@ -99476,16 +97250,10 @@ }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; - if( pTab->nRef==0xffff ){ - sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", - pTab->zName); - pFrom->pTab = 0; - return WRC_Abort; - } pTab->nRef++; #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( pTab->pSelect || IsVirtual(pTab) ){ /* We reach here if the named table is a really a view */ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; @@ -99517,11 +97285,11 @@ ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; knExpr; k++){ - pE = pEList->a[k].pExpr; + Expr *pE = pEList->a[k].pExpr; if( pE->op==TK_ALL ) break; assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break; } @@ -99535,22 +97303,14 @@ ExprList *pNew = 0; int flags = pParse->db->flags; int longNames = (flags & SQLITE_FullColNames)!=0 && (flags & SQLITE_ShortColNames)==0; - /* When processing FROM-clause subqueries, it is always the case - ** that full_column_names=OFF and short_column_names=ON. The - ** sqlite3ResultSetOfSelect() routine makes it so. */ - assert( (p->selFlags & SF_NestedFrom)==0 - || ((flags & SQLITE_FullColNames)==0 && - (flags & SQLITE_ShortColNames)!=0) ); - for(k=0; knExpr; k++){ - pE = a[k].pExpr; - pRight = pE->pRight; - assert( pE->op!=TK_DOT || pRight!=0 ); - if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){ + Expr *pE = a[k].pExpr; + assert( pE->op!=TK_DOT || pE->pRight!=0 ); + if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ pNew->a[pNew->nExpr-1].zName = a[k].zName; @@ -99561,56 +97321,44 @@ a[k].pExpr = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ - char *zTName = 0; /* text of name of TABLE */ + char *zTName; /* text of name of TABLE */ if( pE->op==TK_DOT ){ assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; + }else{ + zTName = 0; } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; - Select *pSub = pFrom->pSelect; char *zTabName = pFrom->zAlias; - const char *zSchemaName = 0; - int iDb; if( zTabName==0 ){ zTabName = pTab->zName; } if( db->mallocFailed ) break; - if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){ - pSub = 0; - if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ - continue; - } - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; - } + if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ + continue; + } + tableSeen = 1; for(j=0; jnCol; j++){ + Expr *pExpr, *pRight; char *zName = pTab->aCol[j].zName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ - assert( zName ); - if( zTName && pSub - && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0 - ){ - continue; - } - /* If a column is marked as 'hidden' (currently only possible ** for virtual tables), do not include it in the expanded ** result-set list. */ if( IsHiddenColumn(&pTab->aCol[j]) ){ assert(IsVirtual(pTab)); continue; } - tableSeen = 1; if( i>0 && zTName==0 ){ if( (pFrom->jointype & JT_NATURAL)!=0 && tableAndColumnIndex(pTabList, i, zName, 0, 0) ){ @@ -99629,14 +97377,10 @@ zToFree = 0; if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); - if( zSchemaName ){ - pLeft = sqlite3Expr(db, TK_ID, zSchemaName); - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0); - } if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zToFree = zColname; } }else{ @@ -99644,22 +97388,10 @@ } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sColname.z = zColname; sColname.n = sqlite3Strlen30(zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); - if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ - struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; - if( pSub ){ - pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); - testcase( pX->zSpan==0 ); - }else{ - pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", - zSchemaName, zTabName, zColname); - testcase( pX->zSpan==0 ); - } - pX->bSpanIsTab = 1; - } sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ @@ -99708,17 +97440,14 @@ ** The calling function can detect the problem by looking at pParse->nErr ** and/or pParse->db->mallocFailed. */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; - memset(&w, 0, sizeof(w)); - w.xSelectCallback = convertCompoundSelectToSubquery; + w.xSelectCallback = selectExpander; w.xExprCallback = exprWalkNoop; w.pParse = pParse; sqlite3WalkSelect(&w, pSelect); - w.xSelectCallback = selectExpander; - sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY /* @@ -99769,15 +97498,13 @@ ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; - memset(&w, 0, sizeof(w)); w.xSelectCallback = selectAddSubqueryTypeInfo; w.xExprCallback = exprWalkNoop; w.pParse = pParse; - w.bSelectDepthFirst = 1; sqlite3WalkSelect(&w, pSelect); #endif } @@ -99799,11 +97526,10 @@ NameContext *pOuterNC /* Name context for container */ ){ sqlite3 *db; if( NEVER(p==0) ) return; db = pParse->db; - if( db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); if( pParse->nErr || db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); if( pParse->nErr || db->mallocFailed ) return; @@ -100100,21 +97826,12 @@ SelectDest dest; Select *pSub = pItem->pSelect; int isAggSub; if( pSub==0 ) continue; - - /* Sometimes the code for a subquery will be generated more than - ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, - ** for example. In that case, do not regenerate the code to manifest - ** a view or the co-routine to implement a view. The first instance - ** is sufficient, though the subroutine to manifest the view does need - ** to be invoked again. */ if( pItem->addrFillSub ){ - if( pItem->viaCoroutine==0 ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); - } + sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); continue; } /* Increment Parse.nHeight by the height of the largest expression ** tree refered to by this, the parent select. The child select @@ -100131,48 +97848,10 @@ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; - }else if( pTabList->nSrc==1 && (p->selFlags & SF_Materialize)==0 - && OptimizationEnabled(db, SQLITE_SubqCoroutine) - ){ - /* Implement a co-routine that will return a single row of the result - ** set on each invocation. - */ - int addrTop; - int addrEof; - pItem->regReturn = ++pParse->nMem; - addrEof = ++pParse->nMem; - /* Before coding the OP_Goto to jump to the start of the main routine, - ** ensure that the jump to the verify-schema routine has already - ** been coded. Otherwise, the verify-schema would likely be coded as - ** part of the co-routine. If the main routine then accessed the - ** database before invoking the co-routine for the first time (for - ** example to initialize a LIMIT register from a sub-select), it would - ** be doing so without having verified the schema version and obtained - ** the required db locks. See ticket d6b36be38. */ - sqlite3CodeVerifySchema(pParse, -1); - sqlite3VdbeAddOp0(v, OP_Goto); - addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor); - sqlite3VdbeChangeP5(v, 1); - VdbeComment((v, "coroutine for %s", pItem->pTab->zName)); - pItem->addrFillSub = addrTop; - sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof); - sqlite3VdbeChangeP5(v, 1); - sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; - pItem->viaCoroutine = 1; - sqlite3VdbeChangeP2(v, addrTop, dest.iSdst); - sqlite3VdbeChangeP3(v, addrTop, dest.nSdst); - sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof); - sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn); - VdbeComment((v, "end %s", pItem->pTab->zName)); - sqlite3VdbeJumpHere(v, addrTop-1); - sqlite3ClearTempRegCache(pParse); }else{ /* Generate a subroutine that will fill an ephemeral table with ** the content of this subquery. pItem->addrFillSub will point ** to the address of the generated subroutine. pItem->regReturn ** is a register allocated to hold the subroutine return address @@ -100184,11 +97863,11 @@ pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); if( pItem->isCorrelated==0 ){ - /* If the subquery is not correlated and if we are not inside of + /* If the subquery is no correlated and if we are not inside of ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3CodeOnce(pParse); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); @@ -100707,11 +98386,11 @@ ** first iteration (since the first iteration of the loop is ** guaranteed to operate on the row with the minimum or maximum ** value of x, the only row required). ** ** A special flag must be passed to sqlite3WhereBegin() to slightly - ** modify behavior as follows: + ** modify behaviour as follows: ** ** + If the query is a "SELECT min(x)", then the loop coded by ** where.c should not iterate over any values with a NULL value ** for x. ** @@ -100719,21 +98398,15 @@ ** index or indices to use) should place a different priority on ** satisfying the 'ORDER BY' clause than it does in other cases. ** Refer to code and comments in where.c for details. */ ExprList *pMinMax = 0; - u8 flag = WHERE_ORDERBY_NORMAL; - - assert( p->pGroupBy==0 ); - assert( flag==0 ); - if( p->pHaving==0 ){ - flag = minMaxQuery(&sAggInfo, &pMinMax); - } - assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) ); - + u8 flag = minMaxQuery(p); if( flag ){ - pMinMax = sqlite3ExprListDup(db, pMinMax, 0); + assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) ); + assert( p->pEList->a[0].pExpr->x.pList->nExpr==1 ); + pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0); pDel = pMinMax; if( pMinMax && !db->mallocFailed ){ pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].pExpr->op = TK_COLUMN; } @@ -100885,14 +98558,11 @@ SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ if( p==0 ){ sqlite3ExplainPrintf(pVdbe, "(null-select)"); return; } - while( p->pPrior ){ - p->pPrior->pNext = p; - p = p->pPrior; - } + while( p->pPrior ) p = p->pPrior; sqlite3ExplainPush(pVdbe); while( p ){ explainOneSelect(pVdbe, p); p = p->pNext; if( p==0 ) break; @@ -101836,19 +99506,10 @@ ** INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy ** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy */ pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf; - /* Clear the cookieGoto flag. When coding triggers, the cookieGoto - ** variable is used as a flag to indicate to sqlite3ExprCodeConstants() - ** that it is not safe to refactor constants (this happens after the - ** start of the first loop in the SQL statement is coded - at that - ** point code may be conditionally executed, so it is no longer safe to - ** initialize constant register values). */ - assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 ); - pParse->cookieGoto = 0; - switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), @@ -102450,11 +100111,10 @@ break; } } if( j>=pTab->nCol ){ if( sqlite3IsRowid(pChanges->a[i].zName) ){ - j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); pParse->checkSchema = 1; @@ -102463,12 +100123,11 @@ } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, - j<0 ? "ROWID" : pTab->aCol[j].zName, - db->aDb[iDb].zName); + pTab->aCol[j].zName, db->aDb[iDb].zName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } @@ -102702,11 +100361,11 @@ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, addr); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are - ** required. This behavior - what happens when the row being updated + ** required. This behaviour - what happens when the row being updated ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); @@ -103003,11 +100662,10 @@ */ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){ Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0); - sqlite3VdbeUsesBtree(v, 0); } return; } /* @@ -103207,11 +100865,10 @@ static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ - BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 1==sqlite3BtreeIsInTrans(pMain) ); @@ -103764,10 +101421,11 @@ return SQLITE_NOMEM; } pVTable->db = db; pVTable->pMod = pMod; + assert( pTab->azModuleArg[1]==0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->azModuleArg[1] = db->aDb[iDb].zName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); @@ -103777,10 +101435,11 @@ pPriorCtx = db->pVtabCtx; db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); db->pVtabCtx = pPriorCtx; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + pTab->azModuleArg[1] = 0; if( SQLITE_OK!=rc ){ if( zErr==0 ){ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); }else { @@ -104468,12 +102127,12 @@ Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ union { int leftColumn; /* Column number of X in "X " */ - WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ - WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ + WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */ + WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */ } u; u16 eOperator; /* A WO_xx value describing */ u8 wtFlags; /* TERM_xxx bit flags. See below */ u8 nChild; /* Number of children that must disable us */ WhereClause *pWC; /* The clause this term is part of */ @@ -104510,10 +102169,11 @@ ** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { Parse *pParse; /* The parser context */ WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ + Bitmask vmask; /* Bitmask identifying virtual table cursors */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ u16 wctrlFlags; /* Might include WHERE_AND_ONLY */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ @@ -104596,11 +102256,10 @@ #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) #define WO_MATCH 0x040 #define WO_ISNULL 0x080 #define WO_OR 0x100 /* Two or more OR-connected terms */ #define WO_AND 0x200 /* Two or more AND-connected terms */ -#define WO_EQUIV 0x400 /* Of the form A==B, both columns */ #define WO_NOOP 0x800 /* This term does not restrict search space */ #define WO_ALL 0xfff /* Mask of all possible WO_* values */ #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */ @@ -104623,21 +102282,19 @@ #define WHERE_COLUMN_RANGE 0x00020000 /* xEXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ -#define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */ +#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */ #define WHERE_TOP_LIMIT 0x00100000 /* xEXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and xpMaskSet = pMaskSet; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; + pWC->vmask = 0; pWC->wctrlFlags = wctrlFlags; } /* Forward reference */ static void whereClauseClear(WhereClause*); @@ -104774,11 +102432,11 @@ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; - pTerm->pExpr = sqlite3ExprSkipCollate(p); + pTerm->pExpr = p; pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; return idx; } @@ -104934,36 +102592,27 @@ /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". ** -** If left/right precedence rules come into play when determining the -** collating +** If a collation sequence is associated with either the left or right ** side of the comparison, it remains associated with the same side after ** the commutation. So "Y collate NOCASE op X" becomes -** "X op Y". This is because any collation sequence on +** "X collate NOCASE op Y". This is because any collation sequence on ** the left hand side of a comparison overrides any collation sequence -** attached to the right. For the same reason the EP_Collate flag +** attached to the right. For the same reason the EP_ExpCollate flag ** is not commuted. */ static void exprCommute(Parse *pParse, Expr *pExpr){ - u16 expRight = (pExpr->pRight->flags & EP_Collate); - u16 expLeft = (pExpr->pLeft->flags & EP_Collate); + u16 expRight = (pExpr->pRight->flags & EP_ExpCollate); + u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate); assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); - if( expRight==expLeft ){ - /* Either X and Y both have COLLATE operator or neither do */ - if( expRight ){ - /* Both X and Y have COLLATE operators. Make sure X is always - ** used by clearing the EP_Collate flag from Y. */ - pExpr->pRight->flags &= ~EP_Collate; - }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ - /* Neither X nor Y have COLLATE operators, but X has a non-default - ** collating sequence. So add the EP_Collate marker on X to cause - ** it to be searched first. */ - pExpr->pLeft->flags |= EP_Collate; - } - } + pExpr->pRight->pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); + pExpr->pLeft->pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl); + pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft; + pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight; SWAP(Expr*,pExpr->pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ assert( TK_LT==TK_GT+2 ); assert( TK_GE==TK_LE+2 ); assert( TK_GT>TK_EQ ); @@ -105000,115 +102649,58 @@ /* ** Search for a term in the WHERE clause that is of the form "X " ** where X is a reference to the iColumn of table iCur and is one of ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. -** -** The term returned might by Y= if there is another constraint in -** the WHERE clause that specifies that X=Y. Any such constraints will be -** identified by the WO_EQUIV bit in the pTerm->eOperator field. The -** aEquiv[] array holds X and all its equivalents, with each SQL variable -** taking up two slots in aEquiv[]. The first slot is for the cursor number -** and the second is for the column number. There are 22 slots in aEquiv[] -** so that means we can look for X plus up to 10 other equivalent values. -** Hence a search for X will return if X=A1 and A1=A2 and A2=A3 -** and ... and A9=A10 and A10=. -** -** If there are multiple terms in the WHERE clause of the form "X " -** then try for the one with no dependencies on - in other words where -** is a constant expression of some kind. Only return entries of -** the form "X Y" where Y is a column in another table if no terms of -** the form "X " exist. If no terms with a constant RHS -** exist, try to return a term that does not use WO_EQUIV. */ static WhereTerm *findTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ - WhereTerm *pTerm; /* Term being examined as possible result */ - WhereTerm *pResult = 0; /* The answer to return */ - WhereClause *pWCOrig = pWC; /* Original pWC value */ - int j, k; /* Loop counters */ - Expr *pX; /* Pointer to an expression */ - Parse *pParse; /* Parsing context */ - int iOrigCol = iColumn; /* Original value of iColumn */ - int nEquiv = 2; /* Number of entires in aEquiv[] */ - int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */ - int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */ - + WhereTerm *pTerm; + int k; assert( iCur>=0 ); - aEquiv[0] = iCur; - aEquiv[1] = iColumn; - for(;;){ - for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){ - for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ - if( pTerm->leftCursor==iCur - && pTerm->u.leftColumn==iColumn - ){ - if( (pTerm->prereqRight & notReady)==0 - && (pTerm->eOperator & op & WO_ALL)!=0 - ){ - if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ - CollSeq *pColl; - char idxaff; - - pX = pTerm->pExpr; - pParse = pWC->pParse; - idxaff = pIdx->pTable->aCol[iOrigCol].affinity; - if( !sqlite3IndexAffinityOk(pX, idxaff) ){ - continue; - } - - /* Figure out the collation sequence required from an index for - ** it to be useful for optimising expression pX. Store this - ** value in variable pColl. - */ - assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight); - if( pColl==0 ) pColl = pParse->db->pDfltColl; - - for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ - if( NEVER(j>=pIdx->nColumn) ) return 0; - } - if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ - continue; - } - } - if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){ - pResult = pTerm; - goto findTerm_success; - }else if( pResult==0 ){ - pResult = pTerm; - } - } - if( (pTerm->eOperator & WO_EQUIV)!=0 - && nEquivpExpr->pRight); - assert( pX->op==TK_COLUMN ); - for(j=0; jiTable && aEquiv[j+1]==pX->iColumn ) break; - } - if( j==nEquiv ){ - aEquiv[j] = pX->iTable; - aEquiv[j+1] = pX->iColumn; - nEquiv += 2; - } - } - } - } - } - if( iEquiv>=nEquiv ) break; - iCur = aEquiv[iEquiv++]; - iColumn = aEquiv[iEquiv++]; - } -findTerm_success: - return pResult; + op &= WO_ALL; + for(; pWC; pWC=pWC->pOuter){ + for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ + if( pTerm->leftCursor==iCur + && (pTerm->prereqRight & notReady)==0 + && pTerm->u.leftColumn==iColumn + && (pTerm->eOperator & op)!=0 + ){ + if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){ + Expr *pX = pTerm->pExpr; + CollSeq *pColl; + char idxaff; + int j; + Parse *pParse = pWC->pParse; + + idxaff = pIdx->pTable->aCol[iColumn].affinity; + if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; + + /* Figure out the collation sequence required from an index for + ** it to be useful for optimising expression pX. Store this + ** value in variable pColl. + */ + assert(pX->pLeft); + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + assert(pColl || pParse->nErr); + + for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + if( NEVER(j>=pIdx->nColumn) ) return 0; + } + if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; + } + return pTerm; + } + } + } + return 0; } /* Forward reference */ static void exprAnalyze(SrcList*, WhereClause*, int); @@ -105290,11 +102882,11 @@ ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) ** ** CASE 1: ** -** If all subterms are of the form T.C=expr for some single column of C and +** If all subterms are of the form T.C=expr for some single column of C ** a single table T (as shown in example B above) then create a new virtual ** term that is an equivalent IN expression. In other words, if the term ** being analyzed is: ** ** x = expr1 OR expr2 = x OR x = expr3 @@ -105378,14 +102970,15 @@ /* ** Compute the set of tables that might satisfy cases 1 or 2. */ indexable = ~(Bitmask)0; - chngToIN = ~(Bitmask)0; + chngToIN = ~(pWC->vmask); for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ WhereAndInfo *pAndInfo; + assert( pOrTerm->eOperator==0 ); assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); chngToIN = 0; pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); if( pAndInfo ){ WhereClause *pAndWC; @@ -105420,11 +103013,11 @@ if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; b |= getMask(pMaskSet, pOther->leftCursor); } indexable &= b; - if( (pOrTerm->eOperator & WO_EQ)==0 ){ + if( pOrTerm->eOperator!=WO_EQ ){ chngToIN = 0; }else{ chngToIN &= b; } } @@ -105471,11 +103064,11 @@ ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ - assert( pOrTerm->eOperator & WO_EQ ); + assert( pOrTerm->eOperator==WO_EQ ); pOrTerm->wtFlags &= ~TERM_OR_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and ** current term is from the first iteration. So skip this term. */ assert( j==1 ); @@ -105497,21 +103090,21 @@ } if( i<0 ){ /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); - assert( IsPowerOfTwo(chngToIN) ); + assert( (chngToIN&(chngToIN-1))==0 ); assert( chngToIN==getMask(pMaskSet, iCursor) ); break; } testcase( j==1 ); /* We have found a candidate table and column. Check to see if that ** table and column is common to every term in the OR clause */ okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ - assert( pOrTerm->eOperator & WO_EQ ); + assert( pOrTerm->eOperator==WO_EQ ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.leftColumn!=iColumn ){ okToChngToIN = 0; }else{ @@ -105543,11 +103136,11 @@ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; - assert( pOrTerm->eOperator & WO_EQ ); + assert( pOrTerm->eOperator==WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; @@ -105572,10 +103165,11 @@ pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */ } } } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ + /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm @@ -105615,11 +103209,10 @@ return; } pTerm = &pWC->a[idxTerm]; pMaskSet = pWC->pMaskSet; pExpr = pTerm->pExpr; - assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ @@ -105641,23 +103234,21 @@ } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; - if( allowedOp(op) ){ - Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); - Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); - u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; + if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){ + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; if( pLeft->op==TK_COLUMN ){ pTerm->leftCursor = pLeft->iTable; pTerm->u.leftColumn = pLeft->iColumn; - pTerm->eOperator = operatorMask(op) & opMask; + pTerm->eOperator = operatorMask(op); } if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; Expr *pDup; - u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); @@ -105668,29 +103259,22 @@ pNew = &pWC->a[idxNew]; pNew->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; - if( pExpr->op==TK_EQ - && !ExprHasProperty(pExpr, EP_FromJoin) - && OptimizationEnabled(db, SQLITE_Transitive) - ){ - pTerm->eOperator |= WO_EQUIV; - eExtraOp = WO_EQUIV; - } }else{ pDup = pExpr; pNew = pTerm; } exprCommute(pParse, pDup); - pLeft = sqlite3ExprSkipCollate(pDup->pLeft); + pLeft = pDup->pLeft; pNew->leftCursor = pLeft->iTable; pNew->u.leftColumn = pLeft->iColumn; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; - pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; + pNew->eOperator = operatorMask(pDup->op); } } #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION /* If a term is the BETWEEN operator, create two new virtual terms @@ -105759,11 +103343,11 @@ Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ Expr *pNewExpr1; Expr *pNewExpr2; int idxNew1; int idxNew2; - Token sCollSeqName; /* Name of collating sequence */ + CollSeq *pColl; /* Collating sequence to use */ pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); if( !db->mallocFailed ){ u8 c, *pC; /* Last character before the first wildcard */ @@ -105781,23 +103365,20 @@ c = sqlite3UpperToLower[c]; } *pC = c + 1; } - sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; - sCollSeqName.n = 6; - pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); + pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, - sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), - pStr1, 0); + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl), + pStr1, 0); idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); - pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, - sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), - pStr2, 0); + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl), + pStr2, 0); idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; if( isComplete ){ @@ -105911,16 +103492,16 @@ ){ int i; const char *zColl = pIdx->azColl[iCol]; for(i=0; inExpr; i++){ - Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); + Expr *p = pList->a[i].pExpr; if( p->op==TK_COLUMN && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, p); if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } } @@ -105963,11 +103544,11 @@ ** matching "col=X" expression and the column is on the same table as pIdx, ** set the corresponding bit in variable mask. */ for(i=0; inExpr; i++){ WhereTerm *pTerm; - Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); + Expr *p = pDistinct->a[i].pExpr; if( p->op!=TK_COLUMN ) return 0; pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0); if( pTerm ){ Expr *pX = pTerm->pExpr; CollSeq *p1 = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); @@ -106015,11 +103596,11 @@ /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the ** current SELECT is a correlated sub-query. */ for(i=0; inExpr; i++){ - Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); + Expr *p = pDistinct->a[i].pExpr; if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; } /* Loop through all indices on the table, checking each to see if it makes ** the DISTINCT qualifier redundant. It does so if: @@ -106145,11 +103726,11 @@ return; } /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 + if( pTerm->eOperator==WO_OR && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; @@ -106166,11 +103747,11 @@ sBOI.ppIdxInfo = 0; for(pOrTerm=pOrWC->a; pOrTerma), (pTerm - pWC->a) )); - if( (pOrTerm->eOperator& WO_AND)!=0 ){ + if( pOrTerm->eOperator==WO_AND ){ sBOI.pWC = &pOrTerm->u.pAndInfo->wc; bestIndex(&sBOI); }else if( pOrTerm->leftCursor==iCur ){ WhereClause tempWC; tempWC.pParse = pWC->pParse; @@ -106227,11 +103808,11 @@ struct SrcList_item *pSrc, /* Table we are trying to access */ Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; - if( (pTerm->eOperator & WO_EQ)==0 ) return 0; + if( pTerm->eOperator!=WO_EQ ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; return 1; } @@ -106263,20 +103844,14 @@ } if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){ /* Automatic indices are disabled at run-time */ return; } - if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 - && (p->cost.plan.wsFlags & WHERE_COVER_SCAN)==0 - ){ + if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){ /* We already have some kind of index in use for this query. */ return; } - if( pSrc->viaCoroutine ){ - /* Cannot index a co-routine */ - return; - } if( pSrc->notIndexed ){ /* The NOT INDEXED clause appears in the SQL. */ return; } if( pSrc->isCorrelated ){ @@ -106489,14 +104064,14 @@ /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; - assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); - testcase( pTerm->eOperator & WO_IN ); - testcase( pTerm->eOperator & WO_ISNULL ); - if( pTerm->eOperator & (WO_ISNULL) ) continue; + assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); + testcase( pTerm->eOperator==WO_IN ); + testcase( pTerm->eOperator==WO_ISNULL ); + if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; nTerm++; } /* If the ORDER BY clause contains only columns in the current @@ -106540,32 +104115,29 @@ *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = pUsage; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - u8 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; - assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); - testcase( pTerm->eOperator & WO_IN ); - testcase( pTerm->eOperator & WO_ISNULL ); - if( pTerm->eOperator & (WO_ISNULL) ) continue; + assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); + testcase( pTerm->eOperator==WO_IN ); + testcase( pTerm->eOperator==WO_ISNULL ); + if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator & WO_ALL; - if( op==WO_IN ) op = WO_EQ; - pIdxCons[j].op = op; + pIdxCons[j].op = (u8)pTerm->eOperator; /* The direct assignment in the previous line is possible only because ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** following asserts verify this fact. */ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); - assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); + assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); j++; } for(i=0; ia[i].pExpr; pIdxOrderBy[i].iColumn = pExpr->iColumn; @@ -106647,11 +104219,10 @@ struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j; int nOrderBy; - int bAllowIN; /* Allow IN optimizations */ double rCost; /* Make sure wsFlags is initialized to some sane value. Otherwise, if the ** malloc in allocateIndexInfo() fails and this function returns leaving ** wsFlags in an uninitialized state, the caller may behave unpredictably. @@ -106682,110 +104253,63 @@ ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); assert( sqlite3GetVTable(pParse->db, pTab) ); - /* Try once or twice. On the first attempt, allow IN optimizations. - ** If an IN optimization is accepted by the virtual table xBestIndex - ** method, but the pInfo->aConstrainUsage.omit flag is not set, then - ** the query will not work because it might allow duplicate rows in - ** output. In that case, run the xBestIndex method a second time - ** without the IN constraints. Usually this loop only runs once. - ** The loop will exit using a "break" statement. - */ - for(bAllowIN=1; 1; bAllowIN--){ - assert( bAllowIN==0 || bAllowIN==1 ); - - /* Set the aConstraint[].usable fields and initialize all - ** output variables to zero. - ** - ** aConstraint[].usable is true for constraints where the right-hand - ** side contains only references to tables to the left of the current - ** table. In other words, if the constraint is of the form: - ** - ** column = expr - ** - ** and we are evaluating a join, then the constraint on column is - ** only valid if all tables referenced in expr occur to the left - ** of the table containing column. - ** - ** The aConstraints[] array contains entries for all constraints - ** on the current table. That way we only have to compute it once - ** even though we might try to pick the best index multiple times. - ** For each attempt at picking an index, the order of tables in the - ** join might be different so we have to recompute the usable flag - ** each time. - */ - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - pUsage = pIdxInfo->aConstraintUsage; - for(i=0; inConstraint; i++, pIdxCons++){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - if( (pTerm->prereqRight&p->notReady)==0 - && (bAllowIN || (pTerm->eOperator & WO_IN)==0) - ){ - pIdxCons->usable = 1; - }else{ - pIdxCons->usable = 0; - } - } - memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); - if( pIdxInfo->needToFreeIdxStr ){ - sqlite3_free(pIdxInfo->idxStr); - } - pIdxInfo->idxStr = 0; - pIdxInfo->idxNum = 0; - pIdxInfo->needToFreeIdxStr = 0; - pIdxInfo->orderByConsumed = 0; - /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); - nOrderBy = pIdxInfo->nOrderBy; - if( !p->pOrderBy ){ - pIdxInfo->nOrderBy = 0; - } - - if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ - return; - } - - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pIdxCons++){ - if( pUsage[i].argvIndex>0 ){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - p->cost.used |= pTerm->prereqRight; - if( (pTerm->eOperator & WO_IN)!=0 ){ - if( pUsage[i].omit==0 ){ - /* Do not attempt to use an IN constraint if the virtual table - ** says that the equivalent EQ constraint cannot be safely omitted. - ** If we do attempt to use such a constraint, some rows might be - ** repeated in the output. */ - break; - } - /* A virtual table that is constrained by an IN clause may not - ** consume the ORDER BY clause because (1) the order of IN terms - ** is not necessarily related to the order of output terms and - ** (2) Multiple outputs from a single IN value will not merge - ** together. */ - pIdxInfo->orderByConsumed = 0; - } - } - } - if( i>=pIdxInfo->nConstraint ) break; - } - - /* The orderByConsumed signal is only valid if all outer loops collectively - ** generate just a single row of output. - */ - if( pIdxInfo->orderByConsumed ){ - for(i=0; ii; i++){ - if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){ - pIdxInfo->orderByConsumed = 0; - } - } - } - + /* Set the aConstraint[].usable fields and initialize all + ** output variables to zero. + ** + ** aConstraint[].usable is true for constraints where the right-hand + ** side contains only references to tables to the left of the current + ** table. In other words, if the constraint is of the form: + ** + ** column = expr + ** + ** and we are evaluating a join, then the constraint on column is + ** only valid if all tables referenced in expr occur to the left + ** of the table containing column. + ** + ** The aConstraints[] array contains entries for all constraints + ** on the current table. That way we only have to compute it once + ** even though we might try to pick the best index multiple times. + ** For each attempt at picking an index, the order of tables in the + ** join might be different so we have to recompute the usable flag + ** each time. + */ + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + pUsage = pIdxInfo->aConstraintUsage; + for(i=0; inConstraint; i++, pIdxCons++){ + j = pIdxCons->iTermOffset; + pTerm = &pWC->a[j]; + pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1; + } + memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); + if( pIdxInfo->needToFreeIdxStr ){ + sqlite3_free(pIdxInfo->idxStr); + } + pIdxInfo->idxStr = 0; + pIdxInfo->idxNum = 0; + pIdxInfo->needToFreeIdxStr = 0; + pIdxInfo->orderByConsumed = 0; + /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); + nOrderBy = pIdxInfo->nOrderBy; + if( !p->pOrderBy ){ + pIdxInfo->nOrderBy = 0; + } + + if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ + return; + } + + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; inConstraint; i++){ + if( pUsage[i].argvIndex>0 ){ + p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; + } + } + /* If there is an ORDER BY clause, and the selected virtual table index ** does not satisfy it, increase the cost of the scan accordingly. This ** matches the processing for non-virtual tables in bestBtreeIndex(). */ rCost = pIdxInfo->estimatedCost; @@ -107076,28 +104600,28 @@ u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); - assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK ){ iLower = a[0]; - if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1]; + if( pLower->eOperator==WO_GT ) iLower += a[1]; } sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); - assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK ){ iUpper = a[0]; - if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1]; + if( pUpper->eOperator==WO_LE ) iUpper += a[1]; } sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK ){ if( iUpper<=iLower ){ @@ -107283,12 +104807,11 @@ */ static int isSortingIndex( WhereBestIdx *p, /* Best index search context */ Index *pIdx, /* The index we are testing */ int base, /* Cursor number for the table to be sorted */ - int *pbRev, /* Set to 1 for reverse-order scan of pIdx */ - int *pbObUnique /* ORDER BY column values will different in every row */ + int *pbRev /* Set to 1 for reverse-order scan of pIdx */ ){ int i; /* Number of pIdx terms used */ int j; /* Number of ORDER BY terms satisfied */ int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */ int nTerm; /* Number of ORDER BY terms */ @@ -107298,32 +104821,25 @@ Parse *pParse = p->pParse; /* Parser context */ sqlite3 *db = pParse->db; /* Database connection */ int nPriorSat; /* ORDER BY terms satisfied by outer loops */ int seenRowid = 0; /* True if an ORDER BY rowid term is seen */ int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */ - int outerObUnique; /* Outer loops generate different values in - ** every row for the ORDER BY columns */ if( p->i==0 ){ nPriorSat = 0; - outerObUnique = 1; }else{ - u32 wsFlags = p->aLevel[p->i-1].plan.wsFlags; nPriorSat = p->aLevel[p->i-1].plan.nOBSat; - if( (wsFlags & WHERE_ORDERED)==0 ){ + if( (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){ /* This loop cannot be ordered unless the next outer loop is ** also ordered */ return nPriorSat; } if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){ /* Only look at the outer-most loop if the OrderByIdxJoin ** optimization is disabled */ return nPriorSat; } - testcase( wsFlags & WHERE_OB_UNIQUE ); - testcase( wsFlags & WHERE_ALL_UNIQUE ); - outerObUnique = (wsFlags & (WHERE_OB_UNIQUE|WHERE_ALL_UNIQUE))!=0; } pOrderBy = p->pOrderBy; assert( pOrderBy!=0 ); if( pIdx->bUnordered ){ /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot @@ -107360,11 +104876,11 @@ WhereTerm *pConstraint; /* A constraint in the WHERE clause */ /* If the next term of the ORDER BY clause refers to anything other than ** a column in the "base" table, then this index will not be of any ** further use in handling the ORDER BY. */ - pOBExpr = sqlite3ExprSkipCollate(pOBItem->pExpr); + pOBExpr = pOBItem->pExpr; if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){ break; } /* Find column number and collating sequence for the next entry @@ -107386,11 +104902,11 @@ /* Check to see if the column number and collating sequence of the ** index match the column number and collating sequence of the ORDER BY ** clause entry. Set isMatch to 1 if they both match. */ if( pOBExpr->iColumn==iColumn ){ if( zColl ){ - pColl = sqlite3ExprCollSeq(pParse, pOBItem->pExpr); + pColl = sqlite3ExprCollSeq(pParse, pOBExpr); if( !pColl ) pColl = db->pDfltColl; isMatch = sqlite3StrICmp(pColl->zName, zColl)==0; }else{ isMatch = 1; } @@ -107409,13 +104925,16 @@ ** if there are any X= or X IS NULL constraints in the WHERE clause. */ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady, WO_EQ|WO_ISNULL|WO_IN, pIdx); if( pConstraint==0 ){ isEq = 0; - }else if( (pConstraint->eOperator & WO_IN)!=0 ){ - isEq = 0; - }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){ + }else if( pConstraint->eOperator==WO_IN ){ + /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY + ** because we do not know in what order the values on the RHS of the IN + ** operator will occur. */ + break; + }else if( pConstraint->eOperator==WO_ISNULL ){ uniqueNotNull = 0; isEq = 1; /* "X IS NULL" means X has only a single value */ }else if( pConstraint->prereqRight==0 ){ isEq = 1; /* Constraint "X=constant" means X has only a single value */ }else{ @@ -107461,38 +104980,23 @@ testcase( isEq==2 ); testcase( isEq==3 ); uniqueNotNull = 0; } } - if( seenRowid ){ - uniqueNotNull = 1; - }else if( uniqueNotNull==0 || inColumn ){ - uniqueNotNull = 0; - } /* If we have not found at least one ORDER BY term that matches the ** index, then show no progress. */ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat; - /* Either the outer queries must generate rows where there are no two - ** rows with the same values in all ORDER BY columns, or else this - ** loop must generate just a single row of output. Example: Suppose - ** the outer loops generate A=1 and A=1, and this loop generates B=3 - ** and B=4. Then without the following test, ORDER BY A,B would - ** generate the wrong order output: 1,3 1,4 1,3 1,4 - */ - if( outerObUnique==0 && uniqueNotNull==0 ) return nPriorSat; - *pbObUnique = uniqueNotNull; - /* Return the necessary scan order back to the caller */ *pbRev = sortOrder & 1; /* If there was an "ORDER BY rowid" term that matched, or it is only ** possible for a single row from this table to match, then skip over ** any additional ORDER BY terms dealing with this table. */ - if( uniqueNotNull ){ + if( seenRowid || (uniqueNotNull && i>=pIdx->nColumn) ){ /* Advance j over additional ORDER BY terms associated with base */ WhereMaskSet *pMS = p->pWC->pMaskSet; Bitmask m = ~getMask(pMS, base); while( ja[j].pExpr)&m)==0 ){ j++; @@ -107521,11 +105025,11 @@ ** the SQL statement, then this function only considers plans using the ** named index. If no such plan is found, then the returned cost is ** SQLITE_BIG_DBL. If a plan is found that uses the named index, ** then the cost is calculated in the usual way. ** -** If a NOT INDEXED clause was attached to the table +** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table ** in the SELECT statement, then no indexes are considered. However, the ** selected plan may still take advantage of the built-in rowid primary key ** index. */ static void bestBtreeIndex(WhereBestIdx *p){ @@ -107539,15 +105043,10 @@ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */ - int nPriorSat; /* ORDER BY terms satisfied by outer loops */ - int nOrderBy; /* Number of ORDER BY terms */ - char bSortInit; /* Initializer for bSort in inner loop */ - char bDistInit; /* Initializer for bDist in inner loop */ - /* Initialize the cost to a worst-case value */ memset(&p->cost, 0, sizeof(p->cost)); p->cost.rCost = SQLITE_BIG_DBL; @@ -107593,21 +105092,10 @@ ); eqTermMask = WO_EQ|WO_IN; pIdx = 0; } - nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0; - if( p->i ){ - nPriorSat = p->aLevel[p->i-1].plan.nOBSat; - bSortInit = nPriorSat0; - bDistInit = p->pDistinct!=0; - } - /* Loop over all indices looking for the best one to use */ for(; pProbe; pIdx=pProbe=pProbe->pNext){ const tRowcnt * const aiRowEst = pProbe->aiRowEst; WhereCost pc; /* Cost of using pProbe */ @@ -107681,13 +105169,15 @@ */ int bInEst = 0; /* True if "x IN (SELECT...)" seen */ int nInMul = 1; /* Number of distinct equalities to lookup */ double rangeDiv = (double)1; /* Estimated reduction in search space */ int nBound = 0; /* Number of range constraints seen */ - char bSort = bSortInit; /* True if external sort required */ - char bDist = bDistInit; /* True if index cannot help with DISTINCT */ - char bLookup = 0; /* True if not a covering index */ + int bSort; /* True if external sort required */ + int bDist; /* True if index cannot help with DISTINCT */ + int bLookup = 0; /* True if not a covering index */ + int nPriorSat; /* ORDER BY terms satisfied by outer loops */ + int nOrderBy; /* Number of ORDER BY terms */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE_ENABLE_STAT3 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif @@ -107694,11 +105184,20 @@ WHERETRACE(( " %s(%s):\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk") )); memset(&pc, 0, sizeof(pc)); - pc.plan.nOBSat = nPriorSat; + nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0; + if( p->i ){ + nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat; + bSort = nPriorSat0; + bDist = p->pDistinct!=0; + } /* Determine the values of pc.plan.nEq and nInMul */ for(pc.plan.nEq=0; pc.plan.nEqnColumn; pc.plan.nEq++){ int j = pProbe->aiColumn[pc.plan.nEq]; pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx); @@ -107729,12 +105228,12 @@ ** constraint for all columns in the index, then this search will find ** at most a single row. In this case set the WHERE_UNIQUE flag to ** indicate this to the caller. ** ** Otherwise, if the search may find more than one row, test to see if - ** there is a range constraint on indexed column (pc.plan.nEq+1) that - ** can be optimized using the index. + ** there is a range constraint on indexed column (pc.plan.nEq+1) that can be + ** optimized using the index. */ if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){ testcase( pc.plan.wsFlags & WHERE_COLUMN_IN ); testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL ); if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ @@ -107772,18 +105271,16 @@ ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but ** the index will scan rows in a different order, set the bSort ** variable. */ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; - int bObUnique = 0; - WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat)); - pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique); - WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n", - bRev, bObUnique, pc.plan.nOBSat)); - if( nPriorSat before isSortingIndex: nPriorSat=%d\n",nPriorSat)); + pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev); + WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n", + bRev, pc.plan.nOBSat)); + if( nPriorSat(double)1 && pc.plan.nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){ assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ - testcase( pFirstTerm->eOperator & WO_EQ ); - testcase( pFirstTerm->eOperator & WO_EQUIV ); - testcase( pFirstTerm->eOperator & WO_ISNULL ); + testcase( pFirstTerm->eOperator==WO_EQ ); + testcase( pFirstTerm->eOperator==WO_ISNULL ); whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &pc.plan.nRow); }else if( bInEst==0 ){ - assert( pFirstTerm->eOperator & WO_IN ); + assert( pFirstTerm->eOperator==WO_IN ); whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &pc.plan.nRow); } } #endif /* SQLITE_ENABLE_STAT3 */ @@ -107873,12 +105369,11 @@ ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do ** not give us data on the relative sizes of table and index records. ** So this computation assumes table records are about twice as big ** as index records */ - if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED|WHERE_OB_UNIQUE)) - ==WHERE_IDX_ONLY + if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED))==WHERE_IDX_ONLY && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan) ){ /* This index is not useful for indexing, but it is a covering index. @@ -107995,11 +105490,11 @@ ** more selective intentionally because of the subjective ** observation that indexed range constraints really are more ** selective in practice, on average. */ pc.plan.nRow /= 3; } - }else if( (pTerm->eOperator & WO_NOOP)==0 ){ + }else if( pTerm->eOperator!=WO_NOOP ){ /* Any other expression lowers the output row count by half */ pc.plan.nRow /= 2; } } if( pc.plan.nRow<2 ) pc.plan.nRow = 2; @@ -108034,11 +105529,11 @@ } /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag ** is set, then reverse the order that the index will be scanned ** in. This is used for application testing, to help find cases - ** where application behavior depends on the (undefined) order that + ** where application behaviour depends on the (undefined) order that ** SQLite outputs rows in in the absence of an ORDER BY clause. */ if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ p->cost.plan.wsFlags |= WHERE_REVERSE; } @@ -108047,13 +105542,12 @@ assert( pSrc->pIndex==0 || p->cost.plan.u.pIdx==0 || p->cost.plan.u.pIdx==pSrc->pIndex ); - WHERETRACE((" best index is %s cost=%.1f\n", - p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk", - p->cost.rCost)); + WHERETRACE((" best index is: %s\n", + p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk")); bestOrClauseIndex(p); bestAutomaticIndex(p); p->cost.plan.wsFlags |= eqTermMask; } @@ -108074,12 +105568,11 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(p->pSrc->pTab) ){ sqlite3_index_info *pIdxInfo = 0; p->ppIdxInfo = &pIdxInfo; bestVirtualIndex(p); - assert( pIdxInfo!=0 || p->pParse->db->mallocFailed ); - if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){ + if( pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); } sqlite3DbFree(p->pParse->db, pIdxInfo); }else #endif @@ -108181,12 +105674,11 @@ ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ - WhereLevel *pLevel, /* The level of the FROM clause we are working on */ - int iEq, /* Index of the equality term within this level */ + WhereLevel *pLevel, /* When level of the FROM clause we are working on */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ @@ -108200,30 +105692,16 @@ #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; struct InLoop *pIn; - u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; - - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 - && pLevel->plan.u.pIdx->aSortOrder[iEq] - ){ - testcase( iEq==0 ); - testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 ); - testcase( iEq>0 && iEq+1plan.u.pIdx->nColumn ); - testcase( bRev ); - bRev = !bRev; - } + assert( pX->op==TK_IN ); iReg = iTarget; eType = sqlite3FindInIndex(pParse, pX, 0); - if( eType==IN_INDEX_INDEX_DESC ){ - testcase( bRev ); - bRev = !bRev; - } iTab = pX->iTable; - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); + sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); assert( pLevel->plan.wsFlags & WHERE_IN_ABLE ); if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } pLevel->u.in.nIn++; @@ -108237,11 +105715,10 @@ if( eType==IN_INDEX_ROWID ){ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); }else{ pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); } - pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; sqlite3VdbeAddOp1(v, OP_IsNull, iReg); }else{ pLevel->u.in.nIn = 0; } #endif @@ -108332,11 +105809,11 @@ if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ - r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j); + r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ @@ -108542,11 +106019,10 @@ struct SrcList_item *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ - Bitmask newNotReady; /* Return value */ pParse = pWInfo->pParse; v = pParse->pVdbe; pWC = pWInfo->pWC; pLevel = &pWInfo->a[iLevel]; @@ -108553,11 +106029,10 @@ pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0 && (wctrlFlags & WHERE_FORCE_TABLE)==0; - VdbeNoopComment((v, "Begin Join Loop %d", iLevel)); /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the ** loop. @@ -108578,56 +106053,38 @@ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN no-match flag")); } - /* Special case of a FROM clause subquery implemented as a co-routine */ - if( pTabItem->viaCoroutine ){ - int regYield = pTabItem->regReturn; - sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield); - pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield); - VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName)); - sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk); - pLevel->op = OP_Goto; - }else - #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 0: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ - int addrNotFound; sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; int nConstraint = pVtabIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pVtabIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pVtabIdx->aConstraint; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); - addrNotFound = pLevel->addrBrk; for(j=1; j<=nConstraint; j++){ for(k=0; ka[aConstraint[k].iTermOffset]; - if( pTerm->eOperator & WO_IN ){ - codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget); - addrNotFound = pLevel->addrNxt; - }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); - } + int iTerm = aConstraint[k].iTermOffset; + sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1); break; } } if( k==nConstraint ) break; } sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); - sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr, + sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr, pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); pVtabIdx->needToFreeIdxStr = 0; for(j=0; jpExpr!=0 ); + assert( pTerm->leftCursor==iCur ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ - iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg); + iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); - sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){ /* Case 2: We have an inequality comparison against the ROWID field. @@ -109041,11 +106498,11 @@ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ pTerm = pLevel->plan.u.pTerm; assert( pTerm!=0 ); - assert( pTerm->eOperator & WO_OR ); + assert( pTerm->eOperator==WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pLevel->op = OP_Return; pLevel->p1 = regReturn; @@ -109096,14 +106553,10 @@ ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. - ** - ** This optimization also only applies if the (x1 OR x2 OR ...) term - ** is not contained in the ON clause of a LEFT JOIN. - ** See ticket http://www.sqlite.org/src/info/f2369304e4 */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTermnTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; @@ -109118,14 +106571,14 @@ } } for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; - if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ + if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; - if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ + if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, @@ -109208,11 +106661,11 @@ pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } - newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur); + notReady &= ~getMask(pWC->pMaskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. ** ** IMPLEMENTATION-OF: R-49525-50935 Terms that cannot be satisfied through @@ -109222,11 +106675,11 @@ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */ testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & newNotReady)!=0 ){ + if( (pTerm->prereqAll & notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); pWInfo->untestedTerms = 1; continue; } @@ -109237,37 +106690,10 @@ } sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } - /* Insert code to test for implied constraints based on transitivity - ** of the "==" operator. - ** - ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" - ** and we are coding the t1 loop and the t2 loop has not yet coded, - ** then we cannot use the "t1.a=t2.b" constraint, but we can code - ** the implied "t1.a=123" constraint. - */ - for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE; - WhereTerm *pAlt; - Expr sEq; - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue; - if( pTerm->leftCursor!=iCur ) continue; - pE = pTerm->pExpr; - assert( !ExprHasProperty(pE, EP_FromJoin) ); - assert( (pTerm->prereqRight & newNotReady)!=0 ); - pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); - if( pAlt==0 ) continue; - if( pAlt->wtFlags & (TERM_CODED) ) continue; - VdbeNoopComment((v, "begin transitive constraint")); - sEq = *pAlt->pExpr; - sEq.pLeft = pE->pLeft; - sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL); - } - /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); @@ -109276,11 +106702,11 @@ sqlite3ExprCacheClear(pParse); for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */ testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & newNotReady)!=0 ){ + if( (pTerm->prereqAll & notReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); @@ -109287,11 +106713,11 @@ pTerm->wtFlags |= TERM_CODED; } } sqlite3ReleaseTempReg(pParse, iReleaseReg); - return newNotReady; + return notReady; } #if defined(SQLITE_TEST) /* ** The following variable holds a text description of query plan generated @@ -109522,18 +106948,29 @@ ** is (X-1). An expression from the ON clause of a LEFT JOIN can use ** its Expr.iRightJoinTable value to find the bitmask of the right table ** of the join. Subtracting one from the right table bitmask gives a ** bitmask for all tables to the left of the join. Knowing the bitmask ** for all tables to the left of a left join is important. Ticket #3015. + ** + ** Configure the WhereClause.vmask variable so that bits that correspond + ** to virtual table cursors are set. This is used to selectively disable + ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful + ** with virtual tables. ** ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_ONETABLE_ONLY flag is set. */ + assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 ); for(ii=0; iinSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){ + sWBI.pWC->vmask |= ((Bitmask)1 << ii); + } +#endif } #ifndef NDEBUG { Bitmask toTheLeft = 0; for(ii=0; iinSrc; ii++){ @@ -109589,11 +107026,10 @@ Index *pIdx; /* Index for FROM table at pTabItem */ int j; /* For looping over FROM tables */ int bestJ = -1; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ int isOptimal; /* Iterator for optimal/non-optimal search */ - int ckOptimal; /* Do the optimal scan check */ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ memset(&bestPlan, 0, sizeof(bestPlan)); bestPlan.rCost = SQLITE_BIG_DBL; @@ -109624,12 +107060,14 @@ ** ** The second loop iteration is only performed if no optimal scan ** strategies were found by the first iteration. This second iteration ** is used to search for the lowest cost scan overall. ** - ** Without the optimal scan step (the first iteration) a suboptimal - ** plan might be chosen for queries like this: + ** Previous versions of SQLite performed only the second iteration - + ** the next outermost loop was always that with the lowest overall + ** cost. However, this meant that SQLite could select the wrong plan + ** for scripts such as the following: ** ** CREATE TABLE t1(a, b); ** CREATE TABLE t2(c, d); ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a; ** @@ -109640,45 +107078,21 @@ ** algorithm may choose to use t2 for the outer loop, which is a much ** costlier approach. */ nUnconstrained = 0; notIndexed = 0; - - /* The optimal scan check only occurs if there are two or more tables - ** available to be reordered */ - if( iFrom==nTabList-1 ){ - ckOptimal = 0; /* Common case of just one table in the FROM clause */ - }else{ - ckOptimal = -1; + for(isOptimal=(iFrom=0 && bestJ<0; isOptimal--){ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jjointype & (JT_LEFT|JT_CROSS))!=0; + if( j!=iFrom && doNotReorder ) break; m = getMask(pMaskSet, sWBI.pSrc->iCursor); if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } - if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break; - if( ++ckOptimal ) break; - if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; - } - } - assert( ckOptimal==0 || ckOptimal==1 ); - - for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){ - for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jiFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){ - /* This break and one like it in the ckOptimal computation loop - ** above prevent table reordering across LEFT and CROSS JOINs. - ** The LEFT JOIN case is necessary for correctness. The prohibition - ** against reordering across a CROSS JOIN is an SQLite feature that - ** allows the developer to control table reordering */ - break; - } - m = getMask(pMaskSet, sWBI.pSrc->iCursor); - if( (m & sWBI.notValid)==0 ){ - assert( j>iFrom ); - continue; - } sWBI.notReady = (isOptimal ? m : sWBI.notValid); if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n", j, sWBI.pSrc->pTab->zName, isOptimal)); @@ -109701,32 +107115,19 @@ || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex ); if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } - if( isOptimal ){ - pWInfo->a[j].rOptCost = sWBI.cost.rCost; - }else if( ckOptimal ){ - /* If two or more tables have nearly the same outer loop cost, but - ** very different inner loop (optimal) cost, we want to choose - ** for the outer loop that table which benefits the least from - ** being in the inner loop. The following code scales the - ** outer loop cost estimate to accomplish that. */ - WHERETRACE((" scaling cost from %.1f to %.1f\n", - sWBI.cost.rCost, - sWBI.cost.rCost/pWInfo->a[j].rOptCost)); - sWBI.cost.rCost /= pWInfo->a[j].rOptCost; - } /* Conditions under which this table becomes the best so far: ** ** (1) The table must not depend on other tables that have not ** yet run. (In other words, it must not depend on tables ** in inner loops.) ** - ** (2) (This rule was removed on 2012-11-09. The scaling of the - ** cost using the optimal scan cost made this rule obsolete.) + ** (2) A full-table-scan plan cannot supercede indexed plan unless + ** the full-table-scan is an "optimal" plan as defined above. ** ** (3) All tables have an INDEXED BY clause or this table lacks an ** INDEXED BY clause or this table uses the specific ** index specified by its INDEXED BY clause. This rule ensures ** that a best-so-far is always selected even if an impossible @@ -109737,10 +107138,13 @@ ** ** (4) The plan cost must be lower than prior plans, where "cost" ** is defined by the compareCost() function above. */ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ + && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ + || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 + || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ ){ WHERETRACE((" === table %d (%s) is best so far\n" @@ -109749,23 +107153,15 @@ sWBI.cost.rCost, sWBI.cost.plan.nRow, sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags)); bestPlan = sWBI.cost; bestJ = j; } - - /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that - ** table y (and not table z) is always the next inner loop inside - ** of table x. */ - if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; + if( doNotReorder ) break; } } assert( bestJ>=0 ); assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); - assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 ); - testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); - testcase( bestJ>iFrom && bestJa[bestJ+1].jointype & JT_LEFT)!=0 ); WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", bestJ, pTabList->a[bestJ].pTab->zName, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow, bestPlan.plan.nOBSat, bestPlan.plan.wsFlags)); @@ -109864,12 +107260,10 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); - }else if( IsVirtual(pTab) ){ - /* noop */ }else #endif if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; @@ -110013,11 +107407,11 @@ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); - sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); + sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->addrInTop); sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } sqlite3DbFree(db, pLevel->u.in.aInLoop); } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); @@ -110321,11 +107715,10 @@ Expr* yy122; Select* yy159; IdList* yy180; struct {int value; int mask;} yy207; u8 yy258; - u16 yy305; struct LikeOp yy318; TriggerStep* yy327; ExprSpan yy342; SrcList* yy347; int yy392; @@ -112272,19 +109665,22 @@ case 82: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==82); case 84: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==84); case 86: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==86); case 98: /* defer_subclause_opt ::= */ yytestcase(yyruleno==98); case 109: /* ifexists ::= */ yytestcase(yyruleno==109); + case 120: /* distinct ::= ALL */ yytestcase(yyruleno==120); + case 121: /* distinct ::= */ yytestcase(yyruleno==121); case 221: /* between_op ::= BETWEEN */ yytestcase(yyruleno==221); case 224: /* in_op ::= IN */ yytestcase(yyruleno==224); {yygotominor.yy392 = 0;} break; case 29: /* ifnotexists ::= IF NOT EXISTS */ case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30); case 70: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==70); case 85: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==85); case 108: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==108); + case 119: /* distinct ::= DISTINCT */ yytestcase(yyruleno==119); case 222: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==222); case 225: /* in_op ::= NOT IN */ yytestcase(yyruleno==225); {yygotominor.yy392 = 1;} break; case 32: /* create_table_args ::= LP columnlist conslist_opt RP */ @@ -112520,19 +109916,12 @@ case 116: /* multiselect_op ::= UNION ALL */ {yygotominor.yy392 = TK_ALL;} break; case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yygotominor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy305,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset); -} - break; - case 119: /* distinct ::= DISTINCT */ -{yygotominor.yy305 = SF_Distinct;} - break; - case 120: /* distinct ::= ALL */ - case 121: /* distinct ::= */ yytestcase(yyruleno==121); -{yygotominor.yy305 = 0;} + yygotominor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset); +} break; case 122: /* sclp ::= selcollist COMMA */ case 246: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==246); {yygotominor.yy442 = yymsp[-1].minor.yy442;} break; @@ -112598,26 +109987,14 @@ break; case 136: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 && yymsp[0].minor.yy180==0 ){ yygotominor.yy347 = yymsp[-4].minor.yy347; - }else if( yymsp[-4].minor.yy347->nSrc==1 ){ - yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); - if( yygotominor.yy347 ){ - struct SrcList_item *pNew = &yygotominor.yy347->a[yygotominor.yy347->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy347->a; - pNew->zName = pOld->zName; - pNew->zDatabase = pOld->zDatabase; - pNew->pSelect = pOld->pSelect; - pOld->zName = pOld->zDatabase = 0; - pOld->pSelect = 0; - } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,SF_NestedFrom,0,0); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,0,0,0); yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); } } break; case 137: /* dbnm ::= */ @@ -112828,11 +110205,11 @@ spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } break; case 194: /* expr ::= expr COLLATE ids */ { - yygotominor.yy342.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0); + yygotominor.yy342.pExpr = sqlite3ExprSetCollByToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0); yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart; yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; case 195: /* expr ::= CAST LP expr AS typetoken RP */ @@ -112846,11 +110223,11 @@ if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); } yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0); spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy305 && yygotominor.yy342.pExpr ){ + if( yymsp[-2].minor.yy392 && yygotominor.yy342.pExpr ){ yygotominor.yy342.pExpr->flags |= EP_Distinct; } } break; case 197: /* expr ::= ID LP STAR RP */ @@ -113087,20 +110464,28 @@ case 244: /* uniqueflag ::= */ {yygotominor.yy392 = OE_None;} break; case 247: /* idxlist ::= idxlist COMMA nm collate sortorder */ { - Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0); + Expr *p = 0; + if( yymsp[-1].minor.yy0.n>0 ){ + p = sqlite3Expr(pParse->db, TK_COLUMN, 0); + sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0); + } yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, p); sqlite3ExprListSetName(pParse,yygotominor.yy442,&yymsp[-2].minor.yy0,1); sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index"); if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392; } break; case 248: /* idxlist ::= nm collate sortorder */ { - Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0); + Expr *p = 0; + if( yymsp[-1].minor.yy0.n>0 ){ + p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); + sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0); + } yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1); sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index"); if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392; } @@ -114911,17 +112296,10 @@ ** must be complete. So isInit must not be set until the very end ** of this routine. */ if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; -#ifdef SQLITE_ENABLE_SQLLOG - { - extern void sqlite3_init_sqllog(void); - sqlite3_init_sqllog(); - } -#endif - /* Make sure the mutex subsystem is initialized. If unable to ** initialize the mutex subsystem, return early with the error. ** If the system is so sick that we are unable to allocate a mutex, ** there is not much SQLite is going to be able to do. ** @@ -115266,32 +112644,10 @@ case SQLITE_CONFIG_COVERING_INDEX_SCAN: { sqlite3GlobalConfig.bUseCis = va_arg(ap, int); break; } -#ifdef SQLITE_ENABLE_SQLLOG - case SQLITE_CONFIG_SQLLOG: { - typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); - sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); - sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); - break; - } -#endif - - case SQLITE_CONFIG_MMAP_SIZE: { - sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); - sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ - mxMmap = SQLITE_MAX_MMAP_SIZE; - } - sqlite3GlobalConfig.mxMmap = mxMmap; - if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; - if( szMmap>mxMmap) szMmap = mxMmap; - sqlite3GlobalConfig.szMmap = szMmap; - break; - } - default: { rc = SQLITE_ERROR; break; } } @@ -115627,17 +112983,10 @@ "statements or unfinished backups"); sqlite3_mutex_leave(db->mutex); return SQLITE_BUSY; } -#ifdef SQLITE_ENABLE_SQLLOG - if( sqlite3GlobalConfig.xSqllog ){ - /* Closing the handle. Fourth parameter is passed the value 2. */ - sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); - } -#endif - /* Convert the connection into a zombie and then close it. */ db->magic = SQLITE_MAGIC_ZOMBIE; sqlite3LeaveMutexAndCloseZombie(db); return SQLITE_OK; @@ -115677,20 +113026,14 @@ return; } /* If we reach this point, it means that the database connection has ** closed all sqlite3_stmt and sqlite3_backup objects and has been - ** passed to sqlite3_close (meaning that it is a zombie). Therefore, + ** pased to sqlite3_close (meaning that it is a zombie). Therefore, ** go ahead and free all resources. */ - /* If a transaction is open, roll it back. This also ensures that if - ** any database schemas have been modified by an uncommitted transaction - ** they are reset. And that the required b-tree mutex is held to make - ** the pager rollback and schema reset an atomic operation. */ - sqlite3RollbackAll(db, SQLITE_OK); - /* Free any outstanding Savepoint structures. */ sqlite3CloseSavepoints(db); /* Close all database connections */ for(j=0; jnDb; j++){ @@ -115787,19 +113130,10 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); - - /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). - ** This is important in case the transaction being rolled back has - ** modified the database schema. If the b-tree mutexes are not taken - ** here, then another shared-cache connection might sneak in between - ** the database rollback and schema reset, which can cause false - ** corruption reports in some cases. */ - sqlite3BtreeEnterAll(db); - for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; @@ -115809,15 +113143,14 @@ } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); - if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ + if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); } - sqlite3BtreeLeaveAll(db); /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; /* If one has been configured, invoke the rollback-hook callback */ @@ -115824,114 +113157,10 @@ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } -/* -** Return a static string containing the name corresponding to the error code -** specified in the argument. -*/ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \ - defined(SQLITE_DEBUG_OS_TRACE) -SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ - const char *zName = 0; - int i, origRc = rc; - for(i=0; i<2 && zName==0; i++, rc &= 0xff){ - switch( rc ){ - case SQLITE_OK: zName = "SQLITE_OK"; break; - case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; - case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; - case SQLITE_PERM: zName = "SQLITE_PERM"; break; - case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; - case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; - case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; - case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; - case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; - case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; - case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; - case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; - case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; - case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; - case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; - case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; - case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; - case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; - case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; - case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; - case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; - case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; - case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; - case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; - case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; - case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; - case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; - case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break; - case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; - case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; - case SQLITE_IOERR_CHECKRESERVEDLOCK: - zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; - case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; - case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; - case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; - case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; - case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; - case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; - case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; - case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; - case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; - case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; - case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; - case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; - case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; - case SQLITE_FULL: zName = "SQLITE_FULL"; break; - case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; - case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; - case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; - case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; - case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; - case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; - case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; - case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; - case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; - case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; - case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; - case SQLITE_CONSTRAINT_FOREIGNKEY: - zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; - case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; - case SQLITE_CONSTRAINT_PRIMARYKEY: - zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; - case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; - case SQLITE_CONSTRAINT_COMMITHOOK: - zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; - case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; - case SQLITE_CONSTRAINT_FUNCTION: - zName = "SQLITE_CONSTRAINT_FUNCTION"; break; - case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; - case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; - case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; - case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; - case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; - case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; - case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; - case SQLITE_ROW: zName = "SQLITE_ROW"; break; - case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; - case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; - case SQLITE_NOTICE_RECOVER_ROLLBACK: - zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; - case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; - case SQLITE_DONE: zName = "SQLITE_DONE"; break; - } - } - if( zName==0 ){ - static char zBuf[50]; - sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); - zName = zBuf; - } - return zName; -} -#endif - /* ** Return a static string that describes the kind of error specified in the ** argument. */ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ @@ -117228,11 +114457,10 @@ assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->autoCommit = 1; db->nextAutovac = -1; - db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif @@ -117387,17 +114615,10 @@ db = 0; }else if( rc!=SQLITE_OK ){ db->magic = SQLITE_MAGIC_SICK; } *ppDb = db; -#ifdef SQLITE_ENABLE_SQLLOG - if( sqlite3GlobalConfig.xSqllog ){ - /* Opening a db handle. Fourth parameter is passed 0. */ - void *pArg = sqlite3GlobalConfig.pSqllogArg; - sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); - } -#endif return sqlite3ApiExit(0, rc); } /* ** Open a new database handle. @@ -117962,11 +115183,11 @@ ** with various optimizations disabled to verify that the same answer ** is obtained in every case. */ case SQLITE_TESTCTRL_OPTIMIZATIONS: { sqlite3 *db = va_arg(ap, sqlite3*); - db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff); + db->dbOptFlags = (u8)(va_arg(ap, int) & 0xff); break; } #ifdef SQLITE_N_KEYWORD /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord) @@ -118850,11 +116071,11 @@ ** 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 + ** sqlite3_tokenizer.pModule variable should not be initialised by ** this callback. The caller will do so. */ int (*xCreate)( int argc, /* Size of argv array */ const char *const*argv, /* Tokenizer argument strings */ @@ -118955,11 +116176,11 @@ ** 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 the header file for the generic hash-table implementation +** This is the header file for the generic hash-table implemenation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS3_HASH_H_ @@ -119545,11 +116766,11 @@ ); SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, - char **, int, int, int, const char *, int, Fts3Expr **, char ** + char **, int, int, int, const char *, int, Fts3Expr ** ); SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); @@ -119570,13 +116791,10 @@ Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); -/* fts3_tokenize_vtab.c */ -SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); - /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifdef SQLITE_ENABLE_FTS4_UNICODE61 SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); @@ -120865,11 +118083,11 @@ if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ return SQLITE_OK; }else{ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ - /* If no row was found and no error has occurred, then the %_content + /* If no row was found and no error has occured, then the %_content ** table is missing a row that is present in the full-text index. ** The data structures are corrupt. */ rc = FTS_CORRUPT_VTAB; pCsr->isEof = 1; } @@ -122105,11 +119323,11 @@ sqlite3Fts3SegReaderFinish(pSegcsr); sqlite3_free(pSegcsr); } /* -** This function retrieves the doclist for the specified term (or term +** This function retreives the doclist for the specified term (or term ** prefix) from the database. */ static int fts3TermSelect( Fts3Table *p, /* Virtual table handle */ Fts3PhraseToken *pTok, /* Token to query for */ @@ -122269,16 +119487,18 @@ } pCsr->iLangid = 0; if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]); - assert( p->base.zErrMsg==0 ); rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, - p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, - &p->base.zErrMsg + p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr ); if( rc!=SQLITE_OK ){ + if( rc==SQLITE_ERROR ){ + static const char *zErr = "malformed MATCH expression: [%s]"; + p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery); + } return rc; } rc = sqlite3Fts3ReadLock(p); if( rc!=SQLITE_OK ) return rc; @@ -122854,11 +120074,11 @@ #ifdef SQLITE_ENABLE_ICU SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* -** Initialize the fts3 extension. If this extension is built as part +** Initialise the fts3 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts3 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ @@ -122888,11 +120108,11 @@ if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); - /* Allocate and initialize the hash-table used to store tokenizers. */ + /* Allocate and initialise the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(Fts3Hash)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); @@ -122938,16 +120158,12 @@ if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2( db, "fts4", &fts3Module, (void *)pHash, 0 ); } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3InitTok(db, (void *)pHash); - } return rc; } - /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts3HashClear(pHash); @@ -124039,43 +121255,39 @@ /* Allocate temporary working space. */ for(p=pExpr; p->pLeft; p=p->pLeft){ nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - if( nTmp==0 ){ - res = 0; - }else{ - aTmp = sqlite3_malloc(nTmp*2); - if( !aTmp ){ - *pRc = SQLITE_NOMEM; - res = 0; - }else{ - char *aPoslist = p->pPhrase->doclist.pList; - int nToken = p->pPhrase->nToken; - - for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ - Fts3Phrase *pPhrase = p->pRight->pPhrase; - int nNear = p->nNear; - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } - - aPoslist = pExpr->pRight->pPhrase->doclist.pList; - nToken = pExpr->pRight->pPhrase->nToken; - for(p=pExpr->pLeft; p && res; p=p->pLeft){ - int nNear; - Fts3Phrase *pPhrase; - assert( p->pParent && p->pParent->pLeft==p ); - nNear = p->pParent->nNear; - pPhrase = ( - p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase - ); - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } - } - - sqlite3_free(aTmp); - } + aTmp = sqlite3_malloc(nTmp*2); + if( !aTmp ){ + *pRc = SQLITE_NOMEM; + res = 0; + }else{ + char *aPoslist = p->pPhrase->doclist.pList; + int nToken = p->pPhrase->nToken; + + for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ + Fts3Phrase *pPhrase = p->pRight->pPhrase; + int nNear = p->nNear; + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } + + aPoslist = pExpr->pRight->pPhrase->doclist.pList; + nToken = pExpr->pRight->pPhrase->nToken; + for(p=pExpr->pLeft; p && res; p=p->pLeft){ + int nNear; + Fts3Phrase *pPhrase; + assert( p->pParent && p->pParent->pLeft==p ); + nNear = p->pParent->nNear; + pPhrase = ( + p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase + ); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } + } + + sqlite3_free(aTmp); } return res; } @@ -124491,11 +121703,11 @@ ** The returned value is either NULL or a pointer to a buffer containing ** a position-list indicating the occurrences of the phrase in column iCol ** of the current row. ** ** More specifically, the returned buffer contains 1 varint for each -** occurrence of the phrase in the column, stored using the normal (delta+2) +** occurence of the phrase in the column, stored using the normal (delta+2) ** compression and is terminated by either an 0x01 or 0x00 byte. For example, ** if the requested column contains "a b X c d X X" and the position-list ** for 'X' is requested, the buffer returned may contain: ** ** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 @@ -124718,30 +121930,21 @@ int rc; /* value returned by declare_vtab() */ Fts3auxTable *p; /* Virtual table object to return */ UNUSED_PARAMETER(pUnused); - /* The user should invoke this in one of two forms: - ** - ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); - ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); - */ - if( argc!=4 && argc!=5 ) goto bad_args; + /* The user should specify a single argument - the name of an fts3 table. */ + if( argc!=4 ){ + *pzErr = sqlite3_mprintf( + "wrong number of arguments to fts4aux constructor" + ); + return SQLITE_ERROR; + } zDb = argv[1]; nDb = (int)strlen(zDb); - if( argc==5 ){ - if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ - zDb = argv[3]; - nDb = (int)strlen(zDb); - zFts3 = argv[4]; - }else{ - goto bad_args; - } - }else{ - zFts3 = argv[3]; - } + zFts3 = argv[3]; nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); if( rc!=SQLITE_OK ) return rc; @@ -124760,14 +121963,10 @@ memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); *ppVtab = (sqlite3_vtab *)p; return SQLITE_OK; - - bad_args: - *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor"); - return SQLITE_ERROR; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect @@ -125243,11 +122442,11 @@ /* ** This function is equivalent to the standard isspace() function. ** ** The standard isspace() can be awkward to use safely, because although it -** is defined to accept an argument of type int, its behavior when passed +** is defined to accept an argument of type int, its behaviour when passed ** an integer that falls outside of the range of the unsigned char type ** is undefined (and sometimes, "undefined" means segfault). This wrapper ** is defined to accept an argument of type char, and always returns 0 for ** any values that fall outside of the range of the unsigned char type (i.e. ** negative values). @@ -125322,11 +122521,11 @@ int nConsumed = 0; rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; - int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; + int nToken, iStart, iEnd, iPosition; int nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; @@ -125437,11 +122636,11 @@ pTokenizer, pParse->iLangid, zInput, nInput, &pCursor); if( rc==SQLITE_OK ){ int ii; for(ii=0; rc==SQLITE_OK; ii++){ const char *zByte; - int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0; + int nByte, iBegin, iEnd, iPos; rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos); if( rc==SQLITE_OK ){ Fts3PhraseToken *pToken; p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken)); @@ -125777,14 +122976,12 @@ rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; - p->pParent = pNot; if( pNotBranch ){ pNot->pLeft = pNotBranch; - pNotBranch->pParent = pNot; } pNotBranch = pNot; p = pPrev; }else{ int eType = p->eType; @@ -125868,11 +123065,10 @@ Fts3Expr *pIter = pNotBranch; while( pIter->pLeft ){ pIter = pIter->pLeft; } pIter->pLeft = pRet; - pRet->pParent = pIter; pRet = pNotBranch; } } } *pnConsumed = n - nIn; @@ -125882,227 +123078,10 @@ sqlite3Fts3ExprFree(pRet); sqlite3Fts3ExprFree(pNotBranch); pRet = 0; } *ppExpr = pRet; - return rc; -} - -/* -** Return SQLITE_ERROR if the maximum depth of the expression tree passed -** as the only argument is more than nMaxDepth. -*/ -static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ - int rc = SQLITE_OK; - if( p ){ - if( nMaxDepth<0 ){ - rc = SQLITE_TOOBIG; - }else{ - rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); - if( rc==SQLITE_OK ){ - rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); - } - } - } - return rc; -} - -/* -** This function attempts to transform the expression tree at (*pp) to -** an equivalent but more balanced form. The tree is modified in place. -** If successful, SQLITE_OK is returned and (*pp) set to point to the -** new root expression node. -** -** nMaxDepth is the maximum allowable depth of the balanced sub-tree. -** -** Otherwise, if an error occurs, an SQLite error code is returned and -** expression (*pp) freed. -*/ -static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ - int rc = SQLITE_OK; /* Return code */ - Fts3Expr *pRoot = *pp; /* Initial root node */ - Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ - int eType = pRoot->eType; /* Type of node in this tree */ - - if( nMaxDepth==0 ){ - rc = SQLITE_ERROR; - } - - if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ - Fts3Expr **apLeaf; - apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); - if( 0==apLeaf ){ - rc = SQLITE_NOMEM; - }else{ - memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); - } - - if( rc==SQLITE_OK ){ - int i; - Fts3Expr *p; - - /* Set $p to point to the left-most leaf in the tree of eType nodes. */ - for(p=pRoot; p->eType==eType; p=p->pLeft){ - assert( p->pParent==0 || p->pParent->pLeft==p ); - assert( p->pLeft && p->pRight ); - } - - /* This loop runs once for each leaf in the tree of eType nodes. */ - while( 1 ){ - int iLvl; - Fts3Expr *pParent = p->pParent; /* Current parent of p */ - - assert( pParent==0 || pParent->pLeft==p ); - p->pParent = 0; - if( pParent ){ - pParent->pLeft = 0; - }else{ - pRoot = 0; - } - rc = fts3ExprBalance(&p, nMaxDepth-1); - if( rc!=SQLITE_OK ) break; - - for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; - pFree->pRight = p; - pFree->pLeft->pParent = pFree; - pFree->pRight->pParent = pFree; - - p = pFree; - pFree = pFree->pParent; - p->pParent = 0; - apLeaf[iLvl] = 0; - } - } - if( p ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_TOOBIG; - break; - } - - /* If that was the last leaf node, break out of the loop */ - if( pParent==0 ) break; - - /* Set $p to point to the next leaf in the tree of eType nodes */ - for(p=pParent->pRight; p->eType==eType; p=p->pLeft); - - /* Remove pParent from the original tree. */ - assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); - pParent->pRight->pParent = pParent->pParent; - if( pParent->pParent ){ - pParent->pParent->pLeft = pParent->pRight; - }else{ - assert( pParent==pRoot ); - pRoot = pParent->pRight; - } - - /* Link pParent into the free node list. It will be used as an - ** internal node of the new tree. */ - pParent->pParent = pFree; - pFree = pParent; - } - - if( rc==SQLITE_OK ){ - p = 0; - for(i=0; ipParent = 0; - }else{ - assert( pFree!=0 ); - pFree->pRight = p; - pFree->pLeft = apLeaf[i]; - pFree->pLeft->pParent = pFree; - pFree->pRight->pParent = pFree; - - p = pFree; - pFree = pFree->pParent; - p->pParent = 0; - } - } - } - pRoot = p; - }else{ - /* An error occurred. Delete the contents of the apLeaf[] array - ** and pFree list. Everything else is cleaned up by the call to - ** sqlite3Fts3ExprFree(pRoot) below. */ - Fts3Expr *pDel; - for(i=0; ipParent; - sqlite3_free(pDel); - } - } - - assert( pFree==0 ); - sqlite3_free( apLeaf ); - } - } - - if( rc!=SQLITE_OK ){ - sqlite3Fts3ExprFree(pRoot); - pRoot = 0; - } - *pp = pRoot; - return rc; -} - -/* -** This function is similar to sqlite3Fts3ExprParse(), with the following -** differences: -** -** 1. It does not do expression rebalancing. -** 2. It does not check that the expression does not exceed the -** maximum allowable depth. -** 3. Even if it fails, *ppExpr may still be set to point to an -** expression tree. It should be deleted using sqlite3Fts3ExprFree() -** in this case. -*/ -static int fts3ExprParseUnbalanced( - sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ - int iLangid, /* Language id for tokenizer */ - char **azCol, /* Array of column names for fts3 table */ - int bFts4, /* True to allow FTS4-only syntax */ - int nCol, /* Number of entries in azCol[] */ - int iDefaultCol, /* Default column to query */ - const char *z, int n, /* Text of MATCH query */ - Fts3Expr **ppExpr /* OUT: Parsed query structure */ -){ - int nParsed; - int rc; - ParseContext sParse; - - memset(&sParse, 0, sizeof(ParseContext)); - sParse.pTokenizer = pTokenizer; - sParse.iLangid = iLangid; - sParse.azCol = (const char **)azCol; - sParse.nCol = nCol; - sParse.iDefaultCol = iDefaultCol; - sParse.bFts4 = bFts4; - if( z==0 ){ - *ppExpr = 0; - return SQLITE_OK; - } - if( n<0 ){ - n = (int)strlen(z); - } - rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); - assert( rc==SQLITE_OK || *ppExpr==0 ); - - /* Check for mismatched parenthesis */ - if( rc==SQLITE_OK && sParse.nNest ){ - rc = SQLITE_ERROR; - } - return rc; } /* ** Parameters z and n contain a pointer to and length of a buffer containing @@ -126134,78 +123113,53 @@ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ - Fts3Expr **ppExpr, /* OUT: Parsed query structure */ - char **pzErr /* OUT: Error message (sqlite3_malloc) */ + Fts3Expr **ppExpr /* OUT: Parsed query structure */ ){ - static const int MAX_EXPR_DEPTH = 12; - int rc = fts3ExprParseUnbalanced( - pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr - ); - - /* Rebalance the expression. And check that its depth does not exceed - ** MAX_EXPR_DEPTH. */ - if( rc==SQLITE_OK && *ppExpr ){ - rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH); - if( rc==SQLITE_OK ){ - rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH); - } - } - - if( rc!=SQLITE_OK ){ + int nParsed; + int rc; + ParseContext sParse; + + memset(&sParse, 0, sizeof(ParseContext)); + sParse.pTokenizer = pTokenizer; + sParse.iLangid = iLangid; + sParse.azCol = (const char **)azCol; + sParse.nCol = nCol; + sParse.iDefaultCol = iDefaultCol; + sParse.bFts4 = bFts4; + if( z==0 ){ + *ppExpr = 0; + return SQLITE_OK; + } + if( n<0 ){ + n = (int)strlen(z); + } + rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); + + /* Check for mismatched parenthesis */ + if( rc==SQLITE_OK && sParse.nNest ){ + rc = SQLITE_ERROR; sqlite3Fts3ExprFree(*ppExpr); *ppExpr = 0; - if( rc==SQLITE_TOOBIG ){ - *pzErr = sqlite3_mprintf( - "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH - ); - rc = SQLITE_ERROR; - }else if( rc==SQLITE_ERROR ){ - *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z); - } } return rc; } -/* -** Free a single node of an expression tree. -*/ -static void fts3FreeExprNode(Fts3Expr *p){ - assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); - sqlite3Fts3EvalPhraseCleanup(p->pPhrase); - sqlite3_free(p->aMI); - sqlite3_free(p); -} - /* ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). -** -** This function would be simpler if it recursively called itself. But -** that would mean passing a sufficiently large expression to ExprParse() -** could cause a stack overflow. */ -SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){ - Fts3Expr *p; - assert( pDel==0 || pDel->pParent==0 ); - for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ - assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); - } - while( p ){ - Fts3Expr *pParent = p->pParent; - fts3FreeExprNode(p); - if( pParent && p==pParent->pLeft && pParent->pRight ){ - p = pParent->pRight; - while( p && (p->pLeft || p->pRight) ){ - assert( p==p->pParent->pRight || p==p->pParent->pLeft ); - p = (p->pLeft ? p->pLeft : p->pRight); - } - }else{ - p = pParent; - } +SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *p){ + if( p ){ + assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); + sqlite3Fts3ExprFree(p->pLeft); + sqlite3Fts3ExprFree(p->pRight); + sqlite3Fts3EvalPhraseCleanup(p->pPhrase); + sqlite3_free(p->aMI); + sqlite3_free(p); } } /**************************************************************************** ***************************************************************************** @@ -126253,13 +123207,10 @@ ** ** If the second argument is not NULL, then its contents are prepended to ** the returned expression text and then freed using sqlite3_free(). */ static char *exprToString(Fts3Expr *pExpr, char *zBuf){ - if( pExpr==0 ){ - return sqlite3_mprintf(""); - } switch( pExpr->eType ){ case FTSQUERY_PHRASE: { Fts3Phrase *pPhrase = pExpr->pPhrase; int i; zBuf = sqlite3_mprintf( @@ -126363,25 +123314,14 @@ } for(ii=0; ii USING fts3tokenize( -** , , ... -** ); -** -** The table created has the following schema: -** -** CREATE TABLE (input, token, start, end, position) -** -** When queried, the query must include a WHERE clause of type: -** -** input = -** -** The virtual table module tokenizes this , using the FTS3 -** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE -** statement and returns one row for each token in the result. With -** fields set as follows: -** -** input: Always set to a copy of -** token: A token from the input. -** start: Byte offset of the token within the input . -** end: Byte offset of the byte immediately following the end of the -** token within the input string. -** pos: Token offset of token within input. -** -*/ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ - -typedef struct Fts3tokTable Fts3tokTable; -typedef struct Fts3tokCursor Fts3tokCursor; - -/* -** Virtual table structure. -*/ -struct Fts3tokTable { - sqlite3_vtab base; /* Base class used by SQLite core */ - const sqlite3_tokenizer_module *pMod; - sqlite3_tokenizer *pTok; -}; - -/* -** Virtual table cursor structure. -*/ -struct Fts3tokCursor { - sqlite3_vtab_cursor base; /* Base class used by SQLite core */ - char *zInput; /* Input string */ - sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ - int iRowid; /* Current 'rowid' value */ - const char *zToken; /* Current 'token' value */ - int nToken; /* Size of zToken in bytes */ - int iStart; /* Current 'start' value */ - int iEnd; /* Current 'end' value */ - int iPos; /* Current 'pos' value */ -}; - -/* -** Query FTS for the tokenizer implementation named zName. -*/ -static int fts3tokQueryTokenizer( - Fts3Hash *pHash, - const char *zName, - const sqlite3_tokenizer_module **pp, - char **pzErr -){ - sqlite3_tokenizer_module *p; - int nName = (int)strlen(zName); - - p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); - if( !p ){ - *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName); - return SQLITE_ERROR; - } - - *pp = p; - return SQLITE_OK; -} - -/* -** The second argument, argv[], is an array of pointers to nul-terminated -** strings. This function makes a copy of the array and strings into a -** single block of memory. It then dequotes any of the strings that appear -** to be quoted. -** -** If successful, output parameter *pazDequote is set to point at the -** array of dequoted strings and SQLITE_OK is returned. The caller is -** responsible for eventually calling sqlite3_free() to free the array -** in this case. Or, if an error occurs, an SQLite error code is returned. -** The final value of *pazDequote is undefined in this case. -*/ -static int fts3tokDequoteArray( - int argc, /* Number of elements in argv[] */ - const char * const *argv, /* Input array */ - char ***pazDequote /* Output array */ -){ - int rc = SQLITE_OK; /* Return code */ - if( argc==0 ){ - *pazDequote = 0; - }else{ - int i; - int nByte = 0; - char **azDequote; - - for(i=0; ixCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); - } - - if( rc==SQLITE_OK ){ - pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); - if( pTab==0 ){ - rc = SQLITE_NOMEM; - } - } - - if( rc==SQLITE_OK ){ - memset(pTab, 0, sizeof(Fts3tokTable)); - pTab->pMod = pMod; - pTab->pTok = pTok; - *ppVtab = &pTab->base; - }else{ - if( pTok ){ - pMod->xDestroy(pTok); - } - } - - sqlite3_free(azDequote); - return rc; -} - -/* -** This function does the work for both the xDisconnect and xDestroy methods. -** These tables have no persistent representation of their own, so xDisconnect -** and xDestroy are identical operations. -*/ -static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ - Fts3tokTable *pTab = (Fts3tokTable *)pVtab; - - pTab->pMod->xDestroy(pTab->pTok); - sqlite3_free(pTab); - return SQLITE_OK; -} - -/* -** xBestIndex - Analyze a WHERE and ORDER BY clause. -*/ -static int fts3tokBestIndexMethod( - sqlite3_vtab *pVTab, - sqlite3_index_info *pInfo -){ - int i; - UNUSED_PARAMETER(pVTab); - - for(i=0; inConstraint; i++){ - if( pInfo->aConstraint[i].usable - && pInfo->aConstraint[i].iColumn==0 - && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ - ){ - pInfo->idxNum = 1; - pInfo->aConstraintUsage[i].argvIndex = 1; - pInfo->aConstraintUsage[i].omit = 1; - pInfo->estimatedCost = 1; - return SQLITE_OK; - } - } - - pInfo->idxNum = 0; - assert( pInfo->estimatedCost>1000000.0 ); - - return SQLITE_OK; -} - -/* -** xOpen - Open a cursor. -*/ -static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - Fts3tokCursor *pCsr; - UNUSED_PARAMETER(pVTab); - - pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); - if( pCsr==0 ){ - return SQLITE_NOMEM; - } - memset(pCsr, 0, sizeof(Fts3tokCursor)); - - *ppCsr = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; -} - -/* -** Reset the tokenizer cursor passed as the only argument. As if it had -** just been returned by fts3tokOpenMethod(). -*/ -static void fts3tokResetCursor(Fts3tokCursor *pCsr){ - if( pCsr->pCsr ){ - Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); - pTab->pMod->xClose(pCsr->pCsr); - pCsr->pCsr = 0; - } - sqlite3_free(pCsr->zInput); - pCsr->zInput = 0; - pCsr->zToken = 0; - pCsr->nToken = 0; - pCsr->iStart = 0; - pCsr->iEnd = 0; - pCsr->iPos = 0; - pCsr->iRowid = 0; -} - -/* -** xClose - Close a cursor. -*/ -static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - - fts3tokResetCursor(pCsr); - sqlite3_free(pCsr); - return SQLITE_OK; -} - -/* -** xNext - Advance the cursor to the next row, if any. -*/ -static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); - int rc; /* Return code */ - - pCsr->iRowid++; - rc = pTab->pMod->xNext(pCsr->pCsr, - &pCsr->zToken, &pCsr->nToken, - &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos - ); - - if( rc!=SQLITE_OK ){ - fts3tokResetCursor(pCsr); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - - return rc; -} - -/* -** xFilter - Initialize a cursor to point at the start of its data. -*/ -static int fts3tokFilterMethod( - sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ - int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ - int nVal, /* Number of elements in apVal */ - sqlite3_value **apVal /* Arguments for the indexing scheme */ -){ - int rc = SQLITE_ERROR; - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); - UNUSED_PARAMETER(idxStr); - UNUSED_PARAMETER(nVal); - - fts3tokResetCursor(pCsr); - if( idxNum==1 ){ - const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); - pCsr->zInput = sqlite3_malloc(nByte+1); - if( pCsr->zInput==0 ){ - rc = SQLITE_NOMEM; - }else{ - memcpy(pCsr->zInput, zByte, nByte); - pCsr->zInput[nByte] = 0; - rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); - if( rc==SQLITE_OK ){ - pCsr->pCsr->pTokenizer = pTab->pTok; - } - } - } - - if( rc!=SQLITE_OK ) return rc; - return fts3tokNextMethod(pCursor); -} - -/* -** xEof - Return true if the cursor is at EOF, or false otherwise. -*/ -static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - return (pCsr->zToken==0); -} - -/* -** xColumn - Return a column value. -*/ -static int fts3tokColumnMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ - int iCol /* Index of column to read value from */ -){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - - /* CREATE TABLE x(input, token, start, end, position) */ - switch( iCol ){ - case 0: - sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); - break; - case 1: - sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); - break; - case 2: - sqlite3_result_int(pCtx, pCsr->iStart); - break; - case 3: - sqlite3_result_int(pCtx, pCsr->iEnd); - break; - default: - assert( iCol==4 ); - sqlite3_result_int(pCtx, pCsr->iPos); - break; - } - return SQLITE_OK; -} - -/* -** xRowid - Return the current rowid for the cursor. -*/ -static int fts3tokRowidMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite_int64 *pRowid /* OUT: Rowid value */ -){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - *pRowid = (sqlite3_int64)pCsr->iRowid; - return SQLITE_OK; -} - -/* -** Register the fts3tok module with database connection db. Return SQLITE_OK -** if successful or an error code if sqlite3_create_module() fails. -*/ -SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ - static const sqlite3_module fts3tok_module = { - 0, /* iVersion */ - fts3tokConnectMethod, /* xCreate */ - fts3tokConnectMethod, /* xConnect */ - fts3tokBestIndexMethod, /* xBestIndex */ - fts3tokDisconnectMethod, /* xDisconnect */ - fts3tokDisconnectMethod, /* xDestroy */ - fts3tokOpenMethod, /* xOpen */ - fts3tokCloseMethod, /* xClose */ - fts3tokFilterMethod, /* xFilter */ - fts3tokNextMethod, /* xNext */ - fts3tokEofMethod, /* xEof */ - fts3tokColumnMethod, /* xColumn */ - fts3tokRowidMethod, /* xRowid */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindFunction */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ - }; - int rc; /* Return code */ - - rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); - return rc; -} - -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ - -/************** End of fts3_tokenize_vtab.c **********************************/ /************** Begin file fts3_write.c **************************************/ /* ** 2009 Oct 23 ** ** The author disclaims copyright to this source code. In place of @@ -129405,20 +125883,20 @@ static int fts3PendingTermsAdd( Fts3Table *p, /* Table into which text will be inserted */ int iLangid, /* Language id to use */ const char *zText, /* Text of document to be inserted */ int iCol, /* Column into which text is being inserted */ - u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */ + u32 *pnWord /* OUT: Number of tokens inserted */ ){ int rc; - int iStart = 0; - int iEnd = 0; - int iPos = 0; + int iStart; + int iEnd; + int iPos; int nWord = 0; char const *zToken; - int nToken = 0; + int nToken; sqlite3_tokenizer *pTokenizer = p->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCsr; int (*xNext)(sqlite3_tokenizer_cursor *pCursor, @@ -129469,11 +125947,11 @@ ); } } pModule->xClose(pCsr); - *pnWord += nWord; + *pnWord = nWord; return (rc==SQLITE_DONE ? SQLITE_OK : rc); } /* ** Calling this function indicates that subsequent calls to @@ -129673,17 +126151,15 @@ */ static void fts3DeleteTerms( int *pRC, /* Result code */ Fts3Table *p, /* The FTS table to delete from */ sqlite3_value *pRowid, /* The docid to be deleted */ - u32 *aSz, /* Sizes of deleted document written here */ - int *pbFound /* OUT: Set to true if row really does exist */ + u32 *aSz /* Sizes of deleted document written here */ ){ int rc; sqlite3_stmt *pSelect; - assert( *pbFound==0 ); if( *pRC ) return; rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; @@ -129697,11 +126173,10 @@ if( rc!=SQLITE_OK ){ sqlite3_reset(pSelect); *pRC = rc; return; } - *pbFound = 1; } rc = sqlite3_reset(pSelect); }else{ sqlite3_reset(pSelect); } @@ -130111,11 +126586,10 @@ if( ppOffsetList ){ *ppOffsetList = pReader->pOffsetList; *pnOffsetList = (int)(p - pReader->pOffsetList - 1); } - /* List may have been edited in place by fts3EvalNearTrim() */ while( papSegment, nMerge, j, xCmp); - if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ - rc = fts3MsrBufferData(pMsr, pList, nList+1); - if( rc!=SQLITE_OK ) return rc; - assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); - pList = pMsr->aBuffer; - } - if( pMsr->iColFilter>=0 ){ - fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); + fts3ColumnFilter(pMsr->iColFilter, &pList, &nList); } if( nList>0 ){ - *paPoslist = pList; + if( fts3SegReaderIsPending(apSegment[0]) ){ + rc = fts3MsrBufferData(pMsr, pList, nList+1); + if( rc!=SQLITE_OK ) return rc; + *paPoslist = pMsr->aBuffer; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + }else{ + *paPoslist = pList; + } *piDocid = iDocid; *pnPoslist = nList; break; } } @@ -131493,11 +127960,11 @@ fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( isColFilter ){ - fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); + fts3ColumnFilter(pFilter->iCol, &pList, &nList); } if( !isIgnoreEmpty || nList>0 ){ /* Calculate the 'docid' delta value to write into the merged @@ -131930,11 +128397,11 @@ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ int iCol; int iLangid = langidFromSelect(p, pStmt); rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0)); - memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); + aSz[p->nColumn] = 0; for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); } @@ -133574,13 +130041,13 @@ sqlite3_tokenizer_cursor *pT = 0; rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT); while( rc==SQLITE_OK ){ char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ + int nToken; /* Number of bytes in token */ + int iDum1, iDum2; /* Dummy variables */ + int iPos; /* Position of token in zText */ rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); if( rc==SQLITE_OK ){ int i; cksum2 = cksum2 ^ fts3ChecksumEntry( @@ -133743,13 +130210,13 @@ sqlite3_tokenizer_cursor *pTC = 0; rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); while( rc==SQLITE_OK ){ char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ + int nToken; /* Number of bytes in token */ + int iDum1, iDum2; /* Dummy variables */ + int iPos; /* Position of token in zText */ rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ Fts3PhraseToken *pPT = pDef->pToken; if( (pDef->iCol>=p->nColumn || pDef->iCol==i) @@ -133834,36 +130301,32 @@ ** of subsiduary data structures accordingly. */ static int fts3DeleteByRowid( Fts3Table *p, sqlite3_value *pRowid, - int *pnChng, /* IN/OUT: Decrement if row is deleted */ + int *pnDoc, u32 *aSzDel ){ - int rc = SQLITE_OK; /* Return code */ - int bFound = 0; /* True if *pRowid really is in the table */ - - fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); - if( bFound && rc==SQLITE_OK ){ - int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ - rc = fts3IsEmpty(p, pRowid, &isEmpty); - if( rc==SQLITE_OK ){ - if( isEmpty ){ - /* Deleting this row means the whole table is empty. In this case - ** delete the contents of all three tables and throw away any - ** data in the pendingTerms hash table. */ - rc = fts3DeleteAll(p, 1); - *pnChng = 0; - memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2); + int isEmpty = 0; + int rc = fts3IsEmpty(p, pRowid, &isEmpty); + if( rc==SQLITE_OK ){ + if( isEmpty ){ + /* Deleting this row means the whole table is empty. In this case + ** delete the contents of all three tables and throw away any + ** data in the pendingTerms hash table. */ + rc = fts3DeleteAll(p, 1); + *pnDoc = *pnDoc - 1; + }else{ + fts3DeleteTerms(&rc, p, pRowid, aSzDel); + if( p->zContentTbl==0 ){ + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; }else{ - *pnChng = *pnChng - 1; - if( p->zContentTbl==0 ){ - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); - } - if( p->bHasDocsize ){ - fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); - } + *pnDoc = *pnDoc - 1; + } + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); } } } return rc; @@ -133890,11 +130353,11 @@ ){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return Code */ int isRemove = 0; /* True for an UPDATE or DELETE */ u32 *aSzIns = 0; /* Sizes of inserted documents */ - u32 *aSzDel = 0; /* Sizes of deleted documents */ + u32 *aSzDel; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; assert( p->pSegments==0 ); assert( @@ -133918,17 +130381,17 @@ rc = SQLITE_CONSTRAINT; goto update_out; } /* Allocate space to hold the change in document sizes */ - aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 ); - if( aSzDel==0 ){ + aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 ); + if( aSzIns==0 ){ rc = SQLITE_NOMEM; goto update_out; } - aSzIns = &aSzDel[p->nColumn+1]; - memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); + aSzDel = &aSzIns[p->nColumn+1]; + memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2); /* If this is an INSERT operation, or an UPDATE that modifies the rowid ** value, then this operation requires constraint handling. ** ** If the on-conflict mode is REPLACE, this means that the existing row @@ -134009,11 +130472,11 @@ if( p->bFts4 ){ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng); } update_out: - sqlite3_free(aSzDel); + sqlite3_free(aSzIns); sqlite3Fts3SegmentsClose(p); return rc; } /* @@ -134430,13 +130893,13 @@ ** Select the fragment of text consisting of nFragment contiguous tokens ** from column iCol that represent the "best" snippet. The best snippet ** is the snippet with the highest score, where scores are calculated ** by adding: ** -** (a) +1 point for each occurrence of a matchable phrase in the snippet. +** (a) +1 point for each occurence of a matchable phrase in the snippet. ** -** (b) +1000 points for the first occurrence of each matchable phrase in +** (b) +1000 points for the first occurence of each matchable phrase in ** the snippet for which the corresponding mCovered bit is not set. ** ** The selected snippet parameters are stored in structure *pFragment before ** returning. The score of the selected snippet is stored in *piScore ** before returning. @@ -134617,11 +131080,11 @@ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC); if( rc!=SQLITE_OK ){ return rc; } while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){ - const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0; + const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3; rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent); } pMod->xClose(pC); if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; } @@ -134661,10 +131124,12 @@ int iPos = pFragment->iPos; /* First token of snippet */ u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */ int iCol = pFragment->iCol+1; /* Query column to extract text from */ sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */ + const char *ZDUMMY; /* Dummy argument used with tokenizer */ + int DUMMY1; /* Dummy argument used with tokenizer */ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol); if( zDoc==0 ){ if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){ return SQLITE_NOMEM; @@ -134679,27 +131144,14 @@ if( rc!=SQLITE_OK ){ return rc; } while( rc==SQLITE_OK ){ - const char *ZDUMMY; /* Dummy argument used with tokenizer */ - int DUMMY1 = -1; /* Dummy argument used with tokenizer */ - int iBegin = 0; /* Offset in zDoc of start of token */ - int iFin = 0; /* Offset in zDoc of end of token */ - int isHighlight = 0; /* True for highlighted terms */ - - /* Variable DUMMY1 is initialized to a negative value above. Elsewhere - ** in the FTS code the variable that the third argument to xNext points to - ** is initialized to zero before the first (*but not necessarily - ** subsequent*) call to xNext(). This is done for a particular application - ** that needs to know whether or not the tokenizer is being used for - ** snippet generation or for some other purpose. - ** - ** Extreme care is required when writing code to depend on this - ** initialization. It is not a documented part of the tokenizer interface. - ** If a tokenizer is used directly by any code outside of FTS, this - ** convention might not be respected. */ + int iBegin; /* Offset in zDoc of start of token */ + int iFin; /* Offset in zDoc of end of token */ + int isHighlight; /* True for highlighted terms */ + rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ /* Special case - the last token of the snippet is also the last token ** of the column. Append any punctuation that occurred between the end @@ -135385,10 +131837,12 @@ sqlite3_context *pCtx, /* SQLite function call context */ Fts3Cursor *pCsr /* Cursor object */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule; + const char *ZDUMMY; /* Dummy argument used with xNext() */ + int NDUMMY; /* Dummy argument used with xNext() */ int rc; /* Return Code */ int nToken; /* Number of tokens in query */ int iCol; /* Column currently being processed */ StrBuffer res = {0, 0, 0}; /* Result string */ TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */ @@ -135417,15 +131871,13 @@ /* Loop through the table columns, appending offset information to ** string-buffer res for each column. */ for(iCol=0; iColnColumn; iCol++){ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ - const char *ZDUMMY; /* Dummy argument used with xNext() */ - int NDUMMY = 0; /* Dummy argument used with xNext() */ - int iStart = 0; - int iEnd = 0; - int iCurrent = 0; + int iStart; + int iEnd; + int iCurrent; const char *zDoc; int nDoc; /* Initialize the contents of sCtx.aTerm[] for column iCol. There is ** no way that this operation can fail, so the return code from @@ -135687,11 +132139,11 @@ ** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all ** codepoints in the aiException[] array. ** ** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() ** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. -** It is not possible to change the behavior of the tokenizer with respect +** It is not possible to change the behaviour of the tokenizer with respect ** to these codepoints. */ static int unicodeAddExceptions( unicode_tokenizer *p, /* Tokenizer to add exceptions to */ int bAlnum, /* Replace Isalnum() return value with this */ @@ -138990,11 +135442,11 @@ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ RtreeNode *pRoot; /* Root node of rtree structure */ - /* Obtain a reference to the root node to initialize Rtree.iDepth */ + /* Obtain a reference to the root node to initialise Rtree.iDepth */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ @@ -139374,12 +135826,11 @@ ** would fit in a single node, use a smaller node-size. */ static int getNodeSize( sqlite3 *db, /* Database handle */ Rtree *pRtree, /* Rtree handle */ - int isCreate, /* True for xCreate, false for xConnect */ - char **pzErr /* OUT: Error message, if any */ + int isCreate /* True for xCreate, false for xConnect */ ){ int rc; char *zSql; if( isCreate ){ int iPageSize = 0; @@ -139388,22 +135839,17 @@ if( rc==SQLITE_OK ){ pRtree->iNodeSize = iPageSize-64; if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; } - }else{ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } }else{ zSql = sqlite3_mprintf( "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); - if( rc!=SQLITE_OK ){ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); - } } sqlite3_free(zSql); return rc; } @@ -139463,11 +135909,11 @@ pRtree->eCoordType = eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Figure out the node size to use. */ - rc = getNodeSize(db, pRtree, isCreate, pzErr); + rc = getNodeSize(db, pRtree, isCreate); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ @@ -140310,19 +136756,19 @@ nInput = strlen(zInput); } nChar = nInput+1; pCsr = (IcuCursor *)sqlite3_malloc( sizeof(IcuCursor) + /* IcuCursor */ - ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ + nChar * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ ); if( !pCsr ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(IcuCursor)); pCsr->aChar = (UChar *)&pCsr[1]; - pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; + pCsr->aOffset = (int *)&pCsr->aChar[nChar]; pCsr->aOffset[iOut] = iInput; U8_NEXT(zInput, iInput, nInput, c); while( c>0 ){ int isError = 0; Index: SQLite.Interop/src/core/sqlite3.h ================================================================== --- SQLite.Interop/src/core/sqlite3.h +++ SQLite.Interop/src/core/sqlite3.h @@ -105,13 +105,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.7.17" -#define SQLITE_VERSION_NUMBER 3007017 -#define SQLITE_SOURCE_ID "2013-05-16 12:41:49 6d45a79fb18dcd305cc41c525060e42f2402bd77" +#define SQLITE_VERSION "3.7.15" +#define SQLITE_VERSION_NUMBER 3007015 +#define SQLITE_SOURCE_ID "2012-10-12 18:06:07 de784399ed1f0e27fc875e32719643d19819c8fb" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -286,11 +286,11 @@ ** ** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ^If -** sqlite3_close_v2() is called on a [database connection] that still has +** sqlite3_close() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** @@ -423,12 +423,10 @@ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ -#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ -#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 */ /* end-of-error-codes */ /* @@ -474,33 +472,19 @@ #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) -#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) -#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) -#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) -#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) -#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) -#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) -#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) -#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) -#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) -#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) -#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) -#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) -#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) -#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the @@ -736,13 +720,10 @@ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ - int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); - int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); - /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes @@ -873,43 +854,22 @@ ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. +** ** **
  4. [[SQLITE_FCNTL_BUSYHANDLER]] -** ^The [SQLITE_FCNTL_BUSYHANDLER] -** file-control may be invoked by SQLite on the database file handle +** ^This file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access ** to the connections busy-handler callback. The argument is of type (void **) ** - an array of two (void *) values. The first (void *) actually points ** to a function of type (int (*)(void *)). In order to invoke the connections ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. -** -**
  5. [[SQLITE_FCNTL_TEMPFILENAME]] -** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control -** to have SQLite generate a -** temporary filename using the same algorithm that is followed to generate -** temporary filenames for TEMP tables and other internal uses. The -** argument should be a char** which will be filled with the filename -** written into memory obtained from [sqlite3_malloc()]. The caller should -** invoke [sqlite3_free()] on the result to avoid a memory leak. -** -**
  6. [[SQLITE_FCNTL_MMAP_SIZE]] -** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the -** maximum number of bytes that will be used for memory-mapped I/O. -** The argument is a pointer to a value of type sqlite3_int64 that -** is an advisory maximum number of bytes in the file to memory map. The -** pointer is overwritten with the old value. The limit is not changed if -** the value originally pointed to is negative, and so the current limit -** can be queried by passing in a pointer to a negative number. This -** file-control is used internally to implement [PRAGMA mmap_size]. -** -** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 @@ -922,12 +882,10 @@ #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 -#define SQLITE_FCNTL_TEMPFILENAME 16 -#define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an @@ -1590,13 +1548,11 @@ **
    ^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^
    ** ** [[SQLITE_CONFIG_LOG]]
    SQLITE_CONFIG_LOG
    -**
    The SQLITE_CONFIG_LOG option is used to configure the SQLite -** global [error log]. -** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a +**
    ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is @@ -1623,11 +1579,11 @@ ** database connection is opened. By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined. ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
    SQLITE_CONFIG_COVERING_INDEX_SCAN -**
    This option takes a single integer argument which is interpreted as +**
    This option taks a single integer argument which is interpreted as ** a boolean in order to enable or disable the use of covering indices for ** full table scans in the query optimizer. The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans @@ -1638,42 +1594,10 @@ ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] **
    SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE **
    These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. -**
    -** -** [[SQLITE_CONFIG_SQLLOG]] -**
    SQLITE_CONFIG_SQLLOG -**
    This option is only available if sqlite is compiled with the -** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should -** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). -** The second should be of type (void*). The callback is invoked by the library -** in three separate circumstances, identified by the value passed as the -** fourth parameter. If the fourth parameter is 0, then the database connection -** passed as the second argument has just been opened. The third argument -** points to a buffer containing the name of the main database file. If the -** fourth parameter is 1, then the SQL statement that the third parameter -** points to has just been executed. Or, if the fourth parameter is 2, then -** the connection being passed as the second parameter is being closed. The -** third parameter is passed NULL In this case. An example of using this -** configuration option can be seen in the "test_sqllog.c" source file in -** the canonical SQLite source tree.
    -** -** [[SQLITE_CONFIG_MMAP_SIZE]] -**
    SQLITE_CONFIG_MMAP_SIZE -**
    SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values -** that are the default mmap size limit (the default setting for -** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. -** The default setting can be overridden by each database connection using -** either the [PRAGMA mmap_size] command, or by using the -** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size -** cannot be changed at run-time. Nor may the maximum allowed mmap size -** exceed the compile-time maximum mmap size set by the -** [SQLITE_MAX_MMAP_SIZE] compile-time option. -** If either argument to this option is negative, then that argument is -** changed to its compile-time default. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -1692,12 +1616,10 @@ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ -#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ -#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that @@ -2527,13 +2449,10 @@ ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** -** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit -** the length of [bound parameter] expansion in the output of sqlite3_trace(). -** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation @@ -2721,11 +2640,11 @@ ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in -** a URI filename, its value overrides any behavior requested by setting +** a URI filename, its value overrides any behaviour requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query @@ -3068,12 +2987,11 @@ ** **
      **
    1. ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL -** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] -** retries will occur before sqlite3_step() gives up and returns an error. +** statement and try to run it again. **
    2. ** **
    3. ** ^When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. ^The legacy behavior was that @@ -3273,13 +3191,10 @@ ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** ** ^The third argument is the value to bind to the parameter. -** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() -** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter -** is ignored and the end result is the same as sqlite3_bind_null(). ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() @@ -4043,12 +3958,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); -SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), - void*,sqlite3_int64); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64); #endif /* ** CAPI3REF: Obtaining SQL Function Parameter Values ** @@ -4124,21 +4038,18 @@ ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** -** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer -** when first called if N is less than or equal to zero or if a memory -** allocate error occurs. +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is +** less than or equal to zero or if a memory allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory -** allocation.)^ Within the xFinal callback, it is customary to set -** N=0 in calls to sqlite3_aggregate_context(C,N) so that no -** pointless memory allocations occur. +** allocation.)^ ** ** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the @@ -4232,11 +4143,11 @@ ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain -** C++ compilers. +** C++ compilers. See ticket #2191. */ typedef void (*sqlite3_destructor_type)(void*); #define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) @@ -5031,24 +4942,15 @@ ** CAPI3REF: Load An Extension ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an -** [SQLite extension] library contained in the file zFile. If -** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. -** So for example, if "samplelib" cannot be loaded, then names like -** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might -** be tried also. +** SQLite extension library contained in the file zFile. ** ** ^The entry point is zProc. -** ^(zProc may be 0, in which case SQLite will try to come up with an -** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** ^zProc may be 0, in which case the name of the entry point +** defaults to "sqlite3_extension_init". ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the ** [sqlite3_load_extension()] interface shall attempt to ** fill *pzErrMsg with error message text stored in memory @@ -5070,15 +4972,15 @@ /* ** CAPI3REF: Enable Or Disable Extension Loading ** ** ^So as not to open security holes in older applications that are -** unprepared to deal with [extension loading], and as a means of disabling -** [extension loading] while evaluating user-entered SQL, the following API +** unprepared to deal with extension loading, and as a means of disabling +** extension loading while evaluating user-entered SQL, the following API ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** -** ^Extension loading is off by default. +** ^Extension loading is off by default. See ticket #1863. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); @@ -5086,11 +4988,11 @@ /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that -** xEntryPoint() is the entry point for a statically linked [SQLite extension] +** xEntryPoint() is the entry point for a statically linked SQLite extension ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects and integer result as if the signature of the @@ -6437,11 +6339,11 @@ ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** **
  7. -** Index: www/contribute.wiki ================================================================== --- www/contribute.wiki +++ www/contribute.wiki @@ -8,24 +8,24 @@ In order to accept your contributions, we must have a [./contrib_agreement.wiki | Contributor Agreement] on file for you. We require this in order to maintain clear title to the System.Data.SQLite code and prevent the introduction of code with incompatible licenses or other entanglements -that might cause legal problems for System.Data.SQLite users. +that might cause legal problems for System.Data.SQLite users. If you do not wish to submit a Contributor Agreement, we would still welcome your suggestions and example code, but we will not use your code directly - we will be forced to reimplement your changes from scratch which might take longer.

    2.0 Submitting Patches

    Suggested changes or bug fixes can be submitted by creating a patch -against the current source tree. Email patches to -drh@sqlite.org. Be sure to +against the current source tree. Email patches to +drh@sqlite.org. Be sure to describe in detail what the patch does and which version of System.Data.SQLite -it is written against. +it is written against. A contributor agreement is not strictly necessary to submit a patch. However, without a contributor agreement on file, your patch will be used for reference only - it will not be applied to the code. This may delay acceptance of your patch. @@ -45,34 +45,32 @@ [http://www.mail-archive.com/sqlite-users@sqlite.org/ | mailing list]. A contributor agreement is, of course, a prerequisite for check-in privileges.

    Contributors are asked to make all non-trivial changes on a branch. A -System.Data.SQLite admin will review the branch and merge the changes +System.Data.SQLite admin will review the branch and merge the changes into the trunk.

    Contributors are required to following the [./checkin.wiki | pre-checkin checklist] prior to every checkin to the System.Data.SQLite self-hosting repository. This checklist is short and succinct -and should only require a few seconds to follow. Contributors +and should only require a few seconds to follow. Contributors should print out a copy of the pre-checkin checklist and keep it on a notecard beside their workstations, for quick reference. Contributors should review and try to mimic the coding style used through the rest of the System.Data.SQLite source code. Your code should blend in. A third-party reader should be unable to distinguish your -code from any other code in the source corpus. +code from any other code in the source corpus.

    4.0 Testing

    -System.Data.SQLite has several automated test suites that excercise its base -functionality, but this is an area that needs further work. +System.Data.SQLite has a simple test harness that excercises the basic +System.Data.SQLite functions, but this is an area that needs further work. (Your contributions here are welcomed!) -Contributors with check-in privileges are expected to run the test suites -on all changes they contribute, and if appropriate add new automated test +Contributors with check-in privileges are expected to run the test harness +on all changes they contribute, and if appropriate add new automated test scripts to cover their additions.

    5.0 See Also

    - * [./build.wiki | Build Procedures] - * [./test.wiki | Test Procedures] * [./release.wiki | Release Procedures] Index: www/downloads.wiki ================================================================== --- www/downloads.wiki +++ www/downloads.wiki @@ -1,30 +1,10 @@ System.Data.SQLite Download Page

    System.Data.SQLite Download Page

    createFlag Behavior when page is not already in cache +**
    createFlag Behaviour when page is not already in cache **
    0 Do not allocate a new page. Return NULL. **
    1 Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. **
    2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. @@ -6866,29 +6768,14 @@ ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); -/* -** CAPI3REF: String Globbing -* -** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches -** the glob pattern P, and it returns non-zero if string X does not match -** the glob pattern P. ^The definition of glob pattern matching used in -** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the -** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case -** sensitive. -** -** Note that this routine returns zero on a match and non-zero if the strings -** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. -*/ -SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); - /* ** CAPI3REF: Error Logging Interface ** -** ^The [sqlite3_log()] interface writes a message into the [error log] +** ^The [sqlite3_log()] interface writes a message into the error log ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** ^If logging is enabled, the zFormat string and subsequent arguments are ** used with [sqlite3_snprintf()] to generate the final output string. ** ** The sqlite3_log() interface is intended for use by extensions such as Index: SQLite.Interop/src/core/sqlite3ext.h ================================================================== --- SQLite.Interop/src/core/sqlite3ext.h +++ SQLite.Interop/src/core/sqlite3ext.h @@ -234,24 +234,10 @@ int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); - /* Version 3.7.16 and later */ - int (*close_v2)(sqlite3*); - const char *(*db_filename)(sqlite3*,const char*); - int (*db_readonly)(sqlite3*,const char*); - int (*db_release_memory)(sqlite3*); - const char *(*errstr)(int); - int (*stmt_busy)(sqlite3_stmt*); - int (*stmt_readonly)(sqlite3_stmt*); - int (*stricmp)(const char*,const char*); - int (*uri_boolean)(const char*,const char*,int); - sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); - const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); - int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); }; /* ** The following macros redefine the API routines so that they are ** redirected throught the global sqlite3_api structure. @@ -451,34 +437,11 @@ #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict -/* Version 3.7.16 and later */ -#define sqlite3_close_v2 sqlite3_api->close_v2 -#define sqlite3_db_filename sqlite3_api->db_filename -#define sqlite3_db_readonly sqlite3_api->db_readonly -#define sqlite3_db_release_memory sqlite3_api->db_release_memory -#define sqlite3_errstr sqlite3_api->errstr -#define sqlite3_stmt_busy sqlite3_api->stmt_busy -#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly -#define sqlite3_stricmp sqlite3_api->stricmp -#define sqlite3_uri_boolean sqlite3_api->uri_boolean -#define sqlite3_uri_int64 sqlite3_api->uri_int64 -#define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf -#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 #endif /* SQLITE_CORE */ -#ifndef SQLITE_CORE - /* This case when the file really is being compiled as a loadable - ** extension */ -# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; -# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; -#else - /* This case when the file is being statically linked into the - ** application */ -# define SQLITE_EXTENSION_INIT1 /*no-op*/ -# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ -#endif +#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; +#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ Index: SQLite.Interop/src/win/AssemblyInfo.cpp ================================================================== --- SQLite.Interop/src/win/AssemblyInfo.cpp +++ SQLite.Interop/src/win/AssemblyInfo.cpp @@ -10,11 +10,11 @@ using namespace System::Runtime::InteropServices; #include "interop.h" [assembly:AssemblyTitleAttribute("SQLite.Interop")]; -[assembly:AssemblyCompanyAttribute("http://system.data.sqlite.org/")]; +[assembly:AssemblyCompanyAttribute("Robert Simpson, et al.")]; [assembly:AssemblyDescriptionAttribute("System.Data.SQLite Interop Assembly")]; [assembly:AssemblyProductAttribute("System.Data.SQLite")]; [assembly:AssemblyCopyrightAttribute("Public Domain")]; [assembly:AssemblyVersionAttribute(INTEROP_VERSION)]; [assembly:AssemblyFileVersionAttribute(INTEROP_VERSION)]; Index: SQLite.Interop/src/win/crypt.c ================================================================== --- SQLite.Interop/src/win/crypt.c +++ SQLite.Interop/src/win/crypt.c @@ -41,26 +41,16 @@ /* Create a cryptographic context. Use the enhanced provider because it is available on ** most platforms */ static BOOL InitializeProvider() { - MUTEX_LOGIC( sqlite3_mutex *pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); ) - sqlite3_mutex_enter(pMaster); - - if (g_hProvider) - { - sqlite3_mutex_leave(pMaster); - return TRUE; - } + if (g_hProvider) return TRUE; if (!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - sqlite3_mutex_leave(pMaster); return FALSE; } - - sqlite3_mutex_leave(pMaster); return TRUE; } /* Create or update a cryptographic context for a pager. ** This function will automatically determine if the encryption algorithm requires @@ -236,26 +226,18 @@ if (!InitializeProvider()) { return MAXDWORD; } - { - MUTEX_LOGIC( sqlite3_mutex *pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); ) - sqlite3_mutex_enter(pMaster); - - if (CryptCreateHash(g_hProvider, CALG_SHA1, 0, 0, &hHash)) - { - if (CryptHashData(hHash, (LPBYTE)pKey, nKeyLen, 0)) - { - CryptDeriveKey(g_hProvider, CALG_RC4, hHash, 0, &hKey); - } - CryptDestroyHash(hHash); - } - - sqlite3_mutex_leave(pMaster); - } - + if (CryptCreateHash(g_hProvider, CALG_SHA1, 0, 0, &hHash)) + { + if (CryptHashData(hHash, (LPBYTE)pKey, nKeyLen, 0)) + { + CryptDeriveKey(g_hProvider, CALG_RC4, hHash, 0, &hKey); + } + CryptDestroyHash(hHash); + } return hKey; } /* Called by sqlite and sqlite3_key_interop to attach a key to a database. */ int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen) Index: SQLite.Interop/src/win/interop.c ================================================================== --- SQLite.Interop/src/win/interop.c +++ SQLite.Interop/src/win/interop.c @@ -39,11 +39,11 @@ #endif typedef void (*SQLITEUSERFUNC)(sqlite3_context *, int, sqlite3_value **); typedef void (*SQLITEFUNCFINAL)(sqlite3_context *); -#if defined(INTEROP_DEBUG) || defined(INTEROP_LOG) +#if defined(INTEROP_DEBUG) SQLITE_PRIVATE void sqlite3InteropDebug(const char *zFormat, ...){ va_list ap; /* Vararg list */ StrAccum acc; /* String accumulator */ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ va_start(ap, zFormat); @@ -67,19 +67,11 @@ fprintf(stderr, "%s", sqlite3StrAccumFinish(&acc)); #endif } #endif -#if defined(INTEROP_LOG) -SQLITE_PRIVATE int logConfigured = 0; - -SQLITE_PRIVATE void sqlite3InteropLogCallback(void *pArg, int iCode, const char *zMsg){ - sqlite3InteropDebug("INTEROP_LOG (%d) %s\n", iCode, zMsg); -} -#endif - -#if defined(INTEROP_LEGACY_CLOSE) || SQLITE_VERSION_NUMBER < 3007014 +#if SQLITE_VERSION_NUMBER < 3007014 SQLITE_PRIVATE void * sqlite3DbMallocZero_interop(sqlite3 *db, int n) { void *p; if (db) { sqlite3_mutex_enter(db->mutex); @@ -120,11 +112,11 @@ GC gets around to calling finalize_interop() on the "bad" statement, we detect that and finish deallocating the pointer. */ SQLITE_API int WINAPI sqlite3_close_interop(sqlite3 *db) { int ret; -#if !defined(INTEROP_LEGACY_CLOSE) && SQLITE_VERSION_NUMBER >= 3007014 +#if SQLITE_VERSION_NUMBER >= 3007014 #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_CLOSE) sqlite3InteropDebug("sqlite3_close_interop(): calling sqlite3_close_v2(%p)...\n", db); #endif @@ -189,29 +181,11 @@ } return ret; #endif } -#if defined(INTEROP_LOG) -SQLITE_API int WINAPI sqlite3_config_log_interop() -{ - int ret; - if( !logConfigured ){ - ret = sqlite3_config(SQLITE_CONFIG_LOG, sqlite3InteropLogCallback, 0); - if( ret==SQLITE_OK ){ - logConfigured = 1; - }else{ - sqlite3InteropDebug("sqlite3_config_log_interop(): sqlite3_config(SQLITE_CONFIG_LOG) returned %d.\n", ret); - } - }else{ - ret = SQLITE_OK; - } - return ret; -} -#endif - -SQLITE_API int WINAPI sqlite3_open_interop(const char *filename, int flags, sqlite3 **ppdb) +SQLITE_API int WINAPI sqlite3_open_interop(const char*filename, int flags, sqlite3 **ppdb) { int ret; #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN) sqlite3InteropDebug("sqlite3_open_interop(): calling sqlite3_open_v2(\"%s\", %d, %p)...\n", filename, flags, ppdb); @@ -267,10 +241,13 @@ #endif #ifndef NDEBUG if (!db) sqlite3InteropBreak("null database handle for sqlite3_changes()"); + + if (!sqlite3SafetyCheckOk(db)) + sqlite3InteropBreak("bad database handle for sqlite3_changes()"); #endif result = sqlite3_changes(db); #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_CHANGES) @@ -286,15 +263,11 @@ #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_PREPARE) sqlite3InteropDebug("sqlite3_prepare_interop(): calling sqlite3_prepare(%p, \"%s\", %d, %p)...\n", db, sql, nbytes, ppstmt); #endif -#if SQLITE_VERSION_NUMBER >= 3003009 - n = sqlite3_prepare_v2(db, sql, nbytes, ppstmt, pztail); -#else n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); -#endif #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_PREPARE) sqlite3InteropDebug("sqlite3_prepare_interop(): sqlite3_prepare(%p, \"%s\", %d, %p) returned %d.\n", db, sql, nbytes, ppstmt, n); #endif @@ -309,15 +282,11 @@ #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_PREPARE16) sqlite3InteropDebug("sqlite3_prepare_interop(): calling sqlite3_prepare16(%p, \"%s\", %d, %p)...\n", db, sql, nchars, ppstmt); #endif -#if SQLITE_VERSION_NUMBER >= 3003009 - n = sqlite3_prepare16_v2(db, sql, nchars * sizeof(wchar_t), ppstmt, pztail); -#else n = sqlite3_prepare16(db, sql, nchars * sizeof(wchar_t), ppstmt, pztail); -#endif #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_PREPARE16) sqlite3InteropDebug("sqlite3_prepare_interop(): sqlite3_prepare16(%p, \"%s\", %d, %p) returned %d.\n", db, sql, nchars, ppstmt, n); #endif @@ -397,25 +366,25 @@ } SQLITE_API const unsigned char * WINAPI sqlite3_column_text_interop(sqlite3_stmt *stmt, int iCol, int *plen) { const unsigned char *pval = sqlite3_column_text(stmt, iCol); - *plen = sqlite3_column_bytes(stmt, iCol); + *plen = (pval != 0) ? strlen((char *)pval) : 0; return pval; } SQLITE_API const void * WINAPI sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol, int *plen) { const void *pval = sqlite3_column_text16(stmt, iCol); - *plen = sqlite3_column_bytes16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; return pval; } SQLITE_API int WINAPI sqlite3_finalize_interop(sqlite3_stmt *stmt) { int ret; -#if !defined(INTEROP_LEGACY_CLOSE) && SQLITE_VERSION_NUMBER >= 3007014 +#if SQLITE_VERSION_NUMBER >= 3007014 #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_FINALIZE) Vdbe *p = (Vdbe *)stmt; sqlite3 *db = p->db; sqlite3InteropDebug("sqlite3_finalize_interop(): calling sqlite3_finalize(%p, %p)...\n", db, stmt); @@ -428,11 +397,11 @@ #endif return ret; #else Vdbe *p; - ret = SQLITE_OK; + int ret = SQLITE_OK; p = (Vdbe *)stmt; if (p) { sqlite3 *db = p->db; @@ -477,11 +446,11 @@ } SQLITE_API int WINAPI sqlite3_reset_interop(sqlite3_stmt *stmt) { int ret; -#if !defined(INTEROP_LEGACY_CLOSE) && SQLITE_VERSION_NUMBER >= 3007014 +#if SQLITE_VERSION_NUMBER >= 3007014 #if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_RESET) sqlite3InteropDebug("sqlite3_reset_interop(): calling sqlite3_reset(%p)...\n", stmt); #endif @@ -533,18 +502,18 @@ } SQLITE_API const unsigned char * WINAPI sqlite3_value_text_interop(sqlite3_value *val, int *plen) { const unsigned char *pval = sqlite3_value_text(val); - *plen = sqlite3_value_bytes(val); + *plen = (pval != 0) ? strlen((char *)pval) : 0; return pval; } SQLITE_API const void * WINAPI sqlite3_value_text16_interop(sqlite3_value *val, int *plen) { const void *pval = sqlite3_value_text16(val); - *plen = sqlite3_value_bytes16(val); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; return pval; } SQLITE_API void WINAPI sqlite3_result_double_interop(sqlite3_context *pctx, double *val) { @@ -766,11 +735,11 @@ /* ** The interopTest() SQL function returns its first argument or raises an ** error if there are not enough arguments. */ -SQLITE_PRIVATE void interopTestFunc( +static void interopTestFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z; @@ -784,33 +753,10 @@ }else{ sqlite3_result_null(context); } } -/* -** The interopSleep() SQL function waits the specified number of milliseconds -** or raises an error if there are not enough arguments. -*/ -SQLITE_PRIVATE void interopSleepFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - int m; - if( argc!=1 ){ - sqlite3_result_error(context, "need exactly one argument", -1); - return; - } - m = sqlite3_value_int(argv[0]); -#if SQLITE_OS_WINCE - Sleep(m); - sqlite3_result_int(context, WAIT_OBJECT_0); -#else - sqlite3_result_int(context, SleepEx(m, TRUE)); -#endif -} - /* SQLite invokes this routine once when it loads the extension. ** Create new functions, collating sequences, and virtual table ** modules here. This is usually the only exported symbol in ** the shared library. */ @@ -817,16 +763,10 @@ SQLITE_API int interop_test_extension_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ - int rc; SQLITE_EXTENSION_INIT2(pApi) - rc = sqlite3_create_function(db, "interopTest", -1, SQLITE_ANY, 0, + return sqlite3_create_function(db, "interopTest", -1, SQLITE_ANY, 0, interopTestFunc, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "interopSleep", 1, SQLITE_ANY, 0, - interopSleepFunc, 0, 0); - } - return rc; } #endif Index: SQLite.Interop/src/win/interop.h ================================================================== --- SQLite.Interop/src/win/interop.h +++ SQLite.Interop/src/win/interop.h @@ -4,7 +4,7 @@ * Written by Joe Mistachkin. * Released to the public domain, use at your own risk! */ #ifndef INTEROP_VERSION -#define INTEROP_VERSION "1.0.86.0" +#define INTEROP_VERSION "1.0.83.0" #endif Index: SQLite.MSIL.nuspec ================================================================== --- SQLite.MSIL.nuspec +++ SQLite.MSIL.nuspec @@ -8,11 +8,11 @@ * --> System.Data.SQLite.MSIL - 1.0.86.0 + 1.0.83.0 SQLite Development Team An ADO.NET provider for SQLite (managed-only). en-US http://system.data.sqlite.org/ http://system.data.sqlite.org/images/sqlite32.png @@ -21,11 +21,9 @@ Public Domain - - Index: SQLite.NET.2005.MSBuild.sln ================================================================== --- SQLite.NET.2005.MSBuild.sln +++ SQLite.NET.2005.MSBuild.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2005.sln ================================================================== --- SQLite.NET.2005.sln +++ SQLite.NET.2005.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2008.MSBuild.sln ================================================================== --- SQLite.NET.2008.MSBuild.sln +++ SQLite.NET.2008.MSBuild.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2008.sln ================================================================== --- SQLite.NET.2008.sln +++ SQLite.NET.2008.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2010.MSBuild.sln ================================================================== --- SQLite.NET.2010.MSBuild.sln +++ SQLite.NET.2010.MSBuild.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2010.sln ================================================================== --- SQLite.NET.2010.sln +++ SQLite.NET.2010.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2012.MSBuild.sln ================================================================== --- SQLite.NET.2012.MSBuild.sln +++ SQLite.NET.2012.MSBuild.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.2012.sln ================================================================== --- SQLite.NET.2012.sln +++ SQLite.NET.2012.sln @@ -4,15 +4,12 @@ ProjectSection(SolutionItems) = preProject exclude_bin.txt = exclude_bin.txt exclude_src.txt = exclude_src.txt install.ps1 = install.ps1 readme.htm = readme.htm - SQLite.Beta.nuspec = SQLite.Beta.nuspec SQLite.MSIL.nuspec = SQLite.MSIL.nuspec SQLite.NET.Settings.targets = SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 = SQLite.NET.Settings.targets.netFx35 - SQLite.NET.targets = SQLite.NET.targets SQLite.nuspec = SQLite.nuspec SQLite.x64.nuspec = SQLite.x64.nuspec SQLite.x86.nuspec = SQLite.x86.nuspec System.Data.SQLite\System.Data.SQLite.CF.snk = System.Data.SQLite\System.Data.SQLite.CF.snk System.Data.SQLite\System.Data.SQLite.Files.targets = System.Data.SQLite\System.Data.SQLite.Files.targets Index: SQLite.NET.Settings.targets ================================================================== --- SQLite.NET.Settings.targets +++ SQLite.NET.Settings.targets @@ -18,41 +18,10 @@ settings, if any, will override the default ones provided below. --> - - - - - - - - - - - @@ -127,50 +96,10 @@ build the project using Visual Studio 2012 and/or the .NET Framework 4.5 (if necessary, it will typically be enabled from within the project file itself). --> false - - - false - - - false - - - false - - - false false - - false - true - - true - true false - - false - - - true - false - DELETED SQLite.NET.Settings.targets.netFx35 Index: SQLite.NET.Settings.targets.netFx35 ================================================================== --- SQLite.NET.Settings.targets.netFx35 +++ /dev/null @@ -1,22 +0,0 @@ - - - - true - true - false - false - v3.5 - - false - v110 - - Index: SQLite.nuspec ================================================================== --- SQLite.nuspec +++ SQLite.nuspec @@ -9,11 +9,11 @@ --> System.Data.SQLite System.Data.SQLite (x86/x64) - 1.0.86.0 + 1.0.83.0 SQLite Development Team The official SQLite database engine for both x86 and x64 along with the ADO.NET provider. en-US http://system.data.sqlite.org/ http://system.data.sqlite.org/images/sqlite32.png @@ -22,18 +22,14 @@ Public Domain - - - - Index: SQLite.x64.nuspec ================================================================== --- SQLite.x64.nuspec +++ SQLite.x64.nuspec @@ -8,11 +8,11 @@ * --> System.Data.SQLite.x64 - 1.0.86.0 + 1.0.83.0 SQLite Development Team The official SQLite database engine combined with a complete ADO.NET provider all rolled into a single mixed-mode assembly for x64. en-US http://system.data.sqlite.org/ http://system.data.sqlite.org/images/sqlite32.png @@ -21,11 +21,9 @@ Public Domain - - Index: SQLite.x86.nuspec ================================================================== --- SQLite.x86.nuspec +++ SQLite.x86.nuspec @@ -8,11 +8,11 @@ * --> System.Data.SQLite.x86 - 1.0.86.0 + 1.0.83.0 SQLite Development Team The official SQLite database engine combined with a complete ADO.NET provider all rolled into a single mixed-mode assembly for x86. en-US http://system.data.sqlite.org/ http://system.data.sqlite.org/images/sqlite32.png @@ -21,11 +21,9 @@ Public Domain - - Index: Setup/CheckForNetFx.pas ================================================================== --- Setup/CheckForNetFx.pas +++ Setup/CheckForNetFx.pas @@ -31,27 +31,10 @@ NetFx4ServicePack: Integer; NetFx4ErrorMessage: String; VcRuntimeRedistributable: String; -function TrimSlash(const Path: String): String; -var - LastCharacter: String; -begin - Result := Path; - - if Result <> '' then - begin - LastCharacter := Copy(Result, Length(Result), 1); - - if (LastCharacter = '\') or (LastCharacter = '/') then - begin - Result := Copy(Result, 1, Length(Result) - 1); - end; - end; -end; - function CheckForNetFx2(const NeedServicePack: Integer): Boolean; var SubKeyName: String; IsInstalled: Cardinal; HasServicePack: Cardinal; @@ -138,18 +121,15 @@ Result := ''; if RegQueryStringValue(HKEY_LOCAL_MACHINE, NetFxSubKeyName, NetFxInstallRoot, InstallRoot) then begin - if InstallRoot <> '' then - begin - Result := TrimSlash(InstallRoot) + '\' + NetFx2Version; - - if FileName <> '' then - begin - Result := TrimSlash(Result) + '\' + FileName; - end; + Result := InstallRoot + '\' + NetFx2Version; + + if FileName <> '' then + begin + Result := Result + '\' + FileName; end; end; end; function GetNetFx4InstallRoot(const FileName: String): String; @@ -159,18 +139,15 @@ Result := ''; if RegQueryStringValue(HKEY_LOCAL_MACHINE, NetFxSubKeyName, NetFxInstallRoot, InstallRoot) then begin - if InstallRoot <> '' then - begin - Result := TrimSlash(InstallRoot) + '\' + NetFx4Version; - - if FileName <> '' then - begin - Result := TrimSlash(Result) + '\' + FileName; - end; + Result := InstallRoot + '\' + NetFx4Version; + + if FileName <> '' then + begin + Result := Result + '\' + FileName; end; end; end; function CheckIsNetFx2Setup(): Boolean; Index: Setup/SQLite.iss ================================================================== --- Setup/SQLite.iss +++ Setup/SQLite.iss @@ -81,11 +81,11 @@ #else Components: Application\Core\MSIL Or Application\LINQ; Name: gac; Description: Install the assemblies into the global assembly cache.; Flags: unchecked; Check: CheckIsNetFx2Setup() or CheckIsNetFx4Setup() #endif #if AppProcessor == "x86" -#if Year == "2005" +#if Year == "2005" || Year == "2008" Components: {#InstallerCondition}; Name: gac\vs2005; Description: Install the designer components for Visual Studio 2005.; Flags: unchecked; Check: CheckIsNetFx2Setup() #endif #if Year == "2008" Components: {#InstallerCondition}; Name: gac\vs2008; Description: Install the designer components for Visual Studio 2008.; Flags: unchecked; Check: CheckIsNetFx2Setup() #endif @@ -106,11 +106,11 @@ Components: Application\LINQ; Tasks: ngen; Filename: {code:GetNetFx2InstallRoot|Ngen.exe}; Parameters: "install ""{app}\bin\System.Data.SQLite.Linq.dll"" /nologo"; Flags: skipifdoesntexist; Check: CheckIsNetFx2Setup() and CheckForNetFx35(1) Components: Application\LINQ; Tasks: ngen; Filename: {code:GetNetFx4InstallRoot|Ngen.exe}; Parameters: "install ""{app}\bin\System.Data.SQLite.Linq.dll"" /nologo"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() #endif #if Pos("NativeOnly", AppConfiguration) == 0 && AppProcessor == "x86" -#if Year == "2005" +#if Year == "2005" || Year == "2008" Components: {#InstallerCondition}; Tasks: gac\vs2005; Filename: {app}\bin\Installer.exe; Parameters: "-install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx35 true -noNetFx40 true -noNetFx45 true -noVs2008 true -noVs2010 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx2Setup() #endif #if Year == "2008" Components: {#InstallerCondition}; Tasks: gac\vs2008; Filename: {app}\bin\Installer.exe; Parameters: "-install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx40 true -noNetFx45 true -noVs2005 true -noVs2010 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx2Setup() #endif @@ -117,27 +117,27 @@ #if Year == "2010" Components: {#InstallerCondition}; Tasks: gac\vs2010; Filename: {app}\bin\Installer.exe; Parameters: "-install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx45 true -noVs2005 true -noVs2008 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() #endif #if Year == "2012" Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() -Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-perUser true -install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noNetFx45 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -vsVersionSuffix _Config -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() +Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-perUser true -install true -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -vsVersionSuffix _Config -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() #endif #endif [UninstallRun] #if Pos("NativeOnly", AppConfiguration) == 0 && AppProcessor == "x86" #if Year == "2012" -Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-perUser true -install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noNetFx45 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -vsVersionSuffix _Config -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() +Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-perUser true -install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -vsVersionSuffix _Config -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() Components: {#InstallerCondition}; Tasks: gac\vs2012; Filename: {app}\bin\Installer.exe; Parameters: "-install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx40 true -noVs2005 true -noVs2008 true -noVs2010 true -configVersion 4.0.30319 -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() #endif #if Year == "2010" Components: {#InstallerCondition}; Tasks: gac\vs2010; Filename: {app}\bin\Installer.exe; Parameters: "-install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx20 true -noNetFx45 true -noVs2005 true -noVs2008 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx4Setup() #endif #if Year == "2008" Components: {#InstallerCondition}; Tasks: gac\vs2008; Filename: {app}\bin\Installer.exe; Parameters: "-install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx40 true -noNetFx45 true -noVs2005 true -noVs2010 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx2Setup() #endif -#if Year == "2005" +#if Year == "2005" || Year == "2008" Components: {#InstallerCondition}; Tasks: gac\vs2005; Filename: {app}\bin\Installer.exe; Parameters: "-install false -wow64 true -installFlags AllExceptGlobalAssemblyCache -tracePriority Lowest -verbose true -noCompact true -noNetFx35 true -noNetFx40 true -noNetFx45 true -noVs2008 true -noVs2010 true -noVs2012 true -whatIf false -confirm true"; Flags: skipifdoesntexist; Check: CheckIsNetFx2Setup() #endif #endif #if Year != "2005" Index: Setup/build_ce.bat ================================================================== --- Setup/build_ce.bat +++ Setup/build_ce.bat @@ -28,16 +28,16 @@ SET TOOLS=%~dp0 SET TOOLS=%TOOLS:~0,-1% %_VECHO% Tools = '%TOOLS%' -SET BUILD_CONFIGURATIONS=Debug Release +SET BUILD_CONFIGURATIONS=Release SET BASE_CONFIGURATIONSUFFIX=Compact SET PLATFORMS="Pocket PC 2003 (ARMV4)" SET PROCESSORS=arm -SET YEARS=2005 2008 -SET BASE_PLATFORM=PocketPC-ARM +SET YEARS=2008 +SET BASE_PLATFORM=PocketPC CALL :fn_ResetErrorLevel %__ECHO3% CALL "%TOOLS%\build_all.bat" Index: Setup/clean.bat ================================================================== --- Setup/clean.bat +++ Setup/clean.bat @@ -74,145 +74,10 @@ %_AECHO% Directory "%SOURCE%\%%D" does not exist. %_AECHO%. ) ) -IF EXIST "%SOURCE%\*.cache" ( - REM - REM NOTE: *WARNING* Deleting from the entire source tree. - REM - %__ECHO% DEL /S /Q "%SOURCE%\*.cache" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.cache". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.cache". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.cache" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.ncb" ( - REM - REM NOTE: *WARNING* Deleting from the entire source tree. - REM - %__ECHO% DEL /S /Q "%SOURCE%\*.ncb" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.ncb". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.ncb". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.ncb" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.psess" ( - %__ECHO% DEL /Q "%SOURCE%\*.psess" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.psess". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.psess". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.psess" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.sdf" ( - %__ECHO% DEL /Q "%SOURCE%\*.sdf" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.sdf". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.sdf". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.sdf" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.suo" ( - REM - REM NOTE: *WARNING* Unhiding in the entire source tree. - REM - %__ECHO% ATTRIB -H "%SOURCE%\*.suo" /S - - IF ERRORLEVEL 1 ( - ECHO Could not make "%SOURCE%\*.suo" visible. - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Made "%SOURCE%\*.suo" visible. - %_AECHO%. - ) - - REM - REM NOTE: *WARNING* Deleting from the entire source tree. - REM - %__ECHO% DEL /S /Q "%SOURCE%\*.suo" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.suo". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.suo". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.suo" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.vsp" ( - %__ECHO% DEL /Q "%SOURCE%\*.vsp" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.vsp". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.vsp". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.vsp" exist. - %_AECHO%. -) - -IF EXIST "%SOURCE%\*.vsps" ( - %__ECHO% DEL /Q "%SOURCE%\*.vsps" - - IF ERRORLEVEL 1 ( - ECHO Could not delete "%SOURCE%\*.vsps". - ECHO. - GOTO errors - ) ELSE ( - %_AECHO% Deleted "%SOURCE%\*.vsps". - %_AECHO%. - ) -) ELSE ( - %_AECHO% No files matching "%SOURCE%\*.vsps" exist. - %_AECHO%. -) - IF EXIST "%SOURCE%\*.nupkg" ( %__ECHO% DEL /Q "%SOURCE%\*.nupkg" IF ERRORLEVEL 1 ( ECHO Could not delete "%SOURCE%\*.nupkg". Index: Setup/deployAndTestCe.eagle ================================================================== --- Setup/deployAndTestCe.eagle +++ Setup/deployAndTestCe.eagle @@ -27,11 +27,11 @@ # NOTE: This procedure will output a diagnostic message, typically to the # standard output channel, using the [puts] command unless the global # variable "quiet" is non-zero. # proc qputs { args } { - if {![info exists ::quiet] || !$::quiet} then { + if {!$::quiet} then { eval puts $args; flush stdout } } # @@ -116,76 +116,42 @@ if {$argc > $index} then { set value [string trim [lindex $argv $index]] } if {[string length $value] > 0} then { - set $name $value; set defaultValue false + set $name $value } else { - set $name $default($name); set defaultValue true + set $name $default($name) } - - qputs stdout [appendArgs \ - "named parameter \"" $name "\" value is now \"" [set $name] \" \ - [expr {$defaultValue ? " (default)" : ""}] .] } # # NOTE: Grab the culture instance based on the configured culture name. # set cultureInfo [object invoke -alias System.Globalization.CultureInfo \ GetCultureInfo $culture] # - # NOTE: Build the list of .NET Compact Framework 2.0 packages that need to - # be deployed to the target device, if necessary. - # - if {![info exists packages(2005)]} then { - # - # NOTE: The three letter Windows language name is needed when building - # the default list of .NET Compact Framework packages because one - # of them is a localized resource package. - # - set language3 [string toupper \ - [$cultureInfo ThreeLetterWindowsLanguageName]] - - # - # NOTE: The default list of .NET Compact Framework 2.0 packages contains - # the .NET Compact Framework 2.0 installation CAB file for ARMV4 - # on the Pocket PC and its associated resource installation CAB - # files. - # - set packages(2005) [list \ - abd785f0-cda7-41c5-8375-2451a7cbff26 \ - \\Windows\\NETCFv2.ppc.armv4.cab \ - c0ccf48e-4bfb-4d84-827c-981a595e40b4 \ - [appendArgs \\Windows\\System_SR_ $language3 .cab]] - } - - # - # NOTE: Build the list of .NET Compact Framework 3.5 packages that need to - # be deployed to the target device, if necessary. - # - if {![info exists packages(2008)]} then { + # NOTE: Build the list of .NET Compact Framework packages that need to be + # deployed to the target device. + # + if {![info exists packages]} then { # # NOTE: The two letter ISO language name is needed when building the # default list of .NET Compact Framework packages because one of # them is a localized resource package. # - set language2 [string toupper \ - [$cultureInfo TwoLetterISOLanguageName]] - - # - # NOTE: The default list of .NET Compact Framework 3.5 packages contains - # the .NET Compact Framework 3.5 installation CAB file for ARMV4 - # on the Pocket PC and its associated resource installation CAB - # files. - # - set packages(2008) [list \ - abd785f0-cda7-41c5-8375-2451a7cbff37 \ - \\Windows\\NETCFv35.ppc.armv4.cab \ - c0ccf48e-4bfb-4d84-827c-981a595e40c5 \ - [appendArgs \\Windows\\NETCFv35.Messages. $language2 .cab]] + set language [string toupper [$cultureInfo TwoLetterISOLanguageName]] + + # + # NOTE: The default list of .NET Compact Framework packages contains the + # .NET Compact Framework 3.5 installation CAB file for ARMV4 on the + # Pocket PC and its associated resource installation CAB file. + # + set packages [list abd785f0-cda7-41c5-8375-2451a7cbff37 \ + \\windows\\NETCFv35.ppc.armv4.cab c0ccf48e-4bfb-4d84-827c-981a595e40c5 \ + [appendArgs \\windows\\NETCFv35.Messages. $language .cab]] } # # NOTE: Save the path where this script is running from. # @@ -234,11 +200,11 @@ # set fileNames [list [file join $managed_directory testce.exe] [file \ join $managed_directory System.Data.SQLite.dll] [file join \ $native_directory [appendArgs SQLite.Interop. [format %03d \ [$assemblyName Version.Build]] .dll]] [file join $managed_directory \ - test.cfg] [file join $managed_directory test.sql]] + test.cfg]] } # # NOTE: Setup the directory on the target device where the application files # should be deployed to. @@ -273,33 +239,27 @@ # be used to download packages and send files to the target device. # set fileDeployer [$device -alias GetFileDeployer] # - # NOTE: If the list of packages related to the configured build year do not - # exist, skip this step. - # - if {[info exists packages($year)]} then { - # - # NOTE: Process each entry in the list of packages to be downloaded to the - # target device. The package list must contain the package Id and - # the file name (relative to the target device), in that order, for - # each package to be downloaded to the target device. - # - foreach {packageId packageFileName} $packages($year) { - qputs stdout [appendArgs \ - "downloading package \"" $packageId "\" to device..."] - - $fileDeployer DownloadPackage [object create \ - Microsoft.SmartDevice.Connectivity.ObjectId $packageId] - - qputs stdout [appendArgs \ - "installing package file \"" $packageFileName "\" on device..."] - - startRemoteProcess $device wceload.exe [appendArgs "/noui " \ - $packageFileName] - } + # NOTE: Process each entry in the list of packages to be downloaded to the + # target device. The package list must contain the package Id and the + # file name (relative to the target device), in that order, for each + # package to be downloaded to the target device. + # + foreach {packageId packageFileName} $packages { + qputs stdout [appendArgs \ + "downloading package \"" $packageId "\" to device..."] + + $fileDeployer DownloadPackage [object create \ + Microsoft.SmartDevice.Connectivity.ObjectId $packageId] + + qputs stdout [appendArgs \ + "installing package file \"" $packageFileName "\" on device..."] + + startRemoteProcess $device wceload.exe [appendArgs "/noui " \ + $packageFileName] } # # NOTE: Process each application file to be sent to the target device. # Index: Setup/release_ce.bat ================================================================== --- Setup/release_ce.bat +++ Setup/release_ce.bat @@ -33,11 +33,11 @@ SET RELEASE_CONFIGURATIONS=Release SET BASE_CONFIGURATIONSUFFIX=Compact SET PLATFORMS="Pocket PC 2003 (ARMV4)" SET PROCESSORS=arm SET YEARS=2008 -SET BASE_PLATFORM=PocketPC-ARM +SET BASE_PLATFORM=PocketPC SET TYPE=binary CALL :fn_ResetErrorLevel %__ECHO3% CALL "%TOOLS%\release_all.bat" Index: Setup/set_common.bat ================================================================== --- Setup/set_common.bat +++ Setup/set_common.bat @@ -18,15 +18,15 @@ IF NOT DEFINED PUBLICKEY ( SET PUBLICKEY=db937bc2d44ff139 ) IF NOT DEFINED BUILD_CONFIGURATIONS ( - SET BUILD_CONFIGURATIONS=Debug DebugNativeOnly Release ReleaseNativeOnly + SET BUILD_CONFIGURATIONS=Release ReleaseNativeOnly ) IF NOT DEFINED TEST_CONFIGURATIONS ( - SET TEST_CONFIGURATIONS=Debug Release + SET TEST_CONFIGURATIONS=Release ) IF NOT DEFINED BAKE_CONFIGURATIONS ( SET BAKE_CONFIGURATIONS=Release ReleaseNativeOnly ) Index: Setup/set_netFx20.bat ================================================================== --- Setup/set_netFx20.bat +++ Setup/set_netFx20.bat @@ -10,11 +10,11 @@ IF NOT DEFINED ISNETFX2 ( SET ISNETFX2=True ) IF NOT DEFINED VCRUNTIME ( - SET VCRUNTIME=2005_SP1_MFC + SET VCRUNTIME=2005_SP1 ) IF NOT DEFINED CONFIGURATION ( SET CONFIGURATION=Release ) Index: Setup/set_netFx35.bat ================================================================== --- Setup/set_netFx35.bat +++ Setup/set_netFx35.bat @@ -10,11 +10,11 @@ IF NOT DEFINED ISNETFX2 ( SET ISNETFX2=True ) IF NOT DEFINED VCRUNTIME ( - SET VCRUNTIME=2008_SP1_MFC + SET VCRUNTIME=2008_SP1 ) IF NOT DEFINED CONFIGURATION ( SET CONFIGURATION=Release ) Index: Setup/set_netFx40.bat ================================================================== --- Setup/set_netFx40.bat +++ Setup/set_netFx40.bat @@ -10,11 +10,11 @@ IF NOT DEFINED ISNETFX2 ( SET ISNETFX2=False ) IF NOT DEFINED VCRUNTIME ( - SET VCRUNTIME=2010_SP1_MFC + SET VCRUNTIME=2010_SP1 ) IF NOT DEFINED CONFIGURATION ( SET CONFIGURATION=Release ) Index: Setup/set_netFx45.bat ================================================================== --- Setup/set_netFx45.bat +++ Setup/set_netFx45.bat @@ -10,11 +10,11 @@ IF NOT DEFINED ISNETFX2 ( SET ISNETFX2=False ) IF NOT DEFINED VCRUNTIME ( - SET VCRUNTIME=2012_VSU1 + SET VCRUNTIME=2012_RTM ) IF NOT DEFINED CONFIGURATION ( SET CONFIGURATION=Release ) Index: Setup/set_user_mistachkin_Debug.bat ================================================================== --- Setup/set_user_mistachkin_Debug.bat +++ Setup/set_user_mistachkin_Debug.bat @@ -11,9 +11,8 @@ REM REM NOTE: Enables the extra debug code helpful in troubleshooting issues. REM SET MSBUILD_ARGS=/p:CheckState=true -SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:CountHandle=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceConnection=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceHandle=true SET MSBUILD_ARGS=%MSBUILD_ARGS% /p:TraceStatement=true Index: Setup/set_x64_2005.bat ================================================================== --- Setup/set_x64_2005.bat +++ Setup/set_x64_2005.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=True -SET VCRUNTIME=2005_SP1_MFC +SET VCRUNTIME=2005_SP1 SET PLATFORM=x64 SET PROCESSOR=x64 SET YEAR=2005 Index: Setup/set_x64_2008.bat ================================================================== --- Setup/set_x64_2008.bat +++ Setup/set_x64_2008.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=True -SET VCRUNTIME=2008_SP1_MFC +SET VCRUNTIME=2008_SP1 SET PLATFORM=x64 SET PROCESSOR=x64 SET YEAR=2008 Index: Setup/set_x64_2010.bat ================================================================== --- Setup/set_x64_2010.bat +++ Setup/set_x64_2010.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2010_SP1_MFC +SET VCRUNTIME=2010_SP1 SET PLATFORM=x64 SET PROCESSOR=x64 SET YEAR=2010 Index: Setup/set_x64_2012.bat ================================================================== --- Setup/set_x64_2012.bat +++ Setup/set_x64_2012.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2012_VSU1 +SET VCRUNTIME=2012_RTM SET PLATFORM=x64 SET PROCESSOR=x64 SET YEAR=2012 Index: Setup/set_x86_2005.bat ================================================================== --- Setup/set_x86_2005.bat +++ Setup/set_x86_2005.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=True -SET VCRUNTIME=2005_SP1_MFC +SET VCRUNTIME=2005_SP1 SET PLATFORM=Win32 SET PROCESSOR=x86 SET YEAR=2005 Index: Setup/set_x86_2008.bat ================================================================== --- Setup/set_x86_2008.bat +++ Setup/set_x86_2008.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=True -SET VCRUNTIME=2008_SP1_MFC +SET VCRUNTIME=2008_SP1 SET PLATFORM=Win32 SET PROCESSOR=x86 SET YEAR=2008 Index: Setup/set_x86_2010.bat ================================================================== --- Setup/set_x86_2010.bat +++ Setup/set_x86_2010.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2010_SP1_MFC +SET VCRUNTIME=2010_SP1 SET PLATFORM=Win32 SET PROCESSOR=x86 SET YEAR=2010 Index: Setup/set_x86_2012.bat ================================================================== --- Setup/set_x86_2012.bat +++ Setup/set_x86_2012.bat @@ -6,9 +6,9 @@ :: Written by Joe Mistachkin. :: Released to the public domain, use at your own risk! :: SET ISNETFX2=False -SET VCRUNTIME=2012_VSU1 +SET VCRUNTIME=2012_RTM SET PLATFORM=Win32 SET PROCESSOR=x86 SET YEAR=2012 Index: Setup/test_all.bat ================================================================== --- Setup/test_all.bat +++ Setup/test_all.bat @@ -98,16 +98,10 @@ IF ERRORLEVEL 1 ( ECHO Could not change directory to "%ROOT%". GOTO errors ) -REM -REM NOTE: Set an environment variable that can be used by the test suite to -REM determine that testing is being performed in batch mode. -REM -SET TEST_ALL=1 - FOR %%C IN (%TEST_CONFIGURATIONS%) DO ( FOR %%Y IN (%YEARS%) DO ( IF NOT DEFINED NOMANAGEDONLY ( %__ECHO% Externals\Eagle\bin\EagleShell.exe -preInitialize "set test_year {%%Y}; set test_configuration {%%C}" -file "%TEST_FILE%" Index: Setup/verify.lst ================================================================== --- Setup/verify.lst +++ Setup/verify.lst @@ -80,11 +80,10 @@ Setup/build.bat Setup/build_all.bat Setup/build_ce.bat Setup/CheckForNetFx.pas Setup/clean.bat - Setup/deployAndTestCe.eagle Setup/InitializeSetup.pas Setup/release.bat Setup/release_all.bat Setup/release_ce.bat Setup/release_static.bat @@ -129,16 +128,14 @@ Setup/set_x86_2008.bat Setup/set_x86_2010.bat Setup/set_x86_2012.bat Setup/SQLite.iss Setup/test_all.bat - Setup/test_ce.bat Setup/updateFileInfo.tcl Setup/verify.eagle Setup/verify.lst Setup/vsSp.bat - SQLite.Beta.nuspec SQLite.Designer/ SQLite.Designer/AssemblyInfo.cs SQLite.Designer/ChangePasswordDialog.cs SQLite.Designer/ChangePasswordDialog.Designer.cs SQLite.Designer/ChangePasswordDialog.resx @@ -248,11 +245,10 @@ SQLite.NET.2010.MSBuild.sln SQLite.NET.2010.sln SQLite.NET.2012.MSBuild.sln SQLite.NET.2012.sln SQLite.NET.Settings.targets - SQLite.NET.Settings.targets.netFx35 SQLite.NET.targets SQLite.nuspec SQLite.x64.nuspec SQLite.x86.nuspec System.Data.SQLite/ @@ -396,52 +392,41 @@ Tests/ Tests/all.eagle Tests/backup.eagle Tests/basic.eagle Tests/common.eagle - Tests/empty.eagle Tests/installer.eagle Tests/Installer_Test_Vs2005.log Tests/Installer_Test_Vs2008.log Tests/Installer_Test_Vs2010.log Tests/Installer_Test_Vs2012.log Tests/nonWal.db Tests/pkgIndex.eagle Tests/stress.eagle Tests/testlinq.out - Tests/thread.eagle Tests/tkt-00f86f9739.eagle Tests/tkt-0d5b1ef362.eagle Tests/tkt-17045010df.eagle - Tests/tkt-1c456ae75f.eagle Tests/tkt-201128cc88.eagle Tests/tkt-2c630bffa7.eagle Tests/tkt-2ce0870fad.eagle Tests/tkt-343d392b51.eagle - Tests/tkt-3567020edf.eagle - Tests/tkt-393d954be0.eagle Tests/tkt-3aa50d8413.eagle Tests/tkt-448d663d11.eagle - Tests/tkt-4a791e70ab.eagle Tests/tkt-544dba0a2f.eagle Tests/tkt-59edc1018b.eagle - Tests/tkt-6434e23a0f.eagle - Tests/tkt-6c6ecccc5f.eagle Tests/tkt-72905c9a77.eagle Tests/tkt-7e3fa93744.eagle Tests/tkt-84718e79fa.eagle Tests/tkt-8554170e09.eagle Tests/tkt-8b7d179c3c.eagle Tests/tkt-8c3bee31c8.eagle Tests/tkt-996d13cd87.eagle Tests/tkt-ac47dd230a.eagle - Tests/tkt-ae5267b863.eagle Tests/tkt-b4a7ddc83f.eagle Tests/tkt-bb4b04d457.eagle - Tests/tkt-c010fa6584.eagle Tests/tkt-ccfa69fc32.eagle - Tests/tkt-e06c4caff3.eagle Tests/tkt-e1b2e0f769.eagle Tests/tkt-e30b820248.eagle Tests/Uninstaller_Test_Vs2005.log Tests/Uninstaller_Test_Vs2008.log Tests/Uninstaller_Test_Vs2010.log @@ -610,74 +595,74 @@ # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 2.0 for x86. # set sds_manifests(setupX86Vs2005) { - {{tmp}\vcredist_x86_2005_SP1_MFC.exe} + {{tmp}\vcredist_x86_2005_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 2.0 for x64. # set sds_manifests(setupX64Vs2005) { - {{tmp}\vcredist_x64_2005_SP1_MFC.exe} + {{tmp}\vcredist_x64_2005_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 3.5 for x86. # set sds_manifests(setupX86Vs2008) { - {{tmp}\vcredist_x86_2008_SP1_MFC.exe} + {{tmp}\vcredist_x86_2008_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 3.5 for x64. # set sds_manifests(setupX64Vs2008) { - {{tmp}\vcredist_x64_2008_SP1_MFC.exe} + {{tmp}\vcredist_x64_2008_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.0 for x86. # set sds_manifests(setupX86Vs2010) { - {{tmp}\vcredist_x86_2010_SP1_MFC.exe} + {{tmp}\vcredist_x86_2010_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.0 for x64. # set sds_manifests(setupX64Vs2010) { - {{tmp}\vcredist_x64_2010_SP1_MFC.exe} + {{tmp}\vcredist_x64_2010_SP1.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.5 for x86. # set sds_manifests(setupX86Vs2012) { - {{tmp}\vcredist_x86_2012_VSU1.exe} + {{tmp}\vcredist_x86_2012_RTM.exe} } ############################################################################### # # NOTE: This is the list of files that should be present in all setup archives # supporting the .NET Framework 4.5 for x64. # set sds_manifests(setupX64Vs2012) { - {{tmp}\vcredist_x64_2012_VSU1.exe} + {{tmp}\vcredist_x64_2012_RTM.exe} } ############################################################################### # # NOTE: These are the master archive manifest groups, based on file name. The @@ -835,14 +820,14 @@ ############################################################################### ################# Visual Studio 2008 / .NET Compact Framework ################# ############################################################################### -set manifests(sqlite-netFx35-binary-PocketPC-ARM-2008-.zip) [list sds \ +set manifests(sqlite-netFx35-binary-PocketPC-2008-.zip) [list sds \ binaryCore binaryCompact] -set manifests(sqlite-netFx35-binary-PocketPC-ARM-2008-.zip,subst) ""; # dynamic +set manifests(sqlite-netFx35-binary-PocketPC-2008-.zip,subst) ""; # dynamic ############################################################################### ################### Visual Studio 2010 / .NET Framework 4.0 ################### ############################################################################### Index: System.Data.SQLite.Linq/AssemblyInfo.cs ================================================================== --- System.Data.SQLite.Linq/AssemblyInfo.cs +++ System.Data.SQLite.Linq/AssemblyInfo.cs @@ -29,15 +29,11 @@ // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] [assembly: CLSCompliant(true)] - -#if !NET_40 && !NET_45 [assembly: AllowPartiallyTrustedCallers] -#endif - [assembly: ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] // Version information for an assembly consists of the following four values: // // Major Version @@ -46,7 +42,7 @@ // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.86.0")] -[assembly: AssemblyFileVersion("1.0.86.0")] +[assembly: AssemblyVersion("1.0.83.0")] +[assembly: AssemblyFileVersion("1.0.83.0")] Index: System.Data.SQLite.Linq/SQLiteProviderServices.cs ================================================================== --- System.Data.SQLite.Linq/SQLiteProviderServices.cs +++ System.Data.SQLite.Linq/SQLiteProviderServices.cs @@ -10,11 +10,11 @@ using System; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Metadata.Edm; using System.Diagnostics; - using System.Collections.Generic; + using System.Collections.Generic; using System.Text; using System.Globalization; internal class SQLiteProviderServices : DbProviderServices, ISQLiteSchemaExtensions { @@ -100,19 +100,11 @@ protected override string GetDbProviderManifestToken(DbConnection connection) { if (String.IsNullOrEmpty(connection.ConnectionString)) throw new ArgumentNullException("ConnectionString"); - bool parseViaFramework = false; - - if (connection is SQLiteConnection) - parseViaFramework = ((SQLiteConnection)connection).ParseViaFramework; - - SortedList opts = parseViaFramework ? - SQLiteConnection.ParseConnectionStringViaFramework(connection.ConnectionString, false) : - SQLiteConnection.ParseConnectionString(connection.ConnectionString); - + SortedList opts = SQLiteConnection.ParseConnectionString(connection.ConnectionString); return SQLiteConnection.FindKey(opts, "DateTimeFormat", "ISO8601"); } protected override DbProviderManifest GetDbProviderManifest(string versionHint) { Index: System.Data.SQLite/AssemblyInfo.cs ================================================================== --- System.Data.SQLite/AssemblyInfo.cs +++ System.Data.SQLite/AssemblyInfo.cs @@ -42,14 +42,11 @@ [assembly: CLSCompliant(true)] [assembly: InternalsVisibleTo("System.Data.SQLite.Linq, PublicKey=" + System.Data.SQLite.SQLite3.PublicKey)] [assembly: NeutralResourcesLanguage("en")] #if !PLATFORM_COMPACTFRAMEWORK -#if !NET_40 && !NET_45 [assembly: AllowPartiallyTrustedCallers] -#endif - [assembly: ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] #if NET_40 || NET_45 // // NOTE: This attribute is only available in .NET Framework 4.0 or higher. @@ -65,9 +62,9 @@ // Build Number // Revision // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.86.0")] +[assembly: AssemblyVersion("1.0.83.0")] #if !PLATFORM_COMPACTFRAMEWORK -[assembly: AssemblyFileVersion("1.0.86.0")] +[assembly: AssemblyFileVersion("1.0.83.0")] #endif Index: System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs ================================================================== --- System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs +++ System.Data.SQLite/LINQ/SQLiteFactory_Linq.cs @@ -24,17 +24,11 @@ { #if (SQLITE_STANDARD || USE_INTEROP_DLL || PLATFORM_COMPACTFRAMEWORK) && PRELOAD_NATIVE_LIBRARY UnsafeNativeMethods.Initialize(); #endif -#if INTEROP_LOG - if (UnsafeNativeMethods.sqlite3_config_log_interop() == SQLiteErrorCode.Ok) - { - UnsafeNativeMethods.sqlite3_log( - SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized.")); - } -#else +#if !PLATFORM_COMPACTFRAMEWORK SQLiteLog.Initialize(); #endif string version = #if NET_40 || NET_45 Index: System.Data.SQLite/SQLite3.cs ================================================================== --- System.Data.SQLite/SQLite3.cs +++ System.Data.SQLite/SQLite3.cs @@ -55,11 +55,11 @@ "b621ddff5d844727418956997f475eb829429e411aff3e93f97b70de698b972640925bdd44280df0" + "a25a843266973704137cbb0e7441c1fe7cae4e2440ae91ab8cde3933febcb1ac48dd33b40e13c421" + "d8215c18a4349a436dd499e3c385cc683015f886f6c10bd90115eb2bd61b67750839e3a19941dc9c"; #if !PLATFORM_COMPACTFRAMEWORK - internal const string DesignerVersion = "1.0.86.0"; + internal const string DesignerVersion = "1.0.83.0"; #endif /// /// The opaque pointer returned to us by the sqlite provider /// @@ -173,18 +173,10 @@ { return SQLite3.SQLiteVersion; } } - internal override int VersionNumber - { - get - { - return SQLite3.SQLiteVersionNumber; - } - } - internal static string DefineConstants { get { StringBuilder result = new StringBuilder(); @@ -214,18 +206,10 @@ { return UTF8ToString(UnsafeNativeMethods.sqlite3_libversion(), -1); } } - internal static int SQLiteVersionNumber - { - get - { - return UnsafeNativeMethods.sqlite3_libversion_number(); - } - } - internal static string SQLiteSourceId { get { return UTF8ToString(UnsafeNativeMethods.sqlite3_sourceid(), -1); @@ -516,18 +500,20 @@ } SQLiteConnectionFlags flags = (cnn != null) ? cnn.Flags : SQLiteConnectionFlags.Default; +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogPrepare) == SQLiteConnectionFlags.LogPrepare) { if ((strSql == null) || (strSql.Length == 0) || (strSql.Trim().Length == 0)) SQLiteLog.LogMessage("Preparing {}..."); else SQLiteLog.LogMessage(String.Format( CultureInfo.CurrentCulture, "Preparing {{{0}}}...", strSql)); } +#endif IntPtr stmt = IntPtr.Zero; IntPtr ptr = IntPtr.Zero; int len = 0; SQLiteErrorCode n = SQLiteErrorCode.Schema; @@ -552,15 +538,11 @@ finally /* NOTE: Thread.Abort() protection. */ { #if !SQLITE_STANDARD n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, psql, b.Length - 1, out stmt, out ptr, out len); #else -#if USE_PREPARE_V2 - n = UnsafeNativeMethods.sqlite3_prepare_v2(_sql, psql, b.Length - 1, out stmt, out ptr); -#else n = UnsafeNativeMethods.sqlite3_prepare(_sql, psql, b.Length - 1, out stmt, out ptr); -#endif len = -1; #endif #if !NET_COMPACT_20 && TRACE_STATEMENT Trace.WriteLine(String.Format("Prepare ({0}): {1}", n, stmt)); @@ -653,10 +635,11 @@ { handle.Free(); } } +#if !PLATFORM_COMPACTFRAMEWORK protected static void LogBind(SQLiteStatementHandle handle, int index) { IntPtr handleIntPtr = handle; SQLiteLog.LogMessage(String.Format( @@ -727,21 +710,22 @@ SQLiteLog.LogMessage(String.Format( "Binding statement {0} paramter #{1} as type {2} with value {{{3}}}...", handleIntPtr, index, typeof(Byte[]), (value != null) ? ToHexadecimalString(value) : "")); } +#endif internal override void Bind_Double(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, double value) { SQLiteStatementHandle handle = stmt._sqlite_stmt; +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) { LogBind(handle, index, value); } -#if !PLATFORM_COMPACTFRAMEWORK SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value); #else SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError()); @@ -749,14 +733,16 @@ internal override void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, int value) { SQLiteStatementHandle handle = stmt._sqlite_stmt; +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) { LogBind(handle, index, value); } +#endif SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_int(handle, index, value); if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError()); } @@ -769,26 +755,11 @@ { LogBind(handle, index, value); } #endif - SQLiteErrorCode n; - - if ((flags & SQLiteConnectionFlags.BindUInt32AsInt64) == SQLiteConnectionFlags.BindUInt32AsInt64) - { - long value2 = value; - -#if !PLATFORM_COMPACTFRAMEWORK - n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value2); -#else - n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value2); -#endif - } - else - { - n = UnsafeNativeMethods.sqlite3_bind_uint(handle, index, value); - } + SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_uint(handle, index, value); if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError()); } internal override void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, long value) { @@ -963,18 +934,20 @@ internal override int Bind_ParamCount(SQLiteStatement stmt, SQLiteConnectionFlags flags) { SQLiteStatementHandle handle = stmt._sqlite_stmt; int value = UnsafeNativeMethods.sqlite3_bind_parameter_count(handle); +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) { IntPtr handleIntPtr = handle; SQLiteLog.LogMessage(String.Format( "Statement {0} paramter count is {1}.", handleIntPtr, value)); } +#endif return value; } internal override string Bind_ParamName(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index) @@ -987,35 +960,39 @@ name = UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(handle, index, out len), len); #else name = UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(handle, index), -1); #endif +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) { IntPtr handleIntPtr = handle; SQLiteLog.LogMessage(String.Format( "Statement {0} paramter #{1} name is {{{2}}}.", handleIntPtr, index, name)); } +#endif return name; } internal override int Bind_ParamIndex(SQLiteStatement stmt, SQLiteConnectionFlags flags, string paramName) { SQLiteStatementHandle handle = stmt._sqlite_stmt; int index = UnsafeNativeMethods.sqlite3_bind_parameter_index(handle, ToUTF8(paramName)); +#if !PLATFORM_COMPACTFRAMEWORK if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) { IntPtr handleIntPtr = handle; SQLiteLog.LogMessage(String.Format( "Statement {0} paramter index of name {{{1}}} is #{2}.", handleIntPtr, paramName, index)); } +#endif return index; } internal override int ColumnCount(SQLiteStatement stmt) @@ -1154,40 +1131,15 @@ UnsafeNativeMethods.sqlite3_column_double_interop(stmt._sqlite_stmt, index, out value); #endif return value; } - internal override sbyte GetSByte(SQLiteStatement stmt, int index) - { - return unchecked((sbyte)(GetInt32(stmt, index) & byte.MaxValue)); - } - - internal override byte GetByte(SQLiteStatement stmt, int index) - { - return unchecked((byte)(GetInt32(stmt, index) & byte.MaxValue)); - } - - internal override short GetInt16(SQLiteStatement stmt, int index) - { - return unchecked((short)(GetInt32(stmt, index) & ushort.MaxValue)); - } - - internal override ushort GetUInt16(SQLiteStatement stmt, int index) - { - return unchecked((ushort)(GetInt32(stmt, index) & ushort.MaxValue)); - } - internal override int GetInt32(SQLiteStatement stmt, int index) { return UnsafeNativeMethods.sqlite3_column_int(stmt._sqlite_stmt, index); } - internal override uint GetUInt32(SQLiteStatement stmt, int index) - { - return unchecked((uint)GetInt32(stmt, index)); - } - internal override long GetInt64(SQLiteStatement stmt, int index) { long value; #if !PLATFORM_COMPACTFRAMEWORK value = UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index); @@ -1195,34 +1147,27 @@ UnsafeNativeMethods.sqlite3_column_int64_interop(stmt._sqlite_stmt, index, out value); #endif return value; } - internal override ulong GetUInt64(SQLiteStatement stmt, int index) - { - return unchecked((ulong)GetInt64(stmt, index)); - } - internal override string GetText(SQLiteStatement stmt, int index) { #if !SQLITE_STANDARD int len; return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len); #else - return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), - UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index)); + return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1); #endif } internal override DateTime GetDateTime(SQLiteStatement stmt, int index) { #if !SQLITE_STANDARD int len; return ToDateTime(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len); #else - return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), - UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index)); + return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1); #endif } internal override long GetBytes(SQLiteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength) { @@ -1436,12 +1381,11 @@ { #if !SQLITE_STANDARD int len; return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text_interop(ptr, out len), len); #else - return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text(ptr), - UnsafeNativeMethods.sqlite3_value_bytes(ptr)); + return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text(ptr), -1); #endif } internal override TypeAffinity GetParamValueType(IntPtr ptr) { @@ -1842,21 +1786,13 @@ if (handlePtr == IntPtr.Zero) throw new InvalidOperationException( "Backup object has an invalid handle pointer."); -#if !SQLITE_STANDARD - SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_backup_finish_interop(handlePtr); -#else SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_backup_finish(handlePtr); -#endif handle.SetHandleAsInvalid(); -#if COUNT_HANDLE - if ((n == SQLiteErrorCode.Ok) || (n == backup._stepResult)) handle.WasReleasedOk(); -#endif - if ((n != SQLiteErrorCode.Ok) && (n != backup._stepResult)) throw new SQLiteException(n, GetLastError()); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -1888,19 +1824,21 @@ // BUGFIX: Prevent races with other threads for this entire block, due // to the try/finally semantics. See ticket [72905c9a77]. // lock (syncRoot) { +#if !PLATFORM_COMPACTFRAMEWORK // // NOTE: Save the state of the logging class and then restore it // after we are done to avoid logging too many false errors. // bool savedEnabled = SQLiteLog.Enabled; SQLiteLog.Enabled = false; try { +#endif // // NOTE: This method [ab]uses the fact that SQLite will always // return SQLITE_ERROR for any unknown configuration option // *unless* the SQLite library has already been initialized. // In that case it will always return SQLITE_MISUSE. @@ -1907,27 +1845,28 @@ // SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3_config_none( SQLiteConfigOpsEnum.SQLITE_CONFIG_NONE); return (rc == SQLiteErrorCode.Misuse); +#if !PLATFORM_COMPACTFRAMEWORK } finally { SQLiteLog.Enabled = savedEnabled; } +#endif } } /// /// Helper function to retrieve a column of data from an active statement. /// /// The statement being step()'d through - /// The flags associated with the connection. /// The column index to retrieve /// The type of data contained in the column. If Uninitialized, this function will retrieve the datatype information. /// Returns the data in the column - internal override object GetValue(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, SQLiteType typ) + internal override object GetValue(SQLiteStatement stmt, int index, SQLiteType typ) { if (IsNull(stmt, index)) return DBNull.Value; TypeAffinity aff = typ.Affinity; Type t = null; @@ -1935,13 +1874,10 @@ { t = SQLiteConvert.SQLiteTypeToType(typ); aff = TypeToAffinity(t); } - if ((flags & SQLiteConnectionFlags.GetAllAsText) == SQLiteConnectionFlags.GetAllAsText) - return GetText(stmt, index); - switch (aff) { case TypeAffinity.Blob: if (typ.Type == DbType.Guid && typ.Affinity == TypeAffinity.Text) return new Guid(GetText(stmt, index)); @@ -1956,21 +1892,16 @@ return b; case TypeAffinity.DateTime: return GetDateTime(stmt, index); case TypeAffinity.Double: if (t == null) return GetDouble(stmt, index); - return Convert.ChangeType(GetDouble(stmt, index), t, null); + else + return Convert.ChangeType(GetDouble(stmt, index), t, null); case TypeAffinity.Int64: if (t == null) return GetInt64(stmt, index); - if (t == typeof(SByte)) return GetSByte(stmt, index); - if (t == typeof(Byte)) return GetByte(stmt, index); - if (t == typeof(Int16)) return GetInt16(stmt, index); - if (t == typeof(UInt16)) return GetUInt16(stmt, index); - if (t == typeof(Int32)) return GetInt32(stmt, index); - if (t == typeof(UInt32)) return GetUInt32(stmt, index); - if (t == typeof(UInt64)) return GetUInt64(stmt, index); - return Convert.ChangeType(GetInt64(stmt, index), t, null); + else + return Convert.ChangeType(GetInt64(stmt, index), t, null); default: return GetText(stmt, index); } } Index: System.Data.SQLite/SQLite3_UTF16.cs ================================================================== --- System.Data.SQLite/SQLite3_UTF16.cs +++ System.Data.SQLite/SQLite3_UTF16.cs @@ -1,115 +1,115 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ - using System; - -#if !NET_COMPACT_20 && TRACE_CONNECTION - using System.Diagnostics; -#endif - - using System.IO; - using System.Runtime.InteropServices; - - /// - /// Alternate SQLite3 object, overriding many text behaviors to support UTF-16 (Unicode) - /// - internal class SQLite3_UTF16 : SQLite3 - { - internal SQLite3_UTF16(SQLiteDateFormats fmt, DateTimeKind kind) - : base(fmt, kind) - { - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - - #region IDisposable "Pattern" Members - private bool disposed; - private void CheckDisposed() /* throw */ - { -#if THROW_ON_DISPOSED - if (disposed) - throw new ObjectDisposedException(typeof(SQLite3_UTF16).Name); -#endif - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - - protected override void Dispose(bool disposing) - { - try - { - if (!disposed) - { - //if (disposing) - //{ - // //////////////////////////////////// - // // dispose managed resources here... - // //////////////////////////////////// - //} - - ////////////////////////////////////// - // release unmanaged resources here... - ////////////////////////////////////// - - disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - #endregion - - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// Overrides SQLiteConvert.ToString() to marshal UTF-16 strings instead of UTF-8 - /// - /// A pointer to a UTF-16 string - /// The length (IN BYTES) of the string - /// A .NET string - public override string ToString(IntPtr b, int nbytelen) - { - CheckDisposed(); - return UTF16ToString(b, nbytelen); - } - - public static string UTF16ToString(IntPtr b, int nbytelen) - { - if (nbytelen == 0 || b == IntPtr.Zero) return ""; - - if (nbytelen == -1) - return Marshal.PtrToStringUni(b); - else - return Marshal.PtrToStringUni(b, nbytelen / 2); - } - - internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) - { - if (_sql != null) return; - - _usePool = usePool; - _fileName = strFilename; - - if (usePool) - { - _sql = SQLiteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion); - -#if !NET_COMPACT_20 && TRACE_CONNECTION - Trace.WriteLine(String.Format("Open16 (Pool): {0}", (_sql != null) ? _sql.ToString() : "")); -#endif - } - - if (_sql == null) +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ + using System; + +#if !NET_COMPACT_20 && TRACE_CONNECTION + using System.Diagnostics; +#endif + + using System.IO; + using System.Runtime.InteropServices; + + /// + /// Alternate SQLite3 object, overriding many text behaviors to support UTF-16 (Unicode) + /// + internal class SQLite3_UTF16 : SQLite3 + { + internal SQLite3_UTF16(SQLiteDateFormats fmt, DateTimeKind kind) + : base(fmt, kind) + { + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + throw new ObjectDisposedException(typeof(SQLite3_UTF16).Name); +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + protected override void Dispose(bool disposing) + { + try + { + if (!disposed) + { + //if (disposing) + //{ + // //////////////////////////////////// + // // dispose managed resources here... + // //////////////////////////////////// + //} + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + + disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// Overrides SQLiteConvert.ToString() to marshal UTF-16 strings instead of UTF-8 + /// + /// A pointer to a UTF-16 string + /// The length (IN BYTES) of the string + /// A .NET string + public override string ToString(IntPtr b, int nbytelen) + { + CheckDisposed(); + return UTF16ToString(b, nbytelen); + } + + public static string UTF16ToString(IntPtr b, int nbytelen) + { + if (nbytelen == 0 || b == IntPtr.Zero) return ""; + + if (nbytelen == -1) + return Marshal.PtrToStringUni(b); + else + return Marshal.PtrToStringUni(b, nbytelen / 2); + } + + internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) + { + if (_sql != null) return; + + _usePool = usePool; + _fileName = strFilename; + + if (usePool) + { + _sql = SQLiteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion); + +#if !NET_COMPACT_20 && TRACE_CONNECTION + Trace.WriteLine(String.Format("Open16 (Pool): {0}", (_sql != null) ? _sql.ToString() : "")); +#endif + } + + if (_sql == null) { try { // do nothing. } @@ -136,141 +136,139 @@ throw new SQLiteException(SQLiteErrorCode.CantOpen, strFilename); n = UnsafeNativeMethods.sqlite3_open16(strFilename, out db); } -#if !NET_COMPACT_20 && TRACE_CONNECTION - Trace.WriteLine(String.Format("Open16: {0}", db)); +#if !NET_COMPACT_20 && TRACE_CONNECTION + Trace.WriteLine(String.Format("Open16: {0}", db)); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); _sql = new SQLiteConnectionHandle(db); - } - lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ } - } - _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); - SetTimeout(0); - GC.KeepAlive(_sql); - } - - internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) - { - switch (_datetimeFormat) - { - case SQLiteDateFormats.Ticks: - case SQLiteDateFormats.JulianDay: - case SQLiteDateFormats.UnixEpoch: - { - base.Bind_DateTime(stmt, flags, index, dt); - break; - } - default: - { -#if !PLATFORM_COMPACTFRAMEWORK - if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) - { - SQLiteStatementHandle handle = - (stmt != null) ? stmt._sqlite_stmt : null; - - LogBind(handle, index, dt); - } -#endif - - Bind_Text(stmt, flags, index, ToString(dt)); - break; - } - } - } - - internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value) - { - SQLiteStatementHandle handle = stmt._sqlite_stmt; - -#if !PLATFORM_COMPACTFRAMEWORK - if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) - { - LogBind(handle, index, value); - } -#endif - - SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_text16(handle, index, value, value.Length * 2, (IntPtr)(-1)); - if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError()); - } - - internal override DateTime GetDateTime(SQLiteStatement stmt, int index) - { - return ToDateTime(GetText(stmt, index)); - } - - internal override string ColumnName(SQLiteStatement stmt, int index) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_name16_interop(stmt._sqlite_stmt, index, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_name16(stmt._sqlite_stmt, index), -1); -#endif - } - - internal override string GetText(SQLiteStatement stmt, int index) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_text16_interop(stmt._sqlite_stmt, index, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_text16(stmt._sqlite_stmt, index), - UnsafeNativeMethods.sqlite3_column_bytes16(stmt._sqlite_stmt, index)); -#endif - } - - internal override string ColumnOriginalName(SQLiteStatement stmt, int index) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_origin_name16_interop(stmt._sqlite_stmt, index, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_origin_name16(stmt._sqlite_stmt, index), -1); -#endif - } - - internal override string ColumnDatabaseName(SQLiteStatement stmt, int index) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_database_name16_interop(stmt._sqlite_stmt, index, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_database_name16(stmt._sqlite_stmt, index), -1); -#endif - } - - internal override string ColumnTableName(SQLiteStatement stmt, int index) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_table_name16_interop(stmt._sqlite_stmt, index, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_column_table_name16(stmt._sqlite_stmt, index), -1); -#endif - } - - internal override string GetParamValueText(IntPtr ptr) - { -#if !SQLITE_STANDARD - int len; - return UTF16ToString(UnsafeNativeMethods.sqlite3_value_text16_interop(ptr, out len), len); -#else - return UTF16ToString(UnsafeNativeMethods.sqlite3_value_text16(ptr), - UnsafeNativeMethods.sqlite3_value_bytes16(ptr)); -#endif - } - - internal override void ReturnError(IntPtr context, string value) - { - UnsafeNativeMethods.sqlite3_result_error16(context, value, value.Length * 2); - } - - internal override void ReturnText(IntPtr context, string value) - { - UnsafeNativeMethods.sqlite3_result_text16(context, value, value.Length * 2, (IntPtr)(-1)); - } - } -} + } + lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ } + } + _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); + SetTimeout(0); + GC.KeepAlive(_sql); + } + + internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) + { + switch (_datetimeFormat) + { + case SQLiteDateFormats.Ticks: + case SQLiteDateFormats.JulianDay: + case SQLiteDateFormats.UnixEpoch: + { + base.Bind_DateTime(stmt, flags, index, dt); + break; + } + default: + { +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + SQLiteStatementHandle handle = + (stmt != null) ? stmt._sqlite_stmt : null; + + LogBind(handle, index, dt); + } +#endif + + Bind_Text(stmt, flags, index, ToString(dt)); + break; + } + } + } + + internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } +#endif + + SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_bind_text16(handle, index, value, value.Length * 2, (IntPtr)(-1)); + if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError()); + } + + internal override DateTime GetDateTime(SQLiteStatement stmt, int index) + { + return ToDateTime(GetText(stmt, index)); + } + + internal override string ColumnName(SQLiteStatement stmt, int index) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_name16_interop(stmt._sqlite_stmt, index, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_name16(stmt._sqlite_stmt, index), -1); +#endif + } + + internal override string GetText(SQLiteStatement stmt, int index) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_text16_interop(stmt._sqlite_stmt, index, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_text16(stmt._sqlite_stmt, index), -1); +#endif + } + + internal override string ColumnOriginalName(SQLiteStatement stmt, int index) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_origin_name16_interop(stmt._sqlite_stmt, index, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_origin_name16(stmt._sqlite_stmt, index), -1); +#endif + } + + internal override string ColumnDatabaseName(SQLiteStatement stmt, int index) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_database_name16_interop(stmt._sqlite_stmt, index, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_database_name16(stmt._sqlite_stmt, index), -1); +#endif + } + + internal override string ColumnTableName(SQLiteStatement stmt, int index) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_table_name16_interop(stmt._sqlite_stmt, index, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_column_table_name16(stmt._sqlite_stmt, index), -1); +#endif + } + + internal override string GetParamValueText(IntPtr ptr) + { +#if !SQLITE_STANDARD + int len; + return UTF16ToString(UnsafeNativeMethods.sqlite3_value_text16_interop(ptr, out len), len); +#else + return UTF16ToString(UnsafeNativeMethods.sqlite3_value_text16(ptr), -1); +#endif + } + + internal override void ReturnError(IntPtr context, string value) + { + UnsafeNativeMethods.sqlite3_result_error16(context, value, value.Length * 2); + } + + internal override void ReturnText(IntPtr context, string value) + { + UnsafeNativeMethods.sqlite3_result_text16(context, value, value.Length * 2, (IntPtr)(-1)); + } + } +} Index: System.Data.SQLite/SQLiteBase.cs ================================================================== --- System.Data.SQLite/SQLiteBase.cs +++ System.Data.SQLite/SQLiteBase.cs @@ -25,14 +25,10 @@ /// /// Returns a string representing the active version of SQLite /// internal abstract string Version { get; } /// - /// Returns an integer representing the active version of SQLite - /// - internal abstract int VersionNumber { get; } - /// /// Returns the rowid of the most recent successful INSERT into the database from this connection. /// internal abstract long LastInsertRowId { get; } /// /// Returns the number of changes the last executing insert/update caused. @@ -161,18 +157,12 @@ internal abstract string ColumnTableName(SQLiteStatement stmt, int index); internal abstract void ColumnMetaData(string dataBase, string table, string column, out string dataType, out string collateSequence, out bool notNull, out bool primaryKey, out bool autoIncrement); internal abstract void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence); internal abstract double GetDouble(SQLiteStatement stmt, int index); - internal abstract SByte GetSByte(SQLiteStatement stmt, int index); - internal abstract Byte GetByte(SQLiteStatement stmt, int index); - internal abstract Int16 GetInt16(SQLiteStatement stmt, int index); - internal abstract UInt16 GetUInt16(SQLiteStatement stmt, int index); internal abstract Int32 GetInt32(SQLiteStatement stmt, int index); - internal abstract UInt32 GetUInt32(SQLiteStatement stmt, int index); internal abstract Int64 GetInt64(SQLiteStatement stmt, int index); - internal abstract UInt64 GetUInt64(SQLiteStatement stmt, int index); internal abstract string GetText(SQLiteStatement stmt, int index); internal abstract long GetBytes(SQLiteStatement stmt, int index, int nDataoffset, byte[] bDest, int nStart, int nLength); internal abstract long GetChars(SQLiteStatement stmt, int index, int nDataoffset, char[] bDest, int nStart, int nLength); internal abstract DateTime GetDateTime(SQLiteStatement stmt, int index); internal abstract bool IsNull(SQLiteStatement stmt, int index); @@ -269,11 +259,11 @@ internal abstract bool IsInitialized(); internal abstract int GetCursorForTable(SQLiteStatement stmt, int database, int rootPage); internal abstract long GetRowIdForCursor(SQLiteStatement stmt, int cursor); - internal abstract object GetValue(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, SQLiteType typ); + internal abstract object GetValue(SQLiteStatement stmt, int index, SQLiteType typ); internal abstract bool AutoCommit { get; } @@ -585,48 +575,27 @@ #endif { #if !SQLITE_STANDARD SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close_interop(db); #else - ResetConnection(hdl, db, false); - - SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close(db); -#endif - if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db)); - } - } - } - -#if !INTEROP_LEGACY_CLOSE - internal static void CloseConnectionV2(SQLiteConnectionHandle hdl, IntPtr db) - { - if ((hdl == null) || (db == IntPtr.Zero)) return; - - try - { - // do nothing. - } - finally /* NOTE: Thread.Abort() protection. */ - { -#if PLATFORM_COMPACTFRAMEWORK - lock (hdl.syncRoot) -#else - lock (hdl) -#endif - { -#if !SQLITE_STANDARD - SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close_interop(db); -#else - ResetConnection(hdl, db, false); - - SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close_v2(db); -#endif - if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db)); - } - } - } -#endif + ResetConnection(hdl, db); + + SQLiteErrorCode n; + + try + { + n = UnsafeNativeMethods.sqlite3_close_v2(db); + } + catch (EntryPointNotFoundException) + { + n = UnsafeNativeMethods.sqlite3_close(db); + } +#endif + if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db)); + } + } + } internal static bool ResetConnection(SQLiteConnectionHandle hdl, IntPtr db, bool canThrow) { if ((hdl == null) || (db == IntPtr.Zero)) return false; @@ -782,38 +751,10 @@ /// Skip adding the extension functions provided by the native /// interop assembly. /// NoExtensionFunctions = 0x20, - /// - /// When binding parameter values with the - /// type, use the interop method that accepts an - /// value. - /// - BindUInt32AsInt64 = 0x40, - - /// - /// When binding parameter values, always bind them as though they were - /// plain text (i.e. no numeric, date/time, or other conversions should - /// be attempted). - /// - BindAllAsText = 0x80, - - /// - /// When returning column values, always return them as though they were - /// plain text (i.e. no numeric, date/time, or other conversions should - /// be attempted). - /// - GetAllAsText = 0x100, - - /// - /// When binding and returning column values, always treat them as though - /// they were plain text (i.e. no numeric, date/time, or other conversions - /// should be attempted). - /// - BindAndGetAllAsText = BindAllAsText | GetAllAsText, - /// /// Enable all logging. /// LogAll = LogPrepare | LogPreBind | LogBind | LogCallbackException | LogBackup, Index: System.Data.SQLite/SQLiteCommand.cs ================================================================== --- System.Data.SQLite/SQLiteCommand.cs +++ System.Data.SQLite/SQLiteCommand.cs @@ -20,17 +20,10 @@ #if !PLATFORM_COMPACTFRAMEWORK [Designer("SQLite.Designer.SQLiteCommandDesigner, SQLite.Designer, Version=" + SQLite3.DesignerVersion + ", Culture=neutral, PublicKeyToken=db937bc2d44ff139"), ToolboxItem(true)] #endif public sealed class SQLiteCommand : DbCommand, ICloneable { - /// - /// The default connection string to be used when creating a temporary - /// connection to execute a command via the static - /// method. - /// - private static readonly string DefaultConnectionString = "Data Source=:memory:;"; - /// /// The command text this command is based on /// private string _commandText; /// @@ -233,45 +226,10 @@ base.Dispose(disposing); } } #endregion - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// This method attempts to query the flags associated with the database - /// connection in use. If the database connection is disposed or any other - /// error occurs, the default flags will be returned. - /// - /// - /// The command containing the databse connection to query the flags from. - /// - /// - /// The connection flags value. - /// - internal static SQLiteConnectionFlags GetFlags( - SQLiteCommand command - ) - { - try - { - if (command != null) - { - SQLiteConnection cnn = command._cnn; - - if (cnn != null) - return cnn.Flags; - } - } - catch (ObjectDisposedException) - { - // do nothing. - } - - return SQLiteConnectionFlags.Default; - } - /////////////////////////////////////////////////////////////////////////////////////////////// /// /// Clears and destroys all statements currently prepared /// @@ -636,93 +594,10 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { return ExecuteReader(behavior); } - /// - /// This method creates a new connection, executes the query using the given - /// execution type, closes the connection, and returns the results. If the - /// connection string is null, a temporary in-memory database connection will - /// be used. - /// - /// - /// The text of the command to be executed. - /// - /// - /// The execution type for the command. This is used to determine which method - /// of the command object to call, which then determines the type of results - /// returned, if any. - /// - /// - /// The connection string to the database to be opened, used, and closed. If - /// this parameter is null, a temporary in-memory databse will be used. - /// - /// - /// The SQL parameter values to be used when building the command object to be - /// executed, if any. - /// - /// - /// The results of the query -OR- null if no results were produced from the - /// given execution type. - /// - public static object Execute( - string commandText, - SQLiteExecuteType executeType, - string connectionString, - params object[] args - ) - { - if (connectionString == null) - connectionString = DefaultConnectionString; - - using (SQLiteConnection connection = new SQLiteConnection(connectionString)) - { - connection.Open(); - - using (SQLiteCommand command = connection.CreateCommand()) - { - command.CommandText = commandText; - - if (args != null) - { - foreach (object arg in args) - { - if (arg is SQLiteParameter) - command.Parameters.Add((SQLiteParameter)arg); - else - command.Parameters.Add(new SQLiteParameter(DbType.Object, arg)); - } - } - - switch (executeType) - { - case SQLiteExecuteType.None: - { - // - // NOTE: Do nothing. - // - break; - } - case SQLiteExecuteType.NonQuery: - { - return command.ExecuteNonQuery(); - } - case SQLiteExecuteType.Scalar: - { - return command.ExecuteScalar(); - } - case SQLiteExecuteType.Reader: - { - return command.ExecuteReader(); - } - } - } - } - - return null; - } - /// /// Overrides the default behavior to return a SQLiteDataReader specialization class /// /// The flags to be associated with the reader /// A SQLiteDataReader Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -14,11 +14,10 @@ using System.Collections.Generic; using System.Globalization; using System.ComponentModel; using System.Runtime.InteropServices; using System.IO; - using System.Text; ///////////////////////////////////////////////////////////////////////////////////////////////// /// /// Event data for connection event handlers. @@ -181,31 +180,18 @@ /// {password} - Using this parameter requires that the CryptoAPI based codec be enabled at compile-time for both the native interop assembly and the core managed assemblies; otherwise, using this parameter may result in an exception being thrown when attempting to open the connection. /// N /// /// /// - /// HexPassword - /// {hexPassword} - Must contain a sequence of zero or more hexadecimal encoded byte values without a leading "0x" prefix. Using this parameter requires that the CryptoAPI based codec be enabled at compile-time for both the native interop assembly and the core managed assemblies; otherwise, using this parameter may result in an exception being thrown when attempting to open the connection. - /// N - /// - /// - /// /// Enlist /// Y - Automatically enlist in distributed transactions
    N - No automatic enlistment
    /// N /// Y ///
    /// /// Pooling - /// - /// True - Use connection pooling.
    - /// False - Do not use connection pooling.

    - /// WARNING: When using the default connection pool implementation, - /// setting this property to True should be avoided by applications that make - /// use of COM (either directly or indirectly) due to possible deadlocks that - /// can occur during the finalization of some COM objects. - ///
    + /// True - Use connection pooling
    False - Do not use connection pooling
    /// N /// False ///
    /// /// FailIfMissing @@ -308,11 +294,10 @@ private const SQLiteDateFormats DefaultDateTimeFormat = SQLiteDateFormats.ISO8601; private const DateTimeKind DefaultDateTimeKind = DateTimeKind.Unspecified; private const string DefaultDataSource = null; private const string DefaultUri = null; private const string DefaultFullUri = null; - private const string DefaultHexPassword = null; private const string DefaultPassword = null; private const int DefaultVersion = 3; private const int DefaultPageSize = 1024; private const int DefaultMaxPageCount = 0; private const int DefaultCacheSize = 2000; @@ -347,17 +332,10 @@ /// /// Static variable to store the connection event handlers to call. /// private static event SQLiteConnectionEventHandler _handlers; - -#if SQLITE_STANDARD && !PLATFORM_COMPACTFRAMEWORK - /// - /// Used to hold the active library version number of SQLite. - /// - private static int _versionNumber; -#endif #endregion /////////////////////////////////////////////////////////////////////////////////////////////// #region Private Data @@ -422,16 +400,10 @@ /// /// Default command timeout /// private int _defaultTimeout = 30; - /// - /// Non-zero if the built-in (i.e. framework provided) connection string - /// parser should be used when opening the connection. - /// - private bool _parseViaFramework; - internal bool _binaryGuid; internal long _version; private event SQLiteUpdateEventHandler _updateHandler; @@ -464,72 +436,23 @@ : this("") { } /// - /// Initializes the connection with the specified connection string. - /// - /// The connection string to use. - public SQLiteConnection(string connectionString) - : this(connectionString, false) - { - // do nothing. - } - - /// - /// Initializes the connection with the specified connection string. - /// - /// - /// The connection string to use on. - /// - /// - /// Non-zero to parse the connection string using the built-in (i.e. - /// framework provided) parser when opening the connection. - /// - public SQLiteConnection(string connectionString, bool parseViaFramework) + /// Initializes the connection with the specified connection string + ///
    + /// The connection string to use on the connection + public SQLiteConnection(string connectionString) { #if (SQLITE_STANDARD || USE_INTEROP_DLL || PLATFORM_COMPACTFRAMEWORK) && PRELOAD_NATIVE_LIBRARY UnsafeNativeMethods.Initialize(); #endif -#if !INTEROP_LOG +#if !PLATFORM_COMPACTFRAMEWORK SQLiteLog.Initialize(); #endif -#if !PLATFORM_COMPACTFRAMEWORK && !INTEROP_LEGACY_CLOSE && SQLITE_STANDARD - // - // NOTE: Check if the sqlite3_close_v2() native API should be available - // to use. This must be done dynamically because the delegate set - // here is used by the SQLiteConnectionHandle class, which is a - // CriticalHandle derived class (i.e. protected by a constrained - // execution region). Therefore, if the underlying native entry - // point is unavailable, an exception will be raised even if it is - // never actually called (i.e. because the runtime eagerly prepares - // all the methods in the call graph of the constrained execution - // region). - // - lock (_syncRoot) - { - if (_versionNumber == 0) - { - _versionNumber = SQLite3.SQLiteVersionNumber; - - if (_versionNumber >= 3007014) - SQLiteConnectionHandle.closeConnection = SQLiteBase.CloseConnectionV2; - } - } -#endif - -#if INTEROP_LOG - if (UnsafeNativeMethods.sqlite3_config_log_interop() == SQLiteErrorCode.Ok) - { - UnsafeNativeMethods.sqlite3_log( - SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized.")); - } -#endif - - _parseViaFramework = parseViaFramework; _flags = SQLiteConnectionFlags.Default; _connectionState = ConnectionState.Closed; _connectionString = ""; //_commandList = new List(); @@ -540,11 +463,11 @@ /// /// Clones the settings and connection string from an existing connection. If the existing connection is already open, this /// function will open its own connection, enumerate any attached databases of the original connection, and automatically /// attach to them. /// - /// The connection to copy the settings from. + /// public SQLiteConnection(SQLiteConnection connection) : this(connection.ConnectionString) { string str; @@ -637,48 +560,10 @@ _handlers -= value; } } } - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// This property is used to obtain or set the custom connection pool - /// implementation to use, if any. Setting this property to null will - /// cause the default connection pool implementation to be used. - /// - public static ISQLiteConnectionPool ConnectionPool - { - get { return SQLiteConnectionPool.GetConnectionPool(); } - set { SQLiteConnectionPool.SetConnectionPool(value); } - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// Creates and returns a new managed database connection handle. This - /// method is intended to be used by implementations of the - /// interface only. In theory, it - /// could be used by other classes; however, that usage is not supported. - /// - /// - /// This must be a native database connection handle returned by the - /// SQLite core library and it must remain valid and open during the - /// entire duration of the calling method. - /// - /// - /// The new managed database connection handle or null if it cannot be - /// created. - /// - public static object CreateHandle( - IntPtr nativeHandle - ) - { - if (nativeHandle == IntPtr.Zero) return null; - return new SQLiteConnectionHandle(nativeHandle); - } - /////////////////////////////////////////////////////////////////////////////////////////////// #region Backup API Members /// /// Backs up the database, using the specified database connection as the @@ -772,10 +657,11 @@ // if (pages == 0) break; } } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) { if ((_flags & SQLiteConnectionFlags.LogBackup) == SQLiteConnectionFlags.LogBackup) { SQLiteLog.LogMessage(String.Format( @@ -783,10 +669,11 @@ "Caught exception while backing up database: {0}", e)); } throw; } +#endif finally { if (backup != null) sqliteBase.FinishBackup(backup); /* throw */ } @@ -1197,31 +1084,18 @@ /// {password} - Using this parameter requires that the CryptoAPI based codec be enabled at compile-time for both the native interop assembly and the core managed assemblies; otherwise, using this parameter may result in an exception being thrown when attempting to open the connection. /// N /// /// /// - /// HexPassword - /// {hexPassword} - Must contain a sequence of zero or more hexadecimal encoded byte values without a leading "0x" prefix. Using this parameter requires that the CryptoAPI based codec be enabled at compile-time for both the native interop assembly and the core managed assemblies; otherwise, using this parameter may result in an exception being thrown when attempting to open the connection. - /// N - /// - /// - /// /// Enlist /// Y - Automatically enlist in distributed transactions
    N - No automatic enlistment
    /// N /// Y ///
    /// /// Pooling - /// - /// True - Use connection pooling.
    - /// False - Do not use connection pooling.

    - /// WARNING: When using the default connection pool implementation, - /// setting this property to True should be avoided by applications that - /// make use of COM (either directly or indirectly) due to possible - /// deadlocks that can occur during the finalization of some COM objects. - ///
    + /// True - Use connection pooling
    False - Do not use connection pooling
    /// N /// False ///
    /// /// FailIfMissing @@ -1388,110 +1262,38 @@ else throw new InvalidOperationException ("Invalid connection string: invalid URI"); } /// - /// Parses the connection string into component parts using the custom - /// connection string parser. + /// Parses the connection string into component parts /// /// The connection string to parse /// An array of key-value pairs representing each parameter of the connection string internal static SortedList ParseConnectionString(string connectionString) { string s = connectionString; int n; SortedList ls = new SortedList(StringComparer.OrdinalIgnoreCase); - // First split into semi-colon delimited values. - string[] arParts = SQLiteConvert.NewSplit(s, ';', true); + // First split into semi-colon delimited values. The Split() function of SQLiteBase accounts for and properly + // skips semi-colons in quoted strings + string[] arParts = SQLiteConvert.Split(s, ';'); int x = arParts.Length; // For each semi-colon piece, split into key and value pairs by the presence of the = sign for (n = 0; n < x; n++) { - if (arParts[n] == null) - continue; - - arParts[n] = arParts[n].Trim(); - - if (arParts[n].Length == 0) - continue; - int indexOf = arParts[n].IndexOf('='); if (indexOf != -1) - ls.Add(UnwrapString(arParts[n].Substring(0, indexOf).Trim()), UnwrapString(arParts[n].Substring(indexOf + 1).Trim())); + ls.Add(arParts[n].Substring(0, indexOf), arParts[n].Substring(indexOf + 1)); else - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid ConnectionString format for part \"{0}\", no equal sign found", arParts[n])); + throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid ConnectionString format for part \"{0}\"", arParts[n])); } return ls; } - /// - /// Parses a connection string using the built-in (i.e. framework provided) - /// connection string parser class and returns the key/value pairs. An - /// exception may be thrown if the connection string is invalid or cannot be - /// parsed. When compiled for the .NET Compact Framework, the custom - /// connection string parser is always used instead because the framework - /// provided one is unavailable there. - /// - /// - /// The connection string to parse. - /// - /// - /// Non-zero to throw an exception if any connection string values are not of - /// the type. - /// - /// The list of key/value pairs. - internal static SortedList ParseConnectionStringViaFramework( - string connectionString, - bool strict - ) - { -#if !PLATFORM_COMPACTFRAMEWORK - DbConnectionStringBuilder connectionStringBuilder - = new DbConnectionStringBuilder(); - - connectionStringBuilder.ConnectionString = connectionString; /* throw */ - - SortedList result = - new SortedList(StringComparer.OrdinalIgnoreCase); - - foreach (string keyName in connectionStringBuilder.Keys) - { - object value = connectionStringBuilder[keyName]; - string keyValue = null; - - if (value is string) - { - keyValue = (string)value; - } - else if (strict) - { - throw new ArgumentException( - "connection property value is not a string", - keyName); - } - else if (value != null) - { - keyValue = value.ToString(); - } - - result.Add(keyName, keyValue); - } - - return result; -#else - // - // NOTE: On the .NET Compact Framework, always use our custom connection - // string parser as the built-in (i.e. framework provided) one is - // unavailable. - // - return ParseConnectionString(connectionString); -#endif - } - #if !PLATFORM_COMPACTFRAMEWORK /// /// Manual distributed transaction enlistment support /// /// The distributed transaction to enlist in @@ -1555,48 +1357,10 @@ } return null; } - /// - /// Attempts to convert an input string into a byte value. - /// - /// - /// The string value to be converted. - /// - /// - /// The number styles to use for the conversion. - /// - /// - /// Upon sucess, this will contain the parsed byte value. - /// Upon failure, the value of this parameter is undefined. - /// - /// - /// Non-zero upon success; zero on failure. - /// - private static bool TryParseByte( - string value, - NumberStyles style, - out byte result - ) - { -#if !PLATFORM_COMPACTFRAMEWORK - return byte.TryParse(value, style, null, out result); -#else - try - { - result = byte.Parse(value, style); - return true; - } - catch - { - result = 0; - return false; - } -#endif - } - /// /// Enables or disabled extension loading. /// /// /// True to enable loading of extensions, false to disable. @@ -1652,116 +1416,10 @@ "Database connection not valid for loading extensions."); _sql.LoadExtension(fileName, procName); } - /// - /// Parses a string containing a sequence of zero or more hexadecimal - /// encoded byte values and returns the resulting byte array. The - /// "0x" prefix is not allowed on the input string. - /// - /// - /// The input string containing zero or more hexadecimal encoded byte - /// values. - /// - /// - /// A byte array containing the parsed byte values or null if an error - /// was encountered. - /// - internal static byte[] FromHexString( - string text - ) - { - string error = null; - - return FromHexString(text, ref error); - } - - /// - /// Creates and returns a string containing the hexadecimal encoded byte - /// values from the input array. - /// - /// - /// The input array of bytes. - /// - /// - /// The resulting string or null upon failure. - /// - internal static string ToHexString( - byte[] array - ) - { - if (array == null) - return null; - - StringBuilder result = new StringBuilder(); - - int length = array.Length; - - for (int index = 0; index < length; index++) -#if NET_COMPACT_20 - result.Append(String.Format("{0:x2}", array[index])); -#else - result.AppendFormat("{0:x2}", array[index]); -#endif - - return result.ToString(); - } - - /// - /// Parses a string containing a sequence of zero or more hexadecimal - /// encoded byte values and returns the resulting byte array. The - /// "0x" prefix is not allowed on the input string. - /// - /// - /// The input string containing zero or more hexadecimal encoded byte - /// values. - /// - /// - /// Upon failure, this will contain an appropriate error message. - /// - /// - /// A byte array containing the parsed byte values or null if an error - /// was encountered. - /// - private static byte[] FromHexString( - string text, - ref string error - ) - { - if (String.IsNullOrEmpty(text)) - { - error = "string is null or empty"; - return null; - } - - if (text.Length % 2 != 0) - { - error = "string contains an odd number of characters"; - return null; - } - - byte[] result = new byte[text.Length / 2]; - - for (int index = 0; index < text.Length; index += 2) - { - string value = text.Substring(index, 2); - - if (!TryParseByte(value, - NumberStyles.HexNumber, out result[index / 2])) - { - error = String.Format( - "string contains \"{0}\", which cannot be converted to a byte value", - value); - - return null; - } - } - - return result; - } - /// /// Opens the connection using the parameters found in the . /// public override void Open() { @@ -1773,16 +1431,11 @@ if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); - SortedList opts = _parseViaFramework ? - ParseConnectionStringViaFramework(_connectionString, false) : - ParseConnectionString(_connectionString); - - OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts)); + SortedList opts = ParseConnectionString(_connectionString); object enumValue; enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true); _flags = (enumValue is SQLiteConnectionFlags) ? (SQLiteConnectionFlags)enumValue : DefaultFlags; @@ -1792,10 +1445,11 @@ if (Convert.ToInt32(FindKey(opts, "Version", DefaultVersion.ToString()), CultureInfo.InvariantCulture) != DefaultVersion) throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, "Only SQLite Version {0} is supported at this time", DefaultVersion)); fileName = FindKey(opts, "Data Source", DefaultDataSource); + fileName = UnwrapFileName(fileName); if (String.IsNullOrEmpty(fileName)) { fileName = FindKey(opts, "Uri", DefaultUri); if (String.IsNullOrEmpty(fileName)) @@ -1893,35 +1547,17 @@ _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling); _binaryGuid = SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", DefaultBinaryGUID.ToString())); #if INTEROP_CODEC - string hexPassword = FindKey(opts, "HexPassword", DefaultHexPassword); - - if (!String.IsNullOrEmpty(hexPassword)) - { - string error = null; - byte[] hexPasswordBytes = FromHexString(hexPassword, ref error); - - if (hexPasswordBytes == null) - { - throw new FormatException(String.Format( - "Cannot parse 'HexPassword' property value into byte values: {0}", - error)); - } - - _sql.SetPassword(hexPasswordBytes); - } - else - { - string password = FindKey(opts, "Password", DefaultPassword); - - if (!String.IsNullOrEmpty(password)) - _sql.SetPassword(UTF8Encoding.UTF8.GetBytes(password)); - else if (_password != null) - _sql.SetPassword(_password); - } + string password = FindKey(opts, "Password", DefaultPassword); + + if (!String.IsNullOrEmpty(password)) + _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password)); + else if (_password != null) + _sql.SetPassword(_password); + _password = null; #endif if (!fullUri) _dataSource = Path.GetFileNameWithoutExtension(fileName); @@ -2066,20 +1702,10 @@ { get { CheckDisposed(); return _defaultTimeout; } set { CheckDisposed(); _defaultTimeout = value; } } - /// - /// Non-zero if the built-in (i.e. framework provided) connection string - /// parser should be used when opening the connection. - /// - public bool ParseViaFramework - { - get { CheckDisposed(); return _parseViaFramework; } - set { CheckDisposed(); _parseViaFramework = value; } - } - /// /// Gets/sets the extra behavioral flags for this connection. See the /// enumeration for a list of /// possible values. /// @@ -2125,29 +1751,10 @@ return _sql.LastInsertRowId; } } - /// - /// This method causes any pending database operation to abort and return at - /// its earliest opportunity. This routine is typically called in response - /// to a user action such as pressing "Cancel" or Ctrl-C where the user wants - /// a long query operation to halt immediately. It is safe to call this - /// routine from any thread. However, it is not safe to call this routine - /// with a database connection that is closed or might close before this method - /// returns. - /// - public void Cancel() - { - CheckDisposed(); - - if (_sql == null) - throw new InvalidOperationException("Database connection not valid for query cancellation."); - - _sql.Cancel(); /* throw */ - } - /// /// Returns the number of rows changed by the last INSERT, UPDATE, or DELETE statement executed on /// this connection. /// #if !PLATFORM_COMPACTFRAMEWORK @@ -2265,14 +1872,11 @@ CheckDisposed(); // make sure we have an instance of the base class if (_sql == null) { - SortedList opts = _parseViaFramework ? - ParseConnectionStringViaFramework(_connectionString, false) : - ParseConnectionString(_connectionString); - + SortedList opts = ParseConnectionString(_connectionString); object enumValue; enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", DefaultDateTimeFormat.ToString()), true); @@ -2362,11 +1966,11 @@ /// The new password to assign to the database public void ChangePassword(string newPassword) { CheckDisposed(); - ChangePassword(String.IsNullOrEmpty(newPassword) ? null : UTF8Encoding.UTF8.GetBytes(newPassword)); + ChangePassword(String.IsNullOrEmpty(newPassword) ? null : System.Text.UTF8Encoding.UTF8.GetBytes(newPassword)); } /// /// Change the password (or assign a password) to an open database. /// @@ -2392,11 +1996,11 @@ /// The password for the database public void SetPassword(string databasePassword) { CheckDisposed(); - SetPassword(String.IsNullOrEmpty(databasePassword) ? null : UTF8Encoding.UTF8.GetBytes(databasePassword)); + SetPassword(String.IsNullOrEmpty(databasePassword) ? null : System.Text.UTF8Encoding.UTF8.GetBytes(databasePassword)); } /// /// Sets the password for a password-protected database. A password-protected database is /// unusable for any operation until the password has been set. @@ -2461,45 +2065,42 @@ return rc; } /// - /// Removes one set of surrounding single -OR- double quotes from the string - /// value and returns the resulting string value. If the string is null, empty, + /// Removes one set of surrounding single -OR- double quotes from the file + /// name and returns the resulting file name. If the string is null, empty, /// or contains quotes that are not balanced, nothing is done and the original - /// string value will be returned. + /// string will be returned. /// - /// The string value to process. - /// - /// The string value, modified to remove one set of surrounding single -OR- - /// double quotes, if applicable. - /// - private static string UnwrapString(string value) - { - if (String.IsNullOrEmpty(value)) + /// The database file name to process. + /// The modified database file name. + private string UnwrapFileName(string sourceFile) + { + if (String.IsNullOrEmpty(sourceFile)) { // // NOTE: The string is null or empty, return it verbatim. // - return value; + return sourceFile; } - int length = value.Length; + int length = sourceFile.Length; - if (((value[0] == '\'') && (value[length - 1] == '\'')) || - ((value[0] == '"') && (value[length - 1] == '"'))) + if (((sourceFile[0] == '\'') && (sourceFile[length - 1] == '\'')) || + ((sourceFile[0] == '"') && (sourceFile[length - 1] == '"'))) { // // NOTE: Remove the first and last character. // - return value.Substring(1, length - 2); + return sourceFile.Substring(1, length - 2); } // // NOTE: No match, return the input string verbatim. // - return value; + return sourceFile; } /// /// Expand the filename of the data source, resolving the |DataDirectory| /// macro as appropriate. Index: System.Data.SQLite/SQLiteConnectionPool.cs ================================================================== --- System.Data.SQLite/SQLiteConnectionPool.cs +++ System.Data.SQLite/SQLiteConnectionPool.cs @@ -1,1028 +1,410 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ - using System; - using System.Collections.Generic; - -#if !PLATFORM_COMPACTFRAMEWORK && DEBUG - using System.Text; -#endif - - using System.Threading; - - /////////////////////////////////////////////////////////////////////////// - - #region Null Connection Pool Class -#if !PLATFORM_COMPACTFRAMEWORK && DEBUG - /// - /// This class implements a connection pool where all methods of the - /// interface are NOPs. This class - /// is used for testing purposes only. - /// - internal sealed class NullConnectionPool : ISQLiteConnectionPool - { - #region Private Data - /// - /// This field keeps track of all method calls made into the - /// interface methods of this - /// class. - /// - private StringBuilder log; - - /////////////////////////////////////////////////////////////////////// - - /// - /// Non-zero to dispose of database connection handles received via the - /// method. - /// - private bool dispose; - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region Private Constructors - /// - /// Constructs a connection pool object where all methods of the - /// interface are NOPs. This - /// class is used for testing purposes only. - /// - private NullConnectionPool() - { - log = new StringBuilder(); - } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region Public Constructors - /// - /// Constructs a connection pool object where all methods of the - /// interface are NOPs. This - /// class is used for testing purposes only. - /// - /// - /// Non-zero to dispose of database connection handles received via the - /// method. - /// - public NullConnectionPool( - bool dispose - ) - : this() - { - this.dispose = dispose; - } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region ISQLiteConnectionPool Members - /// - /// Counts the number of pool entries matching the specified file name. - /// - /// - /// The file name to match or null to match all files. - /// - /// - /// The pool entry counts for each matching file. - /// - /// - /// The total number of connections successfully opened from any pool. - /// - /// - /// The total number of connections successfully closed from any pool. - /// - /// - /// The total number of pool entries for all matching files. - /// - public void GetCounts( - string fileName, - ref Dictionary counts, - ref int openCount, - ref int closeCount, - ref int totalCount - ) - { - if (log != null) - { - log.AppendFormat( - "GetCounts(\"{0}\", {1}, {2}, {3}, {4}){5}", fileName, - counts, openCount, closeCount, totalCount, - Environment.NewLine); - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Disposes of all pooled connections associated with the specified - /// database file name. - /// - /// - /// The database file name. - /// - public void ClearPool( - string fileName - ) - { - if (log != null) - { - log.AppendFormat( - "ClearPool(\"{0}\"){1}", fileName, Environment.NewLine); - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Disposes of all pooled connections. - /// - public void ClearAllPools() - { - if (log != null) - { - log.AppendFormat( - "ClearAllPools(){0}", Environment.NewLine); - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Adds a connection to the pool of those associated with the - /// specified database file name. - /// - /// - /// The database file name. - /// - /// - /// The database connection handle. - /// - /// - /// The connection pool version at the point the database connection - /// handle was received from the connection pool. This is also the - /// connection pool version that the database connection handle was - /// created under. - /// - public void Add( - string fileName, - object handle, - int version - ) - { - if (log != null) - { - log.AppendFormat( - "Add(\"{0}\", {1}, {2}){3}", fileName, handle, version, - Environment.NewLine); - } - - // - // NOTE: If configured to do so, dispose of the received connection - // handle now. - // - if (dispose) - { - IDisposable disposable = handle as IDisposable; - - if (disposable != null) - disposable.Dispose(); - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Removes a connection from the pool of those associated with the - /// specified database file name with the intent of using it to - /// interact with the database. - /// - /// - /// The database file name. - /// - /// - /// The new maximum size of the connection pool for the specified - /// database file name. - /// - /// - /// The connection pool version associated with the returned database - /// connection handle, if any. - /// - /// - /// The database connection handle associated with the specified - /// database file name or null if it cannot be obtained. - /// - public object Remove( - string fileName, - int maxPoolSize, - out int version - ) - { - version = 0; - - if (log != null) - { - log.AppendFormat( - "Remove(\"{0}\", {1}, {2}){3}", fileName, maxPoolSize, - version, Environment.NewLine); - } - - return null; - } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region System.Object Overrides - /// - /// Overrides the default method - /// to provide a log of all methods called on the - /// interface. - /// - /// - /// A string containing a log of all method calls into the - /// interface, along with their - /// parameters, delimited by . - /// - public override string ToString() - { - return (log != null) ? log.ToString() : String.Empty; - } - #endregion - } -#endif - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region Public Connection Pool Interface - /// - /// This interface represents a custom connection pool implementation - /// usable by System.Data.SQLite. - /// - public interface ISQLiteConnectionPool - { - /// - /// Counts the number of pool entries matching the specified file name. - /// - /// - /// The file name to match or null to match all files. - /// - /// - /// The pool entry counts for each matching file. - /// - /// - /// The total number of connections successfully opened from any pool. - /// - /// - /// The total number of connections successfully closed from any pool. - /// - /// - /// The total number of pool entries for all matching files. - /// - void GetCounts(string fileName, ref Dictionary counts, - ref int openCount, ref int closeCount, ref int totalCount); - - /// - /// Disposes of all pooled connections associated with the specified - /// database file name. - /// - /// - /// The database file name. - /// - void ClearPool(string fileName); - - /// - /// Disposes of all pooled connections. - /// - void ClearAllPools(); - - /// - /// Adds a connection to the pool of those associated with the - /// specified database file name. - /// - /// - /// The database file name. - /// - /// - /// The database connection handle. - /// - /// - /// The connection pool version at the point the database connection - /// handle was received from the connection pool. This is also the - /// connection pool version that the database connection handle was - /// created under. - /// - void Add(string fileName, object handle, int version); - - /// - /// Removes a connection from the pool of those associated with the - /// specified database file name with the intent of using it to - /// interact with the database. - /// - /// - /// The database file name. - /// - /// - /// The new maximum size of the connection pool for the specified - /// database file name. - /// - /// - /// The connection pool version associated with the returned database - /// connection handle, if any. - /// - /// - /// The database connection handle associated with the specified - /// database file name or null if it cannot be obtained. - /// - object Remove(string fileName, int maxPoolSize, out int version); - } - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region Connection Pool Subsystem & Default Implementation - /// - /// This default method implementations in this class should not be used by - /// applications that make use of COM (either directly or indirectly) due - /// to possible deadlocks that can occur during finalization of some COM - /// objects. - /// - internal static class SQLiteConnectionPool - { - #region Private Pool Class - /// - /// Keeps track of connections made on a specified file. The PoolVersion - /// dictates whether old objects get returned to the pool or discarded - /// when no longer in use. - /// - private sealed class PoolQueue - { - #region Private Data - /// - /// The queue of weak references to the actual database connection - /// handles. - /// - internal readonly Queue Queue = - new Queue(); - - /////////////////////////////////////////////////////////////////// - - /// - /// This pool version associated with the database connection - /// handles in this pool queue. - /// - internal int PoolVersion; - - /////////////////////////////////////////////////////////////////// - - /// - /// The maximum size of this pool queue. - /// - internal int MaxPoolSize; - #endregion - - /////////////////////////////////////////////////////////////////// - - #region Private Constructors - /// - /// Constructs a connection pool queue using the specified version - /// and maximum size. Normally, all the database connection - /// handles in this pool are associated with a single database file - /// name. - /// - /// - /// The initial pool version for this connection pool queue. - /// - /// - /// The initial maximum size for this connection pool queue. - /// - internal PoolQueue( - int version, - int maxSize - ) - { - PoolVersion = version; - MaxPoolSize = maxSize; - } - #endregion - } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region Private Static Data - /// - /// This field is used to synchronize access to the private static data - /// in this class. - /// - private static readonly object _syncRoot = new object(); - - /////////////////////////////////////////////////////////////////////// - - /// - /// When this field is non-null, it will be used to provide the - /// implementation of all the connection pool methods; otherwise, - /// the default method implementations will be used. - /// - private static ISQLiteConnectionPool _connectionPool = null; - - /////////////////////////////////////////////////////////////////////// - - /// - /// The dictionary of connection pools, based on the normalized file - /// name of the SQLite database. - /// - private static SortedList _queueList = - new SortedList(StringComparer.OrdinalIgnoreCase); - - /////////////////////////////////////////////////////////////////////// - - /// - /// The default version number new pools will get. - /// - private static int _poolVersion = 1; - - /////////////////////////////////////////////////////////////////////// - - /// - /// The number of connections successfully opened from any pool. - /// This value is incremented by the Remove method. - /// - private static int _poolOpened = 0; - - /////////////////////////////////////////////////////////////////////// - - /// - /// The number of connections successfully closed from any pool. - /// This value is incremented by the Add method. - /// - private static int _poolClosed = 0; - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region ISQLiteConnectionPool Members (Static, Non-Formal) - /// - /// Counts the number of pool entries matching the specified file name. - /// - /// - /// The file name to match or null to match all files. - /// - /// - /// The pool entry counts for each matching file. - /// - /// - /// The total number of connections successfully opened from any pool. - /// - /// - /// The total number of connections successfully closed from any pool. - /// - /// - /// The total number of pool entries for all matching files. - /// - internal static void GetCounts( - string fileName, - ref Dictionary counts, - ref int openCount, - ref int closeCount, - ref int totalCount - ) - { - ISQLiteConnectionPool connectionPool = GetConnectionPool(); - - if (connectionPool != null) - { - connectionPool.GetCounts( - fileName, ref counts, ref openCount, ref closeCount, - ref totalCount); - } - else - { - lock (_syncRoot) - { - openCount = _poolOpened; - closeCount = _poolClosed; - - if (counts == null) - { - counts = new Dictionary( - StringComparer.OrdinalIgnoreCase); - } - - if (fileName != null) - { - PoolQueue queue; - - if (_queueList.TryGetValue(fileName, out queue)) - { - Queue poolQueue = queue.Queue; - int count = (poolQueue != null) ? poolQueue.Count : 0; - - counts.Add(fileName, count); - totalCount += count; - } - } - else - { - foreach (KeyValuePair pair in _queueList) - { - if (pair.Value == null) - continue; - - Queue poolQueue = pair.Value.Queue; - int count = (poolQueue != null) ? poolQueue.Count : 0; - - counts.Add(pair.Key, count); - totalCount += count; - } - } - } - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Disposes of all pooled connections associated with the specified - /// database file name. - /// - /// - /// The database file name. - /// - internal static void ClearPool(string fileName) - { - ISQLiteConnectionPool connectionPool = GetConnectionPool(); - - if (connectionPool != null) - { - connectionPool.ClearPool(fileName); - } - else - { - lock (_syncRoot) - { - PoolQueue queue; - - if (_queueList.TryGetValue(fileName, out queue)) - { - queue.PoolVersion++; - - Queue poolQueue = queue.Queue; - if (poolQueue == null) return; - - while (poolQueue.Count > 0) - { - WeakReference connection = poolQueue.Dequeue(); - - if (connection == null) continue; - - SQLiteConnectionHandle handle = - connection.Target as SQLiteConnectionHandle; - - if (handle != null) - handle.Dispose(); - - GC.KeepAlive(handle); - } - } - } - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Disposes of all pooled connections. - /// - internal static void ClearAllPools() - { - ISQLiteConnectionPool connectionPool = GetConnectionPool(); - - if (connectionPool != null) - { - connectionPool.ClearAllPools(); - } - else - { - lock (_syncRoot) - { - foreach (KeyValuePair pair in _queueList) - { - if (pair.Value == null) - continue; - - Queue poolQueue = pair.Value.Queue; - - while (poolQueue.Count > 0) - { - WeakReference connection = poolQueue.Dequeue(); - - if (connection == null) continue; - - SQLiteConnectionHandle handle = - connection.Target as SQLiteConnectionHandle; - - if (handle != null) - handle.Dispose(); - - GC.KeepAlive(handle); - } - - // - // NOTE: Keep track of the highest revision so we can - // go one higher when we are finished. - // - if (_poolVersion <= pair.Value.PoolVersion) - _poolVersion = pair.Value.PoolVersion + 1; - } - - // - // NOTE: All pools are cleared and we have a new highest - // version number to force all old version active - // items to get discarded instead of going back to - // the queue when they are closed. We can get away - // with this because we have pumped up the pool - // version out of range of all active connections, - // so they will all get discarded when they try to - // put themselves back into their pools. - // - _queueList.Clear(); - } - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Adds a connection to the pool of those associated with the - /// specified database file name. - /// - /// - /// The database file name. - /// - /// - /// The database connection handle. - /// - /// - /// The connection pool version at the point the database connection - /// handle was received from the connection pool. This is also the - /// connection pool version that the database connection handle was - /// created under. - /// - internal static void Add( - string fileName, - SQLiteConnectionHandle handle, - int version - ) - { - ISQLiteConnectionPool connectionPool = GetConnectionPool(); - - if (connectionPool != null) - { - connectionPool.Add(fileName, handle, version); - } - else - { - lock (_syncRoot) - { - // - // NOTE: If the queue does not exist in the pool, then it - // must have been cleared sometime after the - // connection was created. - // - PoolQueue queue; - - if (_queueList.TryGetValue(fileName, out queue) && - (version == queue.PoolVersion)) - { - ResizePool(queue, true); - - Queue poolQueue = queue.Queue; - if (poolQueue == null) return; - - poolQueue.Enqueue(new WeakReference(handle, false)); - Interlocked.Increment(ref _poolClosed); - } - else - { - handle.Close(); - } - - GC.KeepAlive(handle); - } - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// Removes a connection from the pool of those associated with the - /// specified database file name with the intent of using it to - /// interact with the database. - /// - /// - /// The database file name. - /// - /// - /// The new maximum size of the connection pool for the specified - /// database file name. - /// - /// - /// The connection pool version associated with the returned database - /// connection handle, if any. - /// - /// - /// The database connection handle associated with the specified - /// database file name or null if it cannot be obtained. - /// - internal static SQLiteConnectionHandle Remove( - string fileName, - int maxPoolSize, - out int version - ) - { - ISQLiteConnectionPool connectionPool = GetConnectionPool(); - - if (connectionPool != null) - { - return connectionPool.Remove(fileName, maxPoolSize, - out version) as SQLiteConnectionHandle; - } - else - { - int localVersion; - Queue poolQueue; - - // - // NOTE: This lock cannot be held while checking the queue for - // available connections because other methods of this - // class are called from the GC finalizer thread and we - // use the WaitForPendingFinalizers method (below). - // Holding this lock while calling that method would - // therefore result in a deadlock. Instead, this lock - // is held only while a temporary copy of the queue is - // created, and if necessary, when committing changes - // back to that original queue prior to returning from - // this method. - // - lock (_syncRoot) - { - PoolQueue queue; - - // - // NOTE: Default to the highest pool version. - // - version = _poolVersion; - - // - // NOTE: If we didn't find a pool for this file, create one - // even though it will be empty. We have to do this - // here because otherwise calling ClearPool() on the - // file will not work for active connections that have - // never seen the pool yet. - // - if (!_queueList.TryGetValue(fileName, out queue)) - { - queue = new PoolQueue(_poolVersion, maxPoolSize); - _queueList.Add(fileName, queue); - - return null; - } - - // - // NOTE: We found a pool for this file, so use its version - // number. - // - version = localVersion = queue.PoolVersion; - queue.MaxPoolSize = maxPoolSize; - - // - // NOTE: Now, resize the pool to the new maximum size, if - // necessary. - // - ResizePool(queue, false); - - // - // NOTE: Try and get a pooled connection from the queue. - // - poolQueue = queue.Queue; - if (poolQueue == null) return null; - - // - // NOTE: Temporarily tranfer the queue for this file into - // a local variable. The queue for this file will - // be modified and then committed back to the real - // pool list (below) prior to returning from this - // method. - // - _queueList.Remove(fileName); - poolQueue = new Queue(poolQueue); - } - - try - { - while (poolQueue.Count > 0) - { - WeakReference connection = poolQueue.Dequeue(); - - if (connection == null) continue; - - SQLiteConnectionHandle handle = - connection.Target as SQLiteConnectionHandle; - - if (handle == null) continue; - - // - // BUGFIX: For ticket [996d13cd87], step #1. After - // this point, make sure that the finalizer for - // the connection handle just obtained from the - // queue cannot START running (i.e. it may - // still be pending but it will no longer start - // after this point). - // - GC.SuppressFinalize(handle); - - try - { - // - // BUGFIX: For ticket [996d13cd87], step #2. Now, - // we must wait for all pending finalizers - // which have STARTED running and have not - // yet COMPLETED. This must be done just - // in case the finalizer for the connection - // handle just obtained from the queue has - // STARTED running at some point before - // SuppressFinalize was called on it. - // - // After this point, checking properties of - // the connection handle (e.g. IsClosed) - // should work reliably without having to - // worry that they will (due to the - // finalizer) change out from under us. - // - GC.WaitForPendingFinalizers(); - - // - // BUGFIX: For ticket [996d13cd87], step #3. Next, - // verify that the connection handle is - // actually valid and [still?] not closed - // prior to actually returning it to our - // caller. - // - if (!handle.IsInvalid && !handle.IsClosed) - { - Interlocked.Increment(ref _poolOpened); - return handle; - } - } - finally - { - // - // BUGFIX: For ticket [996d13cd87], step #4. Next, - // we must re-register the connection - // handle for finalization now that we have - // a strong reference to it (i.e. the - // finalizer will not run at least until - // the connection is subsequently closed). - // - GC.ReRegisterForFinalize(handle); - } - - GC.KeepAlive(handle); - } - } - finally - { - // - // BUGFIX: For ticket [996d13cd87], step #5. Finally, - // commit any changes to the pool/queue for this - // database file. - // - lock (_syncRoot) - { - // - // NOTE: We must check [again] if a pool exists for - // this file because one may have been added - // while the search for an available connection - // was in progress (above). - // - PoolQueue queue; - Queue newPoolQueue; - bool addPool; - - if (_queueList.TryGetValue(fileName, out queue)) - { - addPool = false; - } - else - { - addPool = true; - queue = new PoolQueue(localVersion, maxPoolSize); - } - - newPoolQueue = queue.Queue; - - while (poolQueue.Count > 0) - newPoolQueue.Enqueue(poolQueue.Dequeue()); - - ResizePool(queue, false); - - if (addPool) - _queueList.Add(fileName, queue); - } - } - - return null; - } - } - #endregion - - /////////////////////////////////////////////////////////////////////// - - #region Private Helper Methods - /// - /// This method is used to obtain a reference to the custom connection - /// pool implementation currently in use, if any. - /// - /// - /// The custom connection pool implementation or null if the default - /// connection pool implementation should be used. - /// - internal static ISQLiteConnectionPool GetConnectionPool() - { - lock (_syncRoot) - { - return _connectionPool; - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// This method is used to set the reference to the custom connection - /// pool implementation to use, if any. - /// - /// - /// The custom connection pool implementation to use or null if the - /// default connection pool implementation should be used. - /// - internal static void SetConnectionPool( - ISQLiteConnectionPool connectionPool - ) - { - lock (_syncRoot) - { - _connectionPool = connectionPool; - } - } - - /////////////////////////////////////////////////////////////////////// - - /// - /// We do not have to thread-lock anything in this function, because it - /// is only called by other functions above which already take the lock. - /// - /// - /// The pool queue to resize. - /// - /// - /// If a function intends to add to the pool, this is true, which - /// forces the resize to take one more than it needs from the pool. - /// - private static void ResizePool( - PoolQueue queue, - bool add - ) - { - int target = queue.MaxPoolSize; - - if (add && target > 0) target--; - - Queue poolQueue = queue.Queue; - if (poolQueue == null) return; - - while (poolQueue.Count > target) - { - WeakReference connection = poolQueue.Dequeue(); - - if (connection == null) continue; - - SQLiteConnectionHandle handle = - connection.Target as SQLiteConnectionHandle; - - if (handle != null) - handle.Dispose(); - - GC.KeepAlive(handle); - } - } - #endregion - } - #endregion -} +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ + using System; + using System.Collections.Generic; + using System.Threading; + + internal static class SQLiteConnectionPool + { + /// + /// Keeps track of connections made on a specified file. The PoolVersion dictates whether old objects get + /// returned to the pool or discarded when no longer in use. + /// + internal class Pool + { + internal readonly Queue Queue = new Queue(); + internal int PoolVersion; + internal int MaxPoolSize; + + internal Pool(int version, int maxSize) + { + PoolVersion = version; + MaxPoolSize = maxSize; + } + } + + /// + /// The connection pool object + /// + private static SortedList _connections = new SortedList(StringComparer.OrdinalIgnoreCase); + + /// + /// The default version number new pools will get + /// + private static int _poolVersion = 1; + + /// + /// The number of connections successfully opened from any pool. + /// This value is incremented by the Remove method. + /// + private static int _poolOpened = 0; + + /// + /// The number of connections successfully closed from any pool. + /// This value is incremented by the Add method. + /// + private static int _poolClosed = 0; + + /// + /// Counts the number of pool entries matching the specified file name. + /// + /// The file name to match or null to match all files. + /// The pool entry counts for each matching file. + /// The total number of connections successfully opened from any pool. + /// The total number of connections successfully closed from any pool. + /// The total number of pool entries for all matching files. + internal static void GetCounts( + string fileName, + ref Dictionary counts, + ref int openCount, + ref int closeCount, + ref int totalCount + ) + { + lock (_connections) + { + openCount = _poolOpened; + closeCount = _poolClosed; + + if (counts == null) + { + counts = new Dictionary( + StringComparer.OrdinalIgnoreCase); + } + + if (fileName != null) + { + Pool queue; + + if (_connections.TryGetValue(fileName, out queue)) + { + Queue poolQueue = queue.Queue; + int count = (poolQueue != null) ? poolQueue.Count : 0; + + counts.Add(fileName, count); + totalCount += count; + } + } + else + { + foreach (KeyValuePair pair in _connections) + { + if (pair.Value == null) + continue; + + Queue poolQueue = pair.Value.Queue; + int count = (poolQueue != null) ? poolQueue.Count : 0; + + counts.Add(pair.Key, count); + totalCount += count; + } + } + } + } + + /// + /// Attempt to pull a pooled connection out of the queue for active duty + /// + /// The filename for a desired connection + /// The maximum size the connection pool for the filename can be + /// The pool version the returned connection will belong to + /// Returns NULL if no connections were available. Even if none are, the poolversion will still be a valid pool version + internal static SQLiteConnectionHandle Remove(string fileName, int maxPoolSize, out int version) + { + int localVersion; + Queue poolQueue; + + // + // NOTE: This lock cannot be held while checking the queue for available + // connections because other methods of this class are called from + // the GC finalizer thread and we use the WaitForPendingFinalizers + // method (below). Holding this lock while calling that method + // would therefore result in a deadlock. Instead, this lock is + // held only while a temporary copy of the queue is created, and + // if necessary, when committing changes back to that original + // queue prior to returning from this method. + // + lock (_connections) + { + Pool queue; + + // Default to the highest pool version + version = _poolVersion; + + // If we didn't find a pool for this file, create one even though it will be empty. + // We have to do this here because otherwise calling ClearPool() on the file will not work for active connections + // that have never seen the pool yet. + if (_connections.TryGetValue(fileName, out queue) == false) + { + queue = new Pool(_poolVersion, maxPoolSize); + _connections.Add(fileName, queue); + + return null; + } + + // We found a pool for this file, so use its version number + version = localVersion = queue.PoolVersion; + queue.MaxPoolSize = maxPoolSize; + + ResizePool(queue, false); + + // Try and get a pooled connection from the queue + poolQueue = queue.Queue; + if (poolQueue == null) return null; + + // + // NOTE: Temporarily tranfer the queue for this file into a local + // variable. The queue for this file will be modified and + // then committed back to the real pool list (below) prior + // to returning from this method. + // + _connections.Remove(fileName); + poolQueue = new Queue(poolQueue); + } + + try + { + while (poolQueue.Count > 0) + { + WeakReference cnn = poolQueue.Dequeue(); + if (cnn == null) continue; + + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl == null) continue; + + // + // BUGFIX: For ticket [996d13cd87], step #1. After this point, + // make sure that the finalizer for the connection + // handle just obtained from the queue cannot START + // running (i.e. it may still be pending but it will no + // longer start after this point). + // + GC.SuppressFinalize(hdl); + + try + { + // + // BUGFIX: For ticket [996d13cd87], step #2. Now, we must wait + // for all pending finalizers which have STARTED running + // and have not yet COMPLETED. This must be done just + // in case the finalizer for the connection handle just + // obtained from the queue has STARTED running at some + // point before SuppressFinalize was called on it. + // + // After this point, checking properties of the + // connection handle (e.g. IsClosed) should work + // reliably without having to worry that they will + // (due to the finalizer) change out from under us. + // + GC.WaitForPendingFinalizers(); + + // + // BUGFIX: For ticket [996d13cd87], step #3. Next, verify that + // the connection handle is actually valid and [still?] + // not closed prior to actually returning it to our + // caller. + // + if (!hdl.IsInvalid && !hdl.IsClosed) + { + Interlocked.Increment(ref _poolOpened); + return hdl; + } + } + finally + { + // + // BUGFIX: For ticket [996d13cd87], step #4. Next, we must + // re-register the connection handle for finalization + // now that we have a strong reference to it (i.e. the + // finalizer will not run at least until the connection + // is subsequently closed). + // + GC.ReRegisterForFinalize(hdl); + } + + GC.KeepAlive(hdl); + } + } + finally + { + // + // BUGFIX: For ticket [996d13cd87], step #5. Finally, commit any + // changes to the pool/queue for this database file. + // + lock (_connections) + { + // + // NOTE: We must check [again] if a pool exists for this file + // because one may have been added while the search for + // an available connection was in progress (above). + // + Pool queue; + Queue newPoolQueue; + bool addPool; + + if (_connections.TryGetValue(fileName, out queue)) + { + addPool = false; + } + else + { + addPool = true; + queue = new Pool(localVersion, maxPoolSize); + } + + newPoolQueue = queue.Queue; + + while (poolQueue.Count > 0) + newPoolQueue.Enqueue(poolQueue.Dequeue()); + + ResizePool(queue, false); + + if (addPool) + _connections.Add(fileName, queue); + } + } + + return null; + } + + /// + /// Clears out all pooled connections and rev's up the default pool version to force all old active objects + /// not in the pool to get discarded rather than returned to their pools. + /// + internal static void ClearAllPools() + { + lock (_connections) + { + foreach (KeyValuePair pair in _connections) + { + if (pair.Value == null) + continue; + + Queue poolQueue = pair.Value.Queue; + + while (poolQueue.Count > 0) + { + WeakReference cnn = poolQueue.Dequeue(); + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + + // Keep track of the highest revision so we can go one higher when we're finished + if (_poolVersion <= pair.Value.PoolVersion) + _poolVersion = pair.Value.PoolVersion + 1; + } + // All pools are cleared and we have a new highest version number to force all old version active items to get discarded + // instead of going back to the queue when they are closed. + // We can get away with this because we've pumped up the _poolVersion out of range of all active connections, so they + // will all get discarded when they try to put themselves back in their pool. + _connections.Clear(); + } + } + + /// + /// Clear a given pool for a given filename. Discards anything in the pool for the given file, and revs the pool + /// version so current active objects on the old version of the pool will get discarded rather than be returned to the pool. + /// + /// The filename of the pool to clear + internal static void ClearPool(string fileName) + { + lock (_connections) + { + Pool queue; + if (_connections.TryGetValue(fileName, out queue) == true) + { + queue.PoolVersion++; + + Queue poolQueue = queue.Queue; + if (poolQueue == null) return; + + while (poolQueue.Count > 0) + { + WeakReference cnn = poolQueue.Dequeue(); + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + } + } + } + + /// + /// Return a connection to the pool for someone else to use. + /// + /// The filename of the pool to use + /// The connection handle to pool + /// The pool version the handle was created under + /// + /// If the version numbers don't match between the connection and the pool, then the handle is discarded. + /// + internal static void Add(string fileName, SQLiteConnectionHandle hdl, int version) + { + lock (_connections) + { + // If the queue doesn't exist in the pool, then it must've been cleared sometime after the connection was created. + Pool queue; + if (_connections.TryGetValue(fileName, out queue) == true && version == queue.PoolVersion) + { + ResizePool(queue, true); + + Queue poolQueue = queue.Queue; + if (poolQueue == null) return; + + poolQueue.Enqueue(new WeakReference(hdl, false)); + Interlocked.Increment(ref _poolClosed); + } + else + { + hdl.Close(); + } + GC.KeepAlive(hdl); + } + } + + /// + /// We don't have to thread-lock anything in this function, because it's only called by other functions above + /// which already have a thread-safe lock. + /// + /// The queue to resize + /// If a function intends to add to the pool, this is true, which forces the resize + /// to take one more than it needs from the pool + private static void ResizePool(Pool queue, bool forAdding) + { + int target = queue.MaxPoolSize; + + if (forAdding && target > 0) target--; + + Queue poolQueue = queue.Queue; + if (poolQueue == null) return; + + while (poolQueue.Count > target) + { + WeakReference cnn = poolQueue.Dequeue(); + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + } + } +} Index: System.Data.SQLite/SQLiteConnectionStringBuilder.cs ================================================================== --- System.Data.SQLite/SQLiteConnectionStringBuilder.cs +++ System.Data.SQLite/SQLiteConnectionStringBuilder.cs @@ -1,212 +1,212 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ - using System; - using System.Data.Common; - using System.ComponentModel; - using System.Collections; - using System.Globalization; - using System.Reflection; - -#if !PLATFORM_COMPACTFRAMEWORK - /// - /// SQLite implementation of DbConnectionStringBuilder. - /// - [DefaultProperty("DataSource")] - [DefaultMember("Item")] - public sealed class SQLiteConnectionStringBuilder : DbConnectionStringBuilder - { - /// - /// Properties of this class - /// - private Hashtable _properties; - - /// - /// Constructs a new instance of the class - /// - /// - /// Default constructor - /// - public SQLiteConnectionStringBuilder() - { - Initialize(null); - } - - /// - /// Constructs a new instance of the class using the specified connection string. - /// - /// The connection string to parse - public SQLiteConnectionStringBuilder(string connectionString) - { - Initialize(connectionString); - } - - /// - /// Private initializer, which assigns the connection string and resets the builder - /// - /// The connection string to assign - private void Initialize(string cnnString) - { - _properties = new Hashtable(StringComparer.OrdinalIgnoreCase); - try - { - base.GetProperties(_properties); - } - catch(NotImplementedException) - { - FallbackGetProperties(_properties); - } - - if (String.IsNullOrEmpty(cnnString) == false) - ConnectionString = cnnString; - } - - /// - /// Gets/Sets the default version of the SQLite engine to instantiate. Currently the only valid value is 3, indicating version 3 of the sqlite library. - /// - [Browsable(true)] - [DefaultValue(3)] - public int Version - { - get - { - object value; - TryGetValue("version", out value); - return Convert.ToInt32(value, CultureInfo.CurrentCulture); - } - set - { - if (value != 3) - throw new NotSupportedException(); - - this["version"] = value; - } - } - - /// - /// Gets/Sets the synchronization mode (file flushing) of the connection string. Default is "Normal". - /// - [DisplayName("Synchronous")] - [Browsable(true)] - [DefaultValue(SynchronizationModes.Normal)] - public SynchronizationModes SyncMode - { - get - { - object value; - TryGetValue("synchronous", out value); - if (value is string) - return (SynchronizationModes)TypeDescriptor.GetConverter(typeof(SynchronizationModes)).ConvertFrom(value); - else return (SynchronizationModes)value; - } - set - { - this["synchronous"] = value; - } - } - - /// - /// Gets/Sets the encoding for the connection string. The default is "False" which indicates UTF-8 encoding. - /// - [Browsable(true)] - [DefaultValue(false)] - public bool UseUTF16Encoding - { - get - { - object value; - TryGetValue("useutf16encoding", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["useutf16encoding"] = value; - } - } - - /// - /// Gets/Sets whether or not to use connection pooling. The default is "False" - /// - [Browsable(true)] - [DefaultValue(false)] - public bool Pooling - { - get - { - object value; - TryGetValue("pooling", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["pooling"] = value; - } - } - - /// - /// Gets/Sets whethor not to store GUID's in binary format. The default is True - /// which saves space in the database. - /// - [Browsable(true)] - [DefaultValue(true)] - public bool BinaryGUID - { - get - { - object value; - TryGetValue("binaryguid", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["binaryguid"] = value; - } - } - - /// - /// Gets/Sets the filename to open on the connection string. - /// - [DisplayName("Data Source")] - [Browsable(true)] - [DefaultValue("")] - public string DataSource - { - get - { - object value; - TryGetValue("data source", out value); - return value.ToString(); - } - set - { - this["data source"] = value; - } - } - - /// - /// An alternate to the data source property - /// - [Browsable(false)] - public string Uri - { - get - { - object value; - TryGetValue("uri", out value); - return value.ToString(); - } - set - { - this["uri"] = value; - } +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ + using System; + using System.Data.Common; + using System.ComponentModel; + using System.Collections; + using System.Globalization; + using System.Reflection; + +#if !PLATFORM_COMPACTFRAMEWORK + /// + /// SQLite implementation of DbConnectionStringBuilder. + /// + [DefaultProperty("DataSource")] + [DefaultMember("Item")] + public sealed class SQLiteConnectionStringBuilder : DbConnectionStringBuilder + { + /// + /// Properties of this class + /// + private Hashtable _properties; + + /// + /// Constructs a new instance of the class + /// + /// + /// Default constructor + /// + public SQLiteConnectionStringBuilder() + { + Initialize(null); + } + + /// + /// Constructs a new instance of the class using the specified connection string. + /// + /// The connection string to parse + public SQLiteConnectionStringBuilder(string connectionString) + { + Initialize(connectionString); + } + + /// + /// Private initializer, which assigns the connection string and resets the builder + /// + /// The connection string to assign + private void Initialize(string cnnString) + { + _properties = new Hashtable(StringComparer.OrdinalIgnoreCase); + try + { + base.GetProperties(_properties); + } + catch(NotImplementedException) + { + FallbackGetProperties(_properties); + } + + if (String.IsNullOrEmpty(cnnString) == false) + ConnectionString = cnnString; + } + + /// + /// Gets/Sets the default version of the SQLite engine to instantiate. Currently the only valid value is 3, indicating version 3 of the sqlite library. + /// + [Browsable(true)] + [DefaultValue(3)] + public int Version + { + get + { + object value; + TryGetValue("version", out value); + return Convert.ToInt32(value, CultureInfo.CurrentCulture); + } + set + { + if (value != 3) + throw new NotSupportedException(); + + this["version"] = value; + } + } + + /// + /// Gets/Sets the synchronization mode (file flushing) of the connection string. Default is "Normal". + /// + [DisplayName("Synchronous")] + [Browsable(true)] + [DefaultValue(SynchronizationModes.Normal)] + public SynchronizationModes SyncMode + { + get + { + object value; + TryGetValue("synchronous", out value); + if (value is string) + return (SynchronizationModes)TypeDescriptor.GetConverter(typeof(SynchronizationModes)).ConvertFrom(value); + else return (SynchronizationModes)value; + } + set + { + this["synchronous"] = value; + } + } + + /// + /// Gets/Sets the encoding for the connection string. The default is "False" which indicates UTF-8 encoding. + /// + [Browsable(true)] + [DefaultValue(false)] + public bool UseUTF16Encoding + { + get + { + object value; + TryGetValue("useutf16encoding", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["useutf16encoding"] = value; + } + } + + /// + /// Gets/Sets whether or not to use connection pooling. The default is "False" + /// + [Browsable(true)] + [DefaultValue(false)] + public bool Pooling + { + get + { + object value; + TryGetValue("pooling", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["pooling"] = value; + } + } + + /// + /// Gets/Sets whethor not to store GUID's in binary format. The default is True + /// which saves space in the database. + /// + [Browsable(true)] + [DefaultValue(true)] + public bool BinaryGUID + { + get + { + object value; + TryGetValue("binaryguid", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["binaryguid"] = value; + } + } + + /// + /// Gets/Sets the filename to open on the connection string. + /// + [DisplayName("Data Source")] + [Browsable(true)] + [DefaultValue("")] + public string DataSource + { + get + { + object value; + TryGetValue("data source", out value); + return value.ToString(); + } + set + { + this["data source"] = value; + } + } + + /// + /// An alternate to the data source property + /// + [Browsable(false)] + public string Uri + { + get + { + object value; + TryGetValue("uri", out value); + return value.ToString(); + } + set + { + this["uri"] = value; + } } /// /// An alternate to the data source property that uses the SQLite URI syntax. /// @@ -221,224 +221,196 @@ } set { this["fulluri"] = value; } - } - - /// - /// Gets/sets the default command timeout for newly-created commands. This is especially useful for - /// commands used internally such as inside a SQLiteTransaction, where setting the timeout is not possible. - /// - [DisplayName("Default Timeout")] - [Browsable(true)] - [DefaultValue(30)] - public int DefaultTimeout - { - get - { - object value; - TryGetValue("default timeout", out value); - return Convert.ToInt32(value, CultureInfo.CurrentCulture); - } - set - { - this["default timeout"] = value; - } - } - - /// - /// Determines whether or not the connection will automatically participate - /// in the current distributed transaction (if one exists) - /// - [Browsable(true)] - [DefaultValue(true)] - public bool Enlist - { - get - { - object value; - TryGetValue("enlist", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["enlist"] = value; - } - } - - /// - /// If set to true, will throw an exception if the database specified in the connection - /// string does not exist. If false, the database will be created automatically. - /// - [Browsable(true)] - [DefaultValue(false)] - public bool FailIfMissing - { - get - { - object value; - TryGetValue("failifmissing", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["failifmissing"] = value; - } - } - - /// - /// If enabled, uses the legacy 3.xx format for maximum compatibility, but results in larger - /// database sizes. - /// - [DisplayName("Legacy Format")] - [Browsable(true)] - [DefaultValue(false)] - public bool LegacyFormat - { - get - { - object value; - TryGetValue("legacy format", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["legacy format"] = value; - } - } - - /// - /// When enabled, the database will be opened for read-only access and writing will be disabled. - /// - [DisplayName("Read Only")] - [Browsable(true)] - [DefaultValue(false)] - public bool ReadOnly - { - get - { - object value; - TryGetValue("read only", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["read only"] = value; - } - } - - /// - /// Gets/sets the database encryption password - /// - [Browsable(true)] - [PasswordPropertyText(true)] - [DefaultValue("")] - public string Password - { - get - { - object value; - TryGetValue("password", out value); - return value.ToString(); - } - set - { - this["password"] = value; - } - } - - /// - /// Gets/sets the database encryption hexadecimal password - /// - [Browsable(true)] - [PasswordPropertyText(true)] - [DefaultValue(null)] - public byte[] HexPassword - { - get - { - object value; - - if (TryGetValue("hexpassword", out value)) - { - if (value is string) - return SQLiteConnection.FromHexString((string)value); - else if (value != null) - return (byte[])value; - } - - return null; - } - set - { - this["hexpassword"] = SQLiteConnection.ToHexString(value); - } - } - - /// - /// Gets/Sets the page size for the connection. - /// - [DisplayName("Page Size")] - [Browsable(true)] - [DefaultValue(1024)] - public int PageSize - { - get - { - object value; - TryGetValue("page size", out value); - return Convert.ToInt32(value, CultureInfo.CurrentCulture); - } - set - { - this["page size"] = value; - } - } - - /// - /// Gets/Sets the maximum number of pages the database may hold - /// - [DisplayName("Max Page Count")] - [Browsable(true)] - [DefaultValue(0)] - public int MaxPageCount - { - get - { - object value; - TryGetValue("max page count", out value); - return Convert.ToInt32(value, CultureInfo.CurrentCulture); - } - set - { - this["max page count"] = value; - } - } - - /// - /// Gets/Sets the cache size for the connection. - /// - [DisplayName("Cache Size")] - [Browsable(true)] - [DefaultValue(2000)] - public int CacheSize - { - get - { - object value; - TryGetValue("cache size", out value); - return Convert.ToInt32(value, CultureInfo.CurrentCulture); - } - set - { - this["cache size"] = value; - } - } - - /// - /// Gets/Sets the DateTime format for the connection. + } + + /// + /// Gets/sets the default command timeout for newly-created commands. This is especially useful for + /// commands used internally such as inside a SQLiteTransaction, where setting the timeout is not possible. + /// + [DisplayName("Default Timeout")] + [Browsable(true)] + [DefaultValue(30)] + public int DefaultTimeout + { + get + { + object value; + TryGetValue("default timeout", out value); + return Convert.ToInt32(value, CultureInfo.CurrentCulture); + } + set + { + this["default timeout"] = value; + } + } + + /// + /// Determines whether or not the connection will automatically participate + /// in the current distributed transaction (if one exists) + /// + [Browsable(true)] + [DefaultValue(true)] + public bool Enlist + { + get + { + object value; + TryGetValue("enlist", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["enlist"] = value; + } + } + + /// + /// If set to true, will throw an exception if the database specified in the connection + /// string does not exist. If false, the database will be created automatically. + /// + [Browsable(true)] + [DefaultValue(false)] + public bool FailIfMissing + { + get + { + object value; + TryGetValue("failifmissing", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["failifmissing"] = value; + } + } + + /// + /// If enabled, uses the legacy 3.xx format for maximum compatibility, but results in larger + /// database sizes. + /// + [DisplayName("Legacy Format")] + [Browsable(true)] + [DefaultValue(false)] + public bool LegacyFormat + { + get + { + object value; + TryGetValue("legacy format", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["legacy format"] = value; + } + } + + /// + /// When enabled, the database will be opened for read-only access and writing will be disabled. + /// + [DisplayName("Read Only")] + [Browsable(true)] + [DefaultValue(false)] + public bool ReadOnly + { + get + { + object value; + TryGetValue("read only", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["read only"] = value; + } + } + + /// + /// Gets/sets the database encryption password + /// + [Browsable(true)] + [PasswordPropertyText(true)] + [DefaultValue("")] + public string Password + { + get + { + object value; + TryGetValue("password", out value); + return value.ToString(); + } + set + { + this["password"] = value; + } + } + + /// + /// Gets/Sets the page size for the connection. + /// + [DisplayName("Page Size")] + [Browsable(true)] + [DefaultValue(1024)] + public int PageSize + { + get + { + object value; + TryGetValue("page size", out value); + return Convert.ToInt32(value, CultureInfo.CurrentCulture); + } + set + { + this["page size"] = value; + } + } + + /// + /// Gets/Sets the maximum number of pages the database may hold + /// + [DisplayName("Max Page Count")] + [Browsable(true)] + [DefaultValue(0)] + public int MaxPageCount + { + get + { + object value; + TryGetValue("max page count", out value); + return Convert.ToInt32(value, CultureInfo.CurrentCulture); + } + set + { + this["max page count"] = value; + } + } + + /// + /// Gets/Sets the cache size for the connection. + /// + [DisplayName("Cache Size")] + [Browsable(true)] + [DefaultValue(2000)] + public int CacheSize + { + get + { + object value; + TryGetValue("cache size", out value); + return Convert.ToInt32(value, CultureInfo.CurrentCulture); + } + set + { + this["cache size"] = value; + } + } + + /// + /// Gets/Sets the DateTime format for the connection. /// [Browsable(true)] [DefaultValue(SQLiteDateFormats.Default)] public SQLiteDateFormats DateTimeFormat { @@ -515,76 +487,76 @@ } set { this["baseschemaname"] = value; } - } - - /// - /// Determines how SQLite handles the transaction journal file. - /// - [Browsable(true)] - [DefaultValue(SQLiteJournalModeEnum.Default)] - [DisplayName("Journal Mode")] - public SQLiteJournalModeEnum JournalMode - { - get - { - object value; - TryGetValue("journal mode", out value); - if (value is string) - return (SQLiteJournalModeEnum)TypeDescriptor.GetConverter(typeof(SQLiteJournalModeEnum)).ConvertFrom(value); - else - return (SQLiteJournalModeEnum)value; - } - set - { - this["journal mode"] = value; - } - } - - /// - /// Sets the default isolation level for transactions on the connection. - /// - [Browsable(true)] - [DefaultValue(IsolationLevel.Serializable)] - [DisplayName("Default Isolation Level")] - public IsolationLevel DefaultIsolationLevel - { - get - { - object value; - TryGetValue("default isolationlevel", out value); - if (value is string) - return (IsolationLevel)TypeDescriptor.GetConverter(typeof(IsolationLevel)).ConvertFrom(value); - else - return (IsolationLevel)value; - } - set - { - this["default isolationlevel"] = value; - } - } - - /// - /// If enabled, use foreign key constraints - /// - [DisplayName("Foreign Keys")] - [Browsable(true)] - [DefaultValue(false)] - public bool ForeignKeys - { - get - { - object value; - TryGetValue("foreign keys", out value); - return SQLiteConvert.ToBoolean(value); - } - set - { - this["foreign keys"] = value; - } + } + + /// + /// Determines how SQLite handles the transaction journal file. + /// + [Browsable(true)] + [DefaultValue(SQLiteJournalModeEnum.Default)] + [DisplayName("Journal Mode")] + public SQLiteJournalModeEnum JournalMode + { + get + { + object value; + TryGetValue("journal mode", out value); + if (value is string) + return (SQLiteJournalModeEnum)TypeDescriptor.GetConverter(typeof(SQLiteJournalModeEnum)).ConvertFrom(value); + else + return (SQLiteJournalModeEnum)value; + } + set + { + this["journal mode"] = value; + } + } + + /// + /// Sets the default isolation level for transactions on the connection. + /// + [Browsable(true)] + [DefaultValue(IsolationLevel.Serializable)] + [DisplayName("Default Isolation Level")] + public IsolationLevel DefaultIsolationLevel + { + get + { + object value; + TryGetValue("default isolationlevel", out value); + if (value is string) + return (IsolationLevel)TypeDescriptor.GetConverter(typeof(IsolationLevel)).ConvertFrom(value); + else + return (IsolationLevel)value; + } + set + { + this["default isolationlevel"] = value; + } + } + + /// + /// If enabled, use foreign key constraints + /// + [DisplayName("Foreign Keys")] + [Browsable(true)] + [DefaultValue(false)] + public bool ForeignKeys + { + get + { + object value; + TryGetValue("foreign keys", out value); + return SQLiteConvert.ToBoolean(value); + } + set + { + this["foreign keys"] = value; + } } /// /// Gets/Sets the extra behavioral flags. /// @@ -651,59 +623,59 @@ set { this["tofullpath"] = value; } } - - /// - /// Helper function for retrieving values from the connectionstring - /// - /// The keyword to retrieve settings for - /// The resulting parameter value - /// Returns true if the value was found and returned - public override bool TryGetValue(string keyword, out object value) - { - bool b = base.TryGetValue(keyword, out value); - - if (!_properties.ContainsKey(keyword)) return b; - - PropertyDescriptor pd = _properties[keyword] as PropertyDescriptor; - - if (pd == null) return b; - - // Attempt to coerce the value into something more solid - if (b) - { - if (pd.PropertyType == typeof(Boolean)) - value = SQLiteConvert.ToBoolean(value); - else if (pd.PropertyType != typeof(byte[])) - value = TypeDescriptor.GetConverter(pd.PropertyType).ConvertFrom(value); - } - else - { - DefaultValueAttribute att = pd.Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute; - if (att != null) - { - value = att.Value; - b = true; - } - } - return b; - } - - /// - /// Fallback method for MONO, which doesn't implement DbConnectionStringBuilder.GetProperties() - /// - /// The hashtable to fill with property descriptors - private void FallbackGetProperties(Hashtable propertyList) - { - foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(this, true)) - { - if (descriptor.Name != "ConnectionString" && propertyList.ContainsKey(descriptor.DisplayName) == false) - { - propertyList.Add(descriptor.DisplayName, descriptor); - } - } - } - } -#endif -} + + /// + /// Helper function for retrieving values from the connectionstring + /// + /// The keyword to retrieve settings for + /// The resulting parameter value + /// Returns true if the value was found and returned + public override bool TryGetValue(string keyword, out object value) + { + bool b = base.TryGetValue(keyword, out value); + + if (!_properties.ContainsKey(keyword)) return b; + + PropertyDescriptor pd = _properties[keyword] as PropertyDescriptor; + + if (pd == null) return b; + + // Attempt to coerce the value into something more solid + if (b) + { + if (pd.PropertyType == typeof(Boolean)) + value = SQLiteConvert.ToBoolean(value); + else + value = TypeDescriptor.GetConverter(pd.PropertyType).ConvertFrom(value); + } + else + { + DefaultValueAttribute att = pd.Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute; + if (att != null) + { + value = att.Value; + b = true; + } + } + return b; + } + + /// + /// Fallback method for MONO, which doesn't implement DbConnectionStringBuilder.GetProperties() + /// + /// The hashtable to fill with property descriptors + private void FallbackGetProperties(Hashtable propertyList) + { + foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(this, true)) + { + if (descriptor.Name != "ConnectionString" && propertyList.ContainsKey(descriptor.DisplayName) == false) + { + propertyList.Add(descriptor.DisplayName, descriptor); + } + } + } + } +#endif +} Index: System.Data.SQLite/SQLiteConvert.cs ================================================================== --- System.Data.SQLite/SQLiteConvert.cs +++ System.Data.SQLite/SQLiteConvert.cs @@ -1,9 +1,9 @@ /******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) - * + * * Released to the public domain, use at your own risk! ********************************************************/ namespace System.Data.SQLite { @@ -160,23 +160,21 @@ /// The pointer to the memory where the UTF-8 string is encoded /// The number of bytes to decode /// A string containing the translated character(s) public static string UTF8ToString(IntPtr nativestring, int nativestringlen) { - if (nativestring == IntPtr.Zero || nativestringlen == 0) return String.Empty; - if (nativestringlen < 0) + if (nativestringlen == 0 || nativestring == IntPtr.Zero) return ""; + if (nativestringlen == -1) { - nativestringlen = 0; - - while (Marshal.ReadByte(nativestring, nativestringlen) != 0) + do + { nativestringlen++; - - if (nativestringlen == 0) return String.Empty; + } while (Marshal.ReadByte(nativestring, nativestringlen) != 0); } byte[] byteArray = new byte[nativestringlen]; - + Marshal.Copy(nativestring, byteArray, 0, nativestringlen); return _utf8.GetString(byteArray, 0, nativestringlen); } @@ -505,131 +503,10 @@ ls.CopyTo(ar, 0); return ar; } - /// - /// Splits the specified string into multiple strings based on a separator - /// and returns the result as an array of strings. - /// - /// - /// The string to split into pieces based on the separator character. If - /// this string is null, null will always be returned. If this string is - /// empty, an array of zero strings will always be returned. - /// - /// - /// The character used to divide the original string into sub-strings. - /// This character cannot be a backslash or a double-quote; otherwise, no - /// work will be performed and null will be returned. - /// - /// - /// If this parameter is non-zero, all double-quote characters will be - /// retained in the returned list of strings; otherwise, they will be - /// dropped. - /// - /// - /// The new array of strings or null if the input string is null -OR- the - /// separator character is a backslash or a double-quote -OR- the string - /// contains an unbalanced backslash or double-quote character. - /// - internal static string[] NewSplit( - string value, - char separator, - bool keepQuote - ) - { - const char EscapeChar = '\\'; - const char QuoteChar = '\"'; - - // - // NOTE: It is illegal for the separator character to be either a - // backslash or a double-quote because both of those characters - // are used for escaping other characters (e.g. the separator - // character). - // - if ((separator == EscapeChar) || (separator == QuoteChar)) - return null; - - if (value == null) - return null; - - int length = value.Length; - - if (length == 0) - return new string[0]; - - List list = new List(); - StringBuilder element = new StringBuilder(); - int index = 0; - bool escape = false; - bool quote = false; - - while (index < length) - { - char character = value[index++]; - - if (escape) - { - // - // HACK: Only consider the escape character to be an actual - // "escape" if it is followed by a reserved character; - // otherwise, emit the original escape character and - // the current character in an effort to help preserve - // the original string content. - // - if ((character != EscapeChar) && - (character != QuoteChar) && - (character != separator)) - { - element.Append(EscapeChar); - } - - element.Append(character); - escape = false; - } - else if (character == EscapeChar) - { - escape = true; - } - else if (character == QuoteChar) - { - if (keepQuote) - element.Append(character); - - quote = !quote; - } - else if (character == separator) - { - if (quote) - { - element.Append(character); - } - else - { - list.Add(element.ToString()); - element.Length = 0; - } - } - else - { - element.Append(character); - } - } - - // - // NOTE: An unbalanced escape or quote character in the string is - // considered to be a fatal error; therefore, return null. - // - if (escape || quote) - return null; - - if (element.Length > 0) - list.Add(element.ToString()); - - return list.ToArray(); - } - /// /// Convert a value to true or false. /// /// A string or number representing true or false /// @@ -695,18 +572,18 @@ else return SQLiteConvert.DbTypeToType(t.Type); } private static Type[] _affinitytotype = { - typeof(object), // Uninitialized (0) - typeof(Int64), // Int64 (1) - typeof(Double), // Double (2) - typeof(string), // Text (3) - typeof(byte[]), // Blob (4) - typeof(object), // Null (5) - typeof(DateTime), // DateTime (10) - typeof(object) // None (11) + typeof(object), + typeof(Int64), + typeof(Double), + typeof(string), + typeof(byte[]), + typeof(object), + typeof(DateTime), + typeof(object) }; /// /// For a given intrinsic type, return a DbType /// @@ -723,29 +600,29 @@ } return _typetodbtype[(int)tc]; } private static DbType[] _typetodbtype = { - DbType.Object, // Empty (0) - DbType.Binary, // Object (1) - DbType.Object, // DBNull (2) - DbType.Boolean, // Boolean (3) - DbType.SByte, // Char (4) - DbType.SByte, // SByte (5) - DbType.Byte, // Byte (6) - DbType.Int16, // Int16 (7) - DbType.UInt16, // UInt16 (8) - DbType.Int32, // Int32 (9) - DbType.UInt32, // UInt32 (10) - DbType.Int64, // Int64 (11) - DbType.UInt64, // UInt64 (12) - DbType.Single, // Single (13) - DbType.Double, // Double (14) - DbType.Decimal, // Decimal (15) - DbType.DateTime, // DateTime (16) - DbType.Object, // ?? (17) - DbType.String // String (18) + DbType.Object, + DbType.Binary, + DbType.Object, + DbType.Boolean, + DbType.SByte, + DbType.SByte, + DbType.Byte, + DbType.Int16, // 7 + DbType.UInt16, + DbType.Int32, + DbType.UInt32, + DbType.Int64, // 11 + DbType.UInt64, + DbType.Single, + DbType.Double, + DbType.Decimal, + DbType.DateTime, + DbType.Object, + DbType.String, }; /// /// Returns the ColumnSize for the given DbType /// @@ -755,104 +632,102 @@ { return _dbtypetocolumnsize[(int)typ]; } private static int[] _dbtypetocolumnsize = { - int.MaxValue, // AnsiString (0) - int.MaxValue, // Binary (1) - 1, // Byte (2) - 1, // Boolean (3) - 8, // Currency (4) - 8, // Date (5) - 8, // DateTime (6) - 8, // Decimal (7) - 8, // Double (8) - 16, // Guid (9) - 2, // Int16 (10) - 4, // Int32 (11) - 8, // Int64 (12) - int.MaxValue, // Object (13) - 1, // SByte (14) - 4, // Single (15) - int.MaxValue, // String (16) - 8, // Time (17) - 2, // UInt16 (18) - 4, // UInt32 (19) - 8, // UInt64 (20) - 8, // VarNumeric (21) - int.MaxValue, // AnsiStringFixedLength (22) - int.MaxValue, // StringFixedLength (23) - int.MaxValue, // ?? (24) - int.MaxValue // Xml (25) + 2147483647, // 0 + 2147483647, // 1 + 1, // 2 + 1, // 3 + 8, // 4 + 8, // 5 + 8, // 6 + 8, // 7 + 8, // 8 + 16, // 9 + 2, + 4, + 8, + 2147483647, + 1, + 4, + 2147483647, + 8, + 2, + 4, + 8, + 8, + 2147483647, + 2147483647, + 2147483647, + 2147483647, // 25 (Xml) }; internal static object DbTypeToNumericPrecision(DbType typ) { return _dbtypetonumericprecision[(int)typ]; } private static object[] _dbtypetonumericprecision = { - DBNull.Value, // AnsiString (0) - DBNull.Value, // Binary (1) - 3, // Byte (2) - DBNull.Value, // Boolean (3) - 19, // Currency (4) - DBNull.Value, // Date (5) - DBNull.Value, // DateTime (6) - 53, // Decimal (7) - 53, // Double (8) - DBNull.Value, // Guid (9) - 5, // Int16 (10) - 10, // Int32 (11) - 19, // Int64 (12) - DBNull.Value, // Object (13) - 3, // SByte (14) - 24, // Single (15) - DBNull.Value, // String (16) - DBNull.Value, // Time (17) - 5, // UInt16 (18) - 10, // UInt32 (19) - 19, // UInt64 (20) - 53, // VarNumeric (21) - DBNull.Value, // AnsiStringFixedLength (22) - DBNull.Value, // StringFixedLength (23) - DBNull.Value, // ?? (24) - DBNull.Value // Xml (25) + DBNull.Value, // 0 + DBNull.Value, // 1 + 3, + DBNull.Value, + 19, + DBNull.Value, // 5 + DBNull.Value, // 6 + 53, + 53, + DBNull.Value, + 5, + 10, + 19, + DBNull.Value, + 3, + 24, + DBNull.Value, + DBNull.Value, + 5, + 10, + 19, + 53, + DBNull.Value, + DBNull.Value, + DBNull.Value }; internal static object DbTypeToNumericScale(DbType typ) { return _dbtypetonumericscale[(int)typ]; } private static object[] _dbtypetonumericscale = { - DBNull.Value, // AnsiString (0) - DBNull.Value, // Binary (1) - 0, // Byte (2) - DBNull.Value, // Boolean (3) - 4, // Currency (4) - DBNull.Value, // Date (5) - DBNull.Value, // DateTime (6) - DBNull.Value, // Decimal (7) - DBNull.Value, // Double (8) - DBNull.Value, // Guid (9) - 0, // Int16 (10) - 0, // Int32 (11) - 0, // Int64 (12) - DBNull.Value, // Object (13) - 0, // SByte (14) - DBNull.Value, // Single (15) - DBNull.Value, // String (16) - DBNull.Value, // Time (17) - 0, // UInt16 (18) - 0, // UInt32 (19) - 0, // UInt64 (20) - 0, // VarNumeric (21) - DBNull.Value, // AnsiStringFixedLength (22) - DBNull.Value, // StringFixedLength (23) - DBNull.Value, // ?? (24) - DBNull.Value // Xml (25) + DBNull.Value, // 0 + DBNull.Value, // 1 + 0, + DBNull.Value, + 4, + DBNull.Value, // 5 + DBNull.Value, // 6 + DBNull.Value, + DBNull.Value, + DBNull.Value, + 0, + 0, + 0, + DBNull.Value, + 0, + DBNull.Value, + DBNull.Value, + DBNull.Value, + 0, + 0, + 0, + 0, + DBNull.Value, + DBNull.Value, + DBNull.Value }; internal static string DbTypeToTypeName(DbType typ) { for (int n = 0; n < _dbtypeNames.Length; n++) @@ -870,12 +745,27 @@ #endif return defaultTypeName; } - private static SQLiteTypeNames[] _dbtypeNames = GetSQLiteTypeNames(); - + private static SQLiteTypeNames[] _dbtypeNames = { + new SQLiteTypeNames("INTEGER", DbType.Int64), + new SQLiteTypeNames("TINYINT", DbType.Byte), + new SQLiteTypeNames("INT", DbType.Int32), + new SQLiteTypeNames("VARCHAR", DbType.AnsiString), + new SQLiteTypeNames("NVARCHAR", DbType.String), + new SQLiteTypeNames("CHAR", DbType.AnsiStringFixedLength), + new SQLiteTypeNames("NCHAR", DbType.StringFixedLength), + new SQLiteTypeNames("FLOAT", DbType.Double), + new SQLiteTypeNames("REAL", DbType.Double), + new SQLiteTypeNames("BIT", DbType.Boolean), + new SQLiteTypeNames("DECIMAL", DbType.Decimal), + new SQLiteTypeNames("DATETIME", DbType.DateTime), + new SQLiteTypeNames("BLOB", DbType.Binary), + new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid), + new SQLiteTypeNames("SMALLINT", DbType.Int16), + }; /// /// Convert a DbType to a Type /// /// The DbType to convert from /// The closest-match .NET type @@ -883,36 +773,36 @@ { return _dbtypeToType[(int)typ]; } private static Type[] _dbtypeToType = { - typeof(string), // AnsiString (0) - typeof(byte[]), // Binary (1) - typeof(byte), // Byte (2) - typeof(bool), // Boolean (3) - typeof(decimal), // Currency (4) - typeof(DateTime), // Date (5) - typeof(DateTime), // DateTime (6) - typeof(decimal), // Decimal (7) - typeof(double), // Double (8) - typeof(Guid), // Guid (9) - typeof(Int16), // Int16 (10) - typeof(Int32), // Int32 (11) - typeof(Int64), // Int64 (12) - typeof(object), // Object (13) - typeof(sbyte), // SByte (14) - typeof(float), // Single (15) - typeof(string), // String (16) - typeof(DateTime), // Time (17) - typeof(UInt16), // UInt16 (18) - typeof(UInt32), // UInt32 (19) - typeof(UInt64), // UInt64 (20) - typeof(double), // VarNumeric (21) - typeof(string), // AnsiStringFixedLength (22) - typeof(string), // StringFixedLength (23) - typeof(string), // ?? (24) - typeof(string), // Xml (25) + typeof(string), // 0 + typeof(byte[]), // 1 + typeof(byte), // 2 + typeof(bool), // 3 + typeof(decimal), // 4 + typeof(DateTime), // 5 + typeof(DateTime), // 6 + typeof(decimal), // 7 + typeof(double), // 8 + typeof(Guid), // 9 + typeof(Int16), + typeof(Int32), + typeof(Int64), + typeof(object), + typeof(sbyte), + typeof(float), + typeof(string), + typeof(DateTime), + typeof(UInt16), + typeof(UInt32), + typeof(UInt64), + typeof(double), + typeof(string), + typeof(string), + typeof(string), + typeof(string), // 25 (Xml) }; /// /// For a given type, return the closest-match SQLite TypeAffinity, which only understands a very limited subset of types. /// @@ -930,111 +820,30 @@ } return _typecodeAffinities[(int)tc]; } private static TypeAffinity[] _typecodeAffinities = { - TypeAffinity.Null, // Empty (0) - TypeAffinity.Blob, // Object (1) - TypeAffinity.Null, // DBNull (2) - TypeAffinity.Int64, // Boolean (3) - TypeAffinity.Int64, // Char (4) - TypeAffinity.Int64, // SByte (5) - TypeAffinity.Int64, // Byte (6) - TypeAffinity.Int64, // Int16 (7) - TypeAffinity.Int64, // UInt16 (8) - TypeAffinity.Int64, // Int32 (9) - TypeAffinity.Int64, // UInt32 (10) - TypeAffinity.Int64, // Int64 (11) - TypeAffinity.Int64, // UInt64 (12) - TypeAffinity.Double, // Single (13) - TypeAffinity.Double, // Double (14) - TypeAffinity.Double, // Decimal (15) - TypeAffinity.DateTime, // DateTime (16) - TypeAffinity.Null, // ?? (17) - TypeAffinity.Text // String (18) - }; - - /// - /// Builds and returns an array containing the database column types - /// recognized by this provider. - /// - /// - /// An array containing the database column types recognized by this - /// provider. - /// - private static SQLiteTypeNames[] GetSQLiteTypeNames() - { - return new SQLiteTypeNames[] { - new SQLiteTypeNames("BIGINT", DbType.Int64), - new SQLiteTypeNames("BIGUINT", DbType.UInt64), - new SQLiteTypeNames("BINARY", DbType.Binary), - new SQLiteTypeNames("BIT", DbType.Boolean), - new SQLiteTypeNames("BLOB", DbType.Binary), - new SQLiteTypeNames("BOOL", DbType.Boolean), - new SQLiteTypeNames("BOOLEAN", DbType.Boolean), - new SQLiteTypeNames("CHAR", DbType.AnsiStringFixedLength), - new SQLiteTypeNames("COUNTER", DbType.Int64), - new SQLiteTypeNames("CURRENCY", DbType.Decimal), - new SQLiteTypeNames("DATE", DbType.DateTime), - new SQLiteTypeNames("DATETIME", DbType.DateTime), - new SQLiteTypeNames("DECIMAL", DbType.Decimal), - new SQLiteTypeNames("DOUBLE", DbType.Double), - new SQLiteTypeNames("FLOAT", DbType.Double), - new SQLiteTypeNames("GENERAL", DbType.Binary), - new SQLiteTypeNames("GUID", DbType.Guid), - new SQLiteTypeNames("IDENTITY", DbType.Int64), - new SQLiteTypeNames("IMAGE", DbType.Binary), - new SQLiteTypeNames("INT", DbType.Int32), - new SQLiteTypeNames("INT8", DbType.SByte), - new SQLiteTypeNames("INT16", DbType.Int16), - new SQLiteTypeNames("INT32", DbType.Int32), - new SQLiteTypeNames("INT64", DbType.Int64), - new SQLiteTypeNames("INTEGER", DbType.Int64), - new SQLiteTypeNames("INTEGER8", DbType.SByte), - new SQLiteTypeNames("INTEGER16", DbType.Int16), - new SQLiteTypeNames("INTEGER32", DbType.Int32), - new SQLiteTypeNames("INTEGER64", DbType.Int64), - new SQLiteTypeNames("LOGICAL", DbType.Boolean), - new SQLiteTypeNames("LONG", DbType.Int64), - new SQLiteTypeNames("LONGCHAR", DbType.String), - new SQLiteTypeNames("LONGTEXT", DbType.String), - new SQLiteTypeNames("LONGVARCHAR", DbType.String), - new SQLiteTypeNames("MEMO", DbType.String), - new SQLiteTypeNames("MONEY", DbType.Decimal), - new SQLiteTypeNames("NCHAR", DbType.StringFixedLength), - new SQLiteTypeNames("NOTE", DbType.String), - new SQLiteTypeNames("NTEXT", DbType.String), - new SQLiteTypeNames("NUMERIC", DbType.Decimal), - new SQLiteTypeNames("NVARCHAR", DbType.String), - new SQLiteTypeNames("OLEOBJECT", DbType.Binary), - new SQLiteTypeNames("REAL", DbType.Double), - new SQLiteTypeNames("SMALLDATE", DbType.DateTime), - new SQLiteTypeNames("SMALLINT", DbType.Int16), - new SQLiteTypeNames("SMALLUINT", DbType.UInt16), - new SQLiteTypeNames("STRING", DbType.String), - new SQLiteTypeNames("TEXT", DbType.String), - new SQLiteTypeNames("TIME", DbType.DateTime), - new SQLiteTypeNames("TIMESTAMP", DbType.DateTime), - new SQLiteTypeNames("TINYINT", DbType.Byte), - new SQLiteTypeNames("TINYSINT", DbType.SByte), - new SQLiteTypeNames("UINT", DbType.UInt32), - new SQLiteTypeNames("UINT8", DbType.Byte), - new SQLiteTypeNames("UINT16", DbType.UInt16), - new SQLiteTypeNames("UINT32", DbType.UInt32), - new SQLiteTypeNames("UINT64", DbType.UInt64), - new SQLiteTypeNames("ULONG", DbType.UInt64), - new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid), - new SQLiteTypeNames("UNSIGNEDINTEGER", DbType.UInt64), - new SQLiteTypeNames("UNSIGNEDINTEGER8", DbType.Byte), - new SQLiteTypeNames("UNSIGNEDINTEGER16", DbType.UInt16), - new SQLiteTypeNames("UNSIGNEDINTEGER32", DbType.UInt32), - new SQLiteTypeNames("UNSIGNEDINTEGER64", DbType.UInt64), - new SQLiteTypeNames("VARBINARY", DbType.Binary), - new SQLiteTypeNames("VARCHAR", DbType.AnsiString), - new SQLiteTypeNames("YESNO", DbType.Boolean) - }; - } + TypeAffinity.Null, + TypeAffinity.Blob, + TypeAffinity.Null, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, // 7 + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, // 11 + TypeAffinity.Int64, + TypeAffinity.Double, + TypeAffinity.Double, + TypeAffinity.Double, + TypeAffinity.DateTime, + TypeAffinity.Null, + TypeAffinity.Text, + }; /// /// For a given type name, return a closest-match .NET type /// /// The name of the type to match @@ -1046,12 +855,61 @@ if (_typeNames == null) { _typeNames = new Dictionary( new TypeNameStringComparer()); - foreach (SQLiteTypeNames typeName in GetSQLiteTypeNames()) + foreach (SQLiteTypeNames typeName in new SQLiteTypeNames[] { + new SQLiteTypeNames("COUNTER", DbType.Int64), + new SQLiteTypeNames("AUTOINCREMENT", DbType.Int64), + new SQLiteTypeNames("IDENTITY", DbType.Int64), + new SQLiteTypeNames("LONGTEXT", DbType.String), + new SQLiteTypeNames("LONGCHAR", DbType.String), + new SQLiteTypeNames("LONGVARCHAR", DbType.String), + new SQLiteTypeNames("LONG", DbType.Int64), + new SQLiteTypeNames("TINYINT", DbType.Byte), + new SQLiteTypeNames("INTEGER", DbType.Int64), + new SQLiteTypeNames("INT", DbType.Int32), + new SQLiteTypeNames("VARCHAR", DbType.String), + new SQLiteTypeNames("NVARCHAR", DbType.String), + new SQLiteTypeNames("CHAR", DbType.String), + new SQLiteTypeNames("NCHAR", DbType.String), + new SQLiteTypeNames("TEXT", DbType.String), + new SQLiteTypeNames("NTEXT", DbType.String), + new SQLiteTypeNames("STRING", DbType.String), + new SQLiteTypeNames("DOUBLE", DbType.Double), + new SQLiteTypeNames("FLOAT", DbType.Double), + new SQLiteTypeNames("REAL", DbType.Double), + new SQLiteTypeNames("BIT", DbType.Boolean), + new SQLiteTypeNames("YESNO", DbType.Boolean), + new SQLiteTypeNames("LOGICAL", DbType.Boolean), + new SQLiteTypeNames("BOOL", DbType.Boolean), + new SQLiteTypeNames("BOOLEAN", DbType.Boolean), + new SQLiteTypeNames("NUMERIC", DbType.Decimal), + new SQLiteTypeNames("DECIMAL", DbType.Decimal), + new SQLiteTypeNames("MONEY", DbType.Decimal), + new SQLiteTypeNames("CURRENCY", DbType.Decimal), + new SQLiteTypeNames("TIME", DbType.DateTime), + new SQLiteTypeNames("DATE", DbType.DateTime), + new SQLiteTypeNames("DATETIME", DbType.DateTime), + new SQLiteTypeNames("SMALLDATE", DbType.DateTime), + new SQLiteTypeNames("TIMESTAMP", DbType.DateTime), + new SQLiteTypeNames("BLOB", DbType.Binary), + new SQLiteTypeNames("BINARY", DbType.Binary), + new SQLiteTypeNames("VARBINARY", DbType.Binary), + new SQLiteTypeNames("IMAGE", DbType.Binary), + new SQLiteTypeNames("GENERAL", DbType.Binary), + new SQLiteTypeNames("OLEOBJECT", DbType.Binary), + new SQLiteTypeNames("GUID", DbType.Guid), + new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid), + new SQLiteTypeNames("MEMO", DbType.String), + new SQLiteTypeNames("NOTE", DbType.String), + new SQLiteTypeNames("SMALLINT", DbType.Int16), + new SQLiteTypeNames("BIGINT", DbType.Int64) + }) + { _typeNames.Add(typeName.typeName, typeName); + } } } if (String.IsNullOrEmpty(Name)) return DbType.Object; @@ -1149,50 +1007,45 @@ /// /// The connection is being opened. /// Opening = 1, - /// - /// The connection string has been parsed. - /// - ConnectionString = 2, - /// /// The connection was opened. /// - Opened = 3, + Opened = 2, /// /// The method was called on the /// connection. /// - ChangeDatabase = 4, + ChangeDatabase = 3, /// /// A transaction was created using the connection. /// - NewTransaction = 5, + NewTransaction = 4, /// /// The connection was enlisted into a transaction. /// - EnlistTransaction = 6, + EnlistTransaction = 5, /// /// A command was created using the connection. /// - NewCommand = 7, + NewCommand = 6, /// /// The connection is being closed. /// - Closing = 8, + Closing = 7, /// /// The connection was closed. /// - Closed = 9 + Closed = 8 } /// /// This implementation of SQLite for ADO.NET can process date/time fields in databases in only one of three formats. Ticks, ISO8601 /// and JulianDay. @@ -1200,12 +1053,12 @@ /// /// ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second. /// JulianDay is the numeric format the SQLite uses internally and is arguably the most compatible with 3rd party tools. It is /// not readable as text without post-processing. /// Ticks less compatible with 3rd party tools that query the database, and renders the DateTime field unreadable as text without post-processing. - /// - /// The preferred order of choosing a datetime format is JulianDay, ISO8601, and then Ticks. Ticks is mainly present for legacy + /// + /// The preferred order of choosing a datetime format is JulianDay, ISO8601, and then Ticks. Ticks is mainly present for legacy /// code support. /// public enum SQLiteDateFormats { /// @@ -1244,11 +1097,11 @@ /// /// /// By default SQLite will create and delete the journal file when needed during a transaction. /// However, for some computers running certain filesystem monitoring tools, the rapid /// creation and deletion of the journal file can cause those programs to fail, or to interfere with SQLite. - /// + /// /// If a program or virus scanner is interfering with SQLite's journal file, you may receive errors like "unable to open database file" /// when starting a transaction. If this is happening, you may want to change the default journal mode to Persist. /// public enum SQLiteJournalModeEnum { @@ -1325,48 +1178,10 @@ /// slower. /// Full = 2 } - /// - /// The requested command execution type. This controls which method of the - /// object will be called. - /// - public enum SQLiteExecuteType - { - /// - /// Do nothing. No method will be called. - /// - None = 0, - - /// - /// The command is not expected to return a result -OR- the result is not - /// needed. The method will - /// be called. - /// - NonQuery = 1, - - /// - /// The command is expected to return a scalar result -OR- the result should - /// be limited to a scalar result. The - /// method will be called. - /// - Scalar = 2, - - /// - /// The command is expected to return result. - /// The method will be called. - /// - Reader = 3, - - /// - /// Use the default command execution type. Using this value is the same - /// as using the value. - /// - Default = NonQuery /* TODO: Good default? */ - } - /// /// Struct used internally to determine the datatype of a column in a resultset /// internal class SQLiteType { @@ -1409,12 +1224,12 @@ string value ) { // // NOTE: The only thing that we must guarantee here, according - // to the MSDN documentation for IEqualityComparer, is - // that for two given strings, if Equals return true then + // to the MSDN documentation for IEqualityComparer, is + // that for two given strings, if Equals return true then // the two strings must hash to the same value. // if (value != null) #if !PLATFORM_COMPACTFRAMEWORK return value.ToLowerInvariant().GetHashCode(); Index: System.Data.SQLite/SQLiteDataAdapter.cs ================================================================== --- System.Data.SQLite/SQLiteDataAdapter.cs +++ System.Data.SQLite/SQLiteDataAdapter.cs @@ -19,113 +19,52 @@ [ToolboxItem("SQLite.Designer.SQLiteDataAdapterToolboxItem, SQLite.Designer, Version=" + SQLite3.DesignerVersion + ", Culture=neutral, PublicKeyToken=db937bc2d44ff139")] [Designer("Microsoft.VSDesigner.Data.VS.SqlDataAdapterDesigner, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] #endif public sealed class SQLiteDataAdapter : DbDataAdapter { - private bool disposeSelect = true; - - /////////////////////////////////////////////////////////////////////////////////////////////// - private static object _updatingEventPH = new object(); private static object _updatedEventPH = new object(); - /////////////////////////////////////////////////////////////////////////////////////////////// - - #region Public Constructors /// - /// This class is just a shell around the DbDataAdapter. Nothing from - /// DbDataAdapter is overridden here, just a few constructors are defined. + /// This class is just a shell around the DbDataAdapter. Nothing from DbDataAdapter is overridden here, just a few constructors are defined. /// /// /// Default constructor. /// public SQLiteDataAdapter() { } - /////////////////////////////////////////////////////////////////////////////////////////////// - /// /// Constructs a data adapter using the specified select command. /// - /// - /// The select command to associate with the adapter. - /// + /// The select command to associate with the adapter. public SQLiteDataAdapter(SQLiteCommand cmd) { SelectCommand = cmd; - disposeSelect = false; } - /////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// Constructs a data adapter with the supplied select command text and - /// associated with the specified connection. + /// Constructs a data adapter with the supplied select command text and associated with the specified connection. /// - /// - /// The select command text to associate with the data adapter. - /// - /// - /// The connection to associate with the select command. - /// + /// The select command text to associate with the data adapter. + /// The connection to associate with the select command. public SQLiteDataAdapter(string commandText, SQLiteConnection connection) { SelectCommand = new SQLiteCommand(commandText, connection); } - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// Constructs a data adapter with the specified select command text, - /// and using the specified database connection string. - /// - /// - /// The select command text to use to construct a select command. - /// - /// - /// A connection string suitable for passing to a new SQLiteConnection, - /// which is associated with the select command. - /// - public SQLiteDataAdapter( - string commandText, - string connectionString - ) - : this(commandText, connectionString, false) - { - // do nothing. - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// - /// Constructs a data adapter with the specified select command text, - /// and using the specified database connection string. - /// - /// - /// The select command text to use to construct a select command. - /// - /// - /// A connection string suitable for passing to a new SQLiteConnection, - /// which is associated with the select command. - /// - /// - /// Non-zero to parse the connection string using the built-in (i.e. - /// framework provided) parser when opening the connection. - /// - public SQLiteDataAdapter( - string commandText, - string connectionString, - bool parseViaFramework - ) - { - SQLiteConnection cnn = new SQLiteConnection( - connectionString, parseViaFramework); - + /// + /// Constructs a data adapter with the specified select command text, and using the specified database connection string. + /// + /// The select command text to use to construct a select command. + /// A connection string suitable for passing to a new SQLiteConnection, which is associated with the select command. + public SQLiteDataAdapter(string commandText, string connectionString) + { + SQLiteConnection cnn = new SQLiteConnection(connectionString); SelectCommand = new SQLiteCommand(commandText, cnn); } - #endregion /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; @@ -143,40 +82,16 @@ { try { if (!disposed) { - if (disposing) - { - //////////////////////////////////// - // dispose managed resources here... - //////////////////////////////////// - - if (disposeSelect && (SelectCommand != null)) - { - SelectCommand.Dispose(); - SelectCommand = null; - } - - if (InsertCommand != null) - { - InsertCommand.Dispose(); - InsertCommand = null; - } - - if (UpdateCommand != null) - { - UpdateCommand.Dispose(); - UpdateCommand = null; - } - - if (DeleteCommand != null) - { - DeleteCommand.Dispose(); - DeleteCommand = null; - } - } + //if (disposing) + //{ + // //////////////////////////////////// + // // dispose managed resources here... + // //////////////////////////////////// + //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// Index: System.Data.SQLite/SQLiteDataReader.cs ================================================================== --- System.Data.SQLite/SQLiteDataReader.cs +++ System.Data.SQLite/SQLiteDataReader.cs @@ -644,11 +644,11 @@ /// The int i of the column public override int GetOrdinal(string name) { CheckDisposed(); CheckClosed(); - if (_throwOnDisposed) SQLiteCommand.Check(_command); + SQLiteCommand.Check(_command); // // NOTE: First, check if the column name cache has been initialized yet. // If not, do it now. // @@ -724,11 +724,11 @@ } #endregion /////////////////////////////////////////////////////////////////////////// - #region ColumnParent Class + #region ColumnParent Class private sealed class ColumnParent : IEqualityComparer { #region Public Fields public string DatabaseName; public string TableName; @@ -852,11 +852,11 @@ } internal DataTable GetSchemaTable(bool wantUniqueInfo, bool wantDefaultValue) { CheckClosed(); - if (_throwOnDisposed) SQLiteCommand.Check(_command); + SQLiteCommand.Check(_command); // // BUGFIX: We need to quickly scan all the fields in the current // "result set" to see how many distinct tables are actually // involved. This information is necessary so that some @@ -1115,19 +1115,17 @@ /// The index of the column to retrieve /// object public override object GetValue(int i) { CheckDisposed(); - CheckValidRow(); if (i >= VisibleFieldCount && _keyInfo != null) return _keyInfo.GetValue(i - VisibleFieldCount); SQLiteType typ = GetSQLiteType(i); - return _activeStatement._sql.GetValue( - _activeStatement, SQLiteCommand.GetFlags(_command), i, typ); + return _activeStatement._sql.GetValue(_activeStatement, i, typ); } /// /// Retreives the values of multiple columns, up to the size of the supplied array /// @@ -1221,11 +1219,11 @@ /// True if the command was successful and a new resultset is available, False otherwise. public override bool NextResult() { CheckDisposed(); CheckClosed(); - if (_throwOnDisposed) SQLiteCommand.Check(_command); + SQLiteCommand.Check(_command); SQLiteStatement stmt = null; int fieldCount; while (true) @@ -1246,15 +1244,15 @@ _activeStatementIndex++; stmt._sql.Step(stmt); if (stmt._sql.ColumnCount(stmt) == 0) { - if (_rowsAffected == -1) _rowsAffected = 0; - int changes = 0; - if (stmt.TryGetChanges(ref changes)) - _rowsAffected += changes; - else + if (_rowsAffected == -1) _rowsAffected = 0; + int changes = 0; + if (stmt.TryGetChanges(ref changes)) + _rowsAffected += changes; + else return false; } stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such! } return false; @@ -1283,15 +1281,15 @@ { _readingState = -1; } else if (fieldCount == 0) // No rows returned, if fieldCount is zero, skip to the next statement { - if (_rowsAffected == -1) _rowsAffected = 0; - int changes = 0; - if (stmt.TryGetChanges(ref changes)) - _rowsAffected += changes; - else + if (_rowsAffected == -1) _rowsAffected = 0; + int changes = 0; + if (stmt.TryGetChanges(ref changes)) + _rowsAffected += changes; + else return false; stmt._sql.Reset(stmt); continue; // Skip this command and move to the next, it was not a row-returning resultset } else // No rows, fieldCount is non-zero so stop here @@ -1347,11 +1345,11 @@ /// True if a new row was successfully loaded and is ready for processing public override bool Read() { CheckDisposed(); CheckClosed(); - if (_throwOnDisposed) SQLiteCommand.Check(_command); + SQLiteCommand.Check(_command); if (_readingState == -1) // First step was already done at the NextResult() level, so don't step again, just return true. { _readingState = 0; return true; Index: System.Data.SQLite/SQLiteDefineConstants.cs ================================================================== --- System.Data.SQLite/SQLiteDefineConstants.cs +++ System.Data.SQLite/SQLiteDefineConstants.cs @@ -14,14 +14,10 @@ public static readonly IList OptionList = new List(new string[] { #if CHECK_STATE "CHECK_STATE", #endif -#if COUNT_HANDLE - "COUNT_HANDLE", -#endif - #if DEBUG "DEBUG", #endif #if INTEROP_CODEC @@ -34,18 +30,10 @@ #if INTEROP_EXTENSION_FUNCTIONS "INTEROP_EXTENSION_FUNCTIONS", #endif -#if INTEROP_LEGACY_CLOSE - "INTEROP_LEGACY_CLOSE", -#endif - -#if INTEROP_LOG - "INTEROP_LOG", -#endif - #if INTEROP_TEST_EXTENSION "INTEROP_TEST_EXTENSION", #endif #if NET_20 @@ -114,17 +102,9 @@ #if USE_INTEROP_DLL "USE_INTEROP_DLL", #endif -#if USE_PREPARE_V2 - "USE_PREPARE_V2", -#endif - -#if WINDOWS - "WINDOWS", -#endif - null }); } } Index: System.Data.SQLite/SQLiteException.cs ================================================================== --- System.Data.SQLite/SQLiteException.cs +++ System.Data.SQLite/SQLiteException.cs @@ -1,119 +1,119 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ using System; - using System.Data.Common; - -#if !PLATFORM_COMPACTFRAMEWORK - using System.Reflection; - using System.Runtime.Serialization; + using System.Data.Common; + +#if !PLATFORM_COMPACTFRAMEWORK + using System.Reflection; + using System.Runtime.Serialization; using System.Security.Permissions; -#endif - - /// - /// SQLite exception class. - /// -#if !PLATFORM_COMPACTFRAMEWORK - [Serializable()] - public sealed class SQLiteException : DbException, ISerializable -#else - public sealed class SQLiteException : Exception -#endif - { - private SQLiteErrorCode _errorCode; - -#if !PLATFORM_COMPACTFRAMEWORK - /// - /// Private constructor for use with serialization. - /// - /// - /// Holds the serialized object data about the exception being thrown. - /// - /// - /// Contains contextual information about the source or destination. - /// - private SQLiteException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _errorCode = (SQLiteErrorCode)info.GetInt32("errorCode"); - } -#endif - - /// - /// Public constructor for generating a SQLite exception given the error - /// code and message. - /// - /// - /// The SQLite return code to report. - /// - /// - /// Message text to go along with the return code message text. - /// - public SQLiteException(SQLiteErrorCode errorCode, string message) - : base(GetStockErrorMessage(errorCode, message)) - { - _errorCode = errorCode; - } - - /// - /// Public constructor that uses the base class constructor for the error - /// message. - /// - /// Error message text. - public SQLiteException(string message) - : base(message) - { - } - - /// - /// Public constructor that uses the default base class constructor. - /// - public SQLiteException() - { - } - - /// - /// Public constructor that uses the base class constructor for the error - /// message and inner exception. - /// - /// Error message text. - /// The original (inner) exception. - public SQLiteException(string message, Exception innerException) - : base(message, innerException) - { - } - -#if !PLATFORM_COMPACTFRAMEWORK - /// - /// Adds extra information to the serialized object data specific to this - /// class type. This is only used for serialization. - /// - /// - /// Holds the serialized object data about the exception being thrown. - /// - /// - /// Contains contextual information about the source or destination. - /// - [SecurityPermission( - SecurityAction.LinkDemand, - Flags = SecurityPermissionFlag.SerializationFormatter)] - public override void GetObjectData( - SerializationInfo info, - StreamingContext context) - { - if (info != null) - info.AddValue("errorCode", _errorCode); - - base.GetObjectData(info, context); - } +#endif + + /// + /// SQLite exception class. + /// +#if !PLATFORM_COMPACTFRAMEWORK + [Serializable()] + public sealed class SQLiteException : DbException, ISerializable +#else + public sealed class SQLiteException : Exception +#endif + { + private SQLiteErrorCode _errorCode; + +#if !PLATFORM_COMPACTFRAMEWORK + /// + /// Private constructor for use with serialization. + /// + /// + /// Holds the serialized object data about the exception being thrown. + /// + /// + /// Contains contextual information about the source or destination. + /// + private SQLiteException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _errorCode = (SQLiteErrorCode)info.GetInt32("errorCode"); + } +#endif + + /// + /// Public constructor for generating a SQLite exception given the error + /// code and message. + /// + /// + /// The SQLite return code to report. + /// + /// + /// Message text to go along with the return code message text. + /// + public SQLiteException(SQLiteErrorCode errorCode, string message) + : base(GetStockErrorMessage(errorCode, message)) + { + _errorCode = errorCode; + } + + /// + /// Public constructor that uses the base class constructor for the error + /// message. + /// + /// Error message text. + public SQLiteException(string message) + : base(message) + { + } + + /// + /// Public constructor that uses the default base class constructor. + /// + public SQLiteException() + { + } + + /// + /// Public constructor that uses the base class constructor for the error + /// message and inner exception. + /// + /// Error message text. + /// The original (inner) exception. + public SQLiteException(string message, Exception innerException) + : base(message, innerException) + { + } + +#if !PLATFORM_COMPACTFRAMEWORK + /// + /// Adds extra information to the serialized object data specific to this + /// class type. This is only used for serialization. + /// + /// + /// Holds the serialized object data about the exception being thrown. + /// + /// + /// Contains contextual information about the source or destination. + /// + [SecurityPermission( + SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public override void GetObjectData( + SerializationInfo info, + StreamingContext context) + { + if (info != null) + info.AddValue("errorCode", _errorCode); + + base.GetObjectData(info, context); + } #endif /// /// Gets the associated SQLite return code for this exception as a /// . This property returns the same @@ -121,208 +121,196 @@ /// public SQLiteErrorCode ReturnCode { get { return _errorCode; } } - - /// - /// Gets the associated SQLite return code for this exception as an - /// . For desktop versions of the .NET Framework, - /// this property overrides the property of the same name within the - /// - /// class. This property returns the same underlying value as the - /// property. - /// -#if !PLATFORM_COMPACTFRAMEWORK - public override int ErrorCode -#else - public int ErrorCode -#endif - { - get { return (int)_errorCode; } - } - - /// - /// Returns the error message for the specified SQLite return code. - /// - /// The SQLite return code. - /// The error message or null if it cannot be found. - private static string GetErrorString( - SQLiteErrorCode errorCode - ) - { -#if !PLATFORM_COMPACTFRAMEWORK - // - // HACK: This must be done via reflection in order to prevent - // the RuntimeHelpers.PrepareDelegate method from over- - // eagerly attempting to locate the new (and optional) - // sqlite3_errstr() function in the SQLite core library - // because it happens to be in the static call graph for - // the AppDomain.DomainUnload event handler registered - // by the SQLiteLog class. - // - BindingFlags flags = BindingFlags.Static | - BindingFlags.NonPublic | BindingFlags.InvokeMethod; - - return typeof(SQLiteBase).InvokeMember("GetErrorString", - flags, null, null, new object[] { errorCode }) as string; -#else - return SQLiteBase.GetErrorString(errorCode); -#endif - } - - /// - /// Returns the composite error message based on the SQLite return code - /// and the optional detailed error message. - /// - /// The SQLite return code. - /// Optional detailed error message. - /// Error message text for the return code. - private static string GetStockErrorMessage( - SQLiteErrorCode errorCode, - string message - ) - { - return String.Format("{0}{1}{2}", - GetErrorString(errorCode), -#if !NET_COMPACT_20 - Environment.NewLine, message).Trim(); -#else - "\r\n", message).Trim(); -#endif - } - } - - /// - /// SQLite error codes. Actually, this enumeration represents a return code, - /// which may also indicate success in one of several ways (e.g. SQLITE_OK, - /// SQLITE_ROW, and SQLITE_DONE). Therefore, the name of this enumeration is - /// something of a misnomer. - /// - public enum SQLiteErrorCode - { - /// - /// Successful result - /// - Ok /* 0 */, - /// - /// SQL error or missing database - /// - Error /* 1 */, - /// - /// Internal logic error in SQLite - /// - Internal /* 2 */, - /// - /// Access permission denied - /// - Perm /* 3 */, - /// - /// Callback routine requested an abort - /// - Abort /* 4 */, - /// - /// The database file is locked - /// - Busy /* 5 */, - /// - /// A table in the database is locked - /// - Locked /* 6 */, - /// - /// A malloc() failed - /// - NoMem /* 7 */, - /// - /// Attempt to write a readonly database - /// - ReadOnly /* 8 */, - /// - /// Operation terminated by sqlite3_interrupt() - /// - Interrupt /* 9 */, - /// - /// Some kind of disk I/O error occurred - /// - IoErr /* 10 */, - /// - /// The database disk image is malformed - /// - Corrupt /* 11 */, - /// - /// Unknown opcode in sqlite3_file_control() - /// - NotFound /* 12 */, - /// - /// Insertion failed because database is full - /// - Full /* 13 */, - /// - /// Unable to open the database file - /// - CantOpen /* 14 */, - /// - /// Database lock protocol error - /// - Protocol /* 15 */, - /// - /// Database is empty - /// - Empty /* 16 */, - /// - /// The database schema changed - /// - Schema /* 17 */, - /// - /// String or BLOB exceeds size limit - /// - TooBig /* 18 */, - /// - /// Abort due to constraint violation - /// - Constraint /* 19 */, - /// - /// Data type mismatch - /// - Mismatch /* 20 */, - /// - /// Library used incorrectly - /// - Misuse /* 21 */, - /// - /// Uses OS features not supported on host - /// - NoLfs /* 22 */, - /// - /// Authorization denied - /// - Auth /* 23 */, - /// - /// Auxiliary database format error - /// - Format /* 24 */, - /// - /// 2nd parameter to sqlite3_bind out of range - /// - Range /* 25 */, - /// - /// File opened that is not a database file - /// - NotADb /* 26 */, - /// - /// Notifications from sqlite3_log() - /// - Notice /* 27 */, - /// - /// Warnings from sqlite3_log() - /// - Warning /* 28 */, - /// - /// sqlite3_step() has another row ready - /// - Row = 100, - /// - /// sqlite3_step() has finished executing - /// - Done /* 101 */ - } -} + + /// + /// Gets the associated SQLite return code for this exception as an + /// . For desktop versions of the .NET Framework, + /// this property overrides the property of the same name within the + /// + /// class. This property returns the same underlying value as the + /// property. + /// +#if !PLATFORM_COMPACTFRAMEWORK + public override int ErrorCode +#else + public int ErrorCode +#endif + { + get { return (int)_errorCode; } + } + + /// + /// Returns the error message for the specified SQLite return code. + /// + /// The SQLite return code. + /// The error message or null if it cannot be found. + private static string GetErrorString( + SQLiteErrorCode errorCode + ) + { +#if !PLATFORM_COMPACTFRAMEWORK + // + // HACK: This must be done via reflection in order to prevent + // the RuntimeHelpers.PrepareDelegate method from over- + // eagerly attempting to locate the new (and optional) + // sqlite3_errstr() function in the SQLite core library + // because it happens to be in the static call graph for + // the AppDomain.DomainUnload event handler registered + // by the SQLiteLog class. + // + BindingFlags flags = BindingFlags.Static | + BindingFlags.NonPublic | BindingFlags.InvokeMethod; + + return typeof(SQLiteBase).InvokeMember("GetErrorString", + flags, null, null, new object[] { errorCode }) as string; +#else + return SQLiteBase.GetErrorString(errorCode); +#endif + } + + /// + /// Returns the composite error message based on the SQLite return code + /// and the optional detailed error message. + /// + /// The SQLite return code. + /// Optional detailed error message. + /// Error message text for the return code. + private static string GetStockErrorMessage( + SQLiteErrorCode errorCode, + string message + ) + { + return String.Format("{0}{1}{2}", + GetErrorString(errorCode), + Environment.NewLine, message).Trim(); + } + } + + /// + /// SQLite error codes. Actually, this enumeration represents a return code, + /// which may also indicate success in one of several ways (e.g. SQLITE_OK, + /// SQLITE_ROW, and SQLITE_DONE). Therefore, the name of this enumeration is + /// something of a misnomer. + /// + public enum SQLiteErrorCode + { + /// + /// Successful result + /// + Ok /* 0 */, + /// + /// SQL error or missing database + /// + Error /* 1 */, + /// + /// Internal logic error in SQLite + /// + Internal /* 2 */, + /// + /// Access permission denied + /// + Perm /* 3 */, + /// + /// Callback routine requested an abort + /// + Abort /* 4 */, + /// + /// The database file is locked + /// + Busy /* 5 */, + /// + /// A table in the database is locked + /// + Locked /* 6 */, + /// + /// A malloc() failed + /// + NoMem /* 7 */, + /// + /// Attempt to write a readonly database + /// + ReadOnly /* 8 */, + /// + /// Operation terminated by sqlite3_interrupt() + /// + Interrupt /* 9 */, + /// + /// Some kind of disk I/O error occurred + /// + IoErr /* 10 */, + /// + /// The database disk image is malformed + /// + Corrupt /* 11 */, + /// + /// Unknown opcode in sqlite3_file_control() + /// + NotFound /* 12 */, + /// + /// Insertion failed because database is full + /// + Full /* 13 */, + /// + /// Unable to open the database file + /// + CantOpen /* 14 */, + /// + /// Database lock protocol error + /// + Protocol /* 15 */, + /// + /// Database is empty + /// + Empty /* 16 */, + /// + /// The database schema changed + /// + Schema /* 17 */, + /// + /// String or BLOB exceeds size limit + /// + TooBig /* 18 */, + /// + /// Abort due to constraint violation + /// + Constraint /* 19 */, + /// + /// Data type mismatch + /// + Mismatch /* 20 */, + /// + /// Library used incorrectly + /// + Misuse /* 21 */, + /// + /// Uses OS features not supported on host + /// + NoLfs /* 22 */, + /// + /// Authorization denied + /// + Auth /* 23 */, + /// + /// Auxiliary database format error + /// + Format /* 24 */, + /// + /// 2nd parameter to sqlite3_bind out of range + /// + Range /* 25 */, + /// + /// File opened that is not a database file + /// + NotADb /* 26 */, + /// + /// sqlite3_step() has another row ready + /// + Row = 100, + /// + /// sqlite3_step() has finished executing + /// + Done /* 101 */ + } +} Index: System.Data.SQLite/SQLiteFunction.cs ================================================================== --- System.Data.SQLite/SQLiteFunction.cs +++ System.Data.SQLite/SQLiteFunction.cs @@ -1,41 +1,41 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ using System; - using System.Collections.Generic; - using System.Runtime.InteropServices; - using System.Globalization; - - /// - /// This abstract class is designed to handle user-defined functions easily. An instance of the derived class is made for each - /// connection to the database. - /// - /// - /// Although there is one instance of a class derived from SQLiteFunction per database connection, the derived class has no access - /// to the underlying connection. This is necessary to deter implementers from thinking it would be a good idea to make database - /// calls during processing. - /// - /// It is important to distinguish between a per-connection instance, and a per-SQL statement context. One instance of this class - /// services all SQL statements being stepped through on that connection, and there can be many. One should never store per-statement - /// information in member variables of user-defined function classes. - /// - /// For aggregate functions, always create and store your per-statement data in the contextData object on the 1st step. This data will - /// be automatically freed for you (and Dispose() called if the item supports IDisposable) when the statement completes. - /// - public abstract class SQLiteFunction : IDisposable - { - private class AggregateData - { - internal int _count = 1; - internal object _data; + using System.Collections.Generic; + using System.Runtime.InteropServices; + using System.Globalization; + + /// + /// This abstract class is designed to handle user-defined functions easily. An instance of the derived class is made for each + /// connection to the database. + /// + /// + /// Although there is one instance of a class derived from SQLiteFunction per database connection, the derived class has no access + /// to the underlying connection. This is necessary to deter implementers from thinking it would be a good idea to make database + /// calls during processing. + /// + /// It is important to distinguish between a per-connection instance, and a per-SQL statement context. One instance of this class + /// services all SQL statements being stepped through on that connection, and there can be many. One should never store per-statement + /// information in member variables of user-defined function classes. + /// + /// For aggregate functions, always create and store your per-statement data in the contextData object on the 1st step. This data will + /// be automatically freed for you (and Dispose() called if the item supports IDisposable) when the statement completes. + /// + public abstract class SQLiteFunction : IDisposable + { + private class AggregateData + { + internal int _count = 1; + internal object _data; } ///////////////////////////////////////////////////////////////////////// #region Private Constants @@ -45,62 +45,62 @@ /// private const int COR_E_EXCEPTION = unchecked((int)0x80131500); #endregion ///////////////////////////////////////////////////////////////////////// - - /// - /// The base connection this function is attached to - /// - internal SQLiteBase _base; - - /// - /// Internal array used to keep track of aggregate function context data + + /// + /// The base connection this function is attached to + /// + internal SQLiteBase _base; + + /// + /// Internal array used to keep track of aggregate function context data /// private Dictionary _contextDataList; /// /// The connection flags associated with this object (this should be the /// same value as the flags associated with the parent connection object). /// private SQLiteConnectionFlags _flags; - - /// - /// Holds a reference to the callback function for user functions - /// - private SQLiteCallback _InvokeFunc; - /// - /// Holds a reference to the callbakc function for stepping in an aggregate function - /// - private SQLiteCallback _StepFunc; - /// - /// Holds a reference to the callback function for finalizing an aggregate function - /// - private SQLiteFinalCallback _FinalFunc; - /// - /// Holds a reference to the callback function for collation sequences - /// - private SQLiteCollation _CompareFunc; - - private SQLiteCollation _CompareFunc16; - - /// - /// Current context of the current callback. Only valid during a callback - /// - internal IntPtr _context; - - /// - /// This static list contains all the user-defined functions declared using the proper attributes. - /// - private static List _registeredFunctions; - - /// - /// Internal constructor, initializes the function's internal variables. - /// - protected SQLiteFunction() - { - _contextDataList = new Dictionary(); + + /// + /// Holds a reference to the callback function for user functions + /// + private SQLiteCallback _InvokeFunc; + /// + /// Holds a reference to the callbakc function for stepping in an aggregate function + /// + private SQLiteCallback _StepFunc; + /// + /// Holds a reference to the callback function for finalizing an aggregate function + /// + private SQLiteFinalCallback _FinalFunc; + /// + /// Holds a reference to the callback function for collation sequences + /// + private SQLiteCollation _CompareFunc; + + private SQLiteCollation _CompareFunc16; + + /// + /// Current context of the current callback. Only valid during a callback + /// + internal IntPtr _context; + + /// + /// This static list contains all the user-defined functions declared using the proper attributes. + /// + private static List _registeredFunctions; + + /// + /// Internal constructor, initializes the function's internal variables. + /// + protected SQLiteFunction() + { + _contextDataList = new Dictionary(); } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable Members @@ -181,210 +181,211 @@ } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// Returns a reference to the underlying connection's SQLiteConvert class, which can be used to convert - /// strings and DateTime's into the current connection's encoding schema. - /// - public SQLiteConvert SQLiteConvert - { - get - { - CheckDisposed(); - return _base; - } - } - - /// - /// Scalar functions override this method to do their magic. - /// - /// - /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available - /// to force them into a certain type. Therefore the only types you will ever see as parameters are - /// DBNull.Value, Int64, Double, String or byte[] array. - /// - /// The arguments for the command to process - /// You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or - /// you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, - /// just return it! + /// + /// Returns a reference to the underlying connection's SQLiteConvert class, which can be used to convert + /// strings and DateTime's into the current connection's encoding schema. + /// + public SQLiteConvert SQLiteConvert + { + get + { + CheckDisposed(); + return _base; + } + } + + /// + /// Scalar functions override this method to do their magic. + /// + /// + /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available + /// to force them into a certain type. Therefore the only types you will ever see as parameters are + /// DBNull.Value, Int64, Double, String or byte[] array. + /// + /// The arguments for the command to process + /// You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or + /// you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, + /// just return it! public virtual object Invoke(object[] args) { - CheckDisposed(); - return null; - } - - /// - /// Aggregate functions override this method to do their magic. - /// - /// - /// Typically you'll be updating whatever you've placed in the contextData field and returning as quickly as possible. - /// - /// The arguments for the command to process - /// The 1-based step number. This is incrememted each time the step method is called. - /// A placeholder for implementers to store contextual data pertaining to the current context. + CheckDisposed(); + return null; + } + + /// + /// Aggregate functions override this method to do their magic. + /// + /// + /// Typically you'll be updating whatever you've placed in the contextData field and returning as quickly as possible. + /// + /// The arguments for the command to process + /// The 1-based step number. This is incrememted each time the step method is called. + /// A placeholder for implementers to store contextual data pertaining to the current context. public virtual void Step(object[] args, int stepNumber, ref object contextData) { - CheckDisposed(); - } - - /// - /// Aggregate functions override this method to finish their aggregate processing. - /// - /// - /// If you implemented your aggregate function properly, - /// you've been recording and keeping track of your data in the contextData object provided, and now at this stage you should have - /// all the information you need in there to figure out what to return. - /// NOTE: It is possible to arrive here without receiving a previous call to Step(), in which case the contextData will - /// be null. This can happen when no rows were returned. You can either return null, or 0 or some other custom return value - /// if that is the case. - /// - /// Your own assigned contextData, provided for you so you can return your final results. - /// You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or - /// you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, - /// just return it! - /// - public virtual object Final(object contextData) - { - CheckDisposed(); - return null; - } - - /// - /// User-defined collation sequences override this method to provide a custom string sorting algorithm. - /// - /// The first string to compare - /// The second strnig to compare - /// 1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2 + CheckDisposed(); + } + + /// + /// Aggregate functions override this method to finish their aggregate processing. + /// + /// + /// If you implemented your aggregate function properly, + /// you've been recording and keeping track of your data in the contextData object provided, and now at this stage you should have + /// all the information you need in there to figure out what to return. + /// NOTE: It is possible to arrive here without receiving a previous call to Step(), in which case the contextData will + /// be null. This can happen when no rows were returned. You can either return null, or 0 or some other custom return value + /// if that is the case. + /// + /// Your own assigned contextData, provided for you so you can return your final results. + /// You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or + /// you may return an Exception-derived class if you wish to return an error to SQLite. Do not actually throw the error, + /// just return it! + /// + public virtual object Final(object contextData) + { + CheckDisposed(); + return null; + } + + /// + /// User-defined collation sequences override this method to provide a custom string sorting algorithm. + /// + /// The first string to compare + /// The second strnig to compare + /// 1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2 public virtual int Compare(string param1, string param2) { - CheckDisposed(); - return 0; - } - - /// - /// Converts an IntPtr array of context arguments to an object array containing the resolved parameters the pointers point to. - /// - /// - /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available - /// to force them into a certain type. Therefore the only types you will ever see as parameters are - /// DBNull.Value, Int64, Double, String or byte[] array. - /// - /// The number of arguments - /// A pointer to the array of arguments - /// An object array of the arguments once they've been converted to .NET values - internal object[] ConvertParams(int nArgs, IntPtr argsptr) - { - object[] parms = new object[nArgs]; -#if !PLATFORM_COMPACTFRAMEWORK - IntPtr[] argint = new IntPtr[nArgs]; -#else - int[] argint = new int[nArgs]; -#endif - Marshal.Copy(argsptr, argint, 0, nArgs); - - for (int n = 0; n < nArgs; n++) - { - switch (_base.GetParamValueType((IntPtr)argint[n])) - { - case TypeAffinity.Null: - parms[n] = DBNull.Value; - break; - case TypeAffinity.Int64: - parms[n] = _base.GetParamValueInt64((IntPtr)argint[n]); - break; - case TypeAffinity.Double: - parms[n] = _base.GetParamValueDouble((IntPtr)argint[n]); - break; - case TypeAffinity.Text: - parms[n] = _base.GetParamValueText((IntPtr)argint[n]); - break; - case TypeAffinity.Blob: - { - int x; - byte[] blob; - - x = (int)_base.GetParamValueBytes((IntPtr)argint[n], 0, null, 0, 0); - blob = new byte[x]; - _base.GetParamValueBytes((IntPtr)argint[n], 0, blob, 0, x); - parms[n] = blob; - } - break; - case TypeAffinity.DateTime: // Never happens here but what the heck, maybe it will one day. - parms[n] = _base.ToDateTime(_base.GetParamValueText((IntPtr)argint[n])); - break; - } - } - return parms; - } - - /// - /// Takes the return value from Invoke() and Final() and figures out how to return it to SQLite's context. - /// - /// The context the return value applies to - /// The parameter to return to SQLite - private void SetReturnValue(IntPtr context, object returnValue) - { - if (returnValue == null || returnValue == DBNull.Value) - { - _base.ReturnNull(context); - return; - } - - Type t = returnValue.GetType(); - if (t == typeof(DateTime)) - { - _base.ReturnText(context, _base.ToString((DateTime)returnValue)); - return; - } - else - { - Exception r = returnValue as Exception; - - if (r != null) - { - _base.ReturnError(context, r.Message); - return; - } - } - - switch (SQLiteConvert.TypeToAffinity(t)) - { - case TypeAffinity.Null: - _base.ReturnNull(context); - return; - case TypeAffinity.Int64: - _base.ReturnInt64(context, Convert.ToInt64(returnValue, CultureInfo.CurrentCulture)); - return; - case TypeAffinity.Double: - _base.ReturnDouble(context, Convert.ToDouble(returnValue, CultureInfo.CurrentCulture)); - return; - case TypeAffinity.Text: - _base.ReturnText(context, returnValue.ToString()); - return; - case TypeAffinity.Blob: - _base.ReturnBlob(context, (byte[])returnValue); - return; - } - } - - /// + CheckDisposed(); + return 0; + } + + /// + /// Converts an IntPtr array of context arguments to an object array containing the resolved parameters the pointers point to. + /// + /// + /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available + /// to force them into a certain type. Therefore the only types you will ever see as parameters are + /// DBNull.Value, Int64, Double, String or byte[] array. + /// + /// The number of arguments + /// A pointer to the array of arguments + /// An object array of the arguments once they've been converted to .NET values + internal object[] ConvertParams(int nArgs, IntPtr argsptr) + { + object[] parms = new object[nArgs]; +#if !PLATFORM_COMPACTFRAMEWORK + IntPtr[] argint = new IntPtr[nArgs]; +#else + int[] argint = new int[nArgs]; +#endif + Marshal.Copy(argsptr, argint, 0, nArgs); + + for (int n = 0; n < nArgs; n++) + { + switch (_base.GetParamValueType((IntPtr)argint[n])) + { + case TypeAffinity.Null: + parms[n] = DBNull.Value; + break; + case TypeAffinity.Int64: + parms[n] = _base.GetParamValueInt64((IntPtr)argint[n]); + break; + case TypeAffinity.Double: + parms[n] = _base.GetParamValueDouble((IntPtr)argint[n]); + break; + case TypeAffinity.Text: + parms[n] = _base.GetParamValueText((IntPtr)argint[n]); + break; + case TypeAffinity.Blob: + { + int x; + byte[] blob; + + x = (int)_base.GetParamValueBytes((IntPtr)argint[n], 0, null, 0, 0); + blob = new byte[x]; + _base.GetParamValueBytes((IntPtr)argint[n], 0, blob, 0, x); + parms[n] = blob; + } + break; + case TypeAffinity.DateTime: // Never happens here but what the heck, maybe it will one day. + parms[n] = _base.ToDateTime(_base.GetParamValueText((IntPtr)argint[n])); + break; + } + } + return parms; + } + + /// + /// Takes the return value from Invoke() and Final() and figures out how to return it to SQLite's context. + /// + /// The context the return value applies to + /// The parameter to return to SQLite + private void SetReturnValue(IntPtr context, object returnValue) + { + if (returnValue == null || returnValue == DBNull.Value) + { + _base.ReturnNull(context); + return; + } + + Type t = returnValue.GetType(); + if (t == typeof(DateTime)) + { + _base.ReturnText(context, _base.ToString((DateTime)returnValue)); + return; + } + else + { + Exception r = returnValue as Exception; + + if (r != null) + { + _base.ReturnError(context, r.Message); + return; + } + } + + switch (SQLiteConvert.TypeToAffinity(t)) + { + case TypeAffinity.Null: + _base.ReturnNull(context); + return; + case TypeAffinity.Int64: + _base.ReturnInt64(context, Convert.ToInt64(returnValue, CultureInfo.CurrentCulture)); + return; + case TypeAffinity.Double: + _base.ReturnDouble(context, Convert.ToDouble(returnValue, CultureInfo.CurrentCulture)); + return; + case TypeAffinity.Text: + _base.ReturnText(context, returnValue.ToString()); + return; + case TypeAffinity.Blob: + _base.ReturnBlob(context, (byte[])returnValue); + return; + } + } + + /// /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. - /// WARNING: Must not throw exceptions. - /// - /// A raw context pointer - /// Number of arguments passed in + /// WARNING: Must not throw exceptions. + /// + /// A raw context pointer + /// Number of arguments passed in /// A pointer to the array of arguments internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr) { try { _context = context; SetReturnValue(context, Invoke(ConvertParams(nArgs, argsptr))); /* throw */ } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == @@ -399,30 +400,37 @@ catch { // do nothing. } } - } - - /// +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif + } + + /// /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. - /// WARNING: Must not throw exceptions. - /// - /// Not used - /// Length of the string pv1 - /// Pointer to the first string to compare - /// Length of the string pv2 - /// Pointer to the second string to compare - /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater + /// WARNING: Must not throw exceptions. + /// + /// Not used + /// Length of the string pv1 + /// Pointer to the first string to compare + /// Length of the string pv2 + /// Pointer to the second string to compare + /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater /// than the second. Returns 0 if an exception is caught. internal int CompareCallback(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) { try { return Compare(SQLiteConvert.UTF8ToString(ptr1, len1), SQLiteConvert.UTF8ToString(ptr2, len2)); /* throw */ } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == @@ -437,10 +445,16 @@ catch { // do nothing. } } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif // // NOTE: This must be done to prevent the core SQLite library from // using our (invalid) result. // @@ -466,10 +480,11 @@ try { return Compare(SQLite3_UTF16.UTF16ToString(ptr1, len1), SQLite3_UTF16.UTF16ToString(ptr2, len2)); /* throw */ } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == @@ -484,32 +499,38 @@ catch { // do nothing. } } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif // // NOTE: This must be done to prevent the core SQLite library from // using our (invalid) result. // if (_base != null) _base.Cancel(); return 0; - } - - /// + } + + /// /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method. - /// WARNING: Must not throw exceptions. - /// - /// - /// This function takes care of doing the lookups and getting the important information put together to call the Step() function. - /// That includes pulling out the user's contextData and updating it after the call is made. We use a sorted list for this so - /// binary searches can be done to find the data. - /// - /// A raw context pointer - /// Number of arguments passed in + /// WARNING: Must not throw exceptions. + /// + /// + /// This function takes care of doing the lookups and getting the important information put together to call the Step() function. + /// That includes pulling out the user's contextData and updating it after the call is made. We use a sorted list for this so + /// binary searches can be done to find the data. + /// + /// A raw context pointer + /// Number of arguments passed in /// A pointer to the array of arguments internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr) { try { @@ -539,10 +560,11 @@ finally { data._count++; } } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == @@ -557,16 +579,22 @@ catch { // do nothing. } } - } - - /// +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif + } + + /// /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method. - /// WARNING: Must not throw exceptions. - /// + /// WARNING: Must not throw exceptions. + /// /// A raw context pointer internal void FinalCallback(IntPtr context) { try { @@ -594,10 +622,11 @@ { IDisposable disp = obj as IDisposable; if (disp != null) disp.Dispose(); /* throw */ } } +#if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == @@ -612,173 +641,172 @@ catch { // do nothing. } } - } - - /// - /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that - /// have a SQLiteFunctionAttribute attribute, and registering them accordingly. - /// -#if !PLATFORM_COMPACTFRAMEWORK - [Security.Permissions.FileIOPermission(Security.Permissions.SecurityAction.Assert, AllFiles = Security.Permissions.FileIOPermissionAccess.PathDiscovery)] -#endif - static SQLiteFunction() - { - _registeredFunctions = new List(); - try - { -#if !PLATFORM_COMPACTFRAMEWORK - // - // NOTE: If the "No_SQLiteFunctions" environment variable is set, - // skip all our special code and simply return. - // - if (Environment.GetEnvironmentVariable("No_SQLiteFunctions") != null) - return; - - SQLiteFunctionAttribute at; - System.Reflection.Assembly[] arAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); - int w = arAssemblies.Length; - System.Reflection.AssemblyName sqlite = System.Reflection.Assembly.GetCallingAssembly().GetName(); - - for (int n = 0; n < w; n++) - { - Type[] arTypes; - bool found = false; - System.Reflection.AssemblyName[] references; - try - { - // Inspect only assemblies that reference SQLite - references = arAssemblies[n].GetReferencedAssemblies(); - int t = references.Length; - for (int z = 0; z < t; z++) - { - if (references[z].Name == sqlite.Name) - { - found = true; - break; - } - } - - if (found == false) - continue; - - arTypes = arAssemblies[n].GetTypes(); - } - catch (Reflection.ReflectionTypeLoadException e) - { - arTypes = e.Types; - } - - int v = arTypes.Length; - for (int x = 0; x < v; x++) - { - if (arTypes[x] == null) continue; - - object[] arAtt = arTypes[x].GetCustomAttributes(typeof(SQLiteFunctionAttribute), false); - int u = arAtt.Length; - for (int y = 0; y < u; y++) - { - at = arAtt[y] as SQLiteFunctionAttribute; - if (at != null) - { - at._instanceType = arTypes[x]; - _registeredFunctions.Add(at); - } - } - } - } -#endif - } - catch // SQLite provider can continue without being able to find built-in functions - { - } - } - - /// - /// Manual method of registering a function. The type must still have the SQLiteFunctionAttributes in order to work - /// properly, but this is a workaround for the Compact Framework where enumerating assemblies is not currently supported. - /// - /// The type of the function to register - public static void RegisterFunction(Type typ) - { - object[] arAtt = typ.GetCustomAttributes(typeof(SQLiteFunctionAttribute), false); - int u = arAtt.Length; - SQLiteFunctionAttribute at; - - for (int y = 0; y < u; y++) - { - at = arAtt[y] as SQLiteFunctionAttribute; - if (at != null) - { - at._instanceType = typ; - _registeredFunctions.Add(at); - } - } - } - - /// - /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. - /// It is done this way so that all user-defined functions will access the database using the same encoding scheme - /// as the connection (UTF-8 or UTF-16). - /// - /// - /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to - /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. - /// - /// The base object on which the functions are to bind - /// The flags associated with the parent connection object - /// Returns an array of functions which the connection object should retain until the connection is closed. - internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) - { - SQLiteFunction f; - List lFunctions = new List(); - - foreach (SQLiteFunctionAttribute pr in _registeredFunctions) - { +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif + } + + /// + /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that + /// have a SQLiteFunctionAttribute attribute, and registering them accordingly. + /// +#if !PLATFORM_COMPACTFRAMEWORK + [Security.Permissions.FileIOPermission(Security.Permissions.SecurityAction.Assert, AllFiles = Security.Permissions.FileIOPermissionAccess.PathDiscovery)] +#endif + static SQLiteFunction() + { + _registeredFunctions = new List(); + try + { +#if !PLATFORM_COMPACTFRAMEWORK + SQLiteFunctionAttribute at; + System.Reflection.Assembly[] arAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); + int w = arAssemblies.Length; + System.Reflection.AssemblyName sqlite = System.Reflection.Assembly.GetCallingAssembly().GetName(); + + for (int n = 0; n < w; n++) + { + Type[] arTypes; + bool found = false; + System.Reflection.AssemblyName[] references; + try + { + // Inspect only assemblies that reference SQLite + references = arAssemblies[n].GetReferencedAssemblies(); + int t = references.Length; + for (int z = 0; z < t; z++) + { + if (references[z].Name == sqlite.Name) + { + found = true; + break; + } + } + + if (found == false) + continue; + + arTypes = arAssemblies[n].GetTypes(); + } + catch (Reflection.ReflectionTypeLoadException e) + { + arTypes = e.Types; + } + + int v = arTypes.Length; + for (int x = 0; x < v; x++) + { + if (arTypes[x] == null) continue; + + object[] arAtt = arTypes[x].GetCustomAttributes(typeof(SQLiteFunctionAttribute), false); + int u = arAtt.Length; + for (int y = 0; y < u; y++) + { + at = arAtt[y] as SQLiteFunctionAttribute; + if (at != null) + { + at._instanceType = arTypes[x]; + _registeredFunctions.Add(at); + } + } + } + } +#endif + } + catch // SQLite provider can continue without being able to find built-in functions + { + } + } + + /// + /// Manual method of registering a function. The type must still have the SQLiteFunctionAttributes in order to work + /// properly, but this is a workaround for the Compact Framework where enumerating assemblies is not currently supported. + /// + /// The type of the function to register + public static void RegisterFunction(Type typ) + { + object[] arAtt = typ.GetCustomAttributes(typeof(SQLiteFunctionAttribute), false); + int u = arAtt.Length; + SQLiteFunctionAttribute at; + + for (int y = 0; y < u; y++) + { + at = arAtt[y] as SQLiteFunctionAttribute; + if (at != null) + { + at._instanceType = typ; + _registeredFunctions.Add(at); + } + } + } + + /// + /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. + /// It is done this way so that all user-defined functions will access the database using the same encoding scheme + /// as the connection (UTF-8 or UTF-16). + /// + /// + /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to + /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. + /// + /// The base object on which the functions are to bind + /// The flags associated with the parent connection object + /// Returns an array of functions which the connection object should retain until the connection is closed. + internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) + { + SQLiteFunction f; + List lFunctions = new List(); + + foreach (SQLiteFunctionAttribute pr in _registeredFunctions) + { f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; f._flags = flags; - f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; - f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; - f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; - f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; - f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; - - if (pr.FuncType != FunctionType.Collation) - sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SQLiteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc); - else - sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16); - - - lFunctions.Add(f); - } - - SQLiteFunction[] arFunctions = new SQLiteFunction[lFunctions.Count]; - lFunctions.CopyTo(arFunctions, 0); - - return arFunctions; - } - } - - /// - /// Extends SQLiteFunction and allows an inherited class to obtain the collating sequence associated with a function call. - /// - /// - /// User-defined functions can call the GetCollationSequence() method in this class and use it to compare strings and char arrays. - /// - public class SQLiteFunctionEx : SQLiteFunction - { - /// - /// Obtains the collating sequence in effect for the given function. - /// - /// - protected CollationSequence GetCollationSequence() - { - return _base.GetCollationSequence(this, _context); + f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; + f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; + f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; + f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; + f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; + + if (pr.FuncType != FunctionType.Collation) + sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SQLiteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc); + else + sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16); + + + lFunctions.Add(f); + } + + SQLiteFunction[] arFunctions = new SQLiteFunction[lFunctions.Count]; + lFunctions.CopyTo(arFunctions, 0); + + return arFunctions; + } + } + + /// + /// Extends SQLiteFunction and allows an inherited class to obtain the collating sequence associated with a function call. + /// + /// + /// User-defined functions can call the GetCollationSequence() method in this class and use it to compare strings and char arrays. + /// + public class SQLiteFunctionEx : SQLiteFunction + { + /// + /// Obtains the collating sequence in effect for the given function. + /// + /// + protected CollationSequence GetCollationSequence() + { + return _base.GetCollationSequence(this, _context); } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members @@ -816,152 +844,152 @@ finally { base.Dispose(disposing); } } - #endregion - } - - /// - /// The type of user-defined function to declare - /// - public enum FunctionType - { - /// - /// Scalar functions are designed to be called and return a result immediately. Examples include ABS(), Upper(), Lower(), etc. - /// - Scalar = 0, - /// - /// Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data. - /// Examples include SUM(), COUNT(), AVG(), etc. - /// - Aggregate = 1, - /// - /// Collation sequences are used to sort textual data in a custom manner, and appear in an ORDER BY clause. Typically text in an ORDER BY is - /// sorted using a straight case-insensitive comparison function. Custom collating sequences can be used to alter the behavior of text sorting - /// in a user-defined manner. - /// - Collation = 2, - } - - /// - /// An internal callback delegate declaration. - /// - /// Raw context pointer for the user function - /// Count of arguments to the function - /// A pointer to the array of argument pointers -#if !PLATFORM_COMPACTFRAMEWORK - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] -#endif - internal delegate void SQLiteCallback(IntPtr context, int nArgs, IntPtr argsptr); - /// - /// An internal final callback delegate declaration. - /// - /// Raw context pointer for the user function -#if !PLATFORM_COMPACTFRAMEWORK - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] -#endif - internal delegate void SQLiteFinalCallback(IntPtr context); - /// - /// Internal callback delegate for implementing collation sequences - /// - /// Not used - /// Length of the string pv1 - /// Pointer to the first string to compare - /// Length of the string pv2 - /// Pointer to the second string to compare - /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater - /// than the second. -#if !PLATFORM_COMPACTFRAMEWORK - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] -#endif - internal delegate int SQLiteCollation(IntPtr puser, int len1, IntPtr pv1, int len2, IntPtr pv2); - - /// - /// The type of collating sequence - /// - public enum CollationTypeEnum - { - /// - /// The built-in BINARY collating sequence - /// - Binary = 1, - /// - /// The built-in NOCASE collating sequence - /// - NoCase = 2, - /// - /// The built-in REVERSE collating sequence - /// - Reverse = 3, - /// - /// A custom user-defined collating sequence - /// - Custom = 0, - } - - /// - /// The encoding type the collation sequence uses - /// - public enum CollationEncodingEnum - { - /// - /// The collation sequence is UTF8 - /// - UTF8 = 1, - /// - /// The collation sequence is UTF16 little-endian - /// - UTF16LE = 2, - /// - /// The collation sequence is UTF16 big-endian - /// - UTF16BE = 3, - } - - /// - /// A struct describing the collating sequence a function is executing in - /// - public struct CollationSequence - { - /// - /// The name of the collating sequence - /// - public string Name; - /// - /// The type of collating sequence - /// - public CollationTypeEnum Type; - - /// - /// The text encoding of the collation sequence - /// - public CollationEncodingEnum Encoding; - - /// - /// Context of the function that requested the collating sequence - /// - internal SQLiteFunction _func; - - /// - /// Calls the base collating sequence to compare two strings - /// - /// The first string to compare - /// The second string to compare - /// -1 if s1 is less than s2, 0 if s1 is equal to s2, and 1 if s1 is greater than s2 - public int Compare(string s1, string s2) - { - return _func._base.ContextCollateCompare(Encoding, _func._context, s1, s2); - } - - /// - /// Calls the base collating sequence to compare two character arrays - /// - /// The first array to compare - /// The second array to compare - /// -1 if c1 is less than c2, 0 if c1 is equal to c2, and 1 if c1 is greater than c2 - public int Compare(char[] c1, char[] c2) - { - return _func._base.ContextCollateCompare(Encoding, _func._context, c1, c2); - } - } -} + #endregion + } + + /// + /// The type of user-defined function to declare + /// + public enum FunctionType + { + /// + /// Scalar functions are designed to be called and return a result immediately. Examples include ABS(), Upper(), Lower(), etc. + /// + Scalar = 0, + /// + /// Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data. + /// Examples include SUM(), COUNT(), AVG(), etc. + /// + Aggregate = 1, + /// + /// Collation sequences are used to sort textual data in a custom manner, and appear in an ORDER BY clause. Typically text in an ORDER BY is + /// sorted using a straight case-insensitive comparison function. Custom collating sequences can be used to alter the behavior of text sorting + /// in a user-defined manner. + /// + Collation = 2, + } + + /// + /// An internal callback delegate declaration. + /// + /// Raw context pointer for the user function + /// Count of arguments to the function + /// A pointer to the array of argument pointers +#if !PLATFORM_COMPACTFRAMEWORK + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#endif + internal delegate void SQLiteCallback(IntPtr context, int nArgs, IntPtr argsptr); + /// + /// An internal final callback delegate declaration. + /// + /// Raw context pointer for the user function +#if !PLATFORM_COMPACTFRAMEWORK + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#endif + internal delegate void SQLiteFinalCallback(IntPtr context); + /// + /// Internal callback delegate for implementing collation sequences + /// + /// Not used + /// Length of the string pv1 + /// Pointer to the first string to compare + /// Length of the string pv2 + /// Pointer to the second string to compare + /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater + /// than the second. +#if !PLATFORM_COMPACTFRAMEWORK + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#endif + internal delegate int SQLiteCollation(IntPtr puser, int len1, IntPtr pv1, int len2, IntPtr pv2); + + /// + /// The type of collating sequence + /// + public enum CollationTypeEnum + { + /// + /// The built-in BINARY collating sequence + /// + Binary = 1, + /// + /// The built-in NOCASE collating sequence + /// + NoCase = 2, + /// + /// The built-in REVERSE collating sequence + /// + Reverse = 3, + /// + /// A custom user-defined collating sequence + /// + Custom = 0, + } + + /// + /// The encoding type the collation sequence uses + /// + public enum CollationEncodingEnum + { + /// + /// The collation sequence is UTF8 + /// + UTF8 = 1, + /// + /// The collation sequence is UTF16 little-endian + /// + UTF16LE = 2, + /// + /// The collation sequence is UTF16 big-endian + /// + UTF16BE = 3, + } + + /// + /// A struct describing the collating sequence a function is executing in + /// + public struct CollationSequence + { + /// + /// The name of the collating sequence + /// + public string Name; + /// + /// The type of collating sequence + /// + public CollationTypeEnum Type; + + /// + /// The text encoding of the collation sequence + /// + public CollationEncodingEnum Encoding; + + /// + /// Context of the function that requested the collating sequence + /// + internal SQLiteFunction _func; + + /// + /// Calls the base collating sequence to compare two strings + /// + /// The first string to compare + /// The second string to compare + /// -1 if s1 is less than s2, 0 if s1 is equal to s2, and 1 if s1 is greater than s2 + public int Compare(string s1, string s2) + { + return _func._base.ContextCollateCompare(Encoding, _func._context, s1, s2); + } + + /// + /// Calls the base collating sequence to compare two character arrays + /// + /// The first array to compare + /// The second array to compare + /// -1 if c1 is less than c2, 0 if c1 is equal to c2, and 1 if c1 is greater than c2 + public int Compare(char[] c1, char[] c2) + { + return _func._base.ContextCollateCompare(Encoding, _func._context, c1, c2); + } + } +} Index: System.Data.SQLite/SQLiteLog.cs ================================================================== --- System.Data.SQLite/SQLiteLog.cs +++ System.Data.SQLite/SQLiteLog.cs @@ -64,10 +64,11 @@ /// Event arguments of the trace public delegate void SQLiteLogEventHandler(object sender, LogEventArgs e); /////////////////////////////////////////////////////////////////////////// +#if !PLATFORM_COMPACTFRAMEWORK /// /// Manages the SQLite custom logging functionality and the associated /// callback for the whole process. /// public static class SQLiteLog @@ -76,58 +77,41 @@ /// Object used to synchronize access to the static instance data /// for this class. /// private static object syncRoot = new object(); - /////////////////////////////////////////////////////////////////////// - -#if !PLATFORM_COMPACTFRAMEWORK /// /// Member variable to store the AppDomain.DomainUnload event handler. /// private static EventHandler _domainUnload; -#endif - - /////////////////////////////////////////////////////////////////////// /// /// Member variable to store the application log handler to call. /// private static event SQLiteLogEventHandler _handlers; - - /////////////////////////////////////////////////////////////////////// - /// /// The default log event handler. /// private static SQLiteLogEventHandler _defaultHandler; - /////////////////////////////////////////////////////////////////////// - /// /// The log callback passed to native SQLite engine. This must live /// as long as the SQLite library has a pointer to it. /// private static SQLiteLogCallback _callback; - /////////////////////////////////////////////////////////////////////// - /// /// The base SQLite object to interop with. /// private static SQLiteBase _sql; - /////////////////////////////////////////////////////////////////////// - /// /// This will be non-zero if logging is currently enabled. /// private static bool _enabled; - /////////////////////////////////////////////////////////////////////// - /// /// Initializes the SQLite logging facilities. /// public static void Initialize() { @@ -137,11 +121,10 @@ // the process (see ticket [2ce0870fad]). // if (SQLite3.StaticIsInitialized()) return; -#if !PLATFORM_COMPACTFRAMEWORK // // BUGFIX: To avoid nasty situations where multiple AppDomains are // attempting to initialize and/or shutdown what is really // a shared native resource (i.e. the SQLite core library // is loaded per-process and has only one logging callback, @@ -153,15 +136,13 @@ if (!AppDomain.CurrentDomain.IsDefaultAppDomain() && Environment.GetEnvironmentVariable("Force_SQLiteLog") == null) { return; } -#endif lock (syncRoot) { -#if !PLATFORM_COMPACTFRAMEWORK // // NOTE: Add an event handler for the DomainUnload event so // that we can unhook our logging managed function // pointer from the native SQLite code prior to it // being invalidated. @@ -172,11 +153,10 @@ if (_domainUnload == null) { _domainUnload = new EventHandler(DomainUnload); AppDomain.CurrentDomain.DomainUnload += _domainUnload; } -#endif // // NOTE: Create an instance of the SQLite wrapper class. // if (_sql == null) @@ -210,13 +190,10 @@ // AddDefaultHandler(); } } - /////////////////////////////////////////////////////////////////////// - -#if !PLATFORM_COMPACTFRAMEWORK /// /// Handles the AppDomain being unloaded. /// /// Should be null. /// The data associated with this event. @@ -279,13 +256,10 @@ AppDomain.CurrentDomain.DomainUnload -= _domainUnload; _domainUnload = null; } } } -#endif - - /////////////////////////////////////////////////////////////////////// /// /// This event is raised whenever SQLite raises a logging event. /// Note that this should be set as one of the first things in the /// application. @@ -312,12 +286,10 @@ _handlers -= value; } } } - /////////////////////////////////////////////////////////////////////// - /// /// If this property is true, logging is enabled; otherwise, logging is /// disabled. When logging is disabled, no logging events will fire. /// public static bool Enabled @@ -324,12 +296,10 @@ { get { lock (syncRoot) { return _enabled; } } set { lock (syncRoot) { _enabled = value; } } } - /////////////////////////////////////////////////////////////////////// - /// /// Log a message to all the registered log event handlers without going /// through the SQLite library. /// /// The message to be logged. @@ -338,12 +308,10 @@ ) { LogMessage(null, message); } - /////////////////////////////////////////////////////////////////////// - /// /// Log a message to all the registered log event handlers without going /// through the SQLite library. /// /// The SQLite error code. @@ -354,12 +322,10 @@ ) { LogMessage((object)errorCode, message); } - /////////////////////////////////////////////////////////////////////// - /// /// Log a message to all the registered log event handlers without going /// through the SQLite library. /// /// The integer error code. @@ -370,12 +336,10 @@ ) { LogMessage((object)errorCode, message); } - /////////////////////////////////////////////////////////////////////// - /// /// Log a message to all the registered log event handlers without going /// through the SQLite library. /// /// @@ -392,24 +356,18 @@ SQLiteLogEventHandler handlers; lock (syncRoot) { enabled = _enabled; - - if (_handlers != null) - handlers = _handlers.Clone() as SQLiteLogEventHandler; - else - handlers = null; + handlers = _handlers; } if (enabled && (handlers != null)) handlers(null, new LogEventArgs( IntPtr.Zero, errorCode, message, null)); } - /////////////////////////////////////////////////////////////////////// - /// /// Creates and initializes the default log event handler. /// private static void InitializeDefaultHandler() { @@ -418,34 +376,28 @@ if (_defaultHandler == null) _defaultHandler = new SQLiteLogEventHandler(LogEventHandler); } } - /////////////////////////////////////////////////////////////////////// - /// /// Adds the default log event handler to the list of handlers. /// public static void AddDefaultHandler() { InitializeDefaultHandler(); Log += _defaultHandler; } - /////////////////////////////////////////////////////////////////////// - /// /// Removes the default log event handler from the list of handlers. /// public static void RemoveDefaultHandler() { InitializeDefaultHandler(); Log -= _defaultHandler; } - /////////////////////////////////////////////////////////////////////// - /// /// Internal proxy function that calls any registered application log /// event handlers. /// /// WARNING: This method is used more-or-less directly by native code, @@ -482,12 +434,10 @@ if (enabled && (handlers != null)) handlers(null, new LogEventArgs(pUserData, errorCode, SQLiteBase.UTF8ToString(pMessage, -1), null)); } - /////////////////////////////////////////////////////////////////////// - /// /// Default logger. Currently, uses the Trace class (i.e. sends events /// to the current trace listeners, if any). /// /// Should be null. @@ -495,11 +445,10 @@ private static void LogEventHandler( object sender, LogEventArgs e ) { -#if !NET_COMPACT_20 if (e == null) return; string message = e.Message; @@ -523,9 +472,9 @@ else if (errorCode is int) success = ((int)errorCode == 0); Trace.WriteLine(String.Format("SQLite {0} ({1}): {2}", success ? "message" : "error", errorCode, message)); -#endif } } +#endif } Index: System.Data.SQLite/SQLiteStatement.cs ================================================================== --- System.Data.SQLite/SQLiteStatement.cs +++ System.Data.SQLite/SQLiteStatement.cs @@ -298,29 +298,25 @@ DbType objType = param.DbType; if ((obj != null) && (objType == DbType.Object)) objType = SQLiteConvert.TypeToDbType(obj.GetType()); +#if !PLATFORM_COMPACTFRAMEWORK if ((_flags & SQLiteConnectionFlags.LogPreBind) == SQLiteConnectionFlags.LogPreBind) { IntPtr handle = _sqlite_stmt; SQLiteLog.LogMessage(String.Format( "Binding statement {0} paramter #{1} with database type {2} and raw value {{{3}}}...", handle, index, objType, obj)); } +#endif if ((obj == null) || Convert.IsDBNull(obj)) { _sql.Bind_Null(this, _flags, index); return; - } - - if ((_flags & SQLiteConnectionFlags.BindAllAsText) == SQLiteConnectionFlags.BindAllAsText) - { - _sql.Bind_Text(this, _flags, index, obj.ToString()); - return; } switch (objType) { case DbType.Date: Index: System.Data.SQLite/System.Data.SQLite.Properties.targets ================================================================== --- System.Data.SQLite/System.Data.SQLite.Properties.targets +++ System.Data.SQLite/System.Data.SQLite.Properties.targets @@ -68,33 +68,18 @@ --> $(DefineConstants);CHECK_STATE - - - $(DefineConstants);COUNT_HANDLE - - $(DefineConstants);USE_INTEROP_DLL - - - $(DefineConstants);USE_PREPARE_V2 - - @@ -159,26 +144,10 @@ --> $(DefineConstants);INTEROP_DEBUG - - - $(DefineConstants);INTEROP_LEGACY_CLOSE - - - - - $(DefineConstants);INTEROP_LOG - - Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -1,9 +1,9 @@ /******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) - * + * * Released to the public domain, use at your own risk! ********************************************************/ namespace System.Data.SQLite { @@ -24,38 +24,19 @@ using System.Security; #endif using System.Runtime.InteropServices; -#if !PLATFORM_COMPACTFRAMEWORK || COUNT_HANDLE +#if !PLATFORM_COMPACTFRAMEWORK using System.Threading; #endif #if !PLATFORM_COMPACTFRAMEWORK && !DEBUG [SuppressUnmanagedCodeSecurity] #endif internal static class UnsafeNativeMethods { - #region Critical Handle Counts (Debug Build Only) -#if COUNT_HANDLE - // - // NOTE: These counts represent the total number of outstanding - // (non-disposed) CriticalHandle derived object instances - // created by this library and are primarily for use by - // the test suite. These counts are incremented by the - // associated constructors and are decremented upon the - // successful completion of the associated ReleaseHandle - // methods. - // - internal static int connectionCount; - internal static int statementCount; - internal static int backupCount; -#endif - #endregion - - ///////////////////////////////////////////////////////////////////////// - #region Optional Native SQLite Library Pre-Loading Code // // NOTE: If we are looking for the standard SQLite DLL ("sqlite3.dll"), // the interop DLL ("SQLite.Interop.dll"), or we are running on the // .NET Compact Framework, we should include this code (only if the @@ -93,80 +74,18 @@ /// The name of the executable library. /// /// /// The native module handle upon success -OR- IntPtr.Zero on failure. /// -#if !PLATFORM_COMPACTFRAMEWORK [DllImport("kernel32", -#else - [DllImport("coredll", -#endif CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, #if !PLATFORM_COMPACTFRAMEWORK BestFitMapping = false, ThrowOnUnmappableChar = true, #endif SetLastError = true)] private static extern IntPtr LoadLibrary(string fileName); - ///////////////////////////////////////////////////////////////////////// - -#if PLATFORM_COMPACTFRAMEWORK - /// - /// This is the P/Invoke method that wraps the native Win32 GetSystemInfo - /// function. See the MSDN documentation for full details on what it - /// does. - /// - /// - /// The system information structure to be filled in by the function. - /// - [DllImport("coredll", CallingConvention = CallingConvention.Winapi)] - private static extern void GetSystemInfo(out SYSTEM_INFO systemInfo); - - ///////////////////////////////////////////////////////////////////////// - /// - /// This enumeration contains the possible values for the processor - /// architecture field of the system information structure. - /// - private enum ProcessorArchitecture : ushort /* COMPAT: Win32. */ - { - Intel = 0, - MIPS = 1, - Alpha = 2, - PowerPC = 3, - SHx = 4, - ARM = 5, - IA64 = 6, - Alpha64 = 7, - MSIL = 8, - AMD64 = 9, - IA32_on_Win64 = 10, - Unknown = 0xFFFF - } - - ///////////////////////////////////////////////////////////////////////// - /// - /// This structure contains information about the current computer. This - /// includes the processor type, page size, memory addresses, etc. - /// - [StructLayout(LayoutKind.Sequential)] - private struct SYSTEM_INFO - { - public ProcessorArchitecture wProcessorArchitecture; - public ushort wReserved; /* NOT USED */ - public uint dwPageSize; /* NOT USED */ - public IntPtr lpMinimumApplicationAddress; /* NOT USED */ - public IntPtr lpMaximumApplicationAddress; /* NOT USED */ - public uint dwActiveProcessorMask; /* NOT USED */ - public uint dwNumberOfProcessors; /* NOT USED */ - public uint dwProcessorType; /* NOT USED */ - public uint dwAllocationGranularity; /* NOT USED */ - public ushort wProcessorLevel; /* NOT USED */ - public ushort wProcessorRevision; /* NOT USED */ - } -#endif - - ///////////////////////////////////////////////////////////////////////// /// /// This lock is used to protect the static _SQLiteModule and /// processorArchitecturePlatforms fields, below. /// private static readonly object staticSyncRoot = new object(); @@ -201,12 +120,12 @@ /// internal static void Initialize() { #if !PLATFORM_COMPACTFRAMEWORK // - // NOTE: If the "No_PreLoadSQLite" environment variable is set (to - // anything), skip all our special code and simply return. + // NOTE: If the "NoPreLoadSQLite" environment variable is set, skip + // all our special code and simply return. // if (Environment.GetEnvironmentVariable("No_PreLoadSQLite") != null) return; #endif @@ -233,11 +152,10 @@ // the supported processor architectures. // processorArchitecturePlatforms.Add("x86", "Win32"); processorArchitecturePlatforms.Add("AMD64", "x64"); processorArchitecturePlatforms.Add("IA64", "Itanium"); - processorArchitecturePlatforms.Add("ARM", "WinCE"); } // // BUGBUG: What about other application domains? // @@ -266,38 +184,10 @@ "PreLoadSQLite_BaseDirectory"); if (directory != null) return directory; - // - // NOTE: If the "PreLoadSQLite_UseAssemblyDirectory" environment - // variable is set (to anything), attempt to use the directory - // containing the currently executing assembly (i.e. - // System.Data.SQLite) intsead of the application domain base - // directory. - // - if (Environment.GetEnvironmentVariable( - "PreLoadSQLite_UseAssemblyDirectory") != null) - { - try - { - Assembly assembly = Assembly.GetExecutingAssembly(); - - if (assembly != null) - { - directory = Path.GetDirectoryName(assembly.Location); - - if (!String.IsNullOrEmpty(directory)) - return directory; - } - } - catch - { - // do nothing. - } - } - // // NOTE: Otherwise, fallback on using the base directory of the // current application domain. // return AppDomain.CurrentDomain.BaseDirectory; @@ -366,11 +256,12 @@ /// Queries and returns the processor architecture of the current /// process. /// /// /// The processor architecture of the current process -OR- null if it - /// cannot be determined. + /// cannot be determined. Always returns an empty string when running on + /// the .NET Compact Framework. /// private static string GetProcessorArchitecture() { #if !PLATFORM_COMPACTFRAMEWORK // @@ -388,41 +279,12 @@ // BUGBUG: Will this always be reliable? // return Environment.GetEnvironmentVariable(PROCESSOR_ARCHITECTURE); #else // - // NOTE: On the .NET Compact Framework, attempt to use the native - // Win32 API function (via P/Invoke) that can provide us with - // the processor architecture. - // - try - { - // - // NOTE: The output of the GetSystemInfo function will be placed - // here. Only the processor architecture field is used by - // this method. - // - SYSTEM_INFO systemInfo; - - // - // NOTE: Query the system information via P/Invoke, thus filling - // the structure. - // - GetSystemInfo(out systemInfo); - - // - // NOTE: Return the processor architecture value as a string. - // - return systemInfo.wProcessorArchitecture.ToString(); - } - catch - { - // do nothing. - } - - // - // NOTE: Upon failure, return an empty string. + // BUGBUG: No way to determine this value on the .NET Compact + // Framework (running on Windows CE, etc). // return String.Empty; #endif } @@ -625,11 +487,11 @@ // be used because it provides several workarounds to .NET Compact // Framework limitations important for proper operation of the core // System.Data.SQLite functionality (e.g. being able to bind // parameters and handle column values of types Int64 and Double). // - internal const string SQLITE_DLL = "SQLite.Interop.086.dll"; + internal const string SQLITE_DLL = "SQLite.Interop.083.dll"; #elif SQLITE_STANDARD // // NOTE: Otherwise, if the standard SQLite library is enabled, use it. // private const string SQLITE_DLL = "sqlite3"; @@ -644,12 +506,12 @@ // NOTE: Finally, assume that the mixed-mode assembly is being used. // private const string SQLITE_DLL = "System.Data.SQLite.dll"; #endif - // This section uses interop calls that also fetch text length to optimize conversion. - // When using the standard dll, we can replace these calls with normal sqlite calls and + // This section uses interop calls that also fetch text length to optimize conversion. + // When using the standard dll, we can replace these calls with normal sqlite calls and // do unoptimized conversions instead afterwards #region interop added textlength calls #if !SQLITE_STANDARD @@ -705,14 +567,10 @@ internal static extern IntPtr sqlite3_value_text_interop(IntPtr p, out int len); [DllImport(SQLITE_DLL)] internal static extern IntPtr sqlite3_value_text16_interop(IntPtr p, out int len); -#if INTEROP_LOG - [DllImport(SQLITE_DLL)] - internal static extern SQLiteErrorCode sqlite3_config_log_interop(); -#endif #endif // !SQLITE_STANDARD #endregion @@ -760,18 +618,16 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_close(IntPtr db); -#if !INTEROP_LEGACY_CLOSE #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_close_v2(IntPtr db); /* 3.7.14+ */ -#endif #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] @@ -783,17 +639,10 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_finalize(IntPtr stmt); -#if !PLATFORM_COMPACTFRAMEWORK - [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] -#else - [DllImport(SQLITE_DLL)] -#endif - internal static extern SQLiteErrorCode sqlite3_backup_finish(IntPtr backup); - #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif @@ -902,19 +751,10 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_prepare(IntPtr db, IntPtr pSql, int nBytes, out IntPtr stmt, out IntPtr ptrRemain); -#if USE_PREPARE_V2 -#if !PLATFORM_COMPACTFRAMEWORK - [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] -#else - [DllImport(SQLITE_DLL)] -#endif - internal static extern SQLiteErrorCode sqlite3_prepare_v2(IntPtr db, IntPtr pSql, int nBytes, out IntPtr stmt, out IntPtr ptrRemain); -#endif - #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif @@ -933,11 +773,11 @@ [DllImport(SQLITE_DLL)] #endif internal static extern IntPtr sqlite3_value_text16(IntPtr p); #endif - // SQLITE_STANDARD +// SQLITE_STANDARD #endregion // These functions are custom and have no equivalent standard library method. // All of them are "nice to haves" and not necessarily "need to haves". @@ -999,17 +839,10 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern IntPtr sqlite3_libversion(); -#if !PLATFORM_COMPACTFRAMEWORK - [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] -#else - [DllImport(SQLITE_DLL)] -#endif - internal static extern int sqlite3_libversion_number(); - #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif @@ -1235,17 +1068,10 @@ internal static extern int sqlite3_column_bytes(IntPtr stmt, int index); #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else - [DllImport(SQLITE_DLL)] -#endif - internal static extern int sqlite3_column_bytes16(IntPtr stmt, int index); - -#if !PLATFORM_COMPACTFRAMEWORK - [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] -#else [DllImport(SQLITE_DLL)] #endif internal static extern TypeAffinity sqlite3_column_type(IntPtr stmt, int index); #if !PLATFORM_COMPACTFRAMEWORK @@ -1274,17 +1100,10 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern int sqlite3_value_bytes(IntPtr p); -#if !PLATFORM_COMPACTFRAMEWORK - [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] -#else - [DllImport(SQLITE_DLL)] -#endif - internal static extern int sqlite3_value_bytes16(IntPtr p); - #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] internal static extern double sqlite3_value_double(IntPtr p); #else [DllImport(SQLITE_DLL)] @@ -1514,11 +1333,11 @@ [DllImport(SQLITE_DLL)] #endif internal static extern IntPtr sqlite3_errstr(SQLiteErrorCode rc); /* 3.7.15+ */ // Since sqlite3_log() takes a variable argument list, we have to overload declarations - // for all possible calls. For now, we are only exposing a single string, and + // for all possible calls. For now, we are only exposing a single string, and // depend on the caller to format the string. #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] @@ -1547,10 +1366,17 @@ internal static extern SQLiteErrorCode sqlite3_backup_step(IntPtr backup, int nPage); #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else + [DllImport(SQLITE_DLL)] +#endif + internal static extern SQLiteErrorCode sqlite3_backup_finish(IntPtr backup); + +#if !PLATFORM_COMPACTFRAMEWORK + [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] +#else [DllImport(SQLITE_DLL)] #endif internal static extern int sqlite3_backup_remaining(IntPtr backup); #if !PLATFORM_COMPACTFRAMEWORK @@ -1565,11 +1391,11 @@ #if PLATFORM_COMPACTFRAMEWORK internal abstract class CriticalHandle : IDisposable { private bool _isClosed; protected IntPtr handle; - + protected CriticalHandle(IntPtr invalidHandleValue) { handle = invalidHandleValue; _isClosed = false; } @@ -1637,22 +1463,12 @@ /////////////////////////////////////////////////////////////////////////// #region SQLiteConnectionHandle Class // Handles the unmanaged database pointer, and provides finalization // support for it. - internal sealed class SQLiteConnectionHandle : CriticalHandle - { -#if SQLITE_STANDARD && !PLATFORM_COMPACTFRAMEWORK - internal delegate void CloseConnectionCallback( - SQLiteConnectionHandle hdl, IntPtr db); - - internal static CloseConnectionCallback closeConnection = - SQLiteBase.CloseConnection; -#endif - - /////////////////////////////////////////////////////////////////////// - + internal class SQLiteConnectionHandle : CriticalHandle + { #if PLATFORM_COMPACTFRAMEWORK internal readonly object syncRoot = new object(); #endif /////////////////////////////////////////////////////////////////////// @@ -1687,14 +1503,10 @@ /////////////////////////////////////////////////////////////////////// private SQLiteConnectionHandle() : base(IntPtr.Zero) { -#if COUNT_HANDLE - Interlocked.Increment( - ref UnsafeNativeMethods.connectionCount); -#endif } /////////////////////////////////////////////////////////////////////// protected override bool ReleaseHandle() @@ -1703,17 +1515,12 @@ { #if !PLATFORM_COMPACTFRAMEWORK IntPtr localHandle = Interlocked.Exchange( ref handle, IntPtr.Zero); -#if SQLITE_STANDARD - if (localHandle != IntPtr.Zero) - closeConnection(this, localHandle); -#else if (localHandle != IntPtr.Zero) SQLiteBase.CloseConnection(this, localHandle); -#endif #if !NET_COMPACT_20 && TRACE_HANDLE try { Trace.WriteLine(String.Format( @@ -1731,14 +1538,10 @@ SQLiteBase.CloseConnection(this, handle); SetHandle(IntPtr.Zero); } } #endif -#if COUNT_HANDLE - Interlocked.Decrement( - ref UnsafeNativeMethods.connectionCount); -#endif #if DEBUG return true; #endif } #if !NET_COMPACT_20 && TRACE_HANDLE @@ -1775,20 +1578,10 @@ #endif } /////////////////////////////////////////////////////////////////////// -#if COUNT_HANDLE - public int WasReleasedOk() - { - return Interlocked.Decrement( - ref UnsafeNativeMethods.connectionCount); - } -#endif - - /////////////////////////////////////////////////////////////////////// - public override bool IsInvalid { get { #if PLATFORM_COMPACTFRAMEWORK @@ -1818,11 +1611,11 @@ /////////////////////////////////////////////////////////////////////////// #region SQLiteStatementHandle Class // Provides finalization support for unmanaged SQLite statements. - internal sealed class SQLiteStatementHandle : CriticalHandle + internal class SQLiteStatementHandle : CriticalHandle { #if PLATFORM_COMPACTFRAMEWORK internal readonly object syncRoot = new object(); #endif @@ -1863,14 +1656,10 @@ /////////////////////////////////////////////////////////////////////// private SQLiteStatementHandle() : base(IntPtr.Zero) { -#if COUNT_HANDLE - Interlocked.Increment( - ref UnsafeNativeMethods.statementCount); -#endif } /////////////////////////////////////////////////////////////////////// protected override bool ReleaseHandle() @@ -1902,14 +1691,10 @@ SQLiteBase.FinalizeStatement(cnn, handle); SetHandle(IntPtr.Zero); } } #endif -#if COUNT_HANDLE - Interlocked.Decrement( - ref UnsafeNativeMethods.statementCount); -#endif #if DEBUG return true; #endif } #if !NET_COMPACT_20 && TRACE_HANDLE @@ -1946,20 +1731,10 @@ #endif } /////////////////////////////////////////////////////////////////////// -#if COUNT_HANDLE - public int WasReleasedOk() - { - return Interlocked.Decrement( - ref UnsafeNativeMethods.statementCount); - } -#endif - - /////////////////////////////////////////////////////////////////////// - public override bool IsInvalid { get { #if PLATFORM_COMPACTFRAMEWORK @@ -1989,11 +1764,11 @@ /////////////////////////////////////////////////////////////////////////// #region SQLiteBackupHandle Class // Provides finalization support for unmanaged SQLite backup objects. - internal sealed class SQLiteBackupHandle : CriticalHandle + internal class SQLiteBackupHandle : CriticalHandle { #if PLATFORM_COMPACTFRAMEWORK internal readonly object syncRoot = new object(); #endif @@ -2034,14 +1809,10 @@ /////////////////////////////////////////////////////////////////////// private SQLiteBackupHandle() : base(IntPtr.Zero) { -#if COUNT_HANDLE - Interlocked.Increment( - ref UnsafeNativeMethods.backupCount); -#endif } /////////////////////////////////////////////////////////////////////// protected override bool ReleaseHandle() @@ -2073,14 +1844,10 @@ SQLiteBase.FinishBackup(cnn, handle); SetHandle(IntPtr.Zero); } } #endif -#if COUNT_HANDLE - Interlocked.Decrement( - ref UnsafeNativeMethods.backupCount); -#endif #if DEBUG return true; #endif } #if !NET_COMPACT_20 && TRACE_HANDLE @@ -2115,20 +1882,10 @@ #else return true; #endif } - /////////////////////////////////////////////////////////////////////// - -#if COUNT_HANDLE - public int WasReleasedOk() - { - return Interlocked.Decrement( - ref UnsafeNativeMethods.backupCount); - } -#endif - /////////////////////////////////////////////////////////////////////// public override bool IsInvalid { get Index: Tests/all.eagle ================================================================== --- Tests/all.eagle +++ Tests/all.eagle @@ -46,11 +46,11 @@ # set test_time [time { runAllTests $test_channel $path \ [getTestFiles [list $path] $test_flags(-file) $test_flags(-notFile)] \ [list [file tail [info script]] *.tcl pkgIndex.eagle common.eagle \ - constraints.eagle empty.eagle epilogue.eagle prologue.eagle] + constraints.eagle epilogue.eagle prologue.eagle] }] # # NOTE: Run the local test epilogue, if any. # Index: Tests/backup.eagle ================================================================== --- Tests/backup.eagle +++ Tests/backup.eagle @@ -18,16 +18,10 @@ package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel - -############################################################################### - set params(pages) [list -1 -1 0 0 1 1 2 2 1000 1000] set params(callbacks) [list null "new SQLiteBackupCallback(BackupCallback)" \ null "new SQLiteBackupCallback(BackupCallback)" \ null "new SQLiteBackupCallback(BackupCallback)" \ @@ -109,10 +103,11 @@ set memSource [getDbConnection memDb] unset -nocomplain results errors set code [compileCSharpWith [subst { + using System; using System.Data.SQLite; using System.Text; using Eagle._Components.Public; namespace _Dynamic${id} @@ -231,15 +226,9 @@ ############################################################################### unset -nocomplain i params pages callback -############################################################################### - -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel - ############################################################################### runSQLiteTestEpilogue runTestEpilogue Index: Tests/basic.eagle ================================================================== --- Tests/basic.eagle +++ Tests/basic.eagle @@ -312,10 +312,11 @@ set dataSource [file join [getDatabaseDirectory] $fileName] unset -nocomplain results errors set code [compileCSharpWith [subst { + using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { public static class Test${id} @@ -420,10 +421,11 @@ } unset -nocomplain results errors set code [compileCSharpWith [subst { + using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { public static class Test${id} @@ -477,10 +479,11 @@ } unset -nocomplain results errors set code [compileCSharpWith [subst { + using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { public static class Test${id} @@ -932,35 +935,15 @@ set code [compileCSharpWith [subst { using System; using System.Data.SQLite; using System.Reflection; - using System.Text; namespace _Dynamic${id} { public static class Test${id} { - private static string ToHexString( - byte\[\] array - ) - { - if (array == null) - return null; - - StringBuilder result = new StringBuilder(); - - int length = array.Length; - - for (int index = 0; index < length; index++) - result.AppendFormat("{0:x2}", array\[index\]); - - return result.ToString(); - } - - /////////////////////////////////////////////////////////////////////// - public static string GetConnectionString( string key, string value, string propertyName ) @@ -978,12 +961,11 @@ propertyValue = typeof(SQLiteConnectionStringBuilder).InvokeMember( propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty, null, builder, null); } - return String.Format("{0}, {1}", (propertyValue is byte\[\]) ? - ToHexString((byte\[\])propertyValue) : propertyValue, builder); + return String.Format("{0}, {1}", propertyValue, builder); } /////////////////////////////////////////////////////////////////////// public static void Main() @@ -1001,27 +983,27 @@ BinaryGUID "Data Source" Uri FullUri "Default Timeout" \ Enlist FailIfMissing "Legacy Format" "Read Only" \ Password "Page Size" "Max Page Count" "Cache Size" \ DateTimeFormat DateTimeKind BaseSchemaName \ "Journal Mode" "Default IsolationLevel" "Foreign Keys" \ - Flags SetDefaults ToFullPath HexPassword] + Flags SetDefaults ToFullPath] set values [list null 3 Normal True False \ True test.db test.db file:test.db 60 \ False True False True \ secret 4096 1024 8192 \ UnixEpoch Utc sqlite_schema \ Memory Serializable False \ - Default False False 736563726574] + Default False False] set propertyNames [list null Version SyncMode UseUTF16Encoding Pooling \ BinaryGUID DataSource Uri FullUri DefaultTimeout \ Enlist FailIfMissing LegacyFormat ReadOnly \ Password PageSize MaxPageCount CacheSize \ DateTimeFormat DateTimeKind BaseSchemaName \ JournalMode DefaultIsolationLevel ForeignKeys \ - Flags SetDefaults ToFullPath HexPassword] + Flags SetDefaults ToFullPath] foreach key $keys value $values propertyName $propertyNames { set code [catch { object invoke _Dynamic${id}.Test${id} GetConnectionString \ $key $value $propertyName @@ -1048,17 +1030,17 @@ \{UnixEpoch, DateTimeFormat=UnixEpoch\} 0 \{Utc, DateTimeKind=Utc\} 0\ \{sqlite_schema, BaseSchemaName=sqlite_schema\} 0 \{Memory, Journal\ Mode=Memory\} 0 \{Serializable, Default IsolationLevel=Serializable\} 0\ \{False, Foreign Keys=False\} 0 \{(?:Default|LogCallbackException),\ Flags=(?:Default|LogCallbackException)\} 0 \{False, SetDefaults=False\} 0\ -\{False, ToFullPath=False\} 0 {736563726574, HexPassword=736563726574}$}} +\{False, ToFullPath=False\}$}} ############################################################################### runTest {test data-1.17 {SQLiteConvert ToDateTime (Julian Day)} -body { - set dateTime [object invoke -create System.Data.SQLite.SQLiteConvert \ - ToDateTime 2455928.0 Utc] + set dateTime [object invoke System.Data.SQLite.SQLiteConvert ToDateTime \ + 2455928.0 Utc] object invoke $dateTime ToString [getDateTimeFormat] } -cleanup { unset -nocomplain dateTime } -constraints {eagle System.Data.SQLite} -result {2012-01-01 12:00:00Z}} @@ -1452,11 +1434,11 @@ [object invoke -flags +NonPublic System.Data.SQLite.SQLiteConvert \ TypeNameToDbType "VARCHAR (1)"] \ [object invoke -flags +NonPublic System.Data.SQLite.SQLiteConvert \ TypeNameToDbType "NVARCHAR (1)"] \ } -constraints {eagle System.Data.SQLite} -result \ -{AnsiString String AnsiString String AnsiString String}} +{String String String String String String}} ############################################################################### runTest {test data-1.28 {SetMemoryStatus method} -setup { # @@ -1708,21 +1690,21 @@ {[llength [file list $directory(data) $fileName]] == 1}] set t [object create -alias Thread threadStart] sql execute $db "BEGIN TRANSACTION;"; $t Start - for {set i 1} {$i < 1000} {incr i} { + for {set i 1} {$i < 100} {incr i} { # # NOTE: Execute a query that should force the creation of a temporary file # for its statement journal. # sql execute $db "UPDATE t1 SET x = ?;" [list param1 String $i] # # NOTE: Give the other thread some time to notice the temporary file. # - after [expr {int(rand() * 1000)}] + after 1000 # # NOTE: Stop when the other thread confirms that the temporary file was # created in the correct directory. # @@ -1730,13 +1712,11 @@ break } } $t Join; sql execute $db "COMMIT TRANSACTION;" - - lappend result $found(data) [expr {[info exists found(temp)] ? \ - $found(temp) : False}]; set result + lappend result $found(data) $found(temp); set result } -cleanup { # # NOTE: Close the database; however, do not attempt to delete the file as # it is not located in the database directory known to the cleanupDb # procedure (i.e. the one returned by getDatabaseDirectory). @@ -1811,11 +1791,11 @@ this is a test} CantOpen {unable to open database file this is a test} True True}]} ############################################################################### -runTest {test data-1.35 {unencrypted database, with password} -setup { +runTest {test data-1.35 {open unencrypted database, with password} -setup { setupDb [set fileName data-1.35.db] } -body { sql execute $db "CREATE TABLE t1(x);" sql execute $db "INSERT INTO t1 (x) VALUES(1);" @@ -1831,30 +1811,28 @@ "INSERT INTO t1 (x) VALUES(1);"} error] $error cleanupDb $fileName db true false false setupDb $fileName "" "" "" "" "" true false - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - lappend result [catch {sql execute -execute scalar $db \ "SELECT COUNT(*) FROM t1;"} error] $error set result } -cleanup { cleanupDb $fileName unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ +} -constraints \ +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ +-match regexp -result {^1 \{System\.Data\.SQLite\.SQLiteException\ +\(0x80004005\): file is encrypted or is not a database.*?\} 1\ \{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} +not a database.*?\} 0 1$}} ############################################################################### -runTest {test data-1.36 {encrypted database, wrong password} -setup { +runTest {test data-1.36 {open encrypted database, wrong password} -setup { setupDb [set fileName data-1.36.db] "" "" "" "" "Password=12345;" } -body { sql execute $db "CREATE TABLE t1(x);" sql execute $db "INSERT INTO t1 (x) VALUES(1);" @@ -1870,300 +1848,29 @@ "INSERT INTO t1 (x) VALUES(1);"} error] $error cleanupDb $fileName db true false false setupDb $fileName "" "" "" "" "Password=12345;" true false - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - lappend result [catch {sql execute -execute scalar $db \ "SELECT COUNT(*) FROM t1;"} error] $error set result } -cleanup { cleanupDb $fileName unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test data-1.37 {encrypted database, password w/start-space} -setup { - setupDb [set fileName data-1.37.db] "" "" "" "" "Password= 1234;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1234;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password= 1234;" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -result {0 1 0 1 0 1 0 3}} - -############################################################################### - -runTest {test data-1.38 {encrypted database, w/quoted-start-space} -setup { - setupDb [set fileName data-1.38.db] "" "" "" "" "Password=\" 1234\";" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1234;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=\" 1234\";" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test data-1.39 {encrypted database, password w/mid-space} -setup { - setupDb [set fileName data-1.39.db] "" "" "" "" "Password=12 45;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1245;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=12 45;" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test data-1.40 {encrypted database, password w/end-space} -setup { - setupDb [set fileName data-1.40.db] "" "" "" "" "Password=1234 ;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1234;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1234 ;" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -result {0 1 0 1 0 1 0 3}} - -############################################################################### - -runTest {test data-1.41 {encrypted database, w/quoted-end-space} -setup { - setupDb [set fileName data-1.41.db] "" "" "" "" "Password=\"1234 \";" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=1234;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=\"1234 \";" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test data-1.42 {encrypted database, password via builder} -setup { - setupDb [set fileName data-1.42.db] "" "" "" "" "Password=67 89;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - - set connectionStringBuilder [object create -alias \ - System.Data.SQLite.SQLiteConnectionStringBuilder] - - $connectionStringBuilder DataSource \ - [file join [getDatabaseDirectory] $fileName] - - $connectionStringBuilder Password "67 89" - - set connection [object create -alias \ - System.Data.SQLite.SQLiteConnection \ - [$connectionStringBuilder ToString] true] - - $connection Open; addDbConnection $connection - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=\"67 89\";" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - unset -nocomplain connection - - cleanupDb $fileName; # NOTE: After object disposal. - - unset -nocomplain connectionStringBuilder error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -result {0 1 0 1 0 1 0 3}} - -############################################################################### - -runTest {test data-1.43 {quoted connection string properties} -setup { - unset -nocomplain result list pair strings string -} -body { - set result [list] - - set strings [list \ - "OneTwo=ThreeFour" "\"OneTwo\"=\"ThreeFour\"" \ - "One Two=Three Four" "\"One Two\"=\"Three Four\"" \ - "OneTwo=ThreeFour;" "\"OneTwo\"=\"ThreeFour\";" \ - "One Two=Three Four;" "\"One Two\"=\"Three Four\";"] - - foreach string $strings { - set list [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConnection ParseConnectionString $string] - - object foreach -alias pair $list { - lappend result [list [$pair Key] [$pair Value]] - } - } - - set result -} -cleanup { - unset -nocomplain result list pair strings string -} -constraints {eagle System.Data.SQLite} -result {{OneTwo ThreeFour} {OneTwo\ -ThreeFour} {{One Two} {Three Four}} {{One Two} {Three Four}} {OneTwo ThreeFour}\ -{OneTwo ThreeFour} {{One Two} {Three Four}} {{One Two} {Three Four}}}} - -############################################################################### - -runTest {test data-1.44 {rollback to nested savepoint} -setup { - setupDb [set fileName data-1.44.db] +} -constraints \ +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ +-match regexp -result {^1 \{System\.Data\.SQLite\.SQLiteException\ +\(0x80004005\): file is encrypted or is not a database.*?\} 1\ +\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ +not a database.*?\} 0 1$}} + +############################################################################### + +runTest {test data-1.37 {rollback to nested savepoint} -setup { + setupDb [set fileName data-1.37.db] } -body { sql execute $db "BEGIN IMMEDIATE TRANSACTION;" sql execute $db "SAVEPOINT one;" sql execute $db "CREATE TABLE t1(x);" @@ -2188,12 +1895,12 @@ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ {1 2 1}} ############################################################################### -runTest {test data-1.45 {NoExtensionFunctions connection flag} -setup { - setupDb [set fileName data-1.45.db] +runTest {test data-1.38 {NoExtensionFunctions connection flag} -setup { + setupDb [set fileName data-1.38.db] } -body { set result [list] lappend result [catch {sql execute -execute scalar $db \ "SELECT replicate('1234', 2);"} output] $output @@ -2220,12 +1927,12 @@ regexp -result {^0 12341234 1 \{System\.Data\.SQLite\.SQLiteException\ \(0x80004005\): SQL logic error or missing database.*?\} 0 1234123412341234$}} ############################################################################### -runTest {test data-1.46 {column name and index lookup} -setup { - setupDb [set fileName data-1.46.db] +runTest {test data-1.39 {column name and index lookup} -setup { + setupDb [set fileName data-1.39.db] } -body { sql execute $db { CREATE TABLE t1(x, y, z); INSERT INTO t1 (x, y, z) VALUES(1, 'foo', 1234); } @@ -2254,105 +1961,14 @@ unset -nocomplain result db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ {{x 0 1} {y 1 foo} {z 2 1234}}} -############################################################################### - -runTest {test data-1.47 {nullable value types} -setup { - setupDb [set fileName data-1.47.db] -} -body { - sql execute $db { - CREATE TABLE t1(x INTEGER); - INSERT INTO t1 (x) VALUES(NULL); - INSERT INTO t1 (x) VALUES(1); - } - - set dataReader [sql execute -execute reader -format datareader \ - -alias $db "SELECT x FROM t1 ORDER BY x;"] - - set result [list] - - while {[$dataReader Read]} { - foreach {a b c d e} [list "" "" "" "" ""] break - - set x [$dataReader GetOrdinal x] - - foreach {a b c e} [list \ - [$dataReader GetName $x] [$dataReader GetValue $x] \ - [catch {$dataReader GetInt64 $x} d] [$dataReader Item x]] break - - lappend result [list $x $a $b $c $d $e] - } - - set result -} -cleanup { - unset -nocomplain dataReader - - cleanupDb $fileName - - unset -nocomplain e d c b a x result db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ -regexp -result {^\{0 x System#DBNull#\d+ 1\ -\{System\.Reflection\.TargetInvocationException: Exception has been thrown by\ -the target of an invocation\. ---> System\.InvalidCastException:.*\}\ -System#DBNull#\d+\} \{0 x 1 0 1 1\}$}} - -############################################################################### - -runTest {test data-1.48 {static SQLiteCommand.Execute method} -setup { - unset -nocomplain result sql -} -body { - set sql(1) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES (NULL); \ - SELECT x FROM t1 ORDER BY x; \ - } - - set sql(2) { \ - CREATE TABLE t1(x); \ - INSERT INTO t1 (x) VALUES (?); \ - SELECT x FROM t1 ORDER BY x; \ - } - - set result(1) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - "this will not execute" None null] - - set result(2) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(1) NonQuery null] - - set result(3) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(1) Scalar null] - - set result(4) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(1) Reader null] - - set result(5) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - "this will not execute" None null 1] - - set result(6) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(2) NonQuery null 1] - - set result(7) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(2) Scalar null 1] - - set result(8) [object invoke System.Data.SQLite.SQLiteCommand Execute \ - $sql(2) Reader null 1] - - list $result(1) $result(2) $result(3) $result(4) $result(5) $result(6) \ - $result(7) $result(8) -} -cleanup { - unset -nocomplain result sql -} -constraints {eagle monoBug28 SQLite System.Data.SQLite} -match regexp \ --result {^\{\} 1 System#DBNull#\d+ System#Data#SQLite#SQLiteDataReader#\d+ \{\}\ -1 1 System#Data#SQLite#SQLiteDataReader#\d+$}} - ############################################################################### unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \ testExeFile testLinqExeFile northwindEfDbFile testLinqOutFile ############################################################################### runSQLiteTestEpilogue runTestEpilogue Index: Tests/common.eagle ================================================================== --- Tests/common.eagle +++ Tests/common.eagle @@ -88,67 +88,18 @@ } } } } - proc getBuildYears {} { - # - # NOTE: See if the list of test years has been overridden by the user - # (e.g. on the command line). - # - if {[info exists ::test_years] && [llength $::test_years] > 0} then { - # - # NOTE: Use the specified list of test years. - # - return $::test_years - } else { - # - # NOTE: Use the default list of test years. - # - return [list 2005 2008 2010 2012] - } - } - - proc getBuildPlatform { native } { - if {[info exists ::test_platform] && \ - [string length $::test_platform] > 0} then { - # - # NOTE: Use the specified test platform. If this variable is not set, - # the default value will be based on the machine architecture. - # - return [expr {$native ? $::test_platform : ""}] - } elseif {[info exists ::test_machine] && \ - [string length $::test_machine] > 0} then { - # - # NOTE: For native builds, return the platform name corresponding to - # the test machine architecture; otherwise, return an empty - # string. - # - return [expr {$native ? [machineToPlatform $::test_machine] : ""}] - } elseif {[info exists ::tcl_platform(machine)]} then { - # - # NOTE: For native builds, return the platform name corresponding to - # the machine architecture; otherwise, return an empty string. - # - return [expr {$native ? \ - [machineToPlatform $::tcl_platform(machine)] : ""}] - } else { - # - # NOTE: No machine architecture is available, return an empty string. - # - return "" - } - } - proc getBuildConfiguration {} { # - # NOTE: See if the "configuration" setting has been overridden by the - # user (e.g. on the command line). This helps control exactly - # which set of binaries we are testing (i.e. those built in the - # "Debug" or "Release" build configurations). To override this - # value via the command line, enter a command similar to one of - # the following (all on one line): + # NOTE: See if the "configuration" setting has been overridden by the user + # (e.g. on the command line). This helps control exactly which set + # of binaries we are testing (i.e. those built in the "Debug" or + # "Release" build configurations). To override this value via the + # command line, enter a command similar to one of the following (all + # on one line): # # EagleShell.exe -preInitialize "set test_configuration Debug" # -file .\path\to\all.eagle # # EagleShell.exe -preInitialize "set test_configuration Release" @@ -159,12 +110,11 @@ # if {[info exists ::test_configuration] && \ [string length $::test_configuration] > 0} then { # # NOTE: Use the specified test configuration. The default value used - # for this variable is typically "Release", as set by the test - # suite itself. + # for this variable is "Release", as set by the test suite itself. # return $::test_configuration } else { # # NOTE: Normally, we will never hit this case because the value of the @@ -174,79 +124,10 @@ # return $::eagle_platform(configuration) } } - proc getBuildConfigurations {} { - # - # NOTE: See if the list of test configurations has been overridden by - # the user (e.g. on the command line). - # - if {[info exists ::test_configurations] && \ - [llength $::test_configurations] > 0} then { - # - # NOTE: Use the specified list of test configurations. - # - return $::test_configurations - } else { - # - # NOTE: Use the default list of test configurations. - # - return [list Debug Release] - } - } - - proc getBuildBaseDirectory {} { - # - # NOTE: Figure out the base directory where all the builds should be - # located. This will be the directory that contains the actual - # build output directory (e.g. parent of "bin"). - # - if {[info exists ::build_base_directory] && \ - [string length $::build_base_directory] > 0} then { - # - # NOTE: The location of the build base directory has been overridden; - # therefore, use it verbatim. - # - return $::build_base_directory - } elseif {[info exists ::common_directory] && \ - [string length $::common_directory] > 0} then { - # - # NOTE: Next, fallback to the parent directory of the one containing - # this file (i.e. "common.eagle"), if available. - # - return [file dirname $::common_directory] - } elseif {[info exists ::path] && \ - [string length $::path] > 0} then { - # - # NOTE: Finally, fallback to the parent directory of the EagleTest - # path. The EagleTest package guarantees that this variable - # will be set to the directory containing the first file to - # execute the [runTestPrologue] script library procedure. - # - return [file dirname $::path] - } else { - # - # NOTE: No path is available, return an empty string. This point - # should not be reached. - # - return "" - } - } - - proc joinBuildDirectory { native path year platform configuration } { - # - # NOTE: Figure out and then return the fully qualified path to the build - # directory based on all the arguments provided by our caller. - # - if {$native} then { - return [file join $path bin $year $platform $configuration] - } else { - return [file join $path bin $year $configuration bin] - } - } - proc getBuildDirectory {} { # # NOTE: See if the "native" runtime option has been set. If so, use the # directory for the mixed-mode assembly (a.k.a. the native interop # assembly). To enable this option via the command line, enter a @@ -269,10 +150,38 @@ # NOTE: The location of the build directory has been overridden; # therefore, use it verbatim. # return $::build_directory } else { + # + # NOTE: Figure out the build base directory. This will be the directory + # that contains the actual build output directory (e.g. "bin"). + # + if {[info exists ::build_base_directory] && \ + [string length $::build_base_directory] > 0} then { + # + # NOTE: The location of the build base directory has been overridden; + # therefore, use it verbatim. + # + set path $::build_base_directory + } elseif {[info exists ::common_directory] && \ + [string length $::common_directory] > 0} then { + # + # NOTE: Next, fallback to the parent directory of the one containing + # this file (i.e. "common.eagle"), if available. + # + set path [file dirname $::common_directory] + } else { + # + # NOTE: Finally, fallback to the parent directory of the EagleTest + # path. The EagleTest package guarantees that this variable + # will be set to the directory containing the first file to + # execute the [runTestPrologue] script library procedure. + # + set path [file dirname $::path] + } + # # NOTE: If the "native" runtime option is set, the mixed-mode assembly # is being tested. In that case, the path to the build directory # will contain the platform name and all the binaries under test # should be present in that directory. If the "native" runtime @@ -309,14 +218,17 @@ # the latest version of MSBuild available and the "test_year" may # need to be adjusted accordingly to actually run the test suite. # Refer to the comments in [getBuildYear] for more information on # how to set this variable. # - set native [hasRuntimeOption native] - - return [joinBuildDirectory $native [getBuildBaseDirectory] \ - [getBuildYear] [getBuildPlatform $native] [getBuildConfiguration]] + if {[hasRuntimeOption native]} then { + return [file join $path bin [getBuildYear] [machineToPlatform \ + $::tcl_platform(machine)] [getBuildConfiguration]] + } else { + return [file join $path bin [getBuildYear] [getBuildConfiguration] \ + bin] + } } } proc getBuildFileName { fileName } { # @@ -382,47 +294,10 @@ return [file nativename \ [file join [getBinaryDirectory] SQLite.Interop.dll]] } } - proc getCommonDirectory {} { - # - # NOTE: This procedure returns the directory where the test scripts - # should be located. By default, this just returns the Eagle - # binary directory. - # - if {[info exists ::common_directory] && \ - [string length $::common_directory] > 0} then { - # - # NOTE: The location of the common directory has been set; - # therefore, use it. - # - return $::common_directory - } elseif {[info exists ::vendor_directory] && \ - [string length $::vendor_directory] > 0} then { - # - # NOTE: The location of the vendor directory has been set; - # therefore, use it. - # - return $::vendor_directory - } elseif {[info exists ::tcl_library] && \ - [string length $::tcl_library] > 0 && \ - [file isdirectory $::tcl_library]} then { - # - # NOTE: The variable with the location of the script library is - # set and appears to be a real directory (i.e. not embedded - # within a file); therefore, use it. - # - return $::tcl_library - } else { - # - # NOTE: Fallback to the directory containing the executable. - # - return [info binary] - } - } - proc getDatabaseDirectory {} { # # NOTE: This procedure returns the directory where the test databases # should be located. By default, this just uses the temporary # directory configured for this system. @@ -431,18 +306,18 @@ [string length $::database_directory] > 0} then { # # NOTE: The location of the database directory has been overridden; # therefore, use it. # - return $::database_directory + return [file normalize $::database_directory] } elseif {[info exists ::scratch_directory] && \ [string length $::scratch_directory] > 0} then { # # NOTE: The location of the scratch directory has been overridden; # therefore, use it. # - return $::scratch_directory + return [file normalize $::scratch_directory] } else { return [getTemporaryPath] } } @@ -456,18 +331,18 @@ [string length $::temporary_directory] > 0} then { # # NOTE: The location of the temporary directory has been overridden; # therefore, use it. # - return $::temporary_directory + return [file normalize $::temporary_directory] } elseif {[info exists ::scratch_directory] && \ [string length $::scratch_directory] > 0} then { # # NOTE: The location of the scratch directory has been overridden; # therefore, use it. # - return $::scratch_directory + return [file normalize $::scratch_directory] } else { return [getTemporaryPath] } } @@ -558,40 +433,14 @@ object invoke Interpreter.GetActive AddRuntimeOption native } } [getTestOverridesPreamble [list path test_channel]] $suffix]]] } - proc tryCopyBinaryFile { fileName {newFileName ""} } { - set sourceFileName [getBinaryFileName $fileName] - - if {![file exists $sourceFileName]} then { - tputs $::test_channel [appendArgs \ - "---- skipped copying binary file \"" $sourceFileName \ - "\", it does not exist\n"] - - return - } - - if {[string length $newFileName] > 0} then { - set targetFileName [getBuildFileName $newFileName] - } else { - set targetFileName [getBuildFileName $fileName] - } - - if {[catch { - file copy -force $sourceFileName $targetFileName}] == 0} then { - tputs $::test_channel [appendArgs \ - "---- copied binary file from \"" $sourceFileName "\" to \"" \ - $targetFileName \"\n] - } else { - tputs $::test_channel [appendArgs \ - "---- failed to copy binary file from \"" $sourceFileName \ - "\" to \"" $targetFileName \"\n] - } - } - - proc tryCopyBuildFile { fileName {newFileName ""} } { + proc tryCopyBuildFile { fileName } { + # + # NOTE: If we cannot copy the assembly then it is probably already loaded. + # set sourceFileName [getBuildFileName $fileName] if {![file exists $sourceFileName]} then { tputs $::test_channel [appendArgs \ "---- skipped copying build file \"" $sourceFileName \ @@ -598,15 +447,11 @@ "\", it does not exist\n"] return } - if {[string length $newFileName] > 0} then { - set targetFileName [getBinaryFileName $newFileName] - } else { - set targetFileName [getBinaryFileName $fileName] - } + set targetFileName [getBinaryFileName $fileName] if {[catch { file copy -force $sourceFileName $targetFileName}] == 0} then { tputs $::test_channel [appendArgs \ "---- copied build file from \"" $sourceFileName "\" to \"" \ @@ -636,30 +481,10 @@ tputs $::test_channel [appendArgs \ "---- failed to delete binary file \"" $fileName \"\n] } } - proc tryDeleteBuildFile { fileName } { - set fileName [getBuildFileName $fileName] - - if {![file exists $fileName]} then { - tputs $::test_channel [appendArgs \ - "---- skipped deleting build file \"" $fileName \ - "\", it does not exist\n"] - - return - } - - if {[catch {file delete $fileName}] == 0} then { - tputs $::test_channel [appendArgs \ - "---- deleted build file \"" $fileName \"\n] - } else { - tputs $::test_channel [appendArgs \ - "---- failed to delete build file \"" $fileName \"\n] - } - } - proc tryCopyAssembly { fileName {pdb true} } { tryCopyBuildFile $fileName if {$pdb} then { tryCopyBuildFile [appendArgs [file rootname $fileName] .pdb] @@ -698,52 +523,10 @@ } return "" } - proc isSQLiteReady {} { - # - # NOTE: This procedure must return non-zero only if the SQLite native - # library and the System.Data.SQLite managed assembly are loaded - # and ready for use by the test suite. Currently, this procedure - # should be called only after the [tryLoadAssembly] procedure has - # been called to probe for the System.Data.SQLite managed assembly - # and the [checkForSQLite] procedure has been called to probe for - # the SQLite native library; otherwise, this procedure will simply - # always return zero. - # - return [expr {[haveConstraint System.Data.SQLite] && \ - [haveConstraint SQLite]}] - } - - proc checkForSQLiteBuilds { channel } { - # - # NOTE: Check for every possible valid combination of values used when - # locating out the build output directory, showing each available - # build variation along the way. - # - foreach native [list false true] { - foreach year [getBuildYears] { - foreach configuration [getBuildConfigurations] { - tputs $channel [appendArgs \ - "---- checking for System.Data.SQLite build \"" [expr \ - {$native ? "native/" : ""}] $year / $configuration "\"... "] - - set fileName [file nativename [file join [joinBuildDirectory \ - $native [getBuildBaseDirectory] $year [getBuildPlatform \ - $native] $configuration] System.Data.SQLite.dll]] - - if {[file exists $fileName]} then { - tputs $channel yes\n - } else { - tputs $channel no\n - } - } - } - } - } - proc checkForSQLite { channel } { tputs $channel "---- checking for core SQLite library... " if {[catch { object invoke -flags +NonPublic System.Data.SQLite.SQLite3 \ @@ -939,14 +722,13 @@ # NOTE: First, see if our caller has requested an in-memory database. # set isMemory [isMemoryDb $fileName] # - # NOTE: For now, all test databases used by the test suite are placed - # into the database directory. Each database and related files - # used by a test should be cleaned up by that test using the - # "cleanupDb" procedure, below. + # NOTE: For now, all test databases used by the test suite are placed into + # the temporary directory. Each database used by a test should be + # cleaned up by that test using the "cleanupDb" procedure, below. # if {!$isMemory && $qualify} then { set fileName [file join [getDatabaseDirectory] [file tail $fileName]] } @@ -1041,20 +823,20 @@ tputs $::test_channel [appendArgs \ "---- combined connection flags are: " $flags \n] } # - # NOTE: If our caller specified some SQLiteConnectionFlags, add the - # necessary portion of the connection string now. + # NOTE: If our caller specified a SQLiteConnectionFlags, add the necessary + # portion of the connection string now. # if {[string length $flags] > 0} then { append connection {;Flags=${flags}} } # - # NOTE: If our caller specified an extra payload to the connection - # string, append it now. + # NOTE: If our caller specified an extra payload to the connection string, + # append it now. # if {[string length $extra] > 0} then { append connection \; $extra } @@ -1080,12 +862,12 @@ } proc getDbConnection { {varName db} } { # # NOTE: Refer to the specified variable (e.g. "db") in the context of our - # caller. The handle to the database previously opened via the - # [setupDb] procedure should be stored there. + # caller. The handle to the database previously opened by [setupDb] + # should be stored there. # upvar 1 $varName db # # NOTE: This returns the ADO.NET IDbConnection object instance for the @@ -1113,22 +895,21 @@ } } proc freeDbConnection { {varName connection} } { # - # NOTE: Refer to the specified variable (e.g. "connection") in the - # context of our caller. The opaque object handle for an ADO.NET - # connection previously returned by [getDbConnection] should be - # stored there. + # NOTE: Refer to the specified variable (e.g. "connection") in the context + # of our caller. The opaque object handle for an ADO.NET connection + # previously returned by [getDbConnection] should be stored there. # upvar 1 $varName connection # # NOTE: Attempt to remove the opaque object handle from the interpreter # now. This [object dispose] call will not actually dispose of the - # underlying object because the +NoDispose flag was set on it - # during creation of the opaque object handle. + # underlying object because the +NoDispose flag was set on it during + # creation of the opaque object handle. # if {[info exists connection] && \ [catch {object dispose $connection} error]} then { # # NOTE: We somehow failed to remove the handle, report why. @@ -1137,33 +918,10 @@ "==== WARNING: failed to remove connection handle \"" $connection \ "\", error: " \n\t $error \n] } } - proc addDbConnection { connection {varName db} } { - # - # NOTE: Refer to the specified variable (e.g. "db") in the context of our - # caller. - # - upvar 1 $varName db - - # - # NOTE: Create a correctly formatted name for the database connection to - # be added to the list managed by the Eagle interpreter. - # - set db [object invoke -flags +NonPublic \ - Eagle._Components.Private.FormatOps DatabaseObjectName $connection \ - SQLiteConnection [object invoke Interpreter.GetActive NextId]] - - # - # NOTE: Add the database connection provided by our caller to the list - # of those known to the Eagle interpreter. - # - object invoke -flags +NonPublic Interpreter.GetActive.connections Add \ - $db $connection - } - proc cleanupDb { fileName {varName db} {collect true} {qualify true} {delete true} } { # # NOTE: Attempt to force all pending "garbage" objects to be collected, # including SQLite statements and backup objects; this should allow @@ -1173,18 +931,18 @@ collectGarbage $::test_channel } # # NOTE: Refer to the specified variable (e.g. "db") in the context of our - # caller. The handle to the database previously opened via the - # [setupDb] procedure should be stored there. + # caller. The handle to the database previously opened by [setupDb] + # should be stored there. # upvar 1 $varName db # - # NOTE: Close the connection to the database now. This should allow us - # to delete the underlying database file. + # NOTE: Close the connection to the database now. This should allow us to + # delete the underlying database file. # if {[info exists db] && [catch {sql close $db} error]} then { # # NOTE: We somehow failed to close the database, report why. # @@ -1244,72 +1002,10 @@ } return $code } - proc setupDbInterruptCallback { channel log } { - tputs $channel "---- setting up debugger interrupt callback... " - - if {[catch { - # - # NOTE: Make sure the script debugger and the isolated interpreter are - # setup and ready for use. - # - debug setup true true - - # - # NOTE: Load the necessary packages into the isolated interpreter. - # - debug eval { - package require Eagle - package require Eagle.Library - package require Eagle.Test - } - - # - # NOTE: Copy the necessary variables into the isolated interpreter. - # - debug invoke 0 set ::test_channel $channel; # NOTE: For [tputs]. - debug invoke 0 set ::test_log $log; # NOTE: For [tlog]. - - # - # NOTE: Install the callback script to be evaluated in the isolated - # interpreter when this interpreter is interrupted by script - # cancellation, etc. - # - debug callback apply {{sender e} { - # - # NOTE: Check if this callback is one that we care about. - # - if {"Canceled" in [split [$e InterruptType] ", "]} then { - # - # NOTE: Iterate through all database connections known to the - # parent interpreter. - # - object foreach -alias pair \ - [object invoke -flags +NonPublic $e Interpreter.connections] { - # - # NOTE: Attempt to cancel any SQL queries in progress on this - # database connection. - # - if {[catch {$pair Value.Cancel} error] != 0} then { - tputs $::test_channel [appendArgs \n \ - "==== WARNING: failed to cancel query for connection \"" \ - [$pair Key] "\", error: " \n\t $error \n] - } - } - } - }} - } error] == 0} then { - addConstraint interruptCallback.sqlite3 - - tputs $channel yes\n - } else { - tputs $channel [appendArgs "no, error: " \n\t $error \n] - } - } - proc cleanupFile { fileName {collect true} {force false} } { # # NOTE: Attempt to force all pending "garbage" objects to be collected, # including SQLite statements and backup objects; this should allow # the underlying database file to be deleted. @@ -1356,112 +1052,34 @@ } return $code } - proc collectGarbage { channel {milliseconds 1000} {quiet true} } { - if {[catch {object invoke GC GetTotalMemory false} result] == 0} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- memory in use by the CLR before collection... " \ - $result " bytes\n"] - } - } else { - tputs $channel [appendArgs \ - "==== WARNING: failed to get CLR memory usage, error: " \ - \n\t $result \n] - } - - ######################################################################### - - # - # NOTE: Repeatedly attempt to collect garbage until the allotted number - # of milliseconds has elapsed. Always attempt to collect garbage - # at least once. - # - set start [clock seconds] - set stop [expr {$start + ($milliseconds / 1000)}] - - do { - # - # NOTE: Attempt to force a full garbage collection now. Report any - # error that is encountered if we fail. - # - if {[catch {object invoke GC GetTotalMemory true} error]} then { - tputs $channel [appendArgs \ - "==== WARNING: failed full garbage collection, error: " \ - \n\t $error \n] - } - - set now [clock seconds] - } while {$start <= $now && $now < $stop} - - ######################################################################### - - if {[catch {object invoke GC GetTotalMemory false} result] == 0} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- memory in use by the CLR after collection... " \ - $result " bytes\n"] - } - } else { - tputs $channel [appendArgs \ - "==== WARNING: failed to get CLR memory usage, error: " \ - \n\t $result \n] - } - } - - proc getSQLiteHandleCounts { channel {quiet false} } { - set result [list] - - if {[haveConstraint \ - defineConstant.System.Data.SQLite.COUNT_HANDLE]} then { - # - # NOTE: Add each critical handle count to the resulting list. - # - foreach name [list connectionCount statementCount backupCount] { - set value [object invoke -flags +NonPublic \ - System.Data.SQLite.UnsafeNativeMethods $name] - - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- critical handle count \"" $name "\" is " $value \n] - } - - lappend result $value - } - } elseif {!$quiet} then { - # - # NOTE: The actual handle counts are not available; therefore, just - # return an empty list. - # - tputs $channel "---- critical handle counts unavailable\n" - } - - return $result + proc collectGarbage { channel } { + # + # NOTE: Attempt to force a full garbage collection now. Report any + # error that is encountered if we fail. + # + if {[catch {object invoke GC GetTotalMemory true} error]} then { + tputs $channel [appendArgs \ + "==== WARNING: failed full garbage collection, error: " \ + \n\t $error \n] + } } proc shutdownSQLite { channel {force false} {quiet false} } { # # NOTE: Make sure that SQLite core library is completely shutdown. This # is used by tests that change configuration options and/or those # that need to make sure logging is initialized (i.e. just in case # the SQLite core library was initialized in the process prior to # the SQLiteLog class being able to setup its logging callback). - # Normally, this should only be performed if SQLite is loaded and - # ready for use by the test suite. - # - if {$force || [isSQLiteReady]} then { - # - # BUGFIX: Before calling the native shutdown function, make sure both - # of the PRAGMA related directory names are freed. - # - checkForSQLiteDirectories $channel true - + # + if {$force || [haveConstraint SQLite]} then { if {[catch {object invoke -flags +NonPublic \ - System.Data.SQLite.UnsafeNativeMethods \ - sqlite3_shutdown} result] == 0} then { + System.Data.SQLite.UnsafeNativeMethods \ + sqlite3_shutdown} result] == 0} then { if {!$quiet} then { tputs $channel [appendArgs \ "---- call sqlite3_shutdown()... ok: " $result \n] } } else { @@ -1608,15 +1226,13 @@ } } else { tputs $channel no\n # - # NOTE: Does our caller want to reset the directories? This can only - # be performed if SQLite is loaded and ready for use by the test - # suite. + # NOTE: Does our caller want to reset the directories? # - if {$reset && [isSQLiteReady]} then { + if {$reset} then { # # NOTE: Now make sure the database and temporary directories are # reset their default values, which should be null for both. # Since the sqlite3_win32_set_directory function does not # appear to be available, use the associated PRAGMA commands @@ -1625,12 +1241,12 @@ foreach directory [list data_store_directory temp_store_directory] { set sql [appendArgs "PRAGMA " $directory " = \"\";"] if {[catch {executeSql $sql} result] == 0} then { tputs $channel [appendArgs \ - "---- execute PRAGMA " $directory "... ok: \"" \ - $result \"\n] + "---- execute PRAGMA " $directory "... ok: " \ + $result \n] } else { tputs $channel [appendArgs \ "---- execute PRAGMA " $directory "... error: " \ \n\t $result \n] } @@ -1638,108 +1254,30 @@ } } # # NOTE: Finally, show the current value of the database and temporary - # directories. This can only be performed if SQLite is loaded - # and ready for use by the test suite. - # - if {[isSQLiteReady]} then { - foreach directory [list data_store_directory temp_store_directory] { - tputs $channel [appendArgs "---- checking " $directory "... "] - - set sql [appendArgs "PRAGMA " $directory \;] - - if {[catch {executeSql $sql scalar} result] == 0} then { - tputs $channel [appendArgs "ok: \"" $result \"\n] - } else { - tputs $channel [appendArgs "error: " \n\t $result \n] - } - } - } - } - - proc loadSQLiteTestSettings { channel {suffix ""} {quiet false} } { - # - # NOTE: Skip loading the settings if their usage has been disabled. - # - if {![info exists ::no(sqliteTestSettings)]} then { - # - # NOTE: Load custom per-user and/or per-host test settings now. - # - if {[info exists ::tcl_platform(user)]} then { - set userSettingsFileName [file join [getCommonDirectory] \ - [appendArgs settings $suffix . $::tcl_platform(user) .eagle]] - - if {[file exists $userSettingsFileName]} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- loading per-user test settings file \"" \ - $userSettingsFileName \"...\n] - } - - if {[catch {uplevel 1 [list source $userSettingsFileName]} \ - error]} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "==== WARNING: failed to load per-user settings file \"" \ - $userSettingsFileName "\", error: " \n\t $error \n] - } - } - } else { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- skipped loading per-user test settings file \"" \ - $userSettingsFileName "\", it does not exist\n"] - } - } - } - - ####################################################################### - - if {[info exists ::tcl_platform(host)]} then { - set hostSettingsFileName [file join [getCommonDirectory] \ - [appendArgs settings $suffix . $::tcl_platform(host) .eagle]] - - if {[file exists $hostSettingsFileName]} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- loading per-host test settings file \"" \ - $hostSettingsFileName \"...\n] - } - - if {[catch {uplevel 1 [list source $hostSettingsFileName]} \ - error]} then { - if {!$quiet} then { - tputs $channel [appendArgs \ - "==== WARNING: failed to load per-host settings file \"" \ - $hostSettingsFileName "\", error: " \n\t $error \n] - } - } - } else { - if {!$quiet} then { - tputs $channel [appendArgs \ - "---- skipped loading per-host test settings file \"" \ - $hostSettingsFileName "\", it does not exist\n"] - } - } + # directories. + # + foreach directory [list data_store_directory temp_store_directory] { + tputs $channel [appendArgs "---- checking " $directory "... "] + + set sql [appendArgs "PRAGMA " $directory \;] + + if {[catch {executeSql $sql scalar} result] == 0} then { + tputs $channel [appendArgs "ok: \"" $result \"\n] + } else { + tputs $channel [appendArgs "error: " \n\t $result \n] } } } proc runSQLiteTestPrologue {} { # - # NOTE: Skip running our custom prologue if the main one has been - # skipped. + # NOTE: Skip running our custom prologue if the main one has been skipped. # if {![info exists ::no(prologue.eagle)]} then { - # - # NOTE: Load the "before-constraints" custom per-user and/or per-host - # test settings now. - # - uplevel 1 [list loadSQLiteTestSettings $::test_channel .before] - # # NOTE: Skip all System.Data.SQLite related file handling (deleting, # copying, and loading) if we are so instructed. # if {![info exists ::no(sqliteFiles)]} then { @@ -1758,42 +1296,10 @@ tryDeleteAssembly System.Data.SQLite.Linq.dll removeConstraint file_System.Data.SQLite.Linq.dll } - # - # NOTE: Skip trying to verify the build directory if we are so - # instructed; otherwise, make sure it actually exists or - # halt the entire testing process if it does not exist. - # - if {![info exists ::no(verifyBuildDirectory)]} then { - # - # NOTE: At this point, the build directory MUST exist as a - # valid directory for the testing process to continue. - # - set directory [getBuildDirectory] - - if {![file exists $directory] || \ - ![file isdirectory $directory]} then { - # - # NOTE: Just prior to actually halting the testing process, - # add an error to the test log file. - # - tputs $::test_channel [appendArgs \ - "---- could not verify build directory \"" $directory \ - "\", all testing halted\n"] - - # - # NOTE: Raising a script error from this point should halt - # the testing process. - # - error [appendArgs \ - "could not verify build directory \"" $directory \ - "\", all testing halted"] - } - } - # # NOTE: Skip trying to copy any files if we are so instructed. # if {![info exists ::no(copySqliteFiles)]} then { tryCopyAssembly sqlite3.dll @@ -1807,34 +1313,10 @@ # if {![info exists ::no(loadSqliteFiles)]} then { tryLoadAssembly System.Data.SQLite.dll tryLoadAssembly System.Data.SQLite.Linq.dll } - - # - # NOTE: Skip trying to delete external files if we are so instructed. - # - if {![info exists ::no(deleteSqliteExternalFiles)]} then { - tryDeleteBuildFile Installer.exe.mda.config - tryDeleteBuildFile test.exe.mda.config - tryDeleteBuildFile testlinq.exe.mda.config - } - - # - # NOTE: Skip trying to copy external files if we are so instructed. - # - if {![info exists ::no(copySqliteExternalFiles)]} then { - # - # NOTE: Copy the MDA configuration file for the Eagle shell to the - # build output directory; however, use the name of the legacy - # test executable. This will make sure that the legacy tests - # run with the same set of MDAs configured. - # - tryCopyBinaryFile EagleShell.exe.mda.config Installer.exe.mda.config - tryCopyBinaryFile EagleShell.exe.mda.config test.exe.mda.config - tryCopyBinaryFile EagleShell.exe.mda.config testlinq.exe.mda.config - } } catch { tputs $::test_channel [appendArgs \ "---- file version of \"sqlite3.dll\"... " \ @@ -1880,15 +1362,10 @@ } else { tputs $::test_channel unknown\n } } - # - # NOTE: Check the available builds of SQLite and System.Data.SQLite. - # - checkForSQLiteBuilds $::test_channel - # # NOTE: Now, we need to know if the SQLite core library is available # (i.e. because the managed-only System.Data.SQLite assembly can # load without it; however, it cannot do anything useful without # it). If we are using the mixed-mode assembly and we already @@ -1900,31 +1377,27 @@ # NOTE: Check the SQLite database and temporary directories. # checkForSQLiteDirectories $::test_channel # - # NOTE: Attempt to determine if various compile-time options needed for - # test constraints were enabled for the managed assembly. There - # are some compile-time options that must also have been enabled - # for the interop assembly in order to be effective. For those - # options, it will be assumed that it was enabled for the interop - # assembly if it was enabled for the managed assembly. - # - foreach defineConstant [list \ - CHECK_STATE COUNT_HANDLE DEBUG INTEROP_CODEC INTEROP_DEBUG \ - INTEROP_EXTENSION_FUNCTIONS INTEROP_LEGACY_CLOSE INTEROP_LOG \ - INTEROP_TEST_EXTENSION NET_20 NET_35 NET_40 NET_45 NET_COMPACT_20 \ - PLATFORM_COMPACTFRAMEWORK PRELOAD_NATIVE_LIBRARY RETARGETABLE \ - SQLITE_STANDARD THROW_ON_DISPOSED TRACE TRACE_CONNECTION \ - TRACE_HANDLE TRACE_PRELOAD TRACE_STATEMENT TRACE_WARNING \ - USE_INTEROP_DLL USE_PREPARE_V2 WINDOWS] { - # - # NOTE: Check if the compile-time option is listed in the list of - # "define constants" kept track of by the managed assembly. - # - checkForSQLiteDefineConstant $::test_channel $defineConstant - } + # NOTE: Attempt to determine if the custom extension functions were + # compiled into the SQLite interop assembly. + # + checkForSQLiteDefineConstant $::test_channel \ + CHECK_STATE + + checkForSQLiteDefineConstant $::test_channel \ + USE_INTEROP_DLL + + checkForSQLiteDefineConstant $::test_channel \ + INTEROP_EXTENSION_FUNCTIONS + + checkForSQLiteDefineConstant $::test_channel \ + INTEROP_TEST_EXTENSION + + checkForSQLiteDefineConstant $::test_channel \ + SQLITE_STANDARD # # NOTE: Check the current build year. Basically, this indicates # which version of MSBuild and/or Visual Studio was used to # compile the assembly binaries under test. @@ -1931,11 +1404,11 @@ # tputs $::test_channel \ "---- checking for System.Data.SQLite build year... " set year [getBuildYear] - addConstraint [appendArgs buildYear. $year] + addConstraint [appendArgs buildYear $year] tputs $::test_channel [appendArgs \" $year \"\n] # # NOTE: Check the current build configuration. This should normally # be either "Debug" or "Release". @@ -1942,40 +1415,19 @@ # tputs $::test_channel \ "---- checking for System.Data.SQLite build configuration... " set configuration [getBuildConfiguration] - addConstraint [appendArgs buildConfiguration. $configuration] + addConstraint [appendArgs buildConfiguration $configuration] tputs $::test_channel [appendArgs \" $configuration \"\n] - # - # NOTE: Try to setup an interrupt callback using the script debugger - # that will cancel all SQL queries in progress for all database - # connections known to this interpreter. - # - if {![info exists ::no(sqliteInterruptCallback)]} then { - setupDbInterruptCallback $::test_channel $::test_log - } - # # NOTE: Check for the native runtime option, which would mean we are # using the mixed-mode assembly. # checkForRuntimeOption $::test_channel native - # - # NOTE: Check if the test suite should count the number of connections - # "opened" and "closed" from the pool when determining if a test - # passed. Disabling this behavior is sometimes necessary (e.g. - # during the release testing process) because there are several - # tests that rely on the "opened from pool" count being greater - # than zero. These tests may fail due to the non-deterministic - # behavior of the CLR GC, even when there is no bug in the code - # being tested. - # - checkForRuntimeOption $::test_channel noPoolCounts - # # NOTE: Report the resource usage prior to running any tests. # reportSQLiteResources $::test_channel @@ -1983,25 +1435,10 @@ # NOTE: Show the active test constraints. # tputs $::test_channel [appendArgs "---- constraints: " \ [formatList [lsort [getConstraints]]] \n] - # - # NOTE: Save the test constraints for use by threads created in this - # application domain. This is necessary because all the Eagle - # "test context" information is per-thread. - # - if {![info exists ::test_constraints]} then { - set ::test_constraints $::eagle_tests(constraints) - } - - # - # NOTE: Load the "after-constraints" custom per-user and/or per-host - # test settings now. - # - uplevel 1 [list loadSQLiteTestSettings $::test_channel .after] - # # NOTE: Show when our tests actually began (now). # tputs $::test_channel [appendArgs \ "---- System.Data.SQLite tests began at " \ @@ -2009,36 +1446,24 @@ } } proc runSQLiteTestEpilogue {} { # - # NOTE: Skip running our custom epilogue if the main one has been - # skipped. + # NOTE: Skip running our custom epilogue if the main one has been skipped. # if {![info exists ::no(epilogue.eagle)]} then { # # NOTE: Show when our tests actually ended (now). # tputs $::test_channel [appendArgs \ "---- System.Data.SQLite tests ended at " \ [clock format [clock seconds]] \n] - # - # BUGFIX: Before checking the final resources in use by SQLite, make - # sure both of the PRAGMA related directory names are freed. - # - checkForSQLiteDirectories $::test_channel true - # # NOTE: Also report the resource usage after running the tests. # reportSQLiteResources $::test_channel - - # - # NOTE: Report the critical handle counts after running the tests. - # - getSQLiteHandleCounts $::test_channel } } ########################################################################### ############################# END Eagle ONLY ############################## @@ -2046,14 +1471,14 @@ } # # NOTE: Save the name of the directory containing this file. # - if {![info exists common_directory]} then { - set common_directory [file dirname [info script]] + if {![info exists ::common_directory]} then { + set ::common_directory [file dirname [info script]] } # # NOTE: Provide the System.Data.SQLite test package to the interpreter. # package provide System.Data.SQLite.Test 1.0 } DELETED Tests/empty.eagle Index: Tests/empty.eagle ================================================================== --- Tests/empty.eagle +++ /dev/null @@ -1,38 +0,0 @@ -############################################################################### -# -# empty.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -# -# NOTE: There are no unit tests in this file. This file exists to serve two -# purposes: -# -# 1. Provide a "template" script file that can be used when creating new -# unit test files. -# -# 2. Provide a script file that can be evaluated to setup an interactive -# environment for ad-hoc testing of System.Data.SQLite using the Eagle -# Shell. -# - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/installer.eagle ================================================================== --- Tests/installer.eagle +++ Tests/installer.eagle @@ -151,11 +151,11 @@ [subst -nobackslashes [readFile $testInstallVs2005LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2005 visualStudio2005\ +} -constraints {eagle administrator buildYear2005 visualStudio2005\ System.Data.SQLite.dll_v2.0.50727 file_Installer.exe\ file_System.Data.SQLite.dll file_Installer_Test_Vs2005.log} -result {0 True}} ############################################################################### @@ -188,11 +188,11 @@ [subst -nobackslashes [readFile $testUninstallVs2005LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2005 visualStudio2005\ +} -constraints {eagle administrator buildYear2005 visualStudio2005\ System.Data.SQLite.dll_v2.0.50727 file_Installer.exe\ file_System.Data.SQLite.dll file_Uninstaller_Test_Vs2005.log} -result {0 True}} ############################################################################### @@ -225,11 +225,11 @@ [subst -nobackslashes [readFile $testInstallVs2008LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2008 visualStudio2008\ +} -constraints {eagle administrator buildYear2008 visualStudio2008\ System.Data.SQLite.dll_v2.0.50727 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Installer_Test_Vs2008.log} -result {0 True}} ############################################################################### @@ -263,11 +263,11 @@ [subst -nobackslashes [readFile $testUninstallVs2008LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2008 visualStudio2008\ +} -constraints {eagle administrator buildYear2008 visualStudio2008\ System.Data.SQLite.dll_v2.0.50727 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Uninstaller_Test_Vs2008.log} -result {0 True}} ############################################################################### @@ -301,11 +301,11 @@ [subst -nobackslashes [readFile $testInstallVs2010LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2010 visualStudio2010\ +} -constraints {eagle administrator buildYear2010 visualStudio2010\ System.Data.SQLite.dll_v4.0.30319 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Installer_Test_Vs2010.log} -result {0 True}} ############################################################################### @@ -339,11 +339,11 @@ [subst -nobackslashes [readFile $testUninstallVs2010LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2010 visualStudio2010\ +} -constraints {eagle administrator buildYear2010 visualStudio2010\ System.Data.SQLite.dll_v4.0.30319 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Uninstaller_Test_Vs2010.log} -result {0 True}} ############################################################################### @@ -377,11 +377,11 @@ [subst -nobackslashes [readFile $testInstallVs2012LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2012 visualStudio2012\ +} -constraints {eagle administrator buildYear2012 visualStudio2012\ System.Data.SQLite.dll_v4.0.30319 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Installer_Test_Vs2012.log} -result {0 True}} ############################################################################### @@ -415,11 +415,11 @@ [subst -nobackslashes [readFile $testUninstallVs2012LogFile]]] : $error}] } -cleanup { cleanupFile $fileName unset -nocomplain wow64 is64 code output error fileName -} -constraints {eagle administrator buildYear.2012 visualStudio2012\ +} -constraints {eagle administrator buildYear2012 visualStudio2012\ System.Data.SQLite.dll_v4.0.30319 file_Installer.exe\ file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\ file_Uninstaller_Test_Vs2012.log} -result {0 True}} ############################################################################### Index: Tests/stress.eagle ================================================================== --- Tests/stress.eagle +++ Tests/stress.eagle @@ -18,75 +18,28 @@ package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### -# -# NOTE: Report before test, before shutdown. -# -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel - -############################################################################### - # # NOTE: Make sure that SQLite core library is completely shutdown prior to # starting any of the tests in this file. # shutdownSQLite $test_channel ############################################################################### -# -# NOTE: Report before test, after shutdown. -# -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel - -############################################################################### - runTest {test stress-1.1 {multithreaded stress testing} -setup { - unset -nocomplain result thread index workload priority noWorkload \ - priorities srcDb db fileName compiled options count times logFileName \ - logListener event timeout connection indicators iterations exitOnFail \ - coTaskMem noTrace failures status - - ############################################################################# - - proc setupWorkloadMemDb { fileName {varName db} } { - # - # NOTE: This should be an in-memory database; therefore, skip attempting - # to delete the underlying database file as that would not make any - # sense. Also, disable use of "PRAGMA temp_store_directory" when - # setting up the new connection because it is not thread-safe. - # - uplevel 1 [list setupDb $fileName "" "" "" "" "" false false true false \ - $varName] - } - - ############################################################################# - - proc setupWorkloadFileDb { fileName {varName db} } { - # - # NOTE: Skip attempting to delete the underlying database file. Also, - # disable use of "PRAGMA temp_store_directory" when setting up - # the new connection because it is not thread-safe. - # - uplevel 1 [list setupDb $fileName "" "" "" "" "" true false false false \ - $varName] - } + unset -nocomplain result thread index workload noWorkload srcDb db \ + fileName compiled options count times logFileName logListener \ + connection indicators iterations exitOnFail failures ############################################################################# proc formatWorkloadResult { index } { set result [appendArgs "---- iterations for workload (" $index "): "] - append result [expr {[info exists ::iterations($index,total)] ? \ - $::iterations($index,total) : 0}] " total, " - append result [expr {[info exists ::iterations($index,ok)] ? \ $::iterations($index,ok) : 0}] " ok, " append result [expr {[info exists ::iterations($index,error)] ? \ $::iterations($index,error) : 0}] " error, " @@ -104,166 +57,47 @@ return $result } ############################################################################# - proc formatWorkloadTime { index } { - if {[info exists ::times($index)]} then { - set length [llength $::times($index)] - - if {$length > 0} then { - set sum [expr [join $::times($index) +]] - - return [appendArgs "---- average time for workload (" $index \ - ") is about " [expr {int($sum / $length / 1000.0)}] \ - " milliseconds (" [expr {int($sum / ([info exists \ - ::iterations($index,total)] ? $::iterations($index,total) : \ - $length) / 1000.0)}] " milliseconds per iteration)\n"] - } - } - - return [appendArgs "---- no times for workload (" $index )\n] - } - - ############################################################################# - proc isExpectedError { error } { return [expr {[regexp -- {\sno such table: t1\s} $error] || \ - [regexp -- {\sdatabase is locked\s} $error] || \ - [regexp -- {\sdatabase table is locked\s} $error]}] - } - - ############################################################################# - - proc initTest { indicator } { - set ::eagle_tests(constraints) $::test_constraints - } - - ############################################################################# - - proc delayTest { {extra 0} } { - after [expr {int((rand() * 1000) + $extra)}] - } - - ############################################################################# - - proc waitTest { indicator } { - if {![$::event WaitOne $::timeout]} then { - error [appendArgs "timeout while starting workload #" \ - [expr {[string ordinal $indicator 0] - [string ordinal A 0] + 1}]] - } + [regexp -- {\sdatabase is locked\s} $error]}] } ############################################################################# proc showTest { indicator } { tputs $::test_channel $indicator append ::indicators $indicator - delayTest $::count(2) - } - - ############################################################################# - - proc doneTest { {indicator ""} } { - if {[string length $indicator] > 0} then { - lappend ::status(done) $indicator - } - if {[info exists ::status(done)]} then { - host title $::status(done) - } else { - host title "" - } + after [expr {int(rand() * 1000 + $::count(2))}] } ############################################################################# proc failTest { indicator error } { # # NOTE: Halt all testing and exit the process now # -OR- just record the failure and continue? # - set level [expr {[info level] - 1}] - if {$::exitOnFail} then { + set level [expr {[info level] - 1}] + tputs $::test_channel [appendArgs \ \n [info level $level] ": " \n\t $error \n] - exit failure + exit Failure } else { - tlog [appendArgs \ - "\n---- BEGIN TEST FAILURE OUTPUT\n" \ - \n [info level $level] ": " \n\t $error \n \ - "\n---- END TEST FAILURE OUTPUT\n"] - tputs $::test_channel $indicator if {![info exists ::failures($indicator)]} then { set ::failures($indicator) 0 } incr ::failures($indicator) - delayTest $::count(2) - } - } - - ############################################################################# - - proc allocMem { size } { - if {$::coTaskMem} then { - return [object invoke -create \ - System.Runtime.InteropServices.Marshal \ - AllocCoTaskMem $size]; # throw - } else { - set ptr [object invoke -create -flags +NonPublic \ - System.Data.SQLite.UnsafeNativeMethods \ - sqlite3_malloc $size] - - if {[object invoke $ptr ToInt64] != 0} then { - return $ptr - } else { - error [appendArgs "sqlite3_malloc(" $size ") failed"] - } - } - } - - ############################################################################# - - proc useMem { ptr size } { - if {![isMono]} then { - # - # HACK: The type signature of the ZeroMemory method changed as of the - # .NET Framework 4.5. The second argument went from being of - # type UInt to type UIntPtr. - # - if {[haveConstraint dotNet40] && [haveConstraint dotNet45]} then { - set newSize [object create UIntPtr $size] - } else { - set newSize $size - } - - object invoke -flags +NonPublic Microsoft.Win32.Win32Native \ - ZeroMemory $ptr $newSize - } - } - - ############################################################################# - - proc freeMem { ptr } { - if {$::coTaskMem} then { - object invoke System.Runtime.InteropServices.Marshal \ - FreeCoTaskMem $ptr - } else { - object invoke -flags +NonPublic \ - System.Data.SQLite.UnsafeNativeMethods \ - sqlite3_free $ptr - } - - # - # NOTE: Free extra opaque object handle reference added by the - # [return] command in [allocMem]. - # - object dispose $ptr + after [expr {int(rand() * 1000 + $::count(2))}] + } } ############################################################################# proc setupLogging { fileName } { @@ -304,25 +138,34 @@ "---- disabled SQLite trace logging to file \"" $fileName \"\n] } ############################################################################# + # + # NOTE: The trace listener used with the SQLiteLog class to capture output + # from the core SQLite library requires its own log file because the + # TextWriterTraceListener class opens and locks the log file it uses + # as the basis of the output stream. Before this test is complete, + # the entire contents of this trace log file will be copied into the + # main test log file and then deleted. + # + set logFileName [appendArgs [file rootname $test_log] .trace.log] + setupLogging $logFileName + + ############################################################################# + # # NOTE: Setup the default values for the tunable workload parameters. Any, # all, or none of these may be overriden via the command line. # - set count(0) 3; # Workload repeat count (i.e. total full runs). - set count(1) 5; # Workload iteration count (i.e. within a run). - set count(2) 200; # Workload iteration delay, in milliseconds. - set count(3) 57; # Workload "small" data chunk size, in bytes. - set count(4) 10000; # Workload "big" data chunk size, in bytes. - set count(5) 209715200; # Maximum heap memory to exclude at one time. - set noWorkload [list]; # Workloads to be omitted from the run, by index. - set priorities [list]; # Dictionary of workload thread priorities. - set exitOnFail false; # Halt testing and exit process on test failure? - set coTaskMem true; # Use AllocCoTaskMem/FreeCoTaskMem for memory? - set noTrace false; # Disable SQLite trace logging to a file? + set count(0) 1; # Workload repeat count (i.e. total full runs). + set count(1) 20; # Workload iteration count (i.e. within a run). + set count(2) 500; # Workload iteration delay, in milliseconds. + set count(3) 2000; # Workload "small" data chunk size, in bytes. + set count(4) 10000000; # Workload "big" data chunk size, in bytes. + set noWorkload [list]; # Workloads to be omitted from the run, by index. + set exitOnFail true; # Halt testing and exit process on test failure? ############################################################################# # # NOTE: If command line arguments to the test suite are available, process @@ -335,104 +178,47 @@ [list [list null MustHaveIntegerValue -1 -1 -count0 $count(0)] \ [list null MustHaveIntegerValue -1 -1 -count1 $count(1)] \ [list null MustHaveIntegerValue -1 -1 -count2 $count(2)] \ [list null MustHaveIntegerValue -1 -1 -count3 $count(3)] \ [list null MustHaveIntegerValue -1 -1 -count4 $count(4)] \ - [list null MustHaveIntegerValue -1 -1 -count5 $count(5)] \ [list null MustHaveListValue -1 -1 -noWorkload $noWorkload] \ - [list null MustHaveListValue -1 -1 -priorities $priorities] \ - [list null MustHaveBooleanValue -1 -1 -exitOnFail $exitOnFail] \ - [list null MustHaveBooleanValue -1 -1 -coTaskMem $coTaskMem] \ - [list null MustHaveBooleanValue -1 -1 -noTrace $noTrace]] $argv + [list null MustHaveBooleanValue -1 -1 -exitOnFail $exitOnFail]] $argv set count(0) $options(-count0,value) set count(1) $options(-count1,value) set count(2) $options(-count2,value) set count(3) $options(-count3,value) set count(4) $options(-count4,value) - set count(5) $options(-count5,value) - set noWorkload $options(-noWorkload,value) - set priorities $options(-priorities,value) - set exitOnFail $options(-exitOnFail,value) - set coTaskMem $options(-coTaskMem,value) - set noTrace $options(-noTrace,value) - } - - ############################################################################# - - # - # NOTE: Load custom per-user and/or per-host test settings. Currently, this - # is done after processing the command line options. The settings file - # should take into account the existing workload parameters and avoid - # changing any that may have already been overridden. - # - loadSQLiteTestSettings $test_channel .stress - - ############################################################################# - - # - # NOTE: The trace listener used with the SQLiteLog class to capture output - # from the core SQLite library requires its own log file because the - # TextWriterTraceListener class opens and locks the log file it uses - # as the basis of the output stream. Before this test is complete, - # the entire contents of this trace log file will be copied into the - # main test log file and then deleted. - # - if {!$noTrace} then { - set logFileName [appendArgs [file rootname $test_log] .trace.log] - setupLogging $logFileName - } - - ############################################################################# - - tputs $test_channel [appendArgs \ - "---- workloads will repeat " $count(0) " time(s)\n"] - - tputs $test_channel [appendArgs \ - "---- workloads will have " $count(1) " iteration(s)\n"] - - tputs $test_channel [appendArgs \ - "---- workloads will wait at least " $count(2) \ - " millisecond(s) after each iteration\n"] - - tputs $test_channel [appendArgs \ - "---- small chunk size is " $count(3) " byte(s)\n"] - - tputs $test_channel [appendArgs \ - "---- big chunk size is " $count(4) " byte(s)\n"] - - tputs $test_channel [appendArgs \ - "---- maximum excluded heap memory is " $count(5) " byte(s)\n"] - - tputs $test_channel [appendArgs \ - "---- workloads to be skipped... " \ - [expr {[llength $noWorkload] > 0 ? $noWorkload : "none"}] \n] - - tputs $test_channel [appendArgs \ - "---- workloads priority overrides... " \ - [expr {[llength $priorities] > 0 ? $priorities : "none"}] \n] - - tputs $test_channel [appendArgs \ - "---- unexpected errors " \ - [expr {$exitOnFail ? "will" : "will not"}] \ - " halt testing and exit the process\n"] - - tputs $test_channel [appendArgs \ - "---- the " [expr {$coTaskMem ? "CoTaskMem" : "SQLite"}] \ - " allocator will be used to exclude heap memory\n"] - - tputs $test_channel [appendArgs \ - "---- trace logging to a file is " \ - [expr {$noTrace ? "disabled" : "enabled"}] \n] - - ############################################################################# - - # - # NOTE: Create the workload priority array based on the priority list seen - # on the command line, if any. - # - array set priority $priorities + set noWorkload $options(-noWorkload,value) + set exitOnFail $options(-exitOnFail,value) + } + + ############################################################################# + + tputs $test_channel [appendArgs \ + "---- workloads will repeat " $count(0) " time(s)...\n"] + + tputs $test_channel [appendArgs \ + "---- workloads will have " $count(1) " iteration(s)...\n"] + + tputs $test_channel [appendArgs \ + "---- workloads will wait at least " $count(2) " millisecond(s)...\n"] + + tputs $test_channel [appendArgs \ + "---- workload \"small\" chunk size is " $count(3) " byte(s)...\n"] + + tputs $test_channel [appendArgs \ + "---- workload \"big\" chunk size is " $count(4) " byte(s)...\n"] + + if {[llength $noWorkload] > 0} then { + tputs $test_channel [appendArgs \ + "---- workloads to be skipped... " $noWorkload \n] + } + + tputs $test_channel [appendArgs \ + "---- workload failures " [expr {$exitOnFail ? "will" : "will not"}] \ + " halt testing and exit the process...\n"] ############################################################################# # # NOTE: Workloads #12 and #13 contain C# code that should be compiled, but @@ -461,12 +247,12 @@ set fileName(2) [file join [getDatabaseDirectory] [appendArgs \ stress- [pid] - [string trim [clock seconds] -] .db]] ############################################################################# - setupWorkloadMemDb $fileName(1) srcDb - setupWorkloadFileDb $fileName(2) + setupDb $fileName(1) "" "" "" "" "" false false true true srcDb + setupDb $fileName(2) ############################################################################# # # NOTE: This serves two purposes. First, it allows us to verify the trace @@ -477,36 +263,20 @@ $connection LogMessage 0 [appendArgs \ "starting stress test using database \"" $fileName(2) \"...] ############################################################################# - - set timeout [object invoke -flags +NonPublic \ - Eagle._Components.Private.ThreadOps DefaultJoinTimeout] - - tputs $test_channel [appendArgs \ - "---- workloads will start before or timeout after " $timeout \ - " millisecond(s)\n"] - - ############################################################################# - - set event [object create -alias \ - System.Threading.EventWaitHandle false ManualReset] - - ############################################################################# # WORKLOAD #1 (A) # ############################################################################# set workload(1) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #1, CREATE TABLE statements. # - waitTest A lappend ::times(1) [lindex [time { - initTest A - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 2} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs \ "CREATE TABLE IF NOT EXISTS t" \ $index "(x PRIMARY KEY, y, z);"] @@ -518,11 +288,10 @@ failTest a $error } } } cleanupDb $dstFileName db false true false - doneTest A }] 0] }] ############################################################################# # WORKLOAD #2 (B) # @@ -531,14 +300,12 @@ set workload(2) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #2, DROP TABLE statements. # - waitTest B lappend ::times(2) [lindex [time { - initTest B - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 2} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs \ "DROP TABLE IF EXISTS t" $index \;] showTest B @@ -549,11 +316,10 @@ failTest b $error } } } cleanupDb $dstFileName db false true false - doneTest B }] 0] }] ############################################################################# # WORKLOAD #3 (C) # @@ -562,19 +328,18 @@ set workload(3) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #3, "small" SELECT statements. # - waitTest C lappend ::times(3) [lindex [time { - initTest C - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { + set sql [appendArgs \ + "SELECT x, y FROM " $table " WHERE z = 'small';"] set reader [sql execute -execute reader \ - -format dataReader -alias $db [appendArgs \ - "SELECT x, y FROM " $table " WHERE z = 'small';"]] + -format dataReader -alias $db $sql] while {[$reader Read]} { # # NOTE: Do nothing. # } @@ -587,11 +352,10 @@ failTest c $error } } } cleanupDb $dstFileName db false true false - doneTest C }] 0] }] ############################################################################# # WORKLOAD #4 (D) # @@ -600,19 +364,18 @@ set workload(4) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #4, "big" SELECT statements. # - waitTest D lappend ::times(4) [lindex [time { - initTest D - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { + set sql [appendArgs \ + "SELECT x, y FROM " $table " WHERE z = 'big';"] set reader [sql execute -execute reader \ - -format dataReader -alias $db [appendArgs \ - "SELECT x, y FROM " $table " WHERE z = 'big';"]] + -format dataReader -alias $db $sql] while {[$reader Read]} { # # NOTE: Do nothing. # } @@ -625,11 +388,10 @@ failTest d $error } } } cleanupDb $dstFileName db false true false - doneTest D }] 0] }] ############################################################################# # WORKLOAD #5 (E) # @@ -638,19 +400,18 @@ set workload(5) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #5, "small" INSERT statements. # - waitTest E lappend ::times(5) [lindex [time { - initTest E - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { - sql execute $db [appendArgs "INSERT INTO " $table \ - "(x, y, z) VALUES('" [format %lX [expr {random()}]] \ - "', '" [base64 encode -- [expr {randstr($count2)}]] \ + sql execute $db [appendArgs \ + "INSERT INTO " $table "(x, y, z) VALUES('" \ + [format %lX [expr {random()}]] "', '" \ + [base64 encode -- [expr {randstr($count2)}]] \ "', 'small');"] showTest E } error]} then { if {[isExpectedError $error]} then { showTest e @@ -658,11 +419,10 @@ failTest e $error } } } cleanupDb $dstFileName db false true false - doneTest E }] 0] }] ############################################################################# # WORKLOAD #6 (F) # @@ -671,18 +431,17 @@ set workload(6) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #6, "big" INSERT statements. # - waitTest F lappend ::times(6) [lindex [time { - initTest F - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { - sql execute $db [appendArgs "INSERT INTO " $table \ - "(x, y, z) VALUES('" [format %lX [expr {random()}]] \ + sql execute $db [appendArgs \ + "INSERT INTO " $table "(x, y, z) VALUES('" \ + [format %lX [expr {random()}]] \ "', RANDOMBLOB(" $count3 "), 'big');"] showTest F } error]} then { if {[isExpectedError $error]} then { showTest f @@ -690,11 +449,10 @@ failTest f $error } } } cleanupDb $dstFileName db false true false - doneTest F }] 0] }] ############################################################################# # WORKLOAD #7 (G) # @@ -703,14 +461,12 @@ set workload(7) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #7, "small" UPDATE statements. # - waitTest G lappend ::times(7) [lindex [time { - initTest G - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs "UPDATE " $table \ " SET y = '" [base64 encode -- [expr {randstr($count2)}]] \ "' WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] @@ -722,11 +478,10 @@ failTest g $error } } } cleanupDb $dstFileName db false true false - doneTest G }] 0] }] ############################################################################# # WORKLOAD #8 (H) # @@ -735,19 +490,18 @@ set workload(8) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #8, "big" UPDATE statements. # - waitTest H lappend ::times(8) [lindex [time { - initTest H - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs "UPDATE " $table \ - " SET y = RANDOMBLOB(" $count3 ") WHERE x LIKE '" \ - [format %X $index] "%' AND z = 'big';"] + " SET y = RANDOMBLOB(" $count3 \ + ") WHERE x LIKE '" [format %X $index] \ + "%' AND z = 'big';"] showTest H } error]} then { if {[isExpectedError $error]} then { showTest h } else { @@ -754,11 +508,10 @@ failTest h $error } } } cleanupDb $dstFileName db false true false - doneTest H }] 0] }] ############################################################################# # WORKLOAD #9 (I) # @@ -767,14 +520,12 @@ set workload(9) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #9, "small" DELETE statements. # - waitTest I lappend ::times(9) [lindex [time { - initTest I - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs "DELETE FROM " $table \ " WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] showTest I @@ -785,11 +536,10 @@ failTest i $error } } } cleanupDb $dstFileName db false true false - doneTest I }] 0] }] ############################################################################# # WORKLOAD #10 (J) # @@ -798,14 +548,12 @@ set workload(10) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #10, "big" DELETE statements. # - waitTest J lappend ::times(10) [lindex [time { - initTest J - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { sql execute $db [appendArgs "DELETE FROM " $table \ " WHERE x LIKE '" [format %X $index] "%' AND z = 'big';"] showTest J @@ -816,11 +564,10 @@ failTest j $error } } } cleanupDb $dstFileName db false true false - doneTest J }] 0] }] ############################################################################# # WORKLOAD #11 (K) # @@ -829,14 +576,12 @@ set workload(11) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #11, VACUUM statement. # - waitTest K lappend ::times(11) [lindex [time { - initTest K - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { sql execute $db "VACUUM;" showTest K } error]} then { @@ -846,11 +591,10 @@ failTest k $error } } } cleanupDb $dstFileName db false true false - doneTest K }] 0] }] ############################################################################# # WORKLOAD #12 (L) # @@ -859,13 +603,11 @@ set workload(12) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #12, backup to in-memory database. # - waitTest L lappend ::times(12) [lindex [time { - initTest L for {set index 1} {$index <= $count1} {incr index} { if {[string is integer -strict $::compiled(12)]} then { set id $::compiled(12); # NOTE: Already compiled. if {[catch { object invoke _Dynamic${id}.Test${id} BackupAndGetData @@ -878,11 +620,13 @@ } } } else { set id [object invoke Interpreter.GetActive NextId] set code [compileCSharpWith [subst { + using System; using System.Data.SQLite; + using System.Text; namespace _Dynamic${id} { public static class Test${id} { @@ -890,11 +634,10 @@ { using (SQLiteConnection source = new SQLiteConnection( "FullUri=${dstFileName};")) { source.Open(); - using (SQLiteConnection destination = new SQLiteConnection( "FullUri=${srcFileName};")) { destination.Open(); @@ -928,11 +671,10 @@ } else { error $errors } } } - doneTest L }] 0] }] ############################################################################# # WORKLOAD #13 (M) # @@ -941,13 +683,11 @@ set workload(13) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #13, backup from an in-memory database. # - waitTest M lappend ::times(13) [lindex [time { - initTest M for {set index 1} {$index <= $count1} {incr index} { if {[string is integer -strict $::compiled(13)]} then { set id $::compiled(13); # NOTE: Already compiled. if {[catch { object invoke _Dynamic${id}.Test${id} BackupAndGetData @@ -960,11 +700,13 @@ } } } else { set id [object invoke Interpreter.GetActive NextId] set code [compileCSharpWith [subst { + using System; using System.Data.SQLite; + using System.Text; namespace _Dynamic${id} { public static class Test${id} { @@ -972,11 +714,10 @@ { using (SQLiteConnection source = new SQLiteConnection( "FullUri=${srcFileName};")) { source.Open(); - using (SQLiteConnection destination = new SQLiteConnection( "FullUri=${dstFileName};")) { destination.Open(); @@ -1010,11 +751,10 @@ } else { error $errors } } } - doneTest M }] 0] }] ############################################################################# # WORKLOAD #14 (N) # @@ -1023,32 +763,30 @@ set workload(14) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #14, PRAGMA integrity check statement. # - waitTest N lappend ::times(14) [lindex [time { - initTest N - setupWorkloadFileDb $dstFileName + setupDb $dstFileName "" "" "" "" "" true false for {set index 1} {$index <= $count1} {incr index} { if {[catch { set result [sql execute -execute scalar $db \ "PRAGMA integrity_check;"] - if {$result ne "ok"} then { + if {$result eq "ok"} then { + showTest N + } else { error [appendArgs "integrity check failed: " $result] } - showTest N } error]} then { if {[isExpectedError $error]} then { showTest n } else { failTest n $error } } } cleanupDb $dstFileName db false true false - doneTest N }] 0] }] ############################################################################# # WORKLOAD #15 (O) # @@ -1057,13 +795,11 @@ set workload(15) [list \ [list srcFileName dstFileName table count1 count2 count3] { # # NOTE: Workload #15, force managed garbage collection # - waitTest O lappend ::times(15) [lindex [time { - initTest O for {set index 1} {$index <= $count1} {incr index} { if {[catch { collectGarbage $::test_channel showTest O } error]} then { @@ -1072,238 +808,33 @@ } else { failTest o $error } } } - doneTest O - }] 0] - }] - - ############################################################################# - # WORKLOAD #16 (P) # - ############################################################################# - - set workload(16) [list \ - [list srcFileName dstFileName table count1 count2 count3] { - # - # NOTE: Workload #16, allocate (exclude) some native heap memory - # - waitTest P - lappend ::times(16) [lindex [time { - initTest P - set maxSize $::count(5) - object invoke GC AddMemoryPressure $maxSize - try { - for {set index 1} {$index <= $count1} {incr index} { - if {[catch { - set size [expr {int(min($maxSize, abs($count3 * $index * 5.0)))}] - set ptr [allocMem $size]; # throw - useMem $ptr $size; delayTest $count2 - freeMem $ptr; unset -nocomplain ptr - showTest P - } error]} then { - if {[isExpectedError $error]} then { - showTest p - } else { - failTest p $error - } - } - } - } finally { - if {[info exists ptr]} then { - freeMem $ptr; unset -nocomplain ptr - } - object invoke GC RemoveMemoryPressure $maxSize - } - doneTest P - }] 0] - }] - - ############################################################################# - # WORKLOAD #17 (Q) # - ############################################################################# - - set workload(17) [list \ - [list srcFileName dstFileName table count1 count2 count3] { - # - # NOTE: Workload #17, change the database journal mode - # - waitTest Q - lappend ::times(17) [lindex [time { - initTest Q - setupWorkloadFileDb $dstFileName - for {set index 1} {$index <= $count1} {incr index} { - if {[catch { - sql execute $db [appendArgs "PRAGMA journal_mode = \"" \ - [expr {$index % 2 == 0 ? "delete" : "wal"}] \"\;] - showTest Q - } error]} then { - if {[isExpectedError $error]} then { - showTest q - } else { - failTest q $error - } - } - } - cleanupDb $dstFileName db false true false - doneTest Q - }] 0] - }] - - ############################################################################# - # WORKLOAD #18 (R) # - ############################################################################# - - set workload(18) [list \ - [list srcFileName dstFileName table count1 count2 count3] { - # - # NOTE: Workload #18, execute queries against the in-memory database - # - waitTest R - lappend ::times(18) [lindex [time { - initTest R - setupWorkloadMemDb $srcFileName - for {set index 1} {$index <= $count1} {incr index} { - if {[catch { - # - # NOTE: Workload #18.3, "small" SELECT statements. - # - set reader [sql execute -execute reader \ - -format dataReader -alias $db [appendArgs \ - "SELECT x, y FROM " $table " WHERE z = 'small';"]] - while {[$reader Read]} { - # - # NOTE: Do nothing. - # - } - unset -nocomplain reader - # - # NOTE: Workload #18.4, "big" SELECT statements. - # - set reader [sql execute -execute reader \ - -format dataReader -alias $db [appendArgs \ - "SELECT x, y FROM " $table " WHERE z = 'big';"]] - while {[$reader Read]} { - # - # NOTE: Do nothing. - # - } - unset -nocomplain reader - # - # NOTE: Workload #18.5, "small" INSERT statements. - # - sql execute $db [appendArgs "INSERT INTO " $table \ - "(x, y, z) VALUES('" [format %lX [expr {random()}]] \ - "', '" [base64 encode -- [expr {randstr($count2)}]] \ - "', 'small');"] - # - # NOTE: Workload #18.6, "big" INSERT statements. - # - sql execute $db [appendArgs "INSERT INTO " $table \ - "(x, y, z) VALUES('" [format %lX [expr {random()}]] \ - "', RANDOMBLOB(" $count3 "), 'big');"] - # - # NOTE: Workload #18.7, "small" UPDATE statements. - # - sql execute $db [appendArgs "UPDATE " $table \ - " SET y = '" [base64 encode -- [expr {randstr($count2)}]] \ - "' WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] - # - # NOTE: Workload #18.8, "big" UPDATE statements. - # - sql execute $db [appendArgs "UPDATE " $table \ - " SET y = RANDOMBLOB(" $count3 ") WHERE x LIKE '" \ - [format %X $index] "%' AND z = 'big';"] - # - # NOTE: Workload #18.9, "small" DELETE statements. - # - sql execute $db [appendArgs "DELETE FROM " $table \ - " WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] - # - # NOTE: Workload #18.10, "big" DELETE statements. - # - sql execute $db [appendArgs "DELETE FROM " $table \ - " WHERE x LIKE '" [format %X $index] "%' AND z = 'big';"] - # - # NOTE: Workload #18.11, VACUUM statement. - # - sql execute $db "VACUUM;" - # - # NOTE: Workload #18.14, PRAGMA integrity check statement. - # - set result [sql execute -execute scalar $db \ - "PRAGMA integrity_check;"] - if {$result ne "ok"} then { - error [appendArgs "integrity check failed: " $result] - } - showTest R - } error]} then { - if {[isExpectedError $error]} then { - showTest r - } else { - failTest r $error - } - } - } - cleanupDb $srcFileName db false true false - doneTest R }] 0] }] } -body { - tputs $test_channel [appendArgs \ - "==== WARNING: this stress test may take several minutes...\n"] - - for {set index(0) 1} {$index(0) <= $count(0)} {incr index(0)} { - if {$index(0) > 1} then { - # - # NOTE: Advance output to the next line due to the workload - # iteration progress indicators from the previous run. - # - tputs $test_channel \n - } - - tputs $test_channel [appendArgs \ - "---- starting workload run #" $index(0) ...\n] - - unset -nocomplain thread status; doneTest - - sql execute $srcDb "CREATE TABLE IF NOT EXISTS t1(x PRIMARY KEY, y, z);" + for {set index(0) 0} {$index(0) < $count(0)} {incr index(0)} { sql execute $db "CREATE TABLE IF NOT EXISTS t1(x PRIMARY KEY, y, z);" + + unset -nocomplain thread foreach index(1) [lsort -integer [array names workload]] { if {[lsearch -exact $noWorkload $index(1)] == -1} then { set thread($index(1)) [object create -alias System.Threading.Thread \ [list apply $workload($index(1)) $fileName(1) $fileName(2) t1 \ $count(1) $count(3) $count(4)] 1048576] - - $thread($index(1)) Name [appendArgs \ - [file rootname [file tail $fileName(2)]] " #" $index(1)] - - if {[info exists priority($index(1))]} then { - $thread($index(1)) Priority $priority($index(1)) - } - } - } - - foreach index(1) [array names thread] { - $thread($index(1)) Start - } - - $event Set; # GO - - foreach index(1) [array names thread] { - $thread($index(1)) Join - } - - foreach index(1) [array names thread] { - if {[info exists thread($index(1))] && \ - [cleanupThread $thread($index(1))]} then { - unset -nocomplain thread($index(1)) - } - } - - unset -nocomplain thread status; doneTest + } + } + + foreach index(1) [list Start Join] { + foreach index(2) [array names thread] { + $thread($index(2)) $index(1) + } + } + + unset -nocomplain thread } ############################################################################# foreach index(0) [split $indicators ""] { @@ -1321,38 +852,41 @@ if {![info exists iterations($index(2),$index(3))]} then { set iterations($index(2),$index(3)) 0 } - if {![info exists iterations($index(2),total)]} then { - set iterations($index(2),total) 0 - } - incr iterations($index(2),$index(3)) - incr iterations($index(2),total) } ############################################################################# # - # NOTE: Advance output to the next line due to the workload - # iteration progress indicators from the final run. + # NOTE: Advance output to the next line due to the workload iteration + # progress indicators. # tputs $test_channel \n ############################################################################# - foreach index(0) [lsort -integer [array names workload]] { - if {[lsearch -exact $noWorkload $index(0)] == -1} then { - tputs $test_channel [formatWorkloadResult $index(0)] + foreach index(0) [lsort -integer [array names times]] { + set times(length) [llength $times($index(0))] + + if {$times(length) > 0} then { + tputs $test_channel [appendArgs \ + "---- average time for workload (" $index(0) ") is about " \ + [expr int(([join $times($index(0)) +])/$times(length)/1000.0)] \ + " milliseconds\n"] + } else { + tputs $test_channel [appendArgs \ + "---- no times for workload (" $index(0) ")\n"] } } ############################################################################# - foreach index(0) [lsort -integer [array names times]] { - tputs $test_channel [formatWorkloadTime $index(0)] + foreach index(0) [lsort -integer [array names workload]] { + tputs $test_channel [formatWorkloadResult $index(0)] } ############################################################################# set result [sql execute -execute scalar $srcDb "PRAGMA integrity_check;"] @@ -1380,31 +914,14 @@ # "unexpected errors") encountered during a workload iteration. # expr {[array size failures] > 0 ? \ [expr [join [array values failures] +]] : 0} } -cleanup { - foreach index(0) [array names thread] { - if {[info exists thread($index(0))] && \ - [cleanupThread $thread($index(0))]} then { - unset -nocomplain thread($index(0)) - } - } - - rename freeMem "" - rename useMem "" - rename allocMem "" rename failTest "" - rename doneTest "" rename showTest "" - rename waitTest "" - rename delayTest "" - rename initTest "" rename isExpectedError "" - rename formatWorkloadTime "" rename formatWorkloadResult "" - rename setupWorkloadFileDb "" - rename setupWorkloadMemDb "" cleanupDb $fileName(2) cleanupDb $fileName(1) srcDb foreach index(0) [array names workload] { @@ -1414,32 +931,21 @@ } } freeDbConnection - if {!$noTrace} then { - cleanupLogging $logFileName - } + cleanupLogging $logFileName rename cleanupLogging "" rename setupLogging "" - unset -nocomplain result thread index workload priority noWorkload \ - priorities srcDb db fileName compiled options count times logFileName \ - logListener event timeout connection indicators iterations exitOnFail \ - coTaskMem noTrace failures status -} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ -System.Data.SQLite} -result {0}} - -############################################################################### - -# -# NOTE: Report after test. -# -checkForSQLiteDirectories $test_channel -getSQLiteHandleCounts $test_channel -reportSQLiteResources $test_channel + unset -nocomplain result thread index workload noWorkload srcDb db \ + fileName compiled options count times logFileName logListener \ + connection indicators iterations exitOnFail failures +} -constraints \ +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ +-result {0}} ############################################################################### runSQLiteTestEpilogue runTestEpilogue Index: Tests/thread.eagle ================================================================== --- Tests/thread.eagle +++ Tests/thread.eagle @@ -19,85 +19,47 @@ runSQLiteTestPrologue ############################################################################### checkForSQLiteDirectories $test_channel true -set handle_counts [getSQLiteHandleCounts $test_channel] -set memory_used [reportSQLiteResources $test_channel] +set memory_used [reportSQLiteResources $test_channel true] ############################################################################### # # NOTE: How many test threads should be created and used for these tests? This -# value must be at least two. The first test thread (at index 0) is -# always the "master thread" and just repeatedly calls the Thread.Abort() -# method on other random test threads that appear to be alive until all -# test threads appear to have died. All other test threads will attempt -# to open a connection, execute one or more queries against it, and then -# close it. -# -if {![info exists count(1)]} then { - set count(1) 10 -} - -# -# NOTE: How many milliseconds should the master thread initially wait until it -# starts to abort the other test threads? -# -if {![info exists count(2)]} then { - set count(2) 1000 -} - -# -# NOTE: How many milliseconds (maximum) should the master thread wait between -# aborting other random test threads? -# -if {![info exists count(3)]} then { - set count(3) 1000 -} - -# -# NOTE: How many bytes should be used for the five random data blobs contained -# in the test database? -# -if {![info exists count(4)]} then { - set count(4) 1000 -} +# value must be at least two. The first test thread (at index 0) just +# repeatedly calls the Thread.Abort() method on the other test threads +# that appear to be alive until all test threads appear to be dead. All +# other threads will attempt to open a connection, execute one or more +# queries against it, and then close it. +# +set count 10 ############################################################################### runTest {test thread-1.1 {Thread.Abort() impact on native resources} -setup { setupDb [set fileName thread-1.1.db] tputs $test_channel [appendArgs \ - "---- using " $count(1) " test threads (with one master thread)\n"] - - tputs $test_channel [appendArgs \ - "---- initial wait will be " $count(2) " milliseconds\n"] - - tputs $test_channel [appendArgs \ - "---- subsequent maximum wait will be " $count(3) " milliseconds\n"] - - tputs $test_channel [appendArgs \ - "---- random data blob size will be " $count(4) " bytes\n"] + "---- using a total of " $count " threads...\n"] } -body { - sql execute $db [subst { + sql execute $db { CREATE TABLE t1(x INTEGER PRIMARY KEY, y BLOB); - INSERT INTO t1 (y) VALUES(RANDOMBLOB(${count(4)})); - INSERT INTO t1 (y) VALUES(RANDOMBLOB(${count(4)})); - INSERT INTO t1 (y) VALUES(RANDOMBLOB(${count(4)})); - INSERT INTO t1 (y) VALUES(RANDOMBLOB(${count(4)})); - INSERT INTO t1 (y) VALUES(RANDOMBLOB(${count(4)})); - }] + INSERT INTO t1 (y) VALUES(RANDOMBLOB(1000)); + INSERT INTO t1 (y) VALUES(RANDOMBLOB(1000)); + INSERT INTO t1 (y) VALUES(RANDOMBLOB(1000)); + INSERT INTO t1 (y) VALUES(RANDOMBLOB(1000)); + INSERT INTO t1 (y) VALUES(RANDOMBLOB(1000)); + } # - # NOTE: The data and temporary directories must be reset here (after the - # setupDb call above) because they allocate some SQLite memory and - # this test requires an extremely accurate reading. + # NOTE: The temporary directory must be reset here because it allocates + # some SQLite memory and this test requires an extremely accurate + # reading. # sql execute $db { - PRAGMA data_store_directory = ""; PRAGMA temp_store_directory = ""; } # # NOTE: Close the database now, freeing any native SQLite memory and/or @@ -130,37 +92,37 @@ namespace _Dynamic${id} { public static class Test${id} { - public static LongList RunTestThreads() + public static IntList RunTestThreads() { // // NOTE: This is the total number of data bytes seen in the second // column of the query result rows seen by all test threads. // This value will vary greatly based upon how many loop // iterations are performed prior to each test thread being // aborted. // - long sum = 0; + int sum = 0; // // NOTE: This is the total number of query result rows seen by all // the test threads. // - long rows = 0; + int rows = 0; // // NOTE: This is the total number of exceptions caught by all the // test threads. // - long errors = 0; + int errors = 0; // // NOTE: This is the total number of test threads to create. // - int count = ${count(1)}; + int count = ${count}; // // NOTE: Create the array of thread objects. // Thread\[\] thread = new Thread\[count\]; @@ -317,11 +279,11 @@ // // NOTE: Give the other test threads a slight head start to // make sure that they are fully alive prior to trying // to abort any of them. // - Thread.Sleep(${count(2)}); + Thread.Sleep(1000); // // NOTE: Loop forever until all test threads appear to be dead. // while (true) @@ -328,11 +290,11 @@ { // // NOTE: Wait a random number of milliseconds, up to a full // second. // - Thread.Sleep(random.Next(0, ${count(3)})); + Thread.Sleep(random.Next(0, 1000)); // // NOTE: Select a random thread to abort. // int index = random.Next(1, count); @@ -424,11 +386,11 @@ // // NOTE: Return a list of integers with total number of data bytes // seen, total number of query result rows seen, and the total // number of exceptions caught by all the test threads. // - LongList counts = new LongList(); + IntList counts = new IntList(); counts.Add(sum); counts.Add(rows); counts.Add(errors); @@ -448,29 +410,28 @@ list $code $results \ [expr {[info exists errors] ? $errors : ""}] \ [expr {$code eq "Ok" ? [catch { object invoke _Dynamic${id}.Test${id} RunTestThreads } result] : [set result ""]}] $result \ - [collectGarbage $test_channel [expr {$count(1) * 1000}] false] \ - [getSQLiteHandleCounts $test_channel] \ - [reportSQLiteResources $test_channel] + [collectGarbage $test_channel] \ + [reportSQLiteResources $test_channel true] } -cleanup { cleanupDb $fileName unset -nocomplain result results errors code sql dataSource id db fileName -} -time true -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ -System.Data.SQLite} -match regexp -result [appendArgs "^Ok\ -System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} 0 \\{\\d+ \\d+ " $count(1) \ -"\\} \\{\\} \\{" $handle_counts "\\} " $memory_used \$]} +} -constraints \ +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ +regexp -result [appendArgs "^Ok System#CodeDom#Compiler#CompilerResults#\\d+\ +\\{\\} 0 \\{\\d+ \\d+ " $count "\\} \\{\\} " $memory_used \$]} ############################################################################### unset -nocomplain count ############################################################################### -unset -nocomplain memory_used handle_counts +unset -nocomplain memory_used ############################################################################### runSQLiteTestEpilogue runTestEpilogue Index: Tests/tkt-17045010df.eagle ================================================================== --- Tests/tkt-17045010df.eagle +++ Tests/tkt-17045010df.eagle @@ -53,24 +53,21 @@ unset -nocomplain db fileName } -constraints \ {eagle monoBug28 defineConstant.System.Data.SQLite.INTEROP_TEST_EXTENSION\ command.sql compile.DATA SQLite System.Data.SQLite} -result {{0 {}} {1\ -{EXCEPTION System.Data.SQLite.SQLiteException\ -System.Data.SQLite.SQLite3.LoadExtension}\ +{EXCEPTION System.Data.SQLite.SQLiteException}\ {System.Reflection.TargetInvocationException: Exception has been thrown by the\ target of an invocation. ---> System.Data.SQLite.SQLiteException: SQL logic\ error or missing database, not authorized}} {1 {EXCEPTION\ -System.Data.SQLite.SQLiteException System.Data.SQLite.SQLite3.Prepare}\ -{System.Data.SQLite.SQLiteException (0x80004005): SQL logic error or missing\ -database, no such function: interopTest}} {1 {EXCEPTION\ -System.Data.SQLite.SQLiteException System.Data.SQLite.SQLite3.Prepare}\ +System.Data.SQLite.SQLiteException} {System.Data.SQLite.SQLiteException\ +(0x80004005): SQL logic error or missing database, no such function:\ +interopTest}} {1 {EXCEPTION System.Data.SQLite.SQLiteException}\ {System.Data.SQLite.SQLiteException (0x80004005): SQL logic error or missing\ database, no such function: interopTest}} {0 {}} {0 {}} {0 test2} {1 {EXCEPTION\ -System.Data.SQLite.SQLiteException System.Data.SQLite.SQLite3.Reset}\ -{System.Data.SQLite.SQLiteException (0x80004005): SQL logic error or missing\ -database, need exactly one argument}}}} +System.Data.SQLite.SQLiteException} {System.Data.SQLite.SQLiteException\ +(0x80004005): SQL logic error or missing database, need exactly one argument}}}} ############################################################################### runSQLiteTestEpilogue runTestEpilogue DELETED Tests/tkt-1c456ae75f.eagle Index: Tests/tkt-1c456ae75f.eagle ================================================================== --- Tests/tkt-1c456ae75f.eagle +++ /dev/null @@ -1,192 +0,0 @@ -############################################################################### -# -# tkt-1c456ae75f.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-1c456ae75f-1.1 {unencrypted database, hex password} -setup { - setupDb [set fileName tkt-1c456ae75f-1.1.db] -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "HexPassword=3132333435;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test tkt-1c456ae75f-1.2 {database, hex password} -setup { - setupDb [set fileName tkt-1c456ae75f-1.2.db] "" "" "" "" \ - "HexPassword=3132333435;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=12345;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "HexPassword=3132333435;" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -result {0 1 0 1 0 1 0 3}} - -############################################################################### - -runTest {test tkt-1c456ae75f-1.3 {database, wrong hex password} -setup { - setupDb [set fileName tkt-1c456ae75f-1.3.db] "" "" "" "" \ - "HexPassword=3132333435;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "HexPassword=3132333436;" true false - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "HexPassword=3132333435;" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -match regexp -result {^1\ -\{System\.Data\.SQLite\.SQLiteException \(0x80004005\): file is encrypted or is\ -not a database.*?\} 1 \{System\.Data\.SQLite\.SQLiteException \(0x80004005\):\ -file is encrypted or is not a database.*?\} 0 1 0 2$}} - -############################################################################### - -runTest {test tkt-1c456ae75f-1.4 {database, hex password via builder} -setup { - setupDb [set fileName tkt-1c456ae75f-1.4.db] "" "" "" "" \ - "HexPassword=3132333435;" -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - - cleanupDb $fileName db true false false - - set connectionStringBuilder [object create -alias \ - System.Data.SQLite.SQLiteConnectionStringBuilder] - - $connectionStringBuilder DataSource \ - [file join [getDatabaseDirectory] $fileName] - - $connectionStringBuilder HexPassword [list 0x31 0x32 0x33 0x34 0x35] - - set connection [object create -alias \ - System.Data.SQLite.SQLiteConnection \ - [$connectionStringBuilder ToString] true] - - $connection Open; addDbConnection $connection - - set result [list] - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - cleanupDb $fileName db true false false - setupDb $fileName "" "" "" "" "Password=\"12345\";" true false - - lappend result [catch {sql execute $db \ - "INSERT INTO t1 (x) VALUES(1);"} error] $error - - lappend result [catch {sql execute -execute scalar $db \ - "SELECT COUNT(*) FROM t1;"} error] $error - - set result -} -cleanup { - unset -nocomplain connection - - cleanupDb $fileName; # NOTE: After object disposal. - - unset -nocomplain connectionStringBuilder error result db fileName -} -constraints {eagle defineConstant.System.Data.SQLite.INTEROP_CODEC monoBug28\ -command.sql compile.DATA SQLite System.Data.SQLite} -result {0 1 0 1 0 1 0 3}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-343d392b51.eagle ================================================================== --- Tests/tkt-343d392b51.eagle +++ Tests/tkt-343d392b51.eagle @@ -37,24 +37,20 @@ set paramDateTime1 [clock format [clock scan $dateTime] -format \ [getDateTimeFormat] -gmt true] switch -exact -- $dateTimeFormat { Ticks { - set paramDateTime1 [object invoke \ - -create -alias DateTime Parse $paramDateTime1] - + set paramDateTime1 [object invoke -alias DateTime Parse $paramDateTime1] set paramDateTime1 [$paramDateTime1 ToUniversalTime.Ticks] set paramDateTime2 $paramDateTime1 } ISO8601 { set paramDateTime2 [appendArgs ' $paramDateTime1 '] } JulianDay { - set paramDateTime1 [object invoke \ - -create -alias DateTime Parse $paramDateTime1] - - set paramDateTime1 [$paramDateTime1 -create -alias ToUniversalTime] + set paramDateTime1 [object invoke -alias DateTime Parse $paramDateTime1] + set paramDateTime1 [$paramDateTime1 -alias ToUniversalTime] set paramDateTime1 [expr {[$paramDateTime1 ToOADate] + \ [object invoke -flags +NonPublic System.Data.SQLite.SQLiteConvert \ OleAutomationEpochAsJulianDay]}] @@ -368,10 +364,11 @@ }] unset -nocomplain results errors set code [compileCSharpWith [subst { + using System; using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { DELETED Tests/tkt-3567020edf.eagle Index: Tests/tkt-3567020edf.eagle ================================================================== --- Tests/tkt-3567020edf.eagle +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# -# tkt-3567020edf.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-3567020edf-1.1 {embedded NUL characters (UTF-8)} -setup { - setupDb [set fileName tkt-3567020edf-1.1.db] -} -body { - sql execute $db "CREATE TABLE t1(x);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 String one\x00two] - - sql execute -execute reader -format list $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -"one\x00two"} - -############################################################################### - -runTest {test tkt-3567020edf-1.2 {embedded NUL characters (UTF-16)} -setup { - setupDb [set fileName tkt-3567020edf-1.2.db] "" "" "" "" \ - UseUTF16Encoding=True -} -body { - sql execute $db "CREATE TABLE t1(x);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 String one\x00two] - - sql execute -execute reader -format list $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -"one\x00two"} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue DELETED Tests/tkt-393d954be0.eagle Index: Tests/tkt-393d954be0.eagle ================================================================== --- Tests/tkt-393d954be0.eagle +++ /dev/null @@ -1,72 +0,0 @@ -############################################################################### -# -# tkt-393d954be0.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-393d954be0-1.1 {custom connection pool} -setup { - set nullPool [object create -flags +NonPublic -alias \ - System.Data.SQLite.NullConnectionPool true] - - object invoke System.Data.SQLite.SQLiteConnection ConnectionPool $nullPool - - setupDb [set fileName tkt-393d954be0-1.1.db] "" "" "" "" "Pooling=True;" -} -body { - set exists(0) [file exists [file join [getDatabaseDirectory] [file tail \ - $fileName]]] - - cleanupDb $fileName - - set exists(1) [file exists [file join [getDatabaseDirectory] [file tail \ - $fileName]]] - - set counts null; set openCount 0; set closeCount 0; set totalCount 0 - object invoke -flags +NonPublic System.Data.SQLite.SQLiteConnectionPool \ - GetCounts $fileName counts openCount closeCount totalCount - - object invoke -flags +NonPublic System.Data.SQLite.SQLiteConnectionPool \ - ClearPool $fileName - - object invoke -flags +NonPublic System.Data.SQLite.SQLiteConnectionPool \ - ClearAllPools - - list $exists(0) $exists(1) $counts $openCount $closeCount $totalCount \ - [object invoke $nullPool ToString] -} -cleanup { - cleanupDb $fileName - - catch {object invoke System.Data.SQLite.SQLiteConnection ConnectionPool null} - - unset -nocomplain db fileName exists counts openCount closeCount totalCount \ - nullPool -} -constraints {eagle monoBug28 buildConfiguration.Debug command.sql\ -compile.DATA SQLite System.Data.SQLite} -match regexp -result [string map \ -[list \n \r\n] {^True False \{\} 0 0 0\ -\{Remove\(".*?\\tkt-393d954be0-1\.1\.db",\ -100, 0\) -Add\(".*?\\tkt-393d954be0-1\.1\.db", -?\d+, 0\) -GetCounts\("tkt-393d954be0-1\.1\.db", , 0, 0, 0\) -ClearPool\("tkt-393d954be0-1\.1\.db"\) -ClearAllPools\(\) -\}$}]} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-3aa50d8413.eagle ================================================================== --- Tests/tkt-3aa50d8413.eagle +++ Tests/tkt-3aa50d8413.eagle @@ -37,10 +37,11 @@ } unset -nocomplain results errors set code [compileCSharpWith [subst { + using System; using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { DELETED Tests/tkt-48a6b8e4ca.eagle Index: Tests/tkt-48a6b8e4ca.eagle ================================================================== --- Tests/tkt-48a6b8e4ca.eagle +++ /dev/null @@ -1,88 +0,0 @@ -############################################################################### -# -# tkt-48a6b8e4ca.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-48a6b8e4ca-1.1 {SQLiteTypeToType with NULL values} -setup { - setupDb [set fileName tkt-48a6b8e4ca-1.1.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - sql execute $db { - CREATE TABLE t1(x); - } - - set sql { \ - PRAGMA table_info(t1); \ - } - - unset -nocomplain results errors - - set code [compileCSharpWith [subst { - using System.Data; - using System.Data.SQLite; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static void Main() - { - using (SQLiteConnection connection = new SQLiteConnection( - "Data Source=${dataSource};")) - { - connection.Open(); - - using (SQLiteCommand command = new SQLiteCommand("${sql}", - connection)) - { - using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter( - command)) - { - using (DataSet dataSet = new DataSet()) - { - dataAdapter.Fill(dataSet); - } - } - } - } - } - } - } - }] true true true results errors System.Data.SQLite.dll] - - list $code $results \ - [expr {[info exists errors] ? $errors : ""}] \ - [expr {$code eq "Ok" ? [catch { - object invoke _Dynamic${id}.Test${id} Main - } result] : [set result ""]}] $result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain result code results errors sql dataSource id db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ -regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue DELETED Tests/tkt-4a791e70ab.eagle Index: Tests/tkt-4a791e70ab.eagle ================================================================== --- Tests/tkt-4a791e70ab.eagle +++ /dev/null @@ -1,81 +0,0 @@ -############################################################################### -# -# tkt-4a791e70ab.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-4a791e70ab-1.1 {SQLiteDataAdapter w/SelectCommand} -setup { - setupDb [set fileName tkt-4a791e70ab-1.1.db] -} -body { - sql execute $db "CREATE TABLE t1(x);" - - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - unset -nocomplain results errors - - set code [compileCSharpWith [subst { - using System.Data.SQLite; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static void Main() - { - using (SQLiteConnection connection = new SQLiteConnection( - "Data Source=${dataSource};")) - { - connection.Open(); - - using (SQLiteCommand command = connection.CreateCommand()) - { - command.CommandText = "SELECT x FROM t1 ORDER BY x;"; - - using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter( - command)) - { - // do nothing. - } - - string sql = command.CommandText; /* ObjectDisposedException? */ - } - } - } - } - } - }] true true true results errors System.Data.SQLite.dll] - - list $code $results \ - [expr {[info exists errors] ? $errors : ""}] \ - [expr {$code eq "Ok" ? [catch { - object invoke _Dynamic${id}.Test${id} Main - } result] : [set result ""]}] $result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain result results errors code dataSource id db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ -regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue DELETED Tests/tkt-6434e23a0f.eagle Index: Tests/tkt-6434e23a0f.eagle ================================================================== --- Tests/tkt-6434e23a0f.eagle +++ /dev/null @@ -1,86 +0,0 @@ -############################################################################### -# -# tkt-6434e23a0f.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-6434e23a0f-1.1 {SQLiteDataAdapter command disposal} -setup { - setupDb [set fileName tkt-6434e23a0f-1.1.db] -} -body { - sql execute $db "CREATE TABLE t1(x);" - sql execute $db "INSERT INTO t1 (x) VALUES(1);" - sql execute $db "INSERT INTO t1 (x) VALUES(2);" - - cleanupDb $fileName db true false false - - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - set sql { \ - SELECT x FROM t1; \ - } - - unset -nocomplain results errors - - set code [compileCSharpWith [subst { - using System.Data; - using System.Data.SQLite; - using System.IO; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static void Main() - { - using (SQLiteConnection connection = new SQLiteConnection( - "Data Source=${dataSource};")) - { - connection.Open(); - - using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter( - "${sql}", connection)) - { - dataAdapter.Fill(new DataSet()); - } - } - - File.Delete("${dataSource}"); - } - } - } - }] true true true results errors System.Data.SQLite.dll] - - list $code $results \ - [expr {[info exists errors] ? $errors : ""}] \ - [expr {$code eq "Ok" ? [catch { - object invoke _Dynamic${id}.Test${id} Main - } result] : [set result ""]}] $result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain result results errors code sql dataSource id db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ -regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue DELETED Tests/tkt-6c6ecccc5f.eagle Index: Tests/tkt-6c6ecccc5f.eagle ================================================================== --- Tests/tkt-6c6ecccc5f.eagle +++ /dev/null @@ -1,82 +0,0 @@ -############################################################################### -# -# tkt-6c6ecccc5f.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-6c6ecccc5f-1.1 {CloseConnection with extensions} -setup { - setupDb [set fileName tkt-6c6ecccc5f-1.1.db] -} -body { - sql execute $db { - CREATE VIRTUAL TABLE t1 USING fts4(x TEXT); - INSERT INTO t1 (x) VALUES('one'); - INSERT INTO t1 (x) VALUES('two'); - } - - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - set sql "SELECT x FROM t1 WHERE x MATCH 'one';" - - unset -nocomplain results errors - - set code [compileCSharpWith [subst { - using System.Data; - using System.Data.SQLite; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static void Main() - { - using (SQLiteConnection connection = new SQLiteConnection( - "Data Source=${dataSource};")) - { - connection.Open(); - - using (SQLiteCommand command = new SQLiteCommand("${sql}", - connection)) - { - /* IGNORED */ - command.ExecuteReader(CommandBehavior.CloseConnection); - } - } - } - } - } - }] true true true results errors System.Data.SQLite.dll] - - list $code $results \ - [expr {[info exists errors] ? $errors : ""}] \ - [expr {$code eq "Ok" ? [catch { - object invoke _Dynamic${id}.Test${id} Main - } result] : [set result ""]}] $result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain result results errors code sql dataSource id db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ --match regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0\ -\{\}$}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-72905c9a77.eagle ================================================================== --- Tests/tkt-72905c9a77.eagle +++ Tests/tkt-72905c9a77.eagle @@ -18,18 +18,10 @@ package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### -# -# NOTE: Make sure that SQLite core library is completely shutdown prior to -# starting any of the tests in this file. -# -shutdownSQLite $test_channel - -############################################################################### - # # NOTE: This value is needed as part of the test result; therefore, it must be # set outside of the test setup. # set id [object invoke Interpreter.GetActive NextId] @@ -270,13 +262,12 @@ } result] : [set result ""]}] [string map [list \r\n \n] $result] } -cleanup { cleanupDb $fileName unset -nocomplain result code results errors dataSource fileName -} -constraints [fixConstraints {eagle monoBug28 configuration.Release\ -!defineConstant.System.Data.SQLite.INTEROP_LOG command.sql compile.DATA\ -SQLite System.Data.SQLite}] -match regexp -result [appendArgs "^Ok\ +} -constraints {eagle configuration.Release monoBug28 command.sql compile.DATA\ +SQLite System.Data.SQLite} -match regexp -result [appendArgs "^Ok\ System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} 0 \\{" [string repeat \ "SQLite message \\(0\\): TEST $id " [expr {4 * [info processors]}]] "\\}\$"]} ############################################################################### Index: Tests/tkt-84718e79fa.eagle ================================================================== --- Tests/tkt-84718e79fa.eagle +++ Tests/tkt-84718e79fa.eagle @@ -39,11 +39,11 @@ for {set i 0} {$i < $c} {incr i} { set t($i) [object create -alias Thread threadStart 1048576] } - set results [list] + set ::results [list] for {set i 0} {$i < $c} {incr i} { $t($i) Start } @@ -51,11 +51,11 @@ for {set i 0} {$i < $c} {incr i} { $t($i) Join } - set results + set ::results } -cleanup { cleanupDb $fileName object unimport -importpattern System.Threading Index: Tests/tkt-996d13cd87.eagle ================================================================== --- Tests/tkt-996d13cd87.eagle +++ Tests/tkt-996d13cd87.eagle @@ -29,11 +29,11 @@ set fileName [appendArgs tkt-996d13cd87-1. $i .db] tputs $test_channel [appendArgs \ "---- using a total of " $count " threads...\n"] - if {![haveConstraint runtime.noPoolCounts] && [catch { + if {[catch { object invoke -flags +NonPublic \ System.Data.SQLite.SQLiteConnectionPool _poolOpened 0 object invoke -flags +NonPublic \ System.Data.SQLite.SQLiteConnectionPool _poolClosed 0 DELETED Tests/tkt-ae5267b863.eagle Index: Tests/tkt-ae5267b863.eagle ================================================================== --- Tests/tkt-ae5267b863.eagle +++ /dev/null @@ -1,157 +0,0 @@ -############################################################################### -# -# tkt-ae5267b863.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -# -# NOTE: For some reason, this test does not play nicely when all the managed -# debugging assistants are enabled. -# -runTest {test tkt-ae5267b863-1.1 {segfault during command GC} -setup { - setupDb [set fileName tkt-ae5267b863-1.1.db] -} -body { - set id [object invoke Interpreter.GetActive NextId] - set dataSource [file join [getDatabaseDirectory] $fileName] - - set sql(1) { \ - CREATE TABLE t1( \ - __rowid INTEGER PRIMARY KEY AUTOINCREMENT, \ - z STRING \ - ); \ - } - - set sql(2) { \ - CREATE VIRTUAL TABLE t2 USING RTREE( \ - id, minx, maxx, miny, maxy \ - ); \ - } - - set sql(3) { \ - INSERT INTO t1 VALUES({0}, \"value {0}\"); \ - } - - set sql(4) { \ - INSERT INTO t2 VALUES({0}, {0}, {0}, {0}, {0}); \ - } - - set sql(5) { \ - SELECT COUNT(*) FROM t1, t2 \ - WHERE t1.__rowid = t2.id AND \ - (t2.minx <= :xmax and t2.miny <= :ymax and \ - t2.maxx >= :xmin and t2.maxy >= :ymin); \ - } - - unset -nocomplain results errors - - set code [compileCSharpWith [subst { - using System; - using System.Data.SQLite; - - namespace _Dynamic${id} - { - public static class Test${id} - { - public static void Main() - { - using (SQLiteConnection connection = new SQLiteConnection( - "Data Source=${dataSource};")) - { - connection.Open(); - - using (SQLiteCommand command = connection.CreateCommand()) - { - command.CommandText = "${sql(1)}"; - command.ExecuteNonQuery(); - - command.CommandText = "${sql(2)}"; - command.ExecuteNonQuery(); - } - - using (SQLiteCommand command = connection.CreateCommand()) - { - using (SQLiteTransaction transaction = - connection.BeginTransaction()) - { - for (int index = 0; index < 10; index++) - { - command.CommandText = String.Format("${sql(3)}", index); - command.ExecuteNonQuery(); - - command.CommandText = String.Format("${sql(4)}", index); - command.ExecuteNonQuery(); - } - - transaction.Commit(); - } - } - - // - // NOTE: Perform a huge amount of command creation and execution - // cycles for a better chance to trigger the bug. - // - for (int index = 0; index < 100000; index++) - { - // - // NOTE: Purposely omit the 'using' block here to test - // command disposal via the garbage collector. - // - SQLiteCommand command = connection.CreateCommand(); - - command.CommandText = "${sql(5)}"; - command.Parameters.Add(new SQLiteParameter(":xmin", 2)); - command.Parameters.Add(new SQLiteParameter(":xmax", 8)); - command.Parameters.Add(new SQLiteParameter(":ymin", 2)); - command.Parameters.Add(new SQLiteParameter(":ymax", 8)); - - using (SQLiteDataReader reader = command.ExecuteReader()) - { - while (reader.Read()) { - // - // do nothing. - // - } - } - } - - connection.Close(); - } - } - } - } - }] true true true results errors System.Data.SQLite.dll] - - list $code $results \ - [expr {[info exists errors] ? $errors : ""}] \ - [expr {$code eq "Ok" ? [catch { - object invoke _Dynamic${id}.Test${id} Main - } result] : [set result ""]}] $result -} -cleanup { - cleanupDb $fileName - - unset -nocomplain result code results errors sql dataSource id db fileName -} -constraints [fixConstraints {eagle monoBug28 command.sql compile.DATA\ -SQLite System.Data.SQLite !mda\ -!defineConstant.System.Data.SQLite.INTEROP_LEGACY_CLOSE}] -match regexp \ --result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-bb4b04d457.eagle ================================================================== --- Tests/tkt-bb4b04d457.eagle +++ Tests/tkt-bb4b04d457.eagle @@ -18,17 +18,15 @@ package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### -runTest {test tkt-bb4b04d457-1.1 {TIMESTAMP column with Ticks} -setup { +runTest {test tkt-bb4b04d457-1.1 {} -setup { setupDb [set fileName tkt-bb4b04d457-1.1.db] "" Ticks Utc } -body { - set dateTime [object invoke \ - -create -alias DateTime Parse 2011-11-29T12:34:56Z] - - set dateTime [$dateTime -create -alias ToUniversalTime] + set dateTime [object invoke -alias DateTime Parse 2011-11-29T12:34:56Z] + set dateTime [$dateTime -alias ToUniversalTime] sql execute $db "CREATE TABLE t1(x TIMESTAMP NOT NULL);" sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ [list param1 Int64 [$dateTime Ticks]] DELETED Tests/tkt-c010fa6584.eagle Index: Tests/tkt-c010fa6584.eagle ================================================================== --- Tests/tkt-c010fa6584.eagle +++ /dev/null @@ -1,566 +0,0 @@ -############################################################################### -# -# tkt-c010fa6584.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-c010fa6584-1.1 {column "integral" type handling} -setup { - setupDb [set fileName tkt-c010fa6584-1.1.db] -} -body { - # - # NOTE: Create a database table with all the integral type names that are - # recognized by System.Data.SQLite. Subsequently, each column will - # be tested against a list of values that meet and/or exceed the - # bounds for the underlying primitive integral CLR type. - # - sql execute $db { - CREATE TABLE t1( - a00 SYSNAME, -- This is the 'payload' column name. - a01, -- String - a02 TEXT, -- String - a03 BIGINT, -- Int64 - a04 BIGUINT, -- UInt64 - a05 COUNTER, -- Int64 - a06 IDENTITY, -- Int64 - a07 INT, -- Int32 - a08 INT8, -- SByte - a09 INT16, -- Int16 - a10 INT32, -- Int32 - a11 INT64, -- Int64 - a12 INTEGER, -- Int64 - a13 INTEGER8, -- SByte - a14 INTEGER16, -- Int16 - a15 INTEGER32, -- Int32 - a16 INTEGER64, -- Int64 - a17 LONG, -- Int64 - a18 SMALLINT, -- Int16 - a19 SMALLUINT, -- UInt16 - a20 TINYINT, -- Byte - a21 TINYSINT, -- SByte - a22 UINT, -- UInt32 - a23 UINT8, -- Byte - a24 UINT16, -- UInt16 - a25 UINT32, -- UInt32 - a26 UINT64, -- UInt64 - a27 ULONG, -- UInt64 - a28 UNSIGNEDINTEGER, -- UInt32 - a29 UNSIGNEDINTEGER8, -- Byte - a30 UNSIGNEDINTEGER16, -- UInt16 - a31 UNSIGNEDINTEGER32, -- UInt32 - a32 UNSIGNEDINTEGER64 -- UInt64 - ); - } - - # - # NOTE: These are the numeric values being tested against all the types in - # the database table defined above. This list includes values that - # are out-of-bounds for each primitive integral type. - # - set values [list \ - -9223372036854775809 -9223372036854775808 \ - -2147483649 -2147483648 \ - -32769 -32768 \ - -129 -128 \ - -1 0 1 \ - 127 128 \ - 255 256 \ - 32767 32768 \ - 65535 65536 \ - 2147483647 2147483648 \ - 4294967295 4294967296 \ - 9223372036854775807 9223372036854775808 \ - 18446744073709551615 18446744073709551616] - - for {set index 1} {$index <= 32} {incr index} { - set name [appendArgs a [format %02d $index]] - foreach value $values { - sql execute $db [subst { - INSERT INTO t1 (a00, $name) VALUES('$name', $value); - }] - } - } - - set results [list] - - for {set index 1} {$index <= 32} {incr index} { - set name [appendArgs a [format %02d $index]] - set count [sql execute -execute scalar $db [subst { - SELECT COUNT(*) FROM t1 WHERE a00 = '$name'; - }]] - for {set offset 0} {$offset < $count} {incr offset} { - set code [catch { - sql execute -execute scalar $db [subst { - SELECT $name FROM t1 WHERE a00 = '$name' LIMIT 1 OFFSET $offset; - }] - } result] - - set match [expr {$result eq [lindex $values $offset]}] - - lappend results [list \ - $name $offset $match [lindex $values $offset] \ - $code [expr {$code == 0 ? $result : $errorCode}]] - } - } - - set results -} -cleanup { - cleanupDb $fileName - - unset -nocomplain match result code offset count results value name index \ - values db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{{a01 0 False -9223372036854775809 0 -9.22337203685478E+18} {a01 1 True\ --9223372036854775808 0 -9223372036854775808} {a01 2 True -2147483649 0\ --2147483649} {a01 3 True -2147483648 0 -2147483648} {a01 4 True -32769 0\ --32769} {a01 5 True -32768 0 -32768} {a01 6 True -129 0 -129} {a01 7 True -128\ -0 -128} {a01 8 True -1 0 -1} {a01 9 True 0 0 0} {a01 10 True 1 0 1} {a01 11\ -True 127 0 127} {a01 12 True 128 0 128} {a01 13 True 255 0 255} {a01 14 True\ -256 0 256} {a01 15 True 32767 0 32767} {a01 16 True 32768 0 32768} {a01 17 True\ -65535 0 65535} {a01 18 True 65536 0 65536} {a01 19 True 2147483647 0\ -2147483647} {a01 20 True 2147483648 0 2147483648} {a01 21 True 4294967295 0\ -4294967295} {a01 22 True 4294967296 0 4294967296} {a01 23 True\ -9223372036854775807 0 9223372036854775807} {a01 24 False 9223372036854775808 0\ -9.22337203685478E+18} {a01 25 False 18446744073709551615 0\ -1.84467440737096E+19} {a01 26 False 18446744073709551616 0\ -1.84467440737096E+19} {a02 0 False -9223372036854775809 0\ --9.22337203685478e+18} {a02 1 True -9223372036854775808 0 -9223372036854775808}\ -{a02 2 True -2147483649 0 -2147483649} {a02 3 True -2147483648 0 -2147483648}\ -{a02 4 True -32769 0 -32769} {a02 5 True -32768 0 -32768} {a02 6 True -129 0\ --129} {a02 7 True -128 0 -128} {a02 8 True -1 0 -1} {a02 9 True 0 0 0} {a02 10\ -True 1 0 1} {a02 11 True 127 0 127} {a02 12 True 128 0 128} {a02 13 True 255 0\ -255} {a02 14 True 256 0 256} {a02 15 True 32767 0 32767} {a02 16 True 32768 0\ -32768} {a02 17 True 65535 0 65535} {a02 18 True 65536 0 65536} {a02 19 True\ -2147483647 0 2147483647} {a02 20 True 2147483648 0 2147483648} {a02 21 True\ -4294967295 0 4294967295} {a02 22 True 4294967296 0 4294967296} {a02 23 True\ -9223372036854775807 0 9223372036854775807} {a02 24 False 9223372036854775808 0\ -9.22337203685478e+18} {a02 25 False 18446744073709551615 0\ -1.84467440737096e+19} {a02 26 False 18446744073709551616 0\ -1.84467440737096e+19} {a03 0 False -9223372036854775809 0 -9223372036854775808}\ -{a03 1 True -9223372036854775808 0 -9223372036854775808} {a03 2 True\ --2147483649 0 -2147483649} {a03 3 True -2147483648 0 -2147483648} {a03 4 True\ --32769 0 -32769} {a03 5 True -32768 0 -32768} {a03 6 True -129 0 -129} {a03 7\ -True -128 0 -128} {a03 8 True -1 0 -1} {a03 9 True 0 0 0} {a03 10 True 1 0 1}\ -{a03 11 True 127 0 127} {a03 12 True 128 0 128} {a03 13 True 255 0 255} {a03 14\ -True 256 0 256} {a03 15 True 32767 0 32767} {a03 16 True 32768 0 32768} {a03 17\ -True 65535 0 65535} {a03 18 True 65536 0 65536} {a03 19 True 2147483647 0\ -2147483647} {a03 20 True 2147483648 0 2147483648} {a03 21 True 4294967295 0\ -4294967295} {a03 22 True 4294967296 0 4294967296} {a03 23 True\ -9223372036854775807 0 9223372036854775807} {a03 24 False 9223372036854775808 0\ --9223372036854775808} {a03 25 False 18446744073709551615 0\ --9223372036854775808} {a03 26 False 18446744073709551616 0\ --9223372036854775808} {a04 0 False -9223372036854775809 0 9223372036854775808}\ -{a04 1 False -9223372036854775808 0 9223372036854775808} {a04 2 False\ --2147483649 0 18446744071562067967} {a04 3 False -2147483648 0\ -18446744071562067968} {a04 4 False -32769 0 18446744073709518847} {a04 5 False\ --32768 0 18446744073709518848} {a04 6 False -129 0 18446744073709551487} {a04 7\ -False -128 0 18446744073709551488} {a04 8 False -1 0 18446744073709551615} {a04\ -9 True 0 0 0} {a04 10 True 1 0 1} {a04 11 True 127 0 127} {a04 12 True 128 0\ -128} {a04 13 True 255 0 255} {a04 14 True 256 0 256} {a04 15 True 32767 0\ -32767} {a04 16 True 32768 0 32768} {a04 17 True 65535 0 65535} {a04 18 True\ -65536 0 65536} {a04 19 True 2147483647 0 2147483647} {a04 20 True 2147483648 0\ -2147483648} {a04 21 True 4294967295 0 4294967295} {a04 22 True 4294967296 0\ -4294967296} {a04 23 True 9223372036854775807 0 9223372036854775807} {a04 24\ -True 9223372036854775808 0 9223372036854775808} {a04 25 False\ -18446744073709551615 0 9223372036854775808} {a04 26 False 18446744073709551616\ -0 9223372036854775808} {a05 0 False -9223372036854775809 0\ --9223372036854775808} {a05 1 True -9223372036854775808 0 -9223372036854775808}\ -{a05 2 True -2147483649 0 -2147483649} {a05 3 True -2147483648 0 -2147483648}\ -{a05 4 True -32769 0 -32769} {a05 5 True -32768 0 -32768} {a05 6 True -129 0\ --129} {a05 7 True -128 0 -128} {a05 8 True -1 0 -1} {a05 9 True 0 0 0} {a05 10\ -True 1 0 1} {a05 11 True 127 0 127} {a05 12 True 128 0 128} {a05 13 True 255 0\ -255} {a05 14 True 256 0 256} {a05 15 True 32767 0 32767} {a05 16 True 32768 0\ -32768} {a05 17 True 65535 0 65535} {a05 18 True 65536 0 65536} {a05 19 True\ -2147483647 0 2147483647} {a05 20 True 2147483648 0 2147483648} {a05 21 True\ -4294967295 0 4294967295} {a05 22 True 4294967296 0 4294967296} {a05 23 True\ -9223372036854775807 0 9223372036854775807} {a05 24 False 9223372036854775808 0\ --9223372036854775808} {a05 25 False 18446744073709551615 0\ --9223372036854775808} {a05 26 False 18446744073709551616 0\ --9223372036854775808} {a06 0 False -9223372036854775809 0 -9223372036854775808}\ -{a06 1 True -9223372036854775808 0 -9223372036854775808} {a06 2 True\ --2147483649 0 -2147483649} {a06 3 True -2147483648 0 -2147483648} {a06 4 True\ --32769 0 -32769} {a06 5 True -32768 0 -32768} {a06 6 True -129 0 -129} {a06 7\ -True -128 0 -128} {a06 8 True -1 0 -1} {a06 9 True 0 0 0} {a06 10 True 1 0 1}\ -{a06 11 True 127 0 127} {a06 12 True 128 0 128} {a06 13 True 255 0 255} {a06 14\ -True 256 0 256} {a06 15 True 32767 0 32767} {a06 16 True 32768 0 32768} {a06 17\ -True 65535 0 65535} {a06 18 True 65536 0 65536} {a06 19 True 2147483647 0\ -2147483647} {a06 20 True 2147483648 0 2147483648} {a06 21 True 4294967295 0\ -4294967295} {a06 22 True 4294967296 0 4294967296} {a06 23 True\ -9223372036854775807 0 9223372036854775807} {a06 24 False 9223372036854775808 0\ --9223372036854775808} {a06 25 False 18446744073709551615 0\ --9223372036854775808} {a06 26 False 18446744073709551616 0\ --9223372036854775808} {a07 0 False -9223372036854775809 0 0} {a07 1 False\ --9223372036854775808 0 0} {a07 2 False -2147483649 0 2147483647} {a07 3 True\ --2147483648 0 -2147483648} {a07 4 True -32769 0 -32769} {a07 5 True -32768 0\ --32768} {a07 6 True -129 0 -129} {a07 7 True -128 0 -128} {a07 8 True -1 0 -1}\ -{a07 9 True 0 0 0} {a07 10 True 1 0 1} {a07 11 True 127 0 127} {a07 12 True 128\ -0 128} {a07 13 True 255 0 255} {a07 14 True 256 0 256} {a07 15 True 32767 0\ -32767} {a07 16 True 32768 0 32768} {a07 17 True 65535 0 65535} {a07 18 True\ -65536 0 65536} {a07 19 True 2147483647 0 2147483647} {a07 20 False 2147483648 0\ --2147483648} {a07 21 False 4294967295 0 -1} {a07 22 False 4294967296 0 0} {a07\ -23 False 9223372036854775807 0 -1} {a07 24 False 9223372036854775808 0 0} {a07\ -25 False 18446744073709551615 0 0} {a07 26 False 18446744073709551616 0 0} {a08\ -0 False -9223372036854775809 0 0} {a08 1 False -9223372036854775808 0 0} {a08 2\ -False -2147483649 0 -1} {a08 3 False -2147483648 0 0} {a08 4 False -32769 0 -1}\ -{a08 5 False -32768 0 0} {a08 6 False -129 0 127} {a08 7 True -128 0 -128} {a08\ -8 True -1 0 -1} {a08 9 True 0 0 0} {a08 10 True 1 0 1} {a08 11 True 127 0 127}\ -{a08 12 False 128 0 -128} {a08 13 False 255 0 -1} {a08 14 False 256 0 0} {a08\ -15 False 32767 0 -1} {a08 16 False 32768 0 0} {a08 17 False 65535 0 -1} {a08 18\ -False 65536 0 0} {a08 19 False 2147483647 0 -1} {a08 20 False 2147483648 0 0}\ -{a08 21 False 4294967295 0 -1} {a08 22 False 4294967296 0 0} {a08 23 False\ -9223372036854775807 0 -1} {a08 24 False 9223372036854775808 0 0} {a08 25 False\ -18446744073709551615 0 0} {a08 26 False 18446744073709551616 0 0} {a09 0 False\ --9223372036854775809 0 0} {a09 1 False -9223372036854775808 0 0} {a09 2 False\ --2147483649 0 -1} {a09 3 False -2147483648 0 0} {a09 4 False -32769 0 32767}\ -{a09 5 True -32768 0 -32768} {a09 6 True -129 0 -129} {a09 7 True -128 0 -128}\ -{a09 8 True -1 0 -1} {a09 9 True 0 0 0} {a09 10 True 1 0 1} {a09 11 True 127 0\ -127} {a09 12 True 128 0 128} {a09 13 True 255 0 255} {a09 14 True 256 0 256}\ -{a09 15 True 32767 0 32767} {a09 16 False 32768 0 -32768} {a09 17 False 65535 0\ --1} {a09 18 False 65536 0 0} {a09 19 False 2147483647 0 -1} {a09 20 False\ -2147483648 0 0} {a09 21 False 4294967295 0 -1} {a09 22 False 4294967296 0 0}\ -{a09 23 False 9223372036854775807 0 -1} {a09 24 False 9223372036854775808 0 0}\ -{a09 25 False 18446744073709551615 0 0} {a09 26 False 18446744073709551616 0 0}\ -{a10 0 False -9223372036854775809 0 0} {a10 1 False -9223372036854775808 0 0}\ -{a10 2 False -2147483649 0 2147483647} {a10 3 True -2147483648 0 -2147483648}\ -{a10 4 True -32769 0 -32769} {a10 5 True -32768 0 -32768} {a10 6 True -129 0\ --129} {a10 7 True -128 0 -128} {a10 8 True -1 0 -1} {a10 9 True 0 0 0} {a10 10\ -True 1 0 1} {a10 11 True 127 0 127} {a10 12 True 128 0 128} {a10 13 True 255 0\ -255} {a10 14 True 256 0 256} {a10 15 True 32767 0 32767} {a10 16 True 32768 0\ -32768} {a10 17 True 65535 0 65535} {a10 18 True 65536 0 65536} {a10 19 True\ -2147483647 0 2147483647} {a10 20 False 2147483648 0 -2147483648} {a10 21 False\ -4294967295 0 -1} {a10 22 False 4294967296 0 0} {a10 23 False\ -9223372036854775807 0 -1} {a10 24 False 9223372036854775808 0 0} {a10 25 False\ -18446744073709551615 0 0} {a10 26 False 18446744073709551616 0 0} {a11 0 False\ --9223372036854775809 0 -9223372036854775808} {a11 1 True -9223372036854775808 0\ --9223372036854775808} {a11 2 True -2147483649 0 -2147483649} {a11 3 True\ --2147483648 0 -2147483648} {a11 4 True -32769 0 -32769} {a11 5 True -32768 0\ --32768} {a11 6 True -129 0 -129} {a11 7 True -128 0 -128} {a11 8 True -1 0 -1}\ -{a11 9 True 0 0 0} {a11 10 True 1 0 1} {a11 11 True 127 0 127} {a11 12 True 128\ -0 128} {a11 13 True 255 0 255} {a11 14 True 256 0 256} {a11 15 True 32767 0\ -32767} {a11 16 True 32768 0 32768} {a11 17 True 65535 0 65535} {a11 18 True\ -65536 0 65536} {a11 19 True 2147483647 0 2147483647} {a11 20 True 2147483648 0\ -2147483648} {a11 21 True 4294967295 0 4294967295} {a11 22 True 4294967296 0\ -4294967296} {a11 23 True 9223372036854775807 0 9223372036854775807} {a11 24\ -False 9223372036854775808 0 -9223372036854775808} {a11 25 False\ -18446744073709551615 0 -9223372036854775808} {a11 26 False 18446744073709551616\ -0 -9223372036854775808} {a12 0 False -9223372036854775809 0\ --9223372036854775808} {a12 1 True -9223372036854775808 0 -9223372036854775808}\ -{a12 2 True -2147483649 0 -2147483649} {a12 3 True -2147483648 0 -2147483648}\ -{a12 4 True -32769 0 -32769} {a12 5 True -32768 0 -32768} {a12 6 True -129 0\ --129} {a12 7 True -128 0 -128} {a12 8 True -1 0 -1} {a12 9 True 0 0 0} {a12 10\ -True 1 0 1} {a12 11 True 127 0 127} {a12 12 True 128 0 128} {a12 13 True 255 0\ -255} {a12 14 True 256 0 256} {a12 15 True 32767 0 32767} {a12 16 True 32768 0\ -32768} {a12 17 True 65535 0 65535} {a12 18 True 65536 0 65536} {a12 19 True\ -2147483647 0 2147483647} {a12 20 True 2147483648 0 2147483648} {a12 21 True\ -4294967295 0 4294967295} {a12 22 True 4294967296 0 4294967296} {a12 23 True\ -9223372036854775807 0 9223372036854775807} {a12 24 False 9223372036854775808 0\ --9223372036854775808} {a12 25 False 18446744073709551615 0\ --9223372036854775808} {a12 26 False 18446744073709551616 0\ --9223372036854775808} {a13 0 False -9223372036854775809 0 0} {a13 1 False\ --9223372036854775808 0 0} {a13 2 False -2147483649 0 -1} {a13 3 False\ --2147483648 0 0} {a13 4 False -32769 0 -1} {a13 5 False -32768 0 0} {a13 6\ -False -129 0 127} {a13 7 True -128 0 -128} {a13 8 True -1 0 -1} {a13 9 True 0 0\ -0} {a13 10 True 1 0 1} {a13 11 True 127 0 127} {a13 12 False 128 0 -128} {a13\ -13 False 255 0 -1} {a13 14 False 256 0 0} {a13 15 False 32767 0 -1} {a13 16\ -False 32768 0 0} {a13 17 False 65535 0 -1} {a13 18 False 65536 0 0} {a13 19\ -False 2147483647 0 -1} {a13 20 False 2147483648 0 0} {a13 21 False 4294967295 0\ --1} {a13 22 False 4294967296 0 0} {a13 23 False 9223372036854775807 0 -1} {a13\ -24 False 9223372036854775808 0 0} {a13 25 False 18446744073709551615 0 0} {a13\ -26 False 18446744073709551616 0 0} {a14 0 False -9223372036854775809 0 0} {a14\ -1 False -9223372036854775808 0 0} {a14 2 False -2147483649 0 -1} {a14 3 False\ --2147483648 0 0} {a14 4 False -32769 0 32767} {a14 5 True -32768 0 -32768} {a14\ -6 True -129 0 -129} {a14 7 True -128 0 -128} {a14 8 True -1 0 -1} {a14 9 True 0\ -0 0} {a14 10 True 1 0 1} {a14 11 True 127 0 127} {a14 12 True 128 0 128} {a14\ -13 True 255 0 255} {a14 14 True 256 0 256} {a14 15 True 32767 0 32767} {a14 16\ -False 32768 0 -32768} {a14 17 False 65535 0 -1} {a14 18 False 65536 0 0} {a14\ -19 False 2147483647 0 -1} {a14 20 False 2147483648 0 0} {a14 21 False\ -4294967295 0 -1} {a14 22 False 4294967296 0 0} {a14 23 False\ -9223372036854775807 0 -1} {a14 24 False 9223372036854775808 0 0} {a14 25 False\ -18446744073709551615 0 0} {a14 26 False 18446744073709551616 0 0} {a15 0 False\ --9223372036854775809 0 0} {a15 1 False -9223372036854775808 0 0} {a15 2 False\ --2147483649 0 2147483647} {a15 3 True -2147483648 0 -2147483648} {a15 4 True\ --32769 0 -32769} {a15 5 True -32768 0 -32768} {a15 6 True -129 0 -129} {a15 7\ -True -128 0 -128} {a15 8 True -1 0 -1} {a15 9 True 0 0 0} {a15 10 True 1 0 1}\ -{a15 11 True 127 0 127} {a15 12 True 128 0 128} {a15 13 True 255 0 255} {a15 14\ -True 256 0 256} {a15 15 True 32767 0 32767} {a15 16 True 32768 0 32768} {a15 17\ -True 65535 0 65535} {a15 18 True 65536 0 65536} {a15 19 True 2147483647 0\ -2147483647} {a15 20 False 2147483648 0 -2147483648} {a15 21 False 4294967295 0\ --1} {a15 22 False 4294967296 0 0} {a15 23 False 9223372036854775807 0 -1} {a15\ -24 False 9223372036854775808 0 0} {a15 25 False 18446744073709551615 0 0} {a15\ -26 False 18446744073709551616 0 0} {a16 0 False -9223372036854775809 0\ --9223372036854775808} {a16 1 True -9223372036854775808 0 -9223372036854775808}\ -{a16 2 True -2147483649 0 -2147483649} {a16 3 True -2147483648 0 -2147483648}\ -{a16 4 True -32769 0 -32769} {a16 5 True -32768 0 -32768} {a16 6 True -129 0\ --129} {a16 7 True -128 0 -128} {a16 8 True -1 0 -1} {a16 9 True 0 0 0} {a16 10\ -True 1 0 1} {a16 11 True 127 0 127} {a16 12 True 128 0 128} {a16 13 True 255 0\ -255} {a16 14 True 256 0 256} {a16 15 True 32767 0 32767} {a16 16 True 32768 0\ -32768} {a16 17 True 65535 0 65535} {a16 18 True 65536 0 65536} {a16 19 True\ -2147483647 0 2147483647} {a16 20 True 2147483648 0 2147483648} {a16 21 True\ -4294967295 0 4294967295} {a16 22 True 4294967296 0 4294967296} {a16 23 True\ -9223372036854775807 0 9223372036854775807} {a16 24 False 9223372036854775808 0\ --9223372036854775808} {a16 25 False 18446744073709551615 0\ --9223372036854775808} {a16 26 False 18446744073709551616 0\ --9223372036854775808} {a17 0 False -9223372036854775809 0 -9223372036854775808}\ -{a17 1 True -9223372036854775808 0 -9223372036854775808} {a17 2 True\ --2147483649 0 -2147483649} {a17 3 True -2147483648 0 -2147483648} {a17 4 True\ --32769 0 -32769} {a17 5 True -32768 0 -32768} {a17 6 True -129 0 -129} {a17 7\ -True -128 0 -128} {a17 8 True -1 0 -1} {a17 9 True 0 0 0} {a17 10 True 1 0 1}\ -{a17 11 True 127 0 127} {a17 12 True 128 0 128} {a17 13 True 255 0 255} {a17 14\ -True 256 0 256} {a17 15 True 32767 0 32767} {a17 16 True 32768 0 32768} {a17 17\ -True 65535 0 65535} {a17 18 True 65536 0 65536} {a17 19 True 2147483647 0\ -2147483647} {a17 20 True 2147483648 0 2147483648} {a17 21 True 4294967295 0\ -4294967295} {a17 22 True 4294967296 0 4294967296} {a17 23 True\ -9223372036854775807 0 9223372036854775807} {a17 24 False 9223372036854775808 0\ --9223372036854775808} {a17 25 False 18446744073709551615 0\ --9223372036854775808} {a17 26 False 18446744073709551616 0\ --9223372036854775808} {a18 0 False -9223372036854775809 0 0} {a18 1 False\ --9223372036854775808 0 0} {a18 2 False -2147483649 0 -1} {a18 3 False\ --2147483648 0 0} {a18 4 False -32769 0 32767} {a18 5 True -32768 0 -32768} {a18\ -6 True -129 0 -129} {a18 7 True -128 0 -128} {a18 8 True -1 0 -1} {a18 9 True 0\ -0 0} {a18 10 True 1 0 1} {a18 11 True 127 0 127} {a18 12 True 128 0 128} {a18\ -13 True 255 0 255} {a18 14 True 256 0 256} {a18 15 True 32767 0 32767} {a18 16\ -False 32768 0 -32768} {a18 17 False 65535 0 -1} {a18 18 False 65536 0 0} {a18\ -19 False 2147483647 0 -1} {a18 20 False 2147483648 0 0} {a18 21 False\ -4294967295 0 -1} {a18 22 False 4294967296 0 0} {a18 23 False\ -9223372036854775807 0 -1} {a18 24 False 9223372036854775808 0 0} {a18 25 False\ -18446744073709551615 0 0} {a18 26 False 18446744073709551616 0 0} {a19 0 False\ --9223372036854775809 0 0} {a19 1 False -9223372036854775808 0 0} {a19 2 False\ --2147483649 0 65535} {a19 3 False -2147483648 0 0} {a19 4 False -32769 0 32767}\ -{a19 5 False -32768 0 32768} {a19 6 False -129 0 65407} {a19 7 False -128 0\ -65408} {a19 8 False -1 0 65535} {a19 9 True 0 0 0} {a19 10 True 1 0 1} {a19 11\ -True 127 0 127} {a19 12 True 128 0 128} {a19 13 True 255 0 255} {a19 14 True\ -256 0 256} {a19 15 True 32767 0 32767} {a19 16 True 32768 0 32768} {a19 17 True\ -65535 0 65535} {a19 18 False 65536 0 0} {a19 19 False 2147483647 0 65535} {a19\ -20 False 2147483648 0 0} {a19 21 False 4294967295 0 65535} {a19 22 False\ -4294967296 0 0} {a19 23 False 9223372036854775807 0 65535} {a19 24 False\ -9223372036854775808 0 0} {a19 25 False 18446744073709551615 0 0} {a19 26 False\ -18446744073709551616 0 0} {a20 0 False -9223372036854775809 0 0} {a20 1 False\ --9223372036854775808 0 0} {a20 2 False -2147483649 0 255} {a20 3 False\ --2147483648 0 0} {a20 4 False -32769 0 255} {a20 5 False -32768 0 0} {a20 6\ -False -129 0 127} {a20 7 False -128 0 128} {a20 8 False -1 0 255} {a20 9 True 0\ -0 0} {a20 10 True 1 0 1} {a20 11 True 127 0 127} {a20 12 True 128 0 128} {a20\ -13 True 255 0 255} {a20 14 False 256 0 0} {a20 15 False 32767 0 255} {a20 16\ -False 32768 0 0} {a20 17 False 65535 0 255} {a20 18 False 65536 0 0} {a20 19\ -False 2147483647 0 255} {a20 20 False 2147483648 0 0} {a20 21 False 4294967295\ -0 255} {a20 22 False 4294967296 0 0} {a20 23 False 9223372036854775807 0 255}\ -{a20 24 False 9223372036854775808 0 0} {a20 25 False 18446744073709551615 0 0}\ -{a20 26 False 18446744073709551616 0 0} {a21 0 False -9223372036854775809 0 0}\ -{a21 1 False -9223372036854775808 0 0} {a21 2 False -2147483649 0 -1} {a21 3\ -False -2147483648 0 0} {a21 4 False -32769 0 -1} {a21 5 False -32768 0 0} {a21\ -6 False -129 0 127} {a21 7 True -128 0 -128} {a21 8 True -1 0 -1} {a21 9 True 0\ -0 0} {a21 10 True 1 0 1} {a21 11 True 127 0 127} {a21 12 False 128 0 -128} {a21\ -13 False 255 0 -1} {a21 14 False 256 0 0} {a21 15 False 32767 0 -1} {a21 16\ -False 32768 0 0} {a21 17 False 65535 0 -1} {a21 18 False 65536 0 0} {a21 19\ -False 2147483647 0 -1} {a21 20 False 2147483648 0 0} {a21 21 False 4294967295 0\ --1} {a21 22 False 4294967296 0 0} {a21 23 False 9223372036854775807 0 -1} {a21\ -24 False 9223372036854775808 0 0} {a21 25 False 18446744073709551615 0 0} {a21\ -26 False 18446744073709551616 0 0} {a22 0 False -9223372036854775809 0 0} {a22\ -1 False -9223372036854775808 0 0} {a22 2 False -2147483649 0 2147483647} {a22 3\ -False -2147483648 0 2147483648} {a22 4 False -32769 0 4294934527} {a22 5 False\ --32768 0 4294934528} {a22 6 False -129 0 4294967167} {a22 7 False -128 0\ -4294967168} {a22 8 False -1 0 4294967295} {a22 9 True 0 0 0} {a22 10 True 1 0\ -1} {a22 11 True 127 0 127} {a22 12 True 128 0 128} {a22 13 True 255 0 255} {a22\ -14 True 256 0 256} {a22 15 True 32767 0 32767} {a22 16 True 32768 0 32768} {a22\ -17 True 65535 0 65535} {a22 18 True 65536 0 65536} {a22 19 True 2147483647 0\ -2147483647} {a22 20 True 2147483648 0 2147483648} {a22 21 True 4294967295 0\ -4294967295} {a22 22 False 4294967296 0 0} {a22 23 False 9223372036854775807 0\ -4294967295} {a22 24 False 9223372036854775808 0 0} {a22 25 False\ -18446744073709551615 0 0} {a22 26 False 18446744073709551616 0 0} {a23 0 False\ --9223372036854775809 0 0} {a23 1 False -9223372036854775808 0 0} {a23 2 False\ --2147483649 0 255} {a23 3 False -2147483648 0 0} {a23 4 False -32769 0 255}\ -{a23 5 False -32768 0 0} {a23 6 False -129 0 127} {a23 7 False -128 0 128} {a23\ -8 False -1 0 255} {a23 9 True 0 0 0} {a23 10 True 1 0 1} {a23 11 True 127 0\ -127} {a23 12 True 128 0 128} {a23 13 True 255 0 255} {a23 14 False 256 0 0}\ -{a23 15 False 32767 0 255} {a23 16 False 32768 0 0} {a23 17 False 65535 0 255}\ -{a23 18 False 65536 0 0} {a23 19 False 2147483647 0 255} {a23 20 False\ -2147483648 0 0} {a23 21 False 4294967295 0 255} {a23 22 False 4294967296 0 0}\ -{a23 23 False 9223372036854775807 0 255} {a23 24 False 9223372036854775808 0 0}\ -{a23 25 False 18446744073709551615 0 0} {a23 26 False 18446744073709551616 0 0}\ -{a24 0 False -9223372036854775809 0 0} {a24 1 False -9223372036854775808 0 0}\ -{a24 2 False -2147483649 0 65535} {a24 3 False -2147483648 0 0} {a24 4 False\ --32769 0 32767} {a24 5 False -32768 0 32768} {a24 6 False -129 0 65407} {a24 7\ -False -128 0 65408} {a24 8 False -1 0 65535} {a24 9 True 0 0 0} {a24 10 True 1\ -0 1} {a24 11 True 127 0 127} {a24 12 True 128 0 128} {a24 13 True 255 0 255}\ -{a24 14 True 256 0 256} {a24 15 True 32767 0 32767} {a24 16 True 32768 0 32768}\ -{a24 17 True 65535 0 65535} {a24 18 False 65536 0 0} {a24 19 False 2147483647 0\ -65535} {a24 20 False 2147483648 0 0} {a24 21 False 4294967295 0 65535} {a24 22\ -False 4294967296 0 0} {a24 23 False 9223372036854775807 0 65535} {a24 24 False\ -9223372036854775808 0 0} {a24 25 False 18446744073709551615 0 0} {a24 26 False\ -18446744073709551616 0 0} {a25 0 False -9223372036854775809 0 0} {a25 1 False\ --9223372036854775808 0 0} {a25 2 False -2147483649 0 2147483647} {a25 3 False\ --2147483648 0 2147483648} {a25 4 False -32769 0 4294934527} {a25 5 False -32768\ -0 4294934528} {a25 6 False -129 0 4294967167} {a25 7 False -128 0 4294967168}\ -{a25 8 False -1 0 4294967295} {a25 9 True 0 0 0} {a25 10 True 1 0 1} {a25 11\ -True 127 0 127} {a25 12 True 128 0 128} {a25 13 True 255 0 255} {a25 14 True\ -256 0 256} {a25 15 True 32767 0 32767} {a25 16 True 32768 0 32768} {a25 17 True\ -65535 0 65535} {a25 18 True 65536 0 65536} {a25 19 True 2147483647 0\ -2147483647} {a25 20 True 2147483648 0 2147483648} {a25 21 True 4294967295 0\ -4294967295} {a25 22 False 4294967296 0 0} {a25 23 False 9223372036854775807 0\ -4294967295} {a25 24 False 9223372036854775808 0 0} {a25 25 False\ -18446744073709551615 0 0} {a25 26 False 18446744073709551616 0 0} {a26 0 False\ --9223372036854775809 0 9223372036854775808} {a26 1 False -9223372036854775808 0\ -9223372036854775808} {a26 2 False -2147483649 0 18446744071562067967} {a26 3\ -False -2147483648 0 18446744071562067968} {a26 4 False -32769 0\ -18446744073709518847} {a26 5 False -32768 0 18446744073709518848} {a26 6 False\ --129 0 18446744073709551487} {a26 7 False -128 0 18446744073709551488} {a26 8\ -False -1 0 18446744073709551615} {a26 9 True 0 0 0} {a26 10 True 1 0 1} {a26 11\ -True 127 0 127} {a26 12 True 128 0 128} {a26 13 True 255 0 255} {a26 14 True\ -256 0 256} {a26 15 True 32767 0 32767} {a26 16 True 32768 0 32768} {a26 17 True\ -65535 0 65535} {a26 18 True 65536 0 65536} {a26 19 True 2147483647 0\ -2147483647} {a26 20 True 2147483648 0 2147483648} {a26 21 True 4294967295 0\ -4294967295} {a26 22 True 4294967296 0 4294967296} {a26 23 True\ -9223372036854775807 0 9223372036854775807} {a26 24 True 9223372036854775808 0\ -9223372036854775808} {a26 25 False 18446744073709551615 0 9223372036854775808}\ -{a26 26 False 18446744073709551616 0 9223372036854775808} {a27 0 False\ --9223372036854775809 0 9223372036854775808} {a27 1 False -9223372036854775808 0\ -9223372036854775808} {a27 2 False -2147483649 0 18446744071562067967} {a27 3\ -False -2147483648 0 18446744071562067968} {a27 4 False -32769 0\ -18446744073709518847} {a27 5 False -32768 0 18446744073709518848} {a27 6 False\ --129 0 18446744073709551487} {a27 7 False -128 0 18446744073709551488} {a27 8\ -False -1 0 18446744073709551615} {a27 9 True 0 0 0} {a27 10 True 1 0 1} {a27 11\ -True 127 0 127} {a27 12 True 128 0 128} {a27 13 True 255 0 255} {a27 14 True\ -256 0 256} {a27 15 True 32767 0 32767} {a27 16 True 32768 0 32768} {a27 17 True\ -65535 0 65535} {a27 18 True 65536 0 65536} {a27 19 True 2147483647 0\ -2147483647} {a27 20 True 2147483648 0 2147483648} {a27 21 True 4294967295 0\ -4294967295} {a27 22 True 4294967296 0 4294967296} {a27 23 True\ -9223372036854775807 0 9223372036854775807} {a27 24 True 9223372036854775808 0\ -9223372036854775808} {a27 25 False 18446744073709551615 0 9223372036854775808}\ -{a27 26 False 18446744073709551616 0 9223372036854775808} {a28 0 False\ --9223372036854775809 0 9223372036854775808} {a28 1 False -9223372036854775808 0\ -9223372036854775808} {a28 2 False -2147483649 0 18446744071562067967} {a28 3\ -False -2147483648 0 18446744071562067968} {a28 4 False -32769 0\ -18446744073709518847} {a28 5 False -32768 0 18446744073709518848} {a28 6 False\ --129 0 18446744073709551487} {a28 7 False -128 0 18446744073709551488} {a28 8\ -False -1 0 18446744073709551615} {a28 9 True 0 0 0} {a28 10 True 1 0 1} {a28 11\ -True 127 0 127} {a28 12 True 128 0 128} {a28 13 True 255 0 255} {a28 14 True\ -256 0 256} {a28 15 True 32767 0 32767} {a28 16 True 32768 0 32768} {a28 17 True\ -65535 0 65535} {a28 18 True 65536 0 65536} {a28 19 True 2147483647 0\ -2147483647} {a28 20 True 2147483648 0 2147483648} {a28 21 True 4294967295 0\ -4294967295} {a28 22 True 4294967296 0 4294967296} {a28 23 True\ -9223372036854775807 0 9223372036854775807} {a28 24 True 9223372036854775808 0\ -9223372036854775808} {a28 25 False 18446744073709551615 0 9223372036854775808}\ -{a28 26 False 18446744073709551616 0 9223372036854775808} {a29 0 False\ --9223372036854775809 0 0} {a29 1 False -9223372036854775808 0 0} {a29 2 False\ --2147483649 0 255} {a29 3 False -2147483648 0 0} {a29 4 False -32769 0 255}\ -{a29 5 False -32768 0 0} {a29 6 False -129 0 127} {a29 7 False -128 0 128} {a29\ -8 False -1 0 255} {a29 9 True 0 0 0} {a29 10 True 1 0 1} {a29 11 True 127 0\ -127} {a29 12 True 128 0 128} {a29 13 True 255 0 255} {a29 14 False 256 0 0}\ -{a29 15 False 32767 0 255} {a29 16 False 32768 0 0} {a29 17 False 65535 0 255}\ -{a29 18 False 65536 0 0} {a29 19 False 2147483647 0 255} {a29 20 False\ -2147483648 0 0} {a29 21 False 4294967295 0 255} {a29 22 False 4294967296 0 0}\ -{a29 23 False 9223372036854775807 0 255} {a29 24 False 9223372036854775808 0 0}\ -{a29 25 False 18446744073709551615 0 0} {a29 26 False 18446744073709551616 0 0}\ -{a30 0 False -9223372036854775809 0 0} {a30 1 False -9223372036854775808 0 0}\ -{a30 2 False -2147483649 0 65535} {a30 3 False -2147483648 0 0} {a30 4 False\ --32769 0 32767} {a30 5 False -32768 0 32768} {a30 6 False -129 0 65407} {a30 7\ -False -128 0 65408} {a30 8 False -1 0 65535} {a30 9 True 0 0 0} {a30 10 True 1\ -0 1} {a30 11 True 127 0 127} {a30 12 True 128 0 128} {a30 13 True 255 0 255}\ -{a30 14 True 256 0 256} {a30 15 True 32767 0 32767} {a30 16 True 32768 0 32768}\ -{a30 17 True 65535 0 65535} {a30 18 False 65536 0 0} {a30 19 False 2147483647 0\ -65535} {a30 20 False 2147483648 0 0} {a30 21 False 4294967295 0 65535} {a30 22\ -False 4294967296 0 0} {a30 23 False 9223372036854775807 0 65535} {a30 24 False\ -9223372036854775808 0 0} {a30 25 False 18446744073709551615 0 0} {a30 26 False\ -18446744073709551616 0 0} {a31 0 False -9223372036854775809 0 0} {a31 1 False\ --9223372036854775808 0 0} {a31 2 False -2147483649 0 2147483647} {a31 3 False\ --2147483648 0 2147483648} {a31 4 False -32769 0 4294934527} {a31 5 False -32768\ -0 4294934528} {a31 6 False -129 0 4294967167} {a31 7 False -128 0 4294967168}\ -{a31 8 False -1 0 4294967295} {a31 9 True 0 0 0} {a31 10 True 1 0 1} {a31 11\ -True 127 0 127} {a31 12 True 128 0 128} {a31 13 True 255 0 255} {a31 14 True\ -256 0 256} {a31 15 True 32767 0 32767} {a31 16 True 32768 0 32768} {a31 17 True\ -65535 0 65535} {a31 18 True 65536 0 65536} {a31 19 True 2147483647 0\ -2147483647} {a31 20 True 2147483648 0 2147483648} {a31 21 True 4294967295 0\ -4294967295} {a31 22 False 4294967296 0 0} {a31 23 False 9223372036854775807 0\ -4294967295} {a31 24 False 9223372036854775808 0 0} {a31 25 False\ -18446744073709551615 0 0} {a31 26 False 18446744073709551616 0 0} {a32 0 False\ --9223372036854775809 0 9223372036854775808} {a32 1 False -9223372036854775808 0\ -9223372036854775808} {a32 2 False -2147483649 0 18446744071562067967} {a32 3\ -False -2147483648 0 18446744071562067968} {a32 4 False -32769 0\ -18446744073709518847} {a32 5 False -32768 0 18446744073709518848} {a32 6 False\ --129 0 18446744073709551487} {a32 7 False -128 0 18446744073709551488} {a32 8\ -False -1 0 18446744073709551615} {a32 9 True 0 0 0} {a32 10 True 1 0 1} {a32 11\ -True 127 0 127} {a32 12 True 128 0 128} {a32 13 True 255 0 255} {a32 14 True\ -256 0 256} {a32 15 True 32767 0 32767} {a32 16 True 32768 0 32768} {a32 17 True\ -65535 0 65535} {a32 18 True 65536 0 65536} {a32 19 True 2147483647 0\ -2147483647} {a32 20 True 2147483648 0 2147483648} {a32 21 True 4294967295 0\ -4294967295} {a32 22 True 4294967296 0 4294967296} {a32 23 True\ -9223372036854775807 0 9223372036854775807} {a32 24 True 9223372036854775808 0\ -9223372036854775808} {a32 25 False 18446744073709551615 0 9223372036854775808}\ -{a32 26 False 18446744073709551616 0 9223372036854775808}}} - -############################################################################### - -runTest {test tkt-c010fa6584-1.2 {UInt32 parameter} -setup { - setupDb [set fileName tkt-c010fa6584-1.2.db] -} -body { - sql execute $db "CREATE TABLE t1(x UINT32);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 UInt32 0xFFFFFFFF] - - sql execute -execute scalar $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{4294967295}} - -############################################################################### - -runTest {test tkt-c010fa6584-1.3 {UInt32 parameter (Int64)} -setup { - setupDb [set fileName tkt-c010fa6584-1.3.db] -} -body { - sql execute $db "CREATE TABLE t1(x INTEGER);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 UInt32 0xFFFFFFFF] - - sql execute -execute scalar $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{-1}} - -############################################################################### - -runTest {test tkt-c010fa6584-1.4 {UInt32 parameter (Int64) w/flag} -setup { - setupDb [set fileName tkt-c010fa6584-1.4.db] "" "" "" BindUInt32AsInt64 -} -body { - sql execute $db "CREATE TABLE t1(x INTEGER);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 UInt32 0xFFFFFFFF] - - sql execute -execute scalar $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{4294967295}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue DELETED Tests/tkt-e06c4caff3.eagle Index: Tests/tkt-e06c4caff3.eagle ================================================================== --- Tests/tkt-e06c4caff3.eagle +++ /dev/null @@ -1,99 +0,0 @@ -############################################################################### -# -# tkt-e06c4caff3.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-e06c4caff3-1.1 {NaN to NULL constraint failure} -setup { - setupDb [set fileName tkt-e06c4caff3-1.1.db] -} -body { - sql execute $db "CREATE TABLE t1(x REAL NOT NULL);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 Double [set NaN [object invoke Double NaN]]] -} -cleanup { - cleanupDb $fileName - - unset -nocomplain NaN db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ --returnCodes 1 -match regexp -result [string map [list \n \r\n]\ -{^System\.Data\.SQLite\.SQLiteException \(0x80004005\): constraint failed -t1\.x may not be NULL -.*$}]} - -############################################################################### - -runTest {test tkt-e06c4caff3-1.2 {NaN to NULL} -setup { - setupDb [set fileName tkt-e06c4caff3-1.2.db] -} -body { - sql execute $db "CREATE TABLE t1(x REAL);" - - sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 Double [set NaN [object invoke Double NaN]]] - - sql execute -execute reader -format list $db "SELECT x FROM t1;" -} -cleanup { - cleanupDb $fileName - - unset -nocomplain NaN db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \ --result {}} - -############################################################################### - -runTest {test tkt-e06c4caff3-1.3 {NaN w/BindAllAsText} -setup { - setupDb [set fileName tkt-e06c4caff3-1.3.db] "" "" "" BindAllAsText -} -body { - sql execute $db "CREATE TABLE t1(x REAL NOT NULL);" - - list [sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 Double [set NaN [object invoke Double NaN]]]] \ - [sql execute -execute reader -format list $db "SELECT x FROM t1;"] -} -cleanup { - cleanupDb $fileName - - unset -nocomplain NaN db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{1 0}} - -############################################################################### - -runTest {test tkt-e06c4caff3-1.4 {NaN w/BindAllAsText & GetAllAsText} -setup { - setupDb [set fileName tkt-e06c4caff3-1.4.db] "" "" "" BindAndGetAllAsText -} -body { - sql execute $db "CREATE TABLE t1(x REAL NOT NULL);" - - list [sql execute $db "INSERT INTO t1 (x) VALUES(?);" \ - [list param1 Double [set NaN [object invoke Double NaN]]]] \ - [sql execute -execute reader -format list $db "SELECT x FROM t1;"] -} -cleanup { - cleanupDb $fileName - - unset -nocomplain NaN db fileName -} -constraints \ -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \ -{1 NaN}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/tkt-e1b2e0f769.eagle ================================================================== --- Tests/tkt-e1b2e0f769.eagle +++ Tests/tkt-e1b2e0f769.eagle @@ -122,13 +122,13 @@ cleanupDb $fileName unset -nocomplain result2 result1 code results errors sql table dataSource \ id x db fileName } -constraints \ -[fixConstraints {eagle monoBug28 command.sql compile.DATA SQLite\ -!defineConstant.System.Data.SQLite.CHECK_STATE System.Data.SQLite}] -match \ -regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 3 Ok\ +{eagle monoBug28 !defineConstant.System.Data.SQLite.CHECK_STATE command.sql\ +compile.DATA SQLite System.Data.SQLite} -match regexp -result {^Ok\ +System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 3 Ok\ System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}} ############################################################################### runSQLiteTestEpilogue DELETED Tests/tkt-e47b3d8346.eagle Index: Tests/tkt-e47b3d8346.eagle ================================================================== --- Tests/tkt-e47b3d8346.eagle +++ /dev/null @@ -1,45 +0,0 @@ -############################################################################### -# -# tkt-e47b3d8346.eagle -- -# -# Written by Joe Mistachkin. -# Released to the public domain, use at your own risk! -# -############################################################################### - -package require Eagle -package require Eagle.Library -package require Eagle.Test - -runTestPrologue - -############################################################################### - -package require System.Data.SQLite.Test -runSQLiteTestPrologue - -############################################################################### - -runTest {test tkt-e47b3d8346-1.1 {parse semi-colon in data source} -setup { - unset -nocomplain result list pair -} -body { - set result [list] - - set list [object invoke -flags +NonPublic \ - System.Data.SQLite.SQLiteConnection ParseConnectionString \ - {Data Source="C:\full\path\to\file.db;more.data.here";}] - - object foreach -alias pair $list { - lappend result [list [$pair Key] [$pair Value]] - } - - set result -} -cleanup { - unset -nocomplain result list pair -} -constraints {eagle System.Data.SQLite} -result \ -{{{Data Source} {C:\full\path\to\file.db;more.data.here}}}} - -############################################################################### - -runSQLiteTestEpilogue -runTestEpilogue Index: Tests/version.eagle ================================================================== --- Tests/version.eagle +++ Tests/version.eagle @@ -27,11 +27,11 @@ # numbers must be manually kept synchronized with the version numbers for # the source code files, the built binaries, and the release packages. # set version(major) 1 set version(minor) 0 -set version(build) 86; # NOTE: Incremented with each release. +set version(build) 83; # NOTE: Incremented with each release. set version(revision) 0 ############################################################################### # ********************* END VOLATILE VERSION INFORMATION ********************** ############################################################################### @@ -176,12 +176,10 @@ ] \ [appendArgs [string map [list . \\.] $version(full)] \ ] \ [appendArgs [string map [list . \\.] $version(full)] \ ] \ - [appendArgs [string map [list . \\.] $version(full)] \ - ] \ [appendArgs Version= [string map [list . \\.] $version(full)] ,] \ [appendArgs "\; [format %03d $version(build)] "\;] \ [appendArgs AssemblyVersion\\(\" [string map [list . \\.] \ $version(full)] \"\\)] \ [appendArgs AssemblyFileVersion\\(\" [string map [list . \\.] \ @@ -243,11 +241,10 @@ $version(full)] \"\\)]] set fileNames [list \ readme.htm \ SQLite.nuspec \ - SQLite.Beta.nuspec \ SQLite.MSIL.nuspec \ SQLite.x64.nuspec \ SQLite.x86.nuspec \ [file join Doc Extra dbfactorysupport.html] \ [file join Doc Extra welcome.html] \ Index: exclude_bin.txt ================================================================== --- exclude_bin.txt +++ exclude_bin.txt @@ -1,7 +1,6 @@ *.done *.exp *.lib *.map -*.mda.config *EnvDTE.* *Microsoft.* Index: exclude_src.txt ================================================================== --- exclude_src.txt +++ exclude_src.txt @@ -1,17 +1,14 @@ *.cache *.chw *.docstates *.fossil -*.mistachkin.eagle *.ncb *.nupkg -*.pdb *.suo *.user *.zip -.fossil-settings/* _FOSSIL_ bin/* Doc/Output/* Externals/Eagle/bin/Eagle.dll Externals/Eagle/bin/EagleShell.exe @@ -36,12 +33,12 @@ Membership/* Membership/obj/* Membership/Profile/* Membership/SiteMap/* obj/* -Setup/Output/* Setup/set_user_*.bat +Setup/Output/* SQLite.Designer/obj/* SQLite.Designer/Properties/* SQLite.Designer/VSDesign/* System.Data.SQLite.Linq/obj/* System.Data.SQLite/obj/* Index: readme.htm ================================================================== --- readme.htm +++ readme.htm @@ -3,12 +3,12 @@ ADO.NET SQLite Data Provider
    -Version 1.0.86.0 May XX, 2013 (release scheduled)
    -Using SQLite 3.7.17
    +Version 1.0.83.0 December XX, 2012 (release scheduled)
    +Using SQLite 3.7.15
    Originally written by Robert Simpson
    Released to the public domain, use at your own risk!
    Official provider website: http://system.data.sqlite.org/
    Legacy versions: http://sqlite.phxsoftware.com/

    @@ -49,13 +49,13 @@ support both binary and cleartext password types.
  8. Visual Studio design-time Support, works with all versions of Visual Studio - 2005/2008/2010/2012. You can add a SQLite database to the Servers list, - design queries with the Query Designer, drag-and-drop tables onto a Typed - DataSet, etc. + 2005/2008/2010. You can add a SQLite database to the Servers list, design + queries with the Query Designer, drag-and-drop tables onto a Typed DataSet, + etc.
    Due to Visual Studio licensing restrictions, the Express Editions can no longer be supported. @@ -144,11 +144,11 @@ <configuration> <system.data> <DbProviderFactories> <remove invariant="System.Data.SQLite" /> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" - type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.86.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" /> + type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.83.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" /> </DbProviderFactories> </system.data> </configuration>

    @@ -185,64 +185,18 @@

    Version History

    - 1.0.86.0 - May XX, 2013 (release scheduled) -

    -
      -
    • Updated to SQLite 3.7.17.
    • -
    • Disable use of the AllowPartiallyTrustedCallers attribute when compiled for the .NET Framework 4.0/4.5.
    • -
    • Allow semi-colons in the data source file name. Fix for [e47b3d8346].
    • -
    • NULL values should be reported as type "object", not "DBNull". Fix for [48a6b8e4ca].
    • -
    -

    - 1.0.85.0 - April 18, 2013 -

    -
      -
    • Updated to SQLite 3.7.16.2.
    • -
    • Properly handle embedded NUL characters in parameter and column values. Fix for [3567020edf].
    • -
    • Make use of the sqlite3_prepare_v2 function when applicable.
    • -
    • Check for a valid row in the SQLiteDataReader.GetValue method.
    • -
    • Implement processor architecture detection when running on the .NET Compact Framework (via P/Invoke).
    • -
    • Support automated testing when running on the .NET Compact Framework 2.0.
    • -
    • Skip checking loaded assemblies for types tagged with the SQLiteFunction attribute when the No_SQLiteFunctions environment variable is set. Pursuant to [e4c8121f7b].
    • -
    • Add HexPassword connection string property to work around the inability to include a literal semicolon in a connection string property value. Pursuant to [1c456ae75f].
    • -
    • Add static Execute method to the SQLiteCommand class.
    • -
    • Support custom connection pool implementations by adding the ISQLiteConnectionPool interface, the static SQLiteConnection.ConnectionPool property, and the static CreateHandle method in addition to modifying the SQLiteConnectionPool class. Pursuant to [393d954be0].
    • -
    • Add public constructor to the SQLiteDataAdapter class that allows passing the parseViaFramework parameter to the SQLiteConnection constructor.
    • -
    • When built with the CHECK_STATE compile-time option, skip throwing exceptions from the SQLiteDataReader class when the object is being disposed.
    • -
    • Support automatic value conversions for columns with a declared type of BIGUINT, INTEGER8, INTEGER16, INTEGER32, INTEGER64, SMALLUINT, TINYSINT, UNSIGNEDINTEGER, UNSIGNEDINTEGER8, UNSIGNEDINTEGER16, UNSIGNEDINTEGER32, UNSIGNEDINTEGER64, INT8, INT16, INT32, INT64, UINT, UINT8, UINT16, UINT32, UINT64, or ULONG.
    • -
    • Add BindUInt32AsInt64 connection flag to force binding of UInt32 values as Int64 instead. Pursuant to [c010fa6584].
    • -
    • Add BindAllAsText and GetAllAsText connection flags to force binding and returning of all values as text.
    • -
    • Remove AUTOINCREMENT from the column type name map. ** Potentially Incompatible Change **
    • -
    • Avoid throwing overflow exceptions from the SQLite3.GetValue method for integral column types. Partial fix for [c010fa6584]. ** Potentially Incompatible Change **
    • -
    • Use the legacy connection closing algorithm when built with the INTEROP_LEGACY_CLOSE compile-time option.
    • -
    • Support using the directory containing the primary managed-only assembly as the basis for native library pre-loading.
    • -
    • Still further enhancements to the build and test automation.
    • -
    -

    - 1.0.84.0 - January 9, 2013 -

    -
      -
    • Updated to SQLite 3.7.15.2.
    • -
    • Explicitly dispose of all SQLiteCommand objects managed by the DbDataAdapter class. Fix for [6434e23a0f].
    • -
    • Add Cancel method to the SQLiteConnection class to interrupt a long running query.
    • -
    • Improve thread safety of the SQLiteLog.LogMessage method.
    • -
    -

    - 1.0.83.0 - December 29, 2012 -

    -
      -
    • Updated to SQLite 3.7.15.1.
    • + 1.0.83.0 - December XX, 2012 +

      +
        +
      • Updated to SQLite 3.7.15.
      • Add Visual Studio 2012 support to all the applicable solution/project files, their associated supporting files, and the test suite.
      • Add Visual Studio 2012 support to the redesigned designer support installer.
      • Allow opened connections to skip adding the extension functions included in the interop assembly via the new NoExtensionFunctions connection flag.
      • Support loading of SQLite extensions via the new EnableExtensions and LoadExtension methods of the SQLiteConnection class. Pursuant to [17045010df].
      • -
      • Remove one set of surrounding single or double quotes from property names and values parsed from the connection string. Fix for [b4cc611998].
      • -
      • Modify parsing of connection strings to allow property names and values to be quoted. ** Potentially Incompatible Change **
      • -
      • Add ParseViaFramework property to the SQLiteConnection class to allow the built-in (i.e. framework provided) connection string parser to be used when opening a connection. Pursuant to [b4cc611998].
      • Add notifications before and after any connection is opened and closed, as well as other related notifications, via the new static Changed event.
      • Add an overload of the SQLiteLog.LogMessage method that takes a single string parameter.
      • Add an overload of the SQLiteConnection.LogMessage method that takes a SQLiteErrorCode parameter.
      • All applicable calls into the SQLite core library now return a SQLiteErrorCode instead of an integer error code.
      • Make sure the error code of the SQLiteException class gets serialized.
      • @@ -252,19 +206,15 @@
      • The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code. ** Potentially Incompatible Change **
      • The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden. ** Potentially Incompatible Change **
      • The ErrorCode field of the LogEventArgs is now an object instead of an integer. ** Potentially Incompatible Change **
      • The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library. ** Potentially Incompatible Change **
      • Implement more robust locking semantics for the CriticalHandle derived classes when compiled for the .NET Compact Framework.
      • -
      • Cache column indexes as they are looked up when using the SQLiteDataReader to improve performance.
      • +
      • Cache column indexes are they are looked up when using the SQLiteDataReader to improve performance.
      • Prevent the SQLiteConnection.Close method from throwing non-fatal exceptions during its disposal.
      • Rename the interop assembly functions sqlite3_cursor_rowid, sqlite3_context_collcompare, sqlite3_context_collseq, sqlite3_cursor_rowid, and sqlite3_table_cursor to include an "_interop" suffix. ** Potentially Incompatible Change **
      • Prevent the LastInsertRowId, MemoryUsed, and MemoryHighwater connection properties from throwing NotSupportedException when running on the .NET Compact Framework. Fix for [dd45aba387].
      • -
      • Improve automatic detection of the sqlite3_close_v2 function when compiled to use the standard SQLite library.
      • Add protection against ThreadAbortException asynchronously interrupting native resource initialization and finalization.
      • -
      • Add native logging callback for use with the sqlite3_log function to the interop assembly, enabled via the INTEROP_LOG preprocessor definition.
      • -
      • Add various diagnostic messages to the interop assembly, enabled via flags in the INTEROP_DEBUG preprocessor definition.
      • -
      • Further enhancements to the build and test automation.
      • Add test automation for the Windows CE binaries.

      1.0.82.0 - September 3, 2012

      Index: test/AssemblyInfo.cs ================================================================== --- test/AssemblyInfo.cs +++ test/AssemblyInfo.cs @@ -36,7 +36,7 @@ // Major Version // Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("1.0.86.0")] -[assembly: AssemblyFileVersion("1.0.86.0")] +[assembly: AssemblyVersion("1.0.83.0")] +[assembly: AssemblyFileVersion("1.0.83.0")] Index: test/TestCases.cs ================================================================== --- test/TestCases.cs +++ test/TestCases.cs @@ -20,14 +20,12 @@ private const int NumThreads = 8; private const int ThreadTimeout = 60000; private List droptables = new List(); private List maydroptable = new List(); - -#if !INTEROP_LOG private long logevents = 0; -#endif + internal TestCases() { } @@ -1363,11 +1361,11 @@ bool failed = false; Exception e = null; for (int n = 0; n < arr.Length; n++) { - if (!arr[n].t.Join(ThreadTimeout / arr.Length)) + if (arr[n].t.Join(0) == false) { failed = true; arr[n].t.Abort(); arr[n].t.Join(); } @@ -1629,11 +1627,10 @@ cnn.Close(); } } -#if !INTEROP_LOG //Logging EventHandler public void OnLogEvent(object sender, LogEventArgs logEvent) { object errorCode = logEvent.ErrorCode; string err_msg = logEvent.Message; @@ -1671,11 +1668,10 @@ // remove the log handler before the connection is closed. sqlite_fact.Log -= logHandler; } } -#endif /// /// Open a reader and then attempt to write to test the writer's command timeout property /// SQLite doesn't allow a write when a reader is active. /// *** NOTE AS OF 3.3.8 this test no longer blocks because SQLite now allows you to update table(s) Index: test/TestCasesDialog.cs ================================================================== --- test/TestCasesDialog.cs +++ test/TestCasesDialog.cs @@ -60,11 +60,11 @@ ToolStripMenuItem item = (ToolStripMenuItem)testMenu.DropDownItems.Add(pair.Key, null, new EventHandler(_tests_Clicked)); item.Checked = true; item.CheckOnClick = true; } - this.Shown += new EventHandler(TestCasesDialog_Shown); + this.Load += new EventHandler(TestCasesDialog_Load); } private StringBuilder GridToText() { StringBuilder result = new StringBuilder(); @@ -79,21 +79,20 @@ } return result; } - void TestCasesDialog_Shown(object sender, EventArgs e) + void TestCasesDialog_Load(object sender, EventArgs e) { // // NOTE: In "automatic" mode, run all the tests as soon as the form is // fully loaded. // if (_autoRun) { BeginInvoke(new DelegateWithNoArgs(delegate() { - Hide(); runButton_Click(sender, e); })); } } Index: test/app.config ================================================================== --- test/app.config +++ test/app.config @@ -1,8 +1,8 @@ - + Index: test/test.2005.csproj ================================================================== --- test/test.2005.csproj +++ test/test.2005.csproj @@ -80,11 +80,10 @@ -

       

  9. - - - - - - - - @@ -273,109 +253,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + +
    - Runtime Library Notes -
    - All downloadable packages on this web page that do not include - the word "static" in their file name require the - appropriate version (e.g. 2005, 2008, 2010, or 2012) of the Microsoft - Visual C++ Runtime Library, to be successfully installed on the target - machine, prior to making use of the executables contained therein. It - should also be noted that the downloadable packages on this web page - that include the word "setup" (i.e. the setup packages) - already include and will attempt to automatically install the required - version of the Microsoft Visual C++ Runtime Library. -
    Support Notes
      - sqlite-netFx-source-1.0.85.0.zip + sqlite-netFx-source-1.0.82.0.zip
    - (2.92 MiB) + (2.74 MiB)
    This ZIP archive contains all current source code for System.Data.SQLite - 1.0.85.0 (3.7.16.2) combined into a single archive file. -
    - (sha1: 207847e48263aabb2da02501f7d92d32ed72a6d7) -
    - Setups for 32-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-setup-bundle-x86-2005-1.0.85.0.exe -
    - (4.09 MiB) -
    - This setup package features the mixed-mode assembly and will install all - the necessary runtime components and dependencies for the x86 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 - SP1 runtime for x86 is included. The .NET Framework 2.0 SP2 is - required. -
    - This setup package is capable of installing the design-time - components for Visual Studio 2005. -
    - (sha1: 87ff1451509b9acf24c0be117f9bc89b2f301e19) -
      - sqlite-netFx20-setup-x86-2005-1.0.85.0.exe -
    - (4.09 MiB) -
    - This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x86 is included. - The .NET Framework 2.0 SP2 is required. -
    - (sha1: 76c222be7227e84dee1f1f37df3eb0eba7eef5be) -
    - Setups for 64-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-setup-bundle-x64-2005-1.0.85.0.exe -
    - (4.66 MiB) -
    - This setup package features the mixed-mode assembly and will install all - the necessary runtime components and dependencies for the x64 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 - SP1 runtime for x64 is included. The .NET Framework 2.0 SP2 is - required. -
    - (sha1: d8ae5c4a755d920d09dcab4fcb22bfb8cc54172e) -
      - sqlite-netFx20-setup-x64-2005-1.0.85.0.exe -
    - (4.66 MiB) -
    - This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x64 is included. - The .NET Framework 2.0 SP2 is required. -
    - (sha1: 537b1f59752354076bebd7555cc0c32d7c2f3708) + 1.0.82.0 (3.7.14) combined into a single archive file. +
    + (sha1: accec84da4a59815078e494afd398eb1b3c64898)
    @@ -384,44 +275,44 @@
      - sqlite-netFx35-setup-bundle-x86-2008-1.0.85.0.exe + sqlite-netFx35-setup-bundle-x86-2008-1.0.82.0.exe
    - (6.12 MiB) + (6.07 MiB)
    This setup package features the mixed-mode assembly and will install all the necessary runtime components and dependencies for the x86 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 + the System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 is included. The .NET Framework 3.5 SP1 is required.
    This setup package is capable of installing the design-time - components for Visual Studio 2008. + components for Visual Studio 2005 and/or Visual Studio 2008.
    - (sha1: 47c50ba1ec9bd8c57770e68550b8914642c5c5ae) + (sha1: e38165e4f45e4338d81f2da10050826406aa09b8)
      - sqlite-netFx35-setup-x86-2008-1.0.85.0.exe + sqlite-netFx35-setup-x86-2008-1.0.82.0.exe
    - (6.12 MiB) + (6.06 MiB)
    This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x86 is included. + dependencies for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 is included. The .NET Framework 3.5 SP1 is required.
    - (sha1: 5a9ba8366ab82a8cd5e9180171261caad41dd3a9) + (sha1: aed2059188e2ab66a341ce5167b2316c751fdbb1)
    @@ -430,41 +321,41 @@
      - sqlite-netFx35-setup-bundle-x64-2008-1.0.85.0.exe + sqlite-netFx35-setup-bundle-x64-2008-1.0.82.0.exe
    - (6.86 MiB) + (6.81 MiB)
    This setup package features the mixed-mode assembly and will install all the necessary runtime components and dependencies for the x64 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 + the System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 is included. The .NET Framework 3.5 SP1 is required.
    - (sha1: 50502a4ca7fe2b70f24e84e0ef21ee92818d59bd) + (sha1: aa0f1f958f9febf466807d79f03fae31508993dd)
      - sqlite-netFx35-setup-x64-2008-1.0.85.0.exe + sqlite-netFx35-setup-x64-2008-1.0.82.0.exe
    - (6.85 MiB) + (6.80 MiB)
    This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x64 is included. + dependencies for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 is included. The .NET Framework 3.5 SP1 is required.
    - (sha1: 9645ba0f5d4b62bbb72c9034a6524d45dc3603ae) + (sha1: b5fa5e9c3477a44724356816488ca3fa15a11d4b)
    @@ -473,43 +364,43 @@
      - sqlite-netFx40-setup-bundle-x86-2010-1.0.85.0.exe + sqlite-netFx40-setup-bundle-x86-2010-1.0.82.0.exe
    - (10.45 MiB) + (10.40 MiB)
    This setup package features the mixed-mode assembly and will install all the necessary runtime components and dependencies for the x86 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 + the System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 is included. The .NET Framework 4.0 is required.
    This setup package is capable of installing the design-time components for Visual Studio 2010.
    - (sha1: f6118c219c118008d221b73b2a0e81f281121fe1) + (sha1: bf3defd3b4250e1aa94ea06e10c4b369416d0e2a)
      - sqlite-netFx40-setup-x86-2010-1.0.85.0.exe + sqlite-netFx40-setup-x86-2010-1.0.82.0.exe
    - (10.44 MiB) + (10.39 MiB)
    This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x86 is included. + dependencies for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 is included. The .NET Framework 4.0 is required.
    - (sha1: 0e7753b4e10def666d5bf0aa8030bccaf2f53dc1) + (sha1: 8435fe9fd02655d3df95991e68391d487f6a8776)
    @@ -518,211 +409,40 @@
      - sqlite-netFx40-setup-bundle-x64-2010-1.0.85.0.exe -
    - (11.70 MiB) -
    - This setup package features the mixed-mode assembly and will install all - the necessary runtime components and dependencies for the x64 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 - SP1 runtime for x64 is included. The .NET Framework 4.0 is required. -
    - (sha1: 9b0e4dab2af6606e8290d1baef76319ff71755bf) -
      - sqlite-netFx40-setup-x64-2010-1.0.85.0.exe -
    - (11.70 MiB) -
    - This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x64 is included. - The .NET Framework 4.0 is required. -
    - (sha1: aabefcc62aebd81977d438337b6e6f1f3eec750c) -
    - Setups for 32-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-setup-bundle-x86-2012-1.0.85.0.exe -
    - (7.86 MiB) -
    - This setup package features the mixed-mode assembly and will install all - the necessary runtime components and dependencies for the x86 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x86 is included. The .NET Framework 4.5 is - required. -
    - This setup package is capable of installing the design-time - components for Visual Studio 2012. -
    - (sha1: 25976834544664f83a06c189bf5441512586b3a3) -
      - sqlite-netFx45-setup-x86-2012-1.0.85.0.exe -
    - (7.90 MiB) -
    - This setup package will install all the necessary runtime components and - dependencies for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x86 is - included. The .NET Framework 4.5 is required. -
    - (sha1: 0622135aa0a8befb551e67df50813ea36300eecf) -
    - Setups for 64-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-setup-bundle-x64-2012-1.0.85.0.exe -
    - (8.51 MiB) -
    - This setup package features the mixed-mode assembly and will install all - the necessary runtime components and dependencies for the x64 version of - the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x64 is included. The .NET Framework 4.5 is - required. -
    - (sha1: c5e57ebccc8ffb88dc8ec7423d5d8454170ba962) -
      - sqlite-netFx45-setup-x64-2012-1.0.85.0.exe -
    - (8.56 MiB) -
    - This setup package will install all the necessary runtime components and - dependencies for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x64 is - included. The .NET Framework 4.5 is required. -
    - (sha1: 70dd7721ee041bef789a11714fb58afbb9859c7f) -
    - Precompiled Binaries for 32-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-binary-bundle-Win32-2005-1.0.85.0.zip -
    - (1.25 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x86 and the .NET - Framework 2.0 SP2 are required. -
    - (sha1: d7935c29beb3d280297cf03920d60aadc40240b7) -
      - sqlite-netFx20-binary-Win32-2005-1.0.85.0.zip -
    - (1.24 MiB) -
    - This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 SP1 - runtime for x86 and the .NET Framework 2.0 SP2 are required. -
    - (sha1: c34c916023573e021fb6f819d68ef5895506f596) -
    - Precompiled Binaries for 64-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-binary-bundle-x64-2005-1.0.85.0.zip -
    - (1.43 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x64 and the .NET - Framework 2.0 SP2 are required. -
    - (sha1: 08968e09c936adb41b640b54c3b99ef5a82baff6) -
      - sqlite-netFx20-binary-x64-2005-1.0.85.0.zip -
    - (1.43 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 SP1 - runtime for x64 and the .NET Framework 2.0 SP2 are required. -
    - (sha1: 2ce43d049aff0046d2dd6f6014844803d5bdd645) + sqlite-netFx40-setup-bundle-x64-2010-1.0.82.0.exe +
    + (11.65 MiB) +
    + This setup package features the mixed-mode assembly and will install all + the necessary runtime components and dependencies for the x64 version of + the System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 + SP1 runtime for x64 is included. The .NET Framework 4.0 is required. +
    + (sha1: a7fcc7d410df97817eabbbc6f01e1e448f898aab) +
      + sqlite-netFx40-setup-x64-2010-1.0.82.0.exe +
    + (11.64 MiB) +
    + This setup package will install all the necessary runtime components and + dependencies for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x64 is included. + The .NET Framework 4.0 is required. +
    + (sha1: 0c3d227a1b3c0f3aae1a0b687f17dba18bed6eeb)
    @@ -731,39 +451,39 @@
      - sqlite-netFx35-binary-bundle-Win32-2008-1.0.85.0.zip + sqlite-netFx35-binary-bundle-Win32-2008-1.0.82.0.zip
    - (1.69 MiB) + (1.66 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x86 and the .NET + the binaries for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 and the .NET Framework 3.5 SP1 are required.
    - (sha1: 49300394f8d5c3bf9b0b1ee6763c868920d116aa) + (sha1: cf6ec0622af7a16c5cf32c02d41a29060b91ec79)
      - sqlite-netFx35-binary-Win32-2008-1.0.85.0.zip + sqlite-netFx35-binary-Win32-2008-1.0.82.0.zip
    - (1.69 MiB) + (1.65 MiB)
    This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 and the .NET Framework 3.5 SP1 are required.
    - (sha1: a03cf9b20e862cf22facac6f8e6f1cb492305e7e) + (sha1: 5e4724570d0a9e49450d2c0aac0601db4bebed11)
    @@ -772,39 +492,39 @@
      - sqlite-netFx35-binary-bundle-x64-2008-1.0.85.0.zip + sqlite-netFx35-binary-bundle-x64-2008-1.0.82.0.zip
    - (1.76 MiB) + (1.73 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x64 and the .NET + the binaries for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 and the .NET Framework 3.5 SP1 are required.
    - (sha1: 7fe9ec83c421be0ad0cef2217d97b911df7888c1) + (sha1: 15b5625a7f5fa1a4a74c61c0c46e3969d2c6adc2)
      - sqlite-netFx35-binary-x64-2008-1.0.85.0.zip + sqlite-netFx35-binary-x64-2008-1.0.82.0.zip
    - (1.76 MiB) + (1.72 MiB)
    This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 and the .NET Framework 3.5 SP1 are required.
    - (sha1: 566ac48ebb5b2018024244531d4ce4840dc842cd) + (sha1: 25abc0ea78f8f45b93c9c2fc1381c2acd863638d)
    @@ -813,39 +533,39 @@
      - sqlite-netFx40-binary-bundle-Win32-2010-1.0.85.0.zip + sqlite-netFx40-binary-bundle-Win32-2010-1.0.82.0.zip
    - (1.74 MiB) + (1.71 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x86 and the .NET + the binaries for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 and the .NET Framework 4.0 are required.
    - (sha1: df88785d092d49799875ff17432c74928a45d098) + (sha1: 6f6cdfddb08f254b744e7088b4825db02bec73da)
      - sqlite-netFx40-binary-Win32-2010-1.0.85.0.zip + sqlite-netFx40-binary-Win32-2010-1.0.82.0.zip
    - (1.73 MiB) + (1.70 MiB)
    This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 and the .NET Framework 4.0 are required.
    - (sha1: 13581537c7ffe8bb14929db913f4fdfdf0e895b5) + (sha1: 12ffe8323fcf5af25ef6e6effb4f52300df819ee)
    @@ -854,205 +574,39 @@
      - sqlite-netFx40-binary-bundle-x64-2010-1.0.85.0.zip -
    - (1.77 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x64 and the .NET - Framework 4.0 are required. -
    - (sha1: 869c3a6b132d955b6a7ff48c0162b3fe93664ac8) -
      - sqlite-netFx40-binary-x64-2010-1.0.85.0.zip -
    - (1.76 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 SP1 - runtime for x64 and the .NET Framework 4.0 are required. -
    - (sha1: 63d2314938e0717dd012f748764867548ea75e3d) -
    - Precompiled Binaries for 32-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-binary-bundle-Win32-2012-1.0.85.0.zip -
    - (1.67 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x86 and - the .NET Framework 4.5 are required. -
    - (sha1: 8e87791682524d215956eb509d58e054a4c1ba4d) -
      - sqlite-netFx45-binary-Win32-2012-1.0.85.0.zip + sqlite-netFx40-binary-bundle-x64-2010-1.0.82.0.zip +
    + (1.73 MiB) +
    + This binary package features the mixed-mode assembly and contains all + the binaries for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x64 and the .NET + Framework 4.0 are required. +
    + (sha1: e1b79aa7763853a68068f43c9edb6382a2c67550) +
      + sqlite-netFx40-binary-x64-2010-1.0.82.0.zip
    (1.72 MiB)
    - This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x86 and the .NET Framework 4.5 are required. -
    - (sha1: 35ed300d763562762e5d3629ede7671dfd554540) -
    - Precompiled Binaries for 64-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-binary-bundle-x64-2012-1.0.85.0.zip -
    - (1.70 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x64 and - the .NET Framework 4.5 are required. -
    - (sha1: 5cfd307031cd3c24e6000187b8c76878a87f6ddb) -
      - sqlite-netFx45-binary-x64-2012-1.0.85.0.zip -
    - (1.77 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x64 and the .NET Framework 4.5 are required. -
    - (sha1: 017c3a11a1c47df55fb559dd1b0793fca4651094) -
    - Precompiled Statically-Linked Binaries for 32-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-static-binary-bundle-Win32-2005-1.0.85.0.zip -
    - (1.46 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x86 is statically - linked. The .NET Framework 2.0 SP2 is required. -
    - (sha1: a2829911a1a7743c980f3ca5169df3f7fa018211) -
      - sqlite-netFx20-static-binary-Win32-2005-1.0.85.0.zip -
    - (1.45 MiB) -
    - This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 SP1 - runtime for x86 is statically linked. The .NET Framework 2.0 SP2 is - required. -
    - (sha1: d9c897ea3723cdbc71f9a75fbe7d0bc965b17466) -
    - Precompiled Statically-Linked Binaries for 64-bit Windows (.NET Framework 2.0 SP2) -
      - sqlite-netFx20-static-binary-bundle-x64-2005-1.0.85.0.zip -
    - (1.59 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2005 SP1 runtime for x64 is statically - linked. The .NET Framework 2.0 SP2 is required. -
    - (sha1: 3c9c599e8db46f7aa72bd763aabf8afbd024e720) -
      - sqlite-netFx20-static-binary-x64-2005-1.0.85.0.zip -
    - (1.58 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2005 SP1 - runtime for x64 is statically linked. The .NET Framework 2.0 SP2 is - required. -
    - (sha1: 56dc3929ad82e6ed1a54d0bd33c5f1dd7abcbba7) + This binary package contains all the binaries for the x64 version of the + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 SP1 + runtime for x64 and the .NET Framework 4.0 are required. +
    + (sha1: a91739243166b9ae27be244722acd480d1ce4537)
    @@ -1061,40 +615,40 @@
      - sqlite-netFx35-static-binary-bundle-Win32-2008-1.0.85.0.zip + sqlite-netFx35-static-binary-bundle-Win32-2008-1.0.82.0.zip
    - (1.91 MiB) + (1.87 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x86 is statically + the binaries for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 is statically linked. The .NET Framework 3.5 SP1 is required.
    - (sha1: db8ce18c645e94287d6e763f60196d4829715cef) + (sha1: 43076280a7ee02b1574bb666d3a14c185d6fe84a)
      - sqlite-netFx35-static-binary-Win32-2008-1.0.85.0.zip + sqlite-netFx35-static-binary-Win32-2008-1.0.82.0.zip
    - (1.90 MiB) + (1.86 MiB)
    This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x86 is statically linked. The .NET Framework 3.5 SP1 is required.
    - (sha1: 2af8c9eb950fabe9b5cf2fb0030072f7c17e1e10) + (sha1: 44f8225d4025d2014ded056b31a2b1a5a8de07cc)
    @@ -1103,40 +657,40 @@
      - sqlite-netFx35-static-binary-bundle-x64-2008-1.0.85.0.zip + sqlite-netFx35-static-binary-bundle-x64-2008-1.0.82.0.zip
    - (1.94 MiB) + (1.90 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2008 SP1 runtime for x64 is statically + the binaries for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 is statically linked. The .NET Framework 3.5 SP1 is required.
    - (sha1: b6363097a1a84b206e5872a2371ec17a5e095fd6) + (sha1: 1e29c539c75e106ddbdd18c83563fc0b9df7c1bf)
      - sqlite-netFx35-static-binary-x64-2008-1.0.85.0.zip + sqlite-netFx35-static-binary-x64-2008-1.0.82.0.zip
    - (1.93 MiB) + (1.90 MiB)
    This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2008 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2008 SP1 runtime for x64 is statically linked. The .NET Framework 3.5 SP1 is required.
    - (sha1: bbb10041650407bc226d8c54a666bb3ae7367a26) + (sha1: f10532c9c858465852d179dc88ea6c519212234f)
    @@ -1145,40 +699,40 @@
      - sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.85.0.zip + sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.82.0.zip
    - (1.95 MiB) + (1.92 MiB)
    This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x86 is statically + the binaries for the x86 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 is statically linked. The .NET Framework 4.0 is required.
    - (sha1: dfdcc4babf4a8800ab23cb36199ead8571c2f829) + (sha1: 335da5c15d56b868f948dbf842ad97c94c5c148c)
      - sqlite-netFx40-static-binary-Win32-2010-1.0.85.0.zip + sqlite-netFx40-static-binary-Win32-2010-1.0.82.0.zip
    - (1.95 MiB) + (1.91 MiB)
    This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 SP1 + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 SP1 runtime for x86 is statically linked. The .NET Framework 4.0 is required.
    - (sha1: 5fb0371dff6a5e282632524aaeda1c99591b261c) + (sha1: 22d21e6b97b9b79cd51528fda938e3d601eb1ae4)
    @@ -1187,124 +741,40 @@
      - sqlite-netFx40-static-binary-bundle-x64-2010-1.0.85.0.zip -
    - (1.96 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2010 SP1 runtime for x64 is statically - linked. The .NET Framework 4.0 is required. -
    - (sha1: c46e03f5d633009777875602d83306d82f4b0697) -
      - sqlite-netFx40-static-binary-x64-2010-1.0.85.0.zip -
    - (1.95 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2010 SP1 - runtime for x64 is statically linked. The .NET Framework 4.0 is - required. -
    - (sha1: 75d6095789cc9fc9106354163de462a67eeedf1d) -
    - Precompiled Statically-Linked Binaries for 32-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-static-binary-bundle-Win32-2012-1.0.85.0.zip -
    - (2.00 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x86 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x86 is - statically linked. The .NET Framework 4.5 is required. -
    - (sha1: 2575dbd7f184de6f207aade4f77db41e23e2fcaa) -
      - sqlite-netFx45-static-binary-Win32-2012-1.0.85.0.zip -
    - (2.04 MiB) -
    - This binary package contains all the binaries for the x86 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x86 is statically linked. The .NET Framework 4.5 - is required. -
    - (sha1: 3ce80cc9423b04d304cfed16092ea1f4af204fdf) -
    - Precompiled Statically-Linked Binaries for 64-bit Windows (.NET Framework 4.5) -
      - sqlite-netFx45-static-binary-bundle-x64-2012-1.0.85.0.zip -
    - (1.96 MiB) -
    - This binary package features the mixed-mode assembly and contains all - the binaries for the x64 version of the System.Data.SQLite 1.0.85.0 - (3.7.16.2) package. The Visual C++ 2012 Update 1 runtime for x64 is - statically linked. The .NET Framework 4.5 is required. -
    - (sha1: 048a9863a1244df5450b79112069f064a38056bd) -
      - sqlite-netFx45-static-binary-x64-2012-1.0.85.0.zip -
    - (2.03 MiB) -
    - This binary package contains all the binaries for the x64 version of the - System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The Visual C++ 2012 - Update 1 runtime for x64 is statically linked. The .NET Framework 4.5 - is required. -
    - (sha1: d2ba962b8bb8020afb425aa2a9892fe6ab183ba5) + sqlite-netFx40-static-binary-bundle-x64-2010-1.0.82.0.zip +
    + (1.92 MiB) +
    + This binary package features the mixed-mode assembly and contains all + the binaries for the x64 version of the System.Data.SQLite 1.0.82.0 + (3.7.14) package. The Visual C++ 2010 SP1 runtime for x64 is statically + linked. The .NET Framework 4.0 is required. +
    + (sha1: 929f1d2a0eb9bb697c4e8725bedef1f4042c076b) +
      + sqlite-netFx40-static-binary-x64-2010-1.0.82.0.zip +
    + (1.92 MiB) +
    + This binary package contains all the binaries for the x64 version of the + System.Data.SQLite 1.0.82.0 (3.7.14) package. The Visual C++ 2010 SP1 + runtime for x64 is statically linked. The .NET Framework 4.0 is + required. +
    + (sha1: 4c12b0ad3aae3510bd573e49a6159f6a3405d312)
    @@ -1313,21 +783,21 @@
      - sqlite-netFx35-binary-PocketPC-ARM-2008-1.0.85.0.zip + sqlite-netFx35-binary-PocketPC-2008-1.0.82.0.zip
    - (0.89 MiB) + (0.85 MiB)
    This binary package contains all the binaries for the PocketPC version - of the System.Data.SQLite 1.0.85.0 (3.7.16.2) package. The .NET Compact + of the System.Data.SQLite 1.0.82.0 (3.7.14) package. The .NET Compact Framework 3.5 is required.
    - (sha1: 45c8575f917f8c263f64ca7eb32d210f35be0fcf) + (sha1: f9b2393dde3ad5d2f507ebad26d2b81ea7544b70)
    @@ -1336,83 +806,83 @@
      - System.Data.SQLite.1.0.85.0.nupkg + System.Data.SQLite.1.0.82.0.nupkg
    - (3.22 MiB) + (2.85 MiB)
    This NuGet package contains all the binaries for both the x86 and x64 - versions of System.Data.SQLite 1.0.85.0 (3.7.16.2). The .NET Framework - 3.5 SP1, 4.0, or 4.5 is required. For the included native binaries, the + versions of System.Data.SQLite 1.0.82.0 (3.7.14). The .NET Framework + 3.5 SP1 or 4.0 is required. For the included native binaries, the version of the Visual C++ runtime corresponding to the .NET Framework used by the associated managed assembly is statically linked.
    - (sha1: 4eec87ae7ee6ff063f7acbbf0c83fc95f7a21577) + (sha1: 00192e51c6dda124d809c517125c99e46f7de620)
      - System.Data.SQLite.MSIL.1.0.85.0.nupkg + System.Data.SQLite.MSIL.1.0.82.0.nupkg
    - (0.33 MiB) + (0.26 MiB)
    This NuGet package contains the managed binaries for System.Data.SQLite - 1.0.85.0. The .NET Framework 3.5 SP1, 4.0, or 4.5 is required. + 1.0.82.0. The .NET Framework 3.5 SP1 or 4.0 is required.
    This NuGet package does not include any code from the native SQLite core library and will not work properly without the native assembly "SQLite.Interop.dll" compiled for the processor architecture of the host process being present in a directory in the native library search path.
    - (sha1: 9dbd464e7c670f15a2d081800788bd6c533cbd11) + (sha1: 8d62c9ff2e22fac2ee0040f6fda49b270e7f27a3)
      - System.Data.SQLite.x86.1.0.85.0.nupkg + System.Data.SQLite.x86.1.0.82.0.nupkg
    - (1.61 MiB) + (1.47 MiB)
    This NuGet package contains all the binaries for the x86 version of - System.Data.SQLite 1.0.85.0 (3.7.16.2). The .NET Framework 3.5 SP1, - 4.0, or 4.5 is required. For the included native binaries, the version - of the Visual C++ runtime corresponding to the .NET Framework used by - the associated managed assembly is statically linked. + System.Data.SQLite 1.0.82.0 (3.7.14). The .NET Framework 3.5 SP1 or 4.0 + is required. For the included native binaries, the version of the + Visual C++ runtime corresponding to the .NET Framework used by the + associated managed assembly is statically linked.
    - (sha1: a237094a8ce47d761bb4464844882d04f3a57223) + (sha1: 598242655955a8827cdab065d4224db8341782fc)
      - System.Data.SQLite.x64.1.0.85.0.nupkg + System.Data.SQLite.x64.1.0.82.0.nupkg
    - (1.82 MiB) + (1.67 MiB)
    This NuGet package contains all the binaries for the x64 version of - System.Data.SQLite 1.0.85.0 (3.7.16.2). The .NET Framework 3.5 SP1, - 4.0, or 4.5 is required. For the included native binaries, the version - of the Visual C++ runtime corresponding to the .NET Framework used by - the associated managed assembly is statically linked. + System.Data.SQLite 1.0.82.0 (3.7.14). The .NET Framework 3.5 SP1 or 4.0 + is required. For the included native binaries, the version of the + Visual C++ runtime corresponding to the .NET Framework used by the + associated managed assembly is statically linked.
    - (sha1: 95f076822086e3138e44e24e5daf7f01cd207e3d) + (sha1: 1d0a1646f469ea63e74c9ad0778f9911dbde4d30)
    @@ -1451,12 +921,10 @@
  10. sqlite-framework-binary-platform-year-version.zip
  11. sqlite-framework-binary-bundle-platform-year-version.zip
  12. sqlite-framework-static-binary-platform-year-version.zip
  13. sqlite-framework-static-binary-bundle-platform-year-version.zip
  14. sqlite-netFx-source-date.zip
  15. -
  16. System.Data.SQLite.version.nupkg
  17. -
  18. System.Data.SQLite.variant.version.nupkg
  19. Templates (1) and (2) are used for source-code packages. Template (1) is @@ -1468,11 +936,10 @@ binary package containing the mixed-mode assembly. Template (7) is used for the precompiled binary package statically linked to the Visual C++ runtime. Template (8) is used for the precompiled binary package containing the mixed-mode assembly statically linked to the Visual C++ runtime. Template (9) is used for unofficial pre-release "snapshots" of source code. - Templates (10) and (11) are used for the official NuGet packages.

    The framework in templates (3), (4), (5), (6), (7), and (8) will be one of netFx20, netFx35, netFx40, netFx45. @@ -1482,11 +949,11 @@ The cpu in templates (3) and (4) will be one of x86, x64, arm, ia64.

    The platform in templates (5), (6), (7), and (8) will be one of - Win32, x64, PocketPC, PocketPC-ARM, PocketPC-x86. + Win32, x64, PocketPC.

    The year in templates (3), (4), (5), (6), (7), and (8) will be one of 2005, 2008, 2010, 2012. @@ -1500,14 +967,10 @@

    The date in template (9) is of the form: YYYYMMDDHHMM

    -

    - The variant in template (11) will be one of Beta, MSIL, x86, x64. -

    -

    Canonical Source Code

    The canonical System.Data.SQLite source code is maintained in a Fossil repository that is available for anonymous read-only access. Anyone can view Index: www/faq.wiki ================================================================== --- www/faq.wiki +++ www/faq.wiki @@ -102,16 +102,10 @@ inside Visual Studio, why do I get a DllNotFoundException or a BadImageFormatException (for "sqlite3.dll" or "SQLite.Interop.dll") when trying to run or debug the application? -
    -

  20. - Is this behavior a bug? -OR- Is there a quick way to - view the various lists of tickets for the System.Data.SQLite project? - -

  21. @@ -490,35 +484,5 @@ "Win32" for 32-bit Windows and "x64" for 64-bit Windows). Therefore, it is good practice to double-check the selected build platform against the operating system prior to attempting to run a managed project in the solution.

    - -
    - -

    - (21) Is this behavior a bug? -OR- Is there a quick way to view the various - lists of tickets for the System.Data.SQLite project? -

    - -

    - If any behavior is observed that appears to be a bug, it may be reported via - the sqlite-users public - mailing list or by filing a ticket. Prior - to taking one of these steps, it is always prudent to check the various lists - of previously filed tickets to see if the behavior being observed has already - been reported and possibly fixed in a subsequent release. -

      -
    1. - The list of tickets actively being worked on. -
    2. -
    3. - The list of tickets currently open. -
    4. -
    5. - The list of tickets fixed and then closed. -
    6. -
    7. - The list of tickets closed without needing a fix. -
    8. -
    -

    Index: www/index.wiki ================================================================== --- www/index.wiki +++ www/index.wiki @@ -32,19 +32,10 @@

    Please refer to the download page for a complete list of downloadable packages and information on their use.

    -

    - The current documentation for all public types, methods, properties, - and events is checked into the repository, in - - Microsoft Compiled HTML Help ("CHM") format. It - can also be - - downloaded directly via the web interface to the repository. -

    Index: www/news.wiki ================================================================== --- www/news.wiki +++ www/news.wiki @@ -1,64 +1,18 @@ News Version History

    - 1.0.86.0 - May XX, 2013 (release scheduled) -

    -
      -
    • Updated to [http://www.sqlite.org/src/info/trunk|SQLite 3.7.17].
    • -
    • Disable use of the AllowPartiallyTrustedCallers attribute when compiled for the .NET Framework 4.0/4.5.
    • -
    • Allow semi-colons in the data source file name. Fix for [e47b3d8346].
    • -
    • NULL values should be reported as type "object", not "DBNull". Fix for [48a6b8e4ca].
    • -
    -

    - 1.0.85.0 - April 18, 2013 -

    -
      -
    • Updated to [http://www.sqlite.org/releaselog/3_7_16_2.html|SQLite 3.7.16.2].
    • -
    • Properly handle embedded NUL characters in parameter and column values. Fix for [3567020edf].
    • -
    • Make use of the sqlite3_prepare_v2 function when applicable.
    • -
    • Check for a valid row in the SQLiteDataReader.GetValue method.
    • -
    • Implement processor architecture detection when running on the .NET Compact Framework (via P/Invoke).
    • -
    • Support automated testing when running on the .NET Compact Framework 2.0.
    • -
    • Skip checking loaded assemblies for types tagged with the SQLiteFunction attribute when the No_SQLiteFunctions environment variable is set. Pursuant to [e4c8121f7b].
    • -
    • Add HexPassword connection string property to work around the inability to include a literal semicolon in a connection string property value. Pursuant to [1c456ae75f].
    • -
    • Add static Execute method to the SQLiteCommand class.
    • -
    • Support custom connection pool implementations by adding the ISQLiteConnectionPool interface, the static SQLiteConnection.ConnectionPool property, and the static CreateHandle method in addition to modifying the SQLiteConnectionPool class. Pursuant to [393d954be0].
    • -
    • Add public constructor to the SQLiteDataAdapter class that allows passing the parseViaFramework parameter to the SQLiteConnection constructor.
    • -
    • When built with the CHECK_STATE compile-time option, skip throwing exceptions from the SQLiteDataReader class when the object is being disposed.
    • -
    • Support automatic value conversions for columns with a declared type of BIGUINT, INTEGER8, INTEGER16, INTEGER32, INTEGER64, SMALLUINT, TINYSINT, UNSIGNEDINTEGER, UNSIGNEDINTEGER8, UNSIGNEDINTEGER16, UNSIGNEDINTEGER32, UNSIGNEDINTEGER64, INT8, INT16, INT32, INT64, UINT, UINT8, UINT16, UINT32, UINT64, or ULONG.
    • -
    • Add BindUInt32AsInt64 connection flag to force binding of UInt32 values as Int64 instead. Pursuant to [c010fa6584].
    • -
    • Add BindAllAsText and GetAllAsText connection flags to force binding and returning of all values as text.
    • -
    • Remove AUTOINCREMENT from the column type name map. ** Potentially Incompatible Change **
    • -
    • Avoid throwing overflow exceptions from the SQLite3.GetValue method for integral column types. Partial fix for [c010fa6584]. ** Potentially Incompatible Change **
    • -
    • Use the legacy connection closing algorithm when built with the INTEROP_LEGACY_CLOSE compile-time option.
    • -
    • Support using the directory containing the primary managed-only assembly as the basis for native library pre-loading.
    • -
    • Still further enhancements to the build and test automation.
    • -
    -

    - 1.0.84.0 - January 9, 2013 -

    -
      -
    • Updated to [http://www.sqlite.org/releaselog/3_7_15_2.html|SQLite 3.7.15.2].
    • -
    • Explicitly dispose of all SQLiteCommand objects managed by the DbDataAdapter class. Fix for [6434e23a0f].
    • -
    • Add Cancel method to the SQLiteConnection class to interrupt a long running query.
    • -
    • Improve thread safety of the SQLiteLog.LogMessage method.
    • -
    -

    - 1.0.83.0 - December 29, 2012 -

    -
      -
    • Updated to [http://www.sqlite.org/releaselog/3_7_15_1.html|SQLite 3.7.15.1].
    • + 1.0.83.0 - December XX, 2012 (release scheduled) +

      +
        +
      • Updated to [http://www.sqlite.org/src/info/trunk|SQLite 3.7.15].
      • Add Visual Studio 2012 support to all the applicable solution/project files, their associated supporting files, and the test suite.
      • Add Visual Studio 2012 support to the redesigned designer support installer.
      • Allow opened connections to skip adding the extension functions included in the interop assembly via the new NoExtensionFunctions connection flag.
      • Support loading of SQLite extensions via the new EnableExtensions and LoadExtension methods of the SQLiteConnection class. Pursuant to [17045010df].
      • -
      • Remove one set of surrounding single or double quotes from property names and values parsed from the connection string. Fix for [b4cc611998].
      • -
      • Modify parsing of connection strings to allow property names and values to be quoted. ** Potentially Incompatible Change **
      • -
      • Add ParseViaFramework property to the SQLiteConnection class to allow the built-in (i.e. framework provided) connection string parser to be used when opening a connection. Pursuant to [b4cc611998].
      • Add notifications before and after any connection is opened and closed, as well as other related notifications, via the new static Changed event.
      • Add an overload of the SQLiteLog.LogMessage method that takes a single string parameter.
      • Add an overload of the SQLiteConnection.LogMessage method that takes a SQLiteErrorCode parameter.
      • All applicable calls into the SQLite core library now return a SQLiteErrorCode instead of an integer error code.
      • Make sure the error code of the SQLiteException class gets serialized.
      • @@ -68,19 +22,15 @@
      • The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code. ** Potentially Incompatible Change **
      • The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden. ** Potentially Incompatible Change **
      • The ErrorCode field of the LogEventArgs is now an object instead of an integer. ** Potentially Incompatible Change **
      • The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library. ** Potentially Incompatible Change **
      • Implement more robust locking semantics for the CriticalHandle derived classes when compiled for the .NET Compact Framework.
      • -
      • Cache column indexes as they are looked up when using the SQLiteDataReader to improve performance.
      • +
      • Cache column indexes are they are looked up when using the SQLiteDataReader to improve performance.
      • Prevent the SQLiteConnection.Close method from throwing non-fatal exceptions during its disposal.
      • Rename the interop assembly functions sqlite3_cursor_rowid, sqlite3_context_collcompare, sqlite3_context_collseq, sqlite3_cursor_rowid, and sqlite3_table_cursor to include an "_interop" suffix. ** Potentially Incompatible Change **
      • Prevent the LastInsertRowId, MemoryUsed, and MemoryHighwater connection properties from throwing NotSupportedException when running on the .NET Compact Framework. Fix for [dd45aba387].
      • -
      • Improve automatic detection of the sqlite3_close_v2 function when compiled to use the standard SQLite library.
      • Add protection against ThreadAbortException asynchronously interrupting native resource initialization and finalization.
      • -
      • Add native logging callback for use with the sqlite3_log function to the interop assembly, enabled via the INTEROP_LOG preprocessor definition.
      • -
      • Add various diagnostic messages to the interop assembly, enabled via flags in the INTEROP_DEBUG preprocessor definition.
      • -
      • Further enhancements to the build and test automation.
      • Add test automation for the Windows CE binaries.

      1.0.82.0 - September 3, 2012

      Index: www/release.wiki ================================================================== --- www/release.wiki +++ www/release.wiki @@ -97,15 +97,14 @@ automation described in the previous section, skip this section.
    • - Launch Visual Studio 2005, "Professional" edition or - "better" with the bundled Pocket PC 2003 SDK. As of this writing, - in January 2012, Visual Studio 2010 and later will not work as they - do not include the necessary built-in support for Windows CE and the .NET - Compact Framework. + Launch Visual Studio 2008, "Professional" edition or + "better". As of this writing, in January 2012, Visual Studio + 2010 and later will not work as they do not include the necessary + built-in support for Windows CE and the .NET Compact Framework.
    • Open the "SQLite.NET.2008.sln" solution file in the "<root>" directory. @@ -342,22 +341,22 @@

      Publish Release

        -
      1. Upload all the release packages to the web site.
      2. -
      3. Commit pending source code changes to the [http://www.fossil-scm.org/ | Fossil] repository.
      4. Tag the release in the Fossil repository.
      5. + +
      6. Upload all the release packages to the web site.
      7. Push the [http://www.nuget.org/ | NuGet] packages.
        Please refer to [http://docs.nuget.org/ | NuGet Documentation] for further details.
      8. Announce the release on the System.Data.SQLite mailing list.
      Index: www/source.wiki ================================================================== --- www/source.wiki +++ www/source.wiki @@ -2,31 +2,31 @@

      Follow these steps to obtain the latest (i.e. unreleased) source code for the System.Data.SQLite project. To obtain the latest officially released source code instead, refer to the [./downloads.wiki | downloads page]. Unless - otherwise noted, all steps need to be performed in the order specified. + otherwise noted, all steps need to be done in the order specified.

      Assumptions & Prerequisites

      - The string "<root>" represents the directory where the - local working copy of the source tree (a.k.a. the working check-out directory) - for the System.Data.SQLite project is to reside. This should be a completely - empty directory. + The string "<root>" represents the directory where you + would like a local working copy of source tree (a.k.a. the working check-out + directory) for the System.Data.SQLite project to reside (this should be a + completely empty directory).

      The string "<repositories>" represents the directory - where the local clone of the repository for the System.Data.SQLite project - (and potentially other projects) is to reside. + where you would like the local clone of the repository for the + System.Data.SQLite project (and potentially other projects) to reside.

      -

      Obtain & Install Fossil Itself

      +

      Obtain & Install Fossil

      The [http://www.fossil-scm.org | Fossil] open-source [http://en.wikipedia.org/wiki/Distributed_revision_control | distributed version control] system is a computer program that must be installed on your machine before you use it. @@ -53,15 +53,15 @@

    • Enter the following command to create a complete clone (i.e. local copy) of the entire source code repository for the System.Data.SQLite project, including the entire check-in history:  - fossil [http://www.fossil-scm.org/index.html/help/clone | clone] http://system.data.sqlite.org/ <repositories>/sds.fossil + fossil [http://www.fossil-scm.org/index.html/help/clone | clone] http://system.data.sqlite.org/ <repositories>\sds.fossil
    • - Please note that the repository itself uses an + The repository itself uses an [http://www.fossil-scm.org/index.html/doc/trunk/www/fileformat.wiki | enduring file format] stored in a single [http://www.fossil-scm.org/index.html/doc/trunk/www/tech_overview.wiki | SQLite database file] with a particular schema.
    • @@ -86,11 +86,11 @@
    • Enter the following command to create a local working copy of all the files that are currently part of the System.Data.SQLite project:  - fossil [http://www.fossil-scm.org/index.html/help/open | open] <repositories>/sds.fossil + fossil [http://www.fossil-scm.org/index.html/help/open | open] <repositories>\sds.fossil
    • The local source tree should now be ready for use as described in the [./build.wiki | build procedures] and/or [./test.wiki | test procedures]. @@ -98,9 +98,9 @@
    • In the future, to update the local working copy with the latest changes from the official System.Data.SQLite repository (i.e. instead of having to re-clone the entire thing), enter the following command from the same - directory where the working copy is located:  + directory where a working copy is located:  fossil [http://www.fossil-scm.org/index.html/help/update | update]